1 //===-- A data structure which stores data in blocks -----------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SUPPORT_BLOCKSTORE_H
10 #define LLVM_LIBC_SUPPORT_BLOCKSTORE_H
12 #include <src/__support/CPP/new.h>
13 #include <src/__support/libc_assert.h>
18 namespace __llvm_libc
{
21 // The difference between BlockStore a traditional vector types is that,
22 // when more capacity is desired, a new block is added instead of allocating
23 // a larger sized array and copying over existing items to the new allocation.
24 // Also, the initial block does not need heap allocation. Hence, a BlockStore is
25 // suitable for global objects as it does not require explicit construction.
26 // Also, the destructor of this class does nothing, which eliminates the need
27 // for an atexit global object destruction. But, it also means that the global
28 // object should be explicitly cleaned up at the appropriate time.
30 // If REVERSE_ORDER is true, the iteration of elements will in the reverse
31 // order. Also, since REVERSE_ORDER is a constexpr, conditionals branching
32 // on its value will be optimized out in the code below.
33 template <typename T
, size_t BLOCK_SIZE
, bool REVERSE_ORDER
= false>
37 alignas(T
) uint8_t data
[BLOCK_SIZE
* sizeof(T
)] = {0};
38 Block
*next
= nullptr;
42 Block
*current
= &first
;
43 size_t fill_count
= 0;
46 Block
*first
, *second
;
48 Pair
getLastBlocks() {
50 return {current
, current
->next
};
51 Block
*prev
= nullptr;
53 for (; curr
->next
; prev
= curr
, curr
= curr
->next
)
55 LIBC_ASSERT(curr
== current
);
59 Block
*getLastBlock() { return getLastBlocks().first
; }
62 constexpr BlockStore() = default;
63 ~BlockStore() = default;
70 constexpr iterator(Block
*b
, size_t i
) : block(b
), index(i
) {}
72 iterator
&operator++() {
78 if (index
== 0 && block
->next
!= nullptr) {
83 if (index
== BLOCK_SIZE
)
87 if (index
== BLOCK_SIZE
&& block
->next
!= nullptr) {
97 size_t true_index
= REVERSE_ORDER
? index
- 1 : index
;
98 return *reinterpret_cast<T
*>(block
->data
+ sizeof(T
) * true_index
);
101 bool operator==(const iterator
&rhs
) const {
102 return block
== rhs
.block
&& index
== rhs
.index
;
105 bool operator!=(const iterator
&rhs
) const {
106 return block
!= rhs
.block
|| index
!= rhs
.index
;
110 static void destroy(BlockStore
<T
, BLOCK_SIZE
, REVERSE_ORDER
> *block_store
);
113 if (fill_count
== BLOCK_SIZE
) {
115 auto new_block
= new (ac
) Block();
119 new_block
->next
= current
;
121 new_block
->next
= nullptr;
122 current
->next
= new_block
;
127 T
*obj
= reinterpret_cast<T
*>(current
->data
+ fill_count
* sizeof(T
));
132 [[nodiscard
]] bool push_back(const T
&value
) {
141 return *reinterpret_cast<T
*>(getLastBlock()->data
+
142 sizeof(T
) * (fill_count
- 1));
147 if (fill_count
|| current
== &first
)
149 auto [last
, prev
] = getLastBlocks();
151 LIBC_ASSERT(last
== current
);
152 current
= current
->next
;
154 LIBC_ASSERT(prev
->next
== last
);
156 current
->next
= nullptr;
160 fill_count
= BLOCK_SIZE
;
163 bool empty() const { return current
== &first
&& !fill_count
; }
167 return iterator(current
, fill_count
);
169 return iterator(&first
, 0);
174 return iterator(&first
, 0);
176 return iterator(current
, fill_count
);
180 template <typename T
, size_t BLOCK_SIZE
, bool REVERSE_ORDER
>
181 void BlockStore
<T
, BLOCK_SIZE
, REVERSE_ORDER
>::destroy(
182 BlockStore
<T
, BLOCK_SIZE
, REVERSE_ORDER
> *block_store
) {
184 auto current
= block_store
->current
;
185 while (current
->next
!= nullptr) {
187 current
= current
->next
;
191 auto current
= block_store
->first
.next
;
192 while (current
!= nullptr) {
194 current
= current
->next
;
198 block_store
->current
= nullptr;
199 block_store
->fill_count
= 0;
202 // A convenience type for reverse order block stores.
203 template <typename T
, size_t BLOCK_SIZE
>
204 using ReverseOrderBlockStore
= BlockStore
<T
, BLOCK_SIZE
, true>;
207 } // namespace __llvm_libc
209 #endif // LLVM_LIBC_SUPPORT_BLOCKSTORE_H