1 //===-- Interface for freestore ------------------------------------------===//
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_SRC___SUPPORT_FREESTORE_H
10 #define LLVM_LIBC_SRC___SUPPORT_FREESTORE_H
14 namespace LIBC_NAMESPACE_DECL
{
16 /// A best-fit store of variously-sized free blocks. Blocks can be inserted and
17 /// removed in logarithmic time.
20 FreeStore() = default;
21 FreeStore(const FreeStore
&other
) = delete;
22 FreeStore
&operator=(const FreeStore
&other
) = delete;
24 /// Sets the range of possible block sizes. This can only be called when the
26 LIBC_INLINE
void set_range(FreeTrie::SizeRange range
) {
27 large_trie
.set_range(range
);
30 /// Insert a free block. If the block is too small to be tracked, nothing
32 void insert(Block
<> *block
);
34 /// Remove a free block. If the block is too small to be tracked, nothing
36 void remove(Block
<> *block
);
38 /// Remove a best-fit free block that can contain the given size when
39 /// allocated. Returns nullptr if there is no such block.
40 Block
<> *remove_best_fit(size_t size
);
43 static constexpr size_t ALIGNMENT
= alignof(max_align_t
);
44 static constexpr size_t MIN_OUTER_SIZE
=
45 align_up(Block
<>::BLOCK_OVERHEAD
+ sizeof(FreeList::Node
), ALIGNMENT
);
46 static constexpr size_t MIN_LARGE_OUTER_SIZE
=
47 align_up(Block
<>::BLOCK_OVERHEAD
+ sizeof(FreeTrie::Node
), ALIGNMENT
);
48 static constexpr size_t NUM_SMALL_SIZES
=
49 (MIN_LARGE_OUTER_SIZE
- MIN_OUTER_SIZE
) / ALIGNMENT
;
51 LIBC_INLINE
static bool too_small(Block
<> *block
) {
52 return block
->outer_size() < MIN_OUTER_SIZE
;
54 LIBC_INLINE
static bool is_small(Block
<> *block
) {
55 return block
->outer_size() < MIN_LARGE_OUTER_SIZE
;
58 FreeList
&small_list(Block
<> *block
);
59 FreeList
*find_best_small_fit(size_t size
);
61 cpp::array
<FreeList
, NUM_SMALL_SIZES
> small_lists
;
65 LIBC_INLINE
void FreeStore::insert(Block
<> *block
) {
69 small_list(block
).push(block
);
71 large_trie
.push(block
);
74 LIBC_INLINE
void FreeStore::remove(Block
<> *block
) {
77 if (is_small(block
)) {
78 small_list(block
).remove(
79 reinterpret_cast<FreeList::Node
*>(block
->usable_space()));
82 reinterpret_cast<FreeTrie::Node
*>(block
->usable_space()));
86 LIBC_INLINE Block
<> *FreeStore::remove_best_fit(size_t size
) {
87 if (FreeList
*list
= find_best_small_fit(size
)) {
88 Block
<> *block
= list
->front();
92 if (FreeTrie::Node
*best_fit
= large_trie
.find_best_fit(size
)) {
93 Block
<> *block
= best_fit
->block();
94 large_trie
.remove(best_fit
);
100 LIBC_INLINE FreeList
&FreeStore::small_list(Block
<> *block
) {
101 LIBC_ASSERT(is_small(block
) && "only legal for small blocks");
102 return small_lists
[(block
->outer_size() - MIN_OUTER_SIZE
) / ALIGNMENT
];
105 LIBC_INLINE FreeList
*FreeStore::find_best_small_fit(size_t size
) {
106 for (FreeList
&list
: small_lists
)
107 if (!list
.empty() && list
.size() >= size
)
112 } // namespace LIBC_NAMESPACE_DECL
114 #endif // LLVM_LIBC_SRC___SUPPORT_FREESTORE_H