| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SkBitSet_DEFINED | |
| #define SkBitSet_DEFINED | |
| #include "include/private/SkMalloc.h" | |
| #include "include/private/SkTOptional.h" | |
| #include "include/private/SkTemplates.h" | |
| #include "src/core/SkMathPriv.h" | |
| #include <climits> | |
| #include <cstring> | |
| #include <limits> | |
| #include <memory> | |
| class SkBitSet { | |
| public: | |
| explicit SkBitSet(size_t size) | |
| : fSize(size) | |
| // May http://wg21.link/p0593 be accepted. | |
| , fChunks((Chunk*)sk_calloc_throw(NumChunksFor(fSize) * sizeof(Chunk))) | |
| {} | |
| SkBitSet(const SkBitSet&) = delete; | |
| SkBitSet& operator=(const SkBitSet&) = delete; | |
| SkBitSet(SkBitSet&& that) { *this = std::move(that); } | |
| SkBitSet& operator=(SkBitSet&& that) { | |
| if (this != &that) { | |
| this->fSize = that.fSize; | |
| this->fChunks = std::move(that.fChunks); | |
| that.fSize = 0; | |
| } | |
| return *this; | |
| } | |
| ~SkBitSet() = default; | |
| /** Set the value of the index-th bit to true. */ | |
| void set(size_t index) { | |
| SkASSERT(index < fSize); | |
| *this->chunkFor(index) |= ChunkMaskFor(index); | |
| } | |
| /** Sets every bit in the bitset to true. */ | |
| void set() { | |
| Chunk* chunks = fChunks.get(); | |
| const size_t numChunks = NumChunksFor(fSize); | |
| std::memset(chunks, 0xFF, sizeof(Chunk) * numChunks); | |
| } | |
| /** Set the value of the index-th bit to false. */ | |
| void reset(size_t index) { | |
| SkASSERT(index < fSize); | |
| *this->chunkFor(index) &= ~ChunkMaskFor(index); | |
| } | |
| /** Sets every bit in the bitset to false. */ | |
| void reset() { | |
| Chunk* chunks = fChunks.get(); | |
| const size_t numChunks = NumChunksFor(fSize); | |
| std::memset(chunks, 0, sizeof(Chunk) * numChunks); | |
| } | |
| bool test(size_t index) const { | |
| SkASSERT(index < fSize); | |
| return SkToBool(*this->chunkFor(index) & ChunkMaskFor(index)); | |
| } | |
| size_t size() const { | |
| return fSize; | |
| } | |
| // Calls f(size_t index) for each set index. | |
| template<typename FN> | |
| void forEachSetIndex(FN f) const { | |
| const Chunk* chunks = fChunks.get(); | |
| const size_t numChunks = NumChunksFor(fSize); | |
| for (size_t i = 0; i < numChunks; ++i) { | |
| if (Chunk chunk = chunks[i]) { // There are set bits | |
| const size_t index = i * kChunkBits; | |
| for (size_t j = 0; j < kChunkBits; ++j) { | |
| if (0x1 & (chunk >> j)) { | |
| f(index + j); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| using OptionalIndex = skstd::optional<size_t>; | |
| // If any bits are set, returns the index of the first. | |
| OptionalIndex findFirst() { | |
| const Chunk* chunks = fChunks.get(); | |
| const size_t numChunks = NumChunksFor(fSize); | |
| for (size_t i = 0; i < numChunks; ++i) { | |
| if (Chunk chunk = chunks[i]) { // There are set bits | |
| static_assert(kChunkBits <= std::numeric_limits<uint32_t>::digits, "SkCTZ"); | |
| const size_t bitIndex = i * kChunkBits + SkCTZ(chunk); | |
| return OptionalIndex(bitIndex); | |
| } | |
| } | |
| return OptionalIndex(); | |
| } | |
| // If any bits are not set, returns the index of the first. | |
| OptionalIndex findFirstUnset() { | |
| const Chunk* chunks = fChunks.get(); | |
| const size_t numChunks = NumChunksFor(fSize); | |
| for (size_t i = 0; i < numChunks; ++i) { | |
| if (Chunk chunk = ~chunks[i]) { // if there are unset bits ... | |
| static_assert(kChunkBits <= std::numeric_limits<uint32_t>::digits, "SkCTZ"); | |
| const size_t bitIndex = i * kChunkBits + SkCTZ(chunk); | |
| if (bitIndex >= fSize) { | |
| break; | |
| } | |
| return OptionalIndex(bitIndex); | |
| } | |
| } | |
| return OptionalIndex(); | |
| } | |
| private: | |
| size_t fSize; | |
| using Chunk = uint32_t; | |
| static_assert(std::numeric_limits<Chunk>::radix == 2); | |
| static constexpr size_t kChunkBits = std::numeric_limits<Chunk>::digits; | |
| static_assert(kChunkBits == sizeof(Chunk)*CHAR_BIT, "SkBitSet must use every bit in a Chunk"); | |
| std::unique_ptr<Chunk, SkFunctionWrapper<void(void*), sk_free>> fChunks; | |
| Chunk* chunkFor(size_t index) const { | |
| return fChunks.get() + (index / kChunkBits); | |
| } | |
| static constexpr Chunk ChunkMaskFor(size_t index) { | |
| return (Chunk)1 << (index & (kChunkBits-1)); | |
| } | |
| static constexpr size_t NumChunksFor(size_t size) { | |
| return (size + (kChunkBits-1)) / kChunkBits; | |
| } | |
| }; | |
| #endif |