1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <bitmap/bitmap.h>
8 
9 #include <limits.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <string.h>
13 
14 #include <fbl/algorithm.h>
15 #include <fbl/macros.h>
16 #include <zircon/assert.h>
17 #include <zircon/types.h>
18 
19 namespace bitmap {
20 namespace internal {
21 
22 DECLARE_HAS_MEMBER_FN(has_grow, Grow);
23 
24 } // namespace internal
25 
26 const size_t kBits = sizeof(size_t) * CHAR_BIT;
27 
28 // Translates a max bit into a final index in the bitmap array.
LastIdx(size_t bitmax)29 constexpr size_t LastIdx(size_t bitmax) {
30     return (bitmax - 1) / kBits;
31 }
32 
33 // Base class for RawGenericBitmap, to reduce what needs to be templated.
34 class RawBitmapBase : public Bitmap {
35 public:
36     // Returns the size of this bitmap.
size()37     size_t size() const { return size_; }
38 
39     // Shrinks the accessible portion of the bitmap, without re-allocating
40     // the underlying storage.
41     //
42     // This is useful for programs which require underlying bitmap storage
43     // to be aligned to a certain size (initialized via Reset), but want to
44     // restrict access to a smaller portion of the bitmap (via Shrink).
45     zx_status_t Shrink(size_t size);
46 
47     // Returns true if all bits in the range [*bitoff*, *bitmax*) match
48     // *is_set*, otherwise returns false and sets *out* (if provided) to the
49     // first (or last, in the case of ReverseScan) bit that doesn't match. An
50     // empty region (i.e. *bitoff* is greater than *bitmax*, or *bitoff* is
51     // outside the range of the bitmap) will return true.
52     bool Scan(size_t bitoff, size_t bitmax, bool is_set,
53               size_t* out = nullptr) const;
54     bool ReverseScan(size_t bitoff, size_t bitmax, bool is_set,
55                      size_t* out = nullptr) const;
56 
57     // Finds the first (or last, in the case of ReverseFind) run of *run_len*
58     // *is_set* bits, in [*bitoff*, *bitmax*). Returns the start of the run in
59     // *out* and returns ZX_OK if a run is found, otherwise returns
60     // ZX_ERR_NO_RESOURCES.
61     zx_status_t Find(bool is_set, size_t bitoff, size_t bitmax, size_t run_len,
62                      size_t* out) const override;
63     zx_status_t ReverseFind(bool is_set, size_t bitoff, size_t bitmax,
64                             size_t run_len, size_t* out) const;
65 
66     // Returns true if all the bits in [*bitoff*, *bitmax*) are set. Afterwards,
67     // *first_unset* will be set to the lesser of bitmax and the index of the
68     // first unset bit after *bitoff*.
69     bool Get(size_t bitoff, size_t bitmax,
70              size_t* first_unset = nullptr) const override;
71 
72     // Sets all bits in the range [*bitoff*, *bitmax*).  Returns an error if
73     // bitmax < bitoff or size_ < bitmax, and ZX_OK otherwise.
74     zx_status_t Set(size_t bitoff, size_t bitmax) override;
75 
76     // Clears all bits in the range [*bitoff*, *bitmax*).  Returns an error if
77     // bitmax < bitoff or size_ < bitmax, and ZX_OK otherwise.
78     zx_status_t Clear(size_t bitoff, size_t bitmax) override;
79 
80     // Clear all bits in the bitmap.
81     void ClearAll() override;
82 
83 protected:
84     // The size of this bitmap, in bits.
85     size_t size_ = 0;
86     // Owned by bits_, cached
87     size_t* data_ = nullptr;
88 };
89 
90 // A simple bitmap backed by generic storage.
91 // Storage must implement:
92 //   - zx_status_t Allocate(size_t size)
93 //      To allocate |size| bytes of storage.
94 //   - void* GetData()
95 //      To access the underlying storage.
96 //   - zx_status_t Grow(size_t size)
97 //      (optional) To expand the underlying storage to fit at least |size|
98 //      bytes.
99 template <typename Storage>
100 class RawBitmapGeneric final : public RawBitmapBase {
101 public:
102     RawBitmapGeneric() = default;
103     virtual ~RawBitmapGeneric() = default;
104     RawBitmapGeneric(RawBitmapGeneric&& rhs) = default;
105     RawBitmapGeneric& operator=(RawBitmapGeneric&& rhs) = default;
106     DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(RawBitmapGeneric);
107 
108     // Increases the bitmap size
109     template <typename U = Storage>
110     typename fbl::enable_if<internal::has_grow<U>::value, zx_status_t>::type
Grow(size_t size)111     Grow(size_t size) {
112         if (size < size_) {
113             return ZX_ERR_INVALID_ARGS;
114         } else if (size == size_) {
115             return ZX_OK;
116         }
117 
118         size_t old_len = LastIdx(size_) + 1;
119         size_t new_len = LastIdx(size) + 1;
120         size_t new_bitsize = sizeof(size_t) * new_len;
121         ZX_ASSERT(new_bitsize >= new_len); // Overflow
122         zx_status_t status = bits_.Grow(new_bitsize);
123         if (status != ZX_OK) {
124             return status;
125         }
126 
127         // Clear all the "newly grown" bytes
128         uintptr_t addr = reinterpret_cast<uintptr_t>(bits_.GetData()) +
129                          old_len * sizeof(size_t);
130         memset(reinterpret_cast<void*>(addr), 0,
131                (new_len - old_len) * sizeof(size_t));
132 
133         size_t old_size = size_;
134         data_ = static_cast<size_t*>(bits_.GetData());
135         size_ = size;
136 
137         // Clear the partial bits not included in the new "size_t"s.
138         Clear(old_size, fbl::min(old_len * kBits, size_));
139         return ZX_OK;
140     }
141 
142     template <typename U = Storage>
143     typename fbl::enable_if<!internal::has_grow<U>::value, zx_status_t>::type
144     Grow(size_t size) {
145         return ZX_ERR_NO_RESOURCES;
146     }
147 
148     // Resets the bitmap; clearing and resizing it.
149     // Allocates memory, and can fail.
Reset(size_t size)150     zx_status_t Reset(size_t size) {
151         size_ = size;
152         if (size_ == 0) {
153             data_ = nullptr;
154             return ZX_OK;
155         }
156         size_t last_idx = LastIdx(size);
157         zx_status_t status = bits_.Allocate(sizeof(size_t) * (last_idx + 1));
158         if (status != ZX_OK) {
159             return status;
160         }
161         data_ = static_cast<size_t*>(bits_.GetData());
162         ClearAll();
163         return ZX_OK;
164     }
165 
166     // This function allows access to underlying data, but is dangerous: It
167     // leaks the pointer to bits_. Reset and the bitmap destructor should not
168     // be called on the bitmap while the pointer returned from data() is alive.
StorageUnsafe()169     const Storage* StorageUnsafe() const { return &bits_; }
170 
171 private:
172     // The storage backing this bitmap.
173     Storage bits_;
174 };
175 
176 } // namespace bitmap
177