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