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