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