xref: /aosp_15_r20/external/skia/src/utils/SkBitSet.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkBitSet_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkBitSet_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkMathPriv.h"
14*c8dee2aaSAndroid Build Coastguard Worker 
15*c8dee2aaSAndroid Build Coastguard Worker #include <climits>
16*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
17*c8dee2aaSAndroid Build Coastguard Worker #include <limits>
18*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
19*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
20*c8dee2aaSAndroid Build Coastguard Worker 
21*c8dee2aaSAndroid Build Coastguard Worker class SkBitSet {
22*c8dee2aaSAndroid Build Coastguard Worker public:
SkBitSet(size_t size)23*c8dee2aaSAndroid Build Coastguard Worker     explicit SkBitSet(size_t size)
24*c8dee2aaSAndroid Build Coastguard Worker         : fSize(size)
25*c8dee2aaSAndroid Build Coastguard Worker         , fChunks((Chunk*)sk_calloc_throw(NumChunksFor(fSize) * sizeof(Chunk))) {}
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker     SkBitSet(const SkBitSet&) = delete;
28*c8dee2aaSAndroid Build Coastguard Worker     SkBitSet& operator=(const SkBitSet&) = delete;
SkBitSet(SkBitSet && that)29*c8dee2aaSAndroid Build Coastguard Worker     SkBitSet(SkBitSet&& that) { *this = std::move(that); }
30*c8dee2aaSAndroid Build Coastguard Worker     SkBitSet& operator=(SkBitSet&& that) {
31*c8dee2aaSAndroid Build Coastguard Worker         if (this != &that) {
32*c8dee2aaSAndroid Build Coastguard Worker             this->fSize = that.fSize;
33*c8dee2aaSAndroid Build Coastguard Worker             this->fChunks = std::move(that.fChunks);
34*c8dee2aaSAndroid Build Coastguard Worker             that.fSize = 0;
35*c8dee2aaSAndroid Build Coastguard Worker         }
36*c8dee2aaSAndroid Build Coastguard Worker         return *this;
37*c8dee2aaSAndroid Build Coastguard Worker     }
38*c8dee2aaSAndroid Build Coastguard Worker     ~SkBitSet() = default;
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker     /** Basic equality checks. */
41*c8dee2aaSAndroid Build Coastguard Worker     bool operator==(const SkBitSet& that) {
42*c8dee2aaSAndroid Build Coastguard Worker         if (fSize != that.fSize) {
43*c8dee2aaSAndroid Build Coastguard Worker             return false;
44*c8dee2aaSAndroid Build Coastguard Worker         }
45*c8dee2aaSAndroid Build Coastguard Worker         const size_t numChunks = NumChunksFor(fSize);
46*c8dee2aaSAndroid Build Coastguard Worker         return 0 == memcmp(fChunks.get(), that.fChunks.get(), sizeof(Chunk) * numChunks);
47*c8dee2aaSAndroid Build Coastguard Worker     }
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker     bool operator!=(const SkBitSet& that) {
50*c8dee2aaSAndroid Build Coastguard Worker         return !this->operator==(that);
51*c8dee2aaSAndroid Build Coastguard Worker     }
52*c8dee2aaSAndroid Build Coastguard Worker 
53*c8dee2aaSAndroid Build Coastguard Worker     /** Set the value of the index-th bit to true. */
set(size_t index)54*c8dee2aaSAndroid Build Coastguard Worker     void set(size_t index) {
55*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(index < fSize);
56*c8dee2aaSAndroid Build Coastguard Worker         *this->chunkFor(index) |= ChunkMaskFor(index);
57*c8dee2aaSAndroid Build Coastguard Worker     }
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker     /** Sets every bit in the bitset to true. */
set()60*c8dee2aaSAndroid Build Coastguard Worker     void set() {
61*c8dee2aaSAndroid Build Coastguard Worker         Chunk* chunks = fChunks.get();
62*c8dee2aaSAndroid Build Coastguard Worker         const size_t numChunks = NumChunksFor(fSize);
63*c8dee2aaSAndroid Build Coastguard Worker         std::memset(chunks, 0xFF, sizeof(Chunk) * numChunks);
64*c8dee2aaSAndroid Build Coastguard Worker     }
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker     /** Set the value of the index-th bit to false. */
reset(size_t index)67*c8dee2aaSAndroid Build Coastguard Worker     void reset(size_t index) {
68*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(index < fSize);
69*c8dee2aaSAndroid Build Coastguard Worker         *this->chunkFor(index) &= ~ChunkMaskFor(index);
70*c8dee2aaSAndroid Build Coastguard Worker     }
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker     /** Sets every bit in the bitset to false. */
reset()73*c8dee2aaSAndroid Build Coastguard Worker     void reset() {
74*c8dee2aaSAndroid Build Coastguard Worker         Chunk* chunks = fChunks.get();
75*c8dee2aaSAndroid Build Coastguard Worker         const size_t numChunks = NumChunksFor(fSize);
76*c8dee2aaSAndroid Build Coastguard Worker         std::memset(chunks, 0, sizeof(Chunk) * numChunks);
77*c8dee2aaSAndroid Build Coastguard Worker     }
78*c8dee2aaSAndroid Build Coastguard Worker 
test(size_t index)79*c8dee2aaSAndroid Build Coastguard Worker     bool test(size_t index) const {
80*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(index < fSize);
81*c8dee2aaSAndroid Build Coastguard Worker         return SkToBool(*this->chunkFor(index) & ChunkMaskFor(index));
82*c8dee2aaSAndroid Build Coastguard Worker     }
83*c8dee2aaSAndroid Build Coastguard Worker 
size()84*c8dee2aaSAndroid Build Coastguard Worker     size_t size() const {
85*c8dee2aaSAndroid Build Coastguard Worker         return fSize;
86*c8dee2aaSAndroid Build Coastguard Worker     }
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker     // Calls f(size_t index) for each set index.
89*c8dee2aaSAndroid Build Coastguard Worker     template<typename FN>
forEachSetIndex(FN f)90*c8dee2aaSAndroid Build Coastguard Worker     void forEachSetIndex(FN f) const {
91*c8dee2aaSAndroid Build Coastguard Worker         const Chunk* chunks = fChunks.get();
92*c8dee2aaSAndroid Build Coastguard Worker         const size_t numChunks = NumChunksFor(fSize);
93*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = 0; i < numChunks; ++i) {
94*c8dee2aaSAndroid Build Coastguard Worker             if (Chunk chunk = chunks[i]) {  // There are set bits
95*c8dee2aaSAndroid Build Coastguard Worker                 const size_t index = i * kChunkBits;
96*c8dee2aaSAndroid Build Coastguard Worker                 for (size_t j = 0; j < kChunkBits; ++j) {
97*c8dee2aaSAndroid Build Coastguard Worker                     if (0x1 & (chunk >> j)) {
98*c8dee2aaSAndroid Build Coastguard Worker                         f(index + j);
99*c8dee2aaSAndroid Build Coastguard Worker                     }
100*c8dee2aaSAndroid Build Coastguard Worker                 }
101*c8dee2aaSAndroid Build Coastguard Worker             }
102*c8dee2aaSAndroid Build Coastguard Worker         }
103*c8dee2aaSAndroid Build Coastguard Worker     }
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker     using OptionalIndex = std::optional<size_t>;
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker     // If any bits are set, returns the index of the first.
findFirst()108*c8dee2aaSAndroid Build Coastguard Worker     OptionalIndex findFirst() {
109*c8dee2aaSAndroid Build Coastguard Worker         const Chunk* chunks = fChunks.get();
110*c8dee2aaSAndroid Build Coastguard Worker         const size_t numChunks = NumChunksFor(fSize);
111*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = 0; i < numChunks; ++i) {
112*c8dee2aaSAndroid Build Coastguard Worker             if (Chunk chunk = chunks[i]) {  // There are set bits
113*c8dee2aaSAndroid Build Coastguard Worker                 static_assert(kChunkBits <= std::numeric_limits<uint32_t>::digits, "SkCTZ");
114*c8dee2aaSAndroid Build Coastguard Worker                 const size_t bitIndex = i * kChunkBits + SkCTZ(chunk);
115*c8dee2aaSAndroid Build Coastguard Worker                 return OptionalIndex(bitIndex);
116*c8dee2aaSAndroid Build Coastguard Worker             }
117*c8dee2aaSAndroid Build Coastguard Worker         }
118*c8dee2aaSAndroid Build Coastguard Worker         return OptionalIndex();
119*c8dee2aaSAndroid Build Coastguard Worker     }
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker     // If any bits are not set, returns the index of the first.
findFirstUnset()122*c8dee2aaSAndroid Build Coastguard Worker     OptionalIndex findFirstUnset() {
123*c8dee2aaSAndroid Build Coastguard Worker         const Chunk* chunks = fChunks.get();
124*c8dee2aaSAndroid Build Coastguard Worker         const size_t numChunks = NumChunksFor(fSize);
125*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = 0; i < numChunks; ++i) {
126*c8dee2aaSAndroid Build Coastguard Worker             if (Chunk chunk = ~chunks[i]) {  // if there are unset bits ...
127*c8dee2aaSAndroid Build Coastguard Worker                 static_assert(kChunkBits <= std::numeric_limits<uint32_t>::digits, "SkCTZ");
128*c8dee2aaSAndroid Build Coastguard Worker                 const size_t bitIndex = i * kChunkBits + SkCTZ(chunk);
129*c8dee2aaSAndroid Build Coastguard Worker                 if (bitIndex >= fSize) {
130*c8dee2aaSAndroid Build Coastguard Worker                     break;
131*c8dee2aaSAndroid Build Coastguard Worker                 }
132*c8dee2aaSAndroid Build Coastguard Worker                 return OptionalIndex(bitIndex);
133*c8dee2aaSAndroid Build Coastguard Worker             }
134*c8dee2aaSAndroid Build Coastguard Worker         }
135*c8dee2aaSAndroid Build Coastguard Worker         return OptionalIndex();
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker 
138*c8dee2aaSAndroid Build Coastguard Worker private:
139*c8dee2aaSAndroid Build Coastguard Worker     size_t fSize;
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker     using Chunk = uint32_t;
142*c8dee2aaSAndroid Build Coastguard Worker     static_assert(std::numeric_limits<Chunk>::radix == 2);
143*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr size_t kChunkBits = std::numeric_limits<Chunk>::digits;
144*c8dee2aaSAndroid Build Coastguard Worker     static_assert(kChunkBits == sizeof(Chunk)*CHAR_BIT, "SkBitSet must use every bit in a Chunk");
145*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<Chunk, SkOverloadedFunctionObject<void(void*), sk_free>> fChunks;
146*c8dee2aaSAndroid Build Coastguard Worker 
chunkFor(size_t index)147*c8dee2aaSAndroid Build Coastguard Worker     Chunk* chunkFor(size_t index) const {
148*c8dee2aaSAndroid Build Coastguard Worker         return fChunks.get() + (index / kChunkBits);
149*c8dee2aaSAndroid Build Coastguard Worker     }
150*c8dee2aaSAndroid Build Coastguard Worker 
ChunkMaskFor(size_t index)151*c8dee2aaSAndroid Build Coastguard Worker     static constexpr Chunk ChunkMaskFor(size_t index) {
152*c8dee2aaSAndroid Build Coastguard Worker         return (Chunk)1 << (index & (kChunkBits-1));
153*c8dee2aaSAndroid Build Coastguard Worker     }
154*c8dee2aaSAndroid Build Coastguard Worker 
NumChunksFor(size_t size)155*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t NumChunksFor(size_t size) {
156*c8dee2aaSAndroid Build Coastguard Worker         return (size + (kChunkBits-1)) / kChunkBits;
157*c8dee2aaSAndroid Build Coastguard Worker     }
158*c8dee2aaSAndroid Build Coastguard Worker };
159*c8dee2aaSAndroid Build Coastguard Worker 
160*c8dee2aaSAndroid Build Coastguard Worker #endif
161