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