1*71db0c75SAndroid Build Coastguard Worker //===-- Interface for freetrie --------------------------------------------===//
2*71db0c75SAndroid Build Coastguard Worker //
3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*71db0c75SAndroid Build Coastguard Worker //
7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*71db0c75SAndroid Build Coastguard Worker
9*71db0c75SAndroid Build Coastguard Worker #ifndef LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
10*71db0c75SAndroid Build Coastguard Worker #define LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
11*71db0c75SAndroid Build Coastguard Worker
12*71db0c75SAndroid Build Coastguard Worker #include "freelist.h"
13*71db0c75SAndroid Build Coastguard Worker
14*71db0c75SAndroid Build Coastguard Worker namespace LIBC_NAMESPACE_DECL {
15*71db0c75SAndroid Build Coastguard Worker
16*71db0c75SAndroid Build Coastguard Worker /// A trie of free lists.
17*71db0c75SAndroid Build Coastguard Worker ///
18*71db0c75SAndroid Build Coastguard Worker /// This is an unusual little data structure originally from Doug Lea's malloc.
19*71db0c75SAndroid Build Coastguard Worker /// Finding the best fit from a set of differently-sized free list typically
20*71db0c75SAndroid Build Coastguard Worker /// required some kind of ordered map, and these are typically implemented using
21*71db0c75SAndroid Build Coastguard Worker /// a self-balancing binary search tree. Those are notorious for having a
22*71db0c75SAndroid Build Coastguard Worker /// relatively large number of special cases, while this trie has relatively
23*71db0c75SAndroid Build Coastguard Worker /// few, which helps with code size.
24*71db0c75SAndroid Build Coastguard Worker ///
25*71db0c75SAndroid Build Coastguard Worker /// Operations on the trie are logarithmic not on the number of nodes within it,
26*71db0c75SAndroid Build Coastguard Worker /// but rather the fixed range of possible sizes that the trie can contain. This
27*71db0c75SAndroid Build Coastguard Worker /// means that the data structure would likely actually perform worse than an
28*71db0c75SAndroid Build Coastguard Worker /// e.g. red-black tree, but its implementation is still much simpler.
29*71db0c75SAndroid Build Coastguard Worker ///
30*71db0c75SAndroid Build Coastguard Worker /// Each trie node's children subdivide the range of possible sizes into two
31*71db0c75SAndroid Build Coastguard Worker /// halves: a lower and an upper. The node itself holds a free list of some size
32*71db0c75SAndroid Build Coastguard Worker /// within its range. This makes it possible to summarily replace any node with
33*71db0c75SAndroid Build Coastguard Worker /// any leaf within its subtrie, which makes it very straightforward to remove a
34*71db0c75SAndroid Build Coastguard Worker /// node. Insertion is also simple; the only real complexity lies with finding
35*71db0c75SAndroid Build Coastguard Worker /// the best fit. This can still be done in logarithmic time with only a few
36*71db0c75SAndroid Build Coastguard Worker /// cases to consider.
37*71db0c75SAndroid Build Coastguard Worker ///
38*71db0c75SAndroid Build Coastguard Worker /// The trie refers to, but does not own, the Nodes that comprise it.
39*71db0c75SAndroid Build Coastguard Worker class FreeTrie {
40*71db0c75SAndroid Build Coastguard Worker public:
41*71db0c75SAndroid Build Coastguard Worker /// A trie node that is also a free list. Only the head node of each list is
42*71db0c75SAndroid Build Coastguard Worker /// actually part of the trie. The subtrie contains a continous SizeRange of
43*71db0c75SAndroid Build Coastguard Worker /// free lists. The lower and upper subtrie's contain the lower and upper half
44*71db0c75SAndroid Build Coastguard Worker /// of the subtries range. There is no direct relationship between the size of
45*71db0c75SAndroid Build Coastguard Worker /// this node's free list and the contents of the lower and upper subtries.
46*71db0c75SAndroid Build Coastguard Worker class Node : public FreeList::Node {
47*71db0c75SAndroid Build Coastguard Worker /// The child subtrie covering the lower half of this subtrie's size range.
48*71db0c75SAndroid Build Coastguard Worker /// Undefined if this is not the head of the list.
49*71db0c75SAndroid Build Coastguard Worker Node *lower;
50*71db0c75SAndroid Build Coastguard Worker /// The child subtrie covering the upper half of this subtrie's size range.
51*71db0c75SAndroid Build Coastguard Worker /// Undefined if this is not the head of the list.
52*71db0c75SAndroid Build Coastguard Worker Node *upper;
53*71db0c75SAndroid Build Coastguard Worker /// The parent subtrie. nullptr if this is the root or not the head of the
54*71db0c75SAndroid Build Coastguard Worker /// list.
55*71db0c75SAndroid Build Coastguard Worker Node *parent;
56*71db0c75SAndroid Build Coastguard Worker
57*71db0c75SAndroid Build Coastguard Worker friend class FreeTrie;
58*71db0c75SAndroid Build Coastguard Worker };
59*71db0c75SAndroid Build Coastguard Worker
60*71db0c75SAndroid Build Coastguard Worker /// Power-of-two range of sizes covered by a subtrie.
61*71db0c75SAndroid Build Coastguard Worker struct SizeRange {
62*71db0c75SAndroid Build Coastguard Worker size_t min;
63*71db0c75SAndroid Build Coastguard Worker size_t width;
64*71db0c75SAndroid Build Coastguard Worker
SizeRangeSizeRange65*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE constexpr SizeRange(size_t min, size_t width)
66*71db0c75SAndroid Build Coastguard Worker : min(min), width(width) {
67*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT(!(width & (width - 1)) && "width must be a power of two");
68*71db0c75SAndroid Build Coastguard Worker }
69*71db0c75SAndroid Build Coastguard Worker
70*71db0c75SAndroid Build Coastguard Worker /// @returns The lower half of the size range.
lowerSizeRange71*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE SizeRange lower() const { return {min, width / 2}; }
72*71db0c75SAndroid Build Coastguard Worker
73*71db0c75SAndroid Build Coastguard Worker /// @returns The upper half of the size range.
upperSizeRange74*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE SizeRange upper() const { return {min + width / 2, width / 2}; }
75*71db0c75SAndroid Build Coastguard Worker
76*71db0c75SAndroid Build Coastguard Worker /// @returns The largest size in this range.
maxSizeRange77*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE size_t max() const { return min + (width - 1); }
78*71db0c75SAndroid Build Coastguard Worker
79*71db0c75SAndroid Build Coastguard Worker /// @returns Whether the range contains the given size.
containsSizeRange80*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE bool contains(size_t size) const {
81*71db0c75SAndroid Build Coastguard Worker return min <= size && size < min + width;
82*71db0c75SAndroid Build Coastguard Worker }
83*71db0c75SAndroid Build Coastguard Worker };
84*71db0c75SAndroid Build Coastguard Worker
FreeTrie()85*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE constexpr FreeTrie() : FreeTrie(SizeRange{0, 0}) {}
FreeTrie(SizeRange range)86*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE constexpr FreeTrie(SizeRange range) : range(range) {}
87*71db0c75SAndroid Build Coastguard Worker
88*71db0c75SAndroid Build Coastguard Worker /// Sets the range of possible block sizes. This can only be called when the
89*71db0c75SAndroid Build Coastguard Worker /// trie is empty.
set_range(FreeTrie::SizeRange range)90*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE void set_range(FreeTrie::SizeRange range) {
91*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT(empty() && "cannot change the range of a preexisting trie");
92*71db0c75SAndroid Build Coastguard Worker this->range = range;
93*71db0c75SAndroid Build Coastguard Worker }
94*71db0c75SAndroid Build Coastguard Worker
95*71db0c75SAndroid Build Coastguard Worker /// @returns Whether the trie contains any blocks.
empty()96*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE bool empty() const { return !root; }
97*71db0c75SAndroid Build Coastguard Worker
98*71db0c75SAndroid Build Coastguard Worker /// Push a block to the trie.
99*71db0c75SAndroid Build Coastguard Worker void push(Block *block);
100*71db0c75SAndroid Build Coastguard Worker
101*71db0c75SAndroid Build Coastguard Worker /// Remove a node from this trie node's free list.
102*71db0c75SAndroid Build Coastguard Worker void remove(Node *node);
103*71db0c75SAndroid Build Coastguard Worker
104*71db0c75SAndroid Build Coastguard Worker /// @returns A smallest node that can allocate the given size; otherwise
105*71db0c75SAndroid Build Coastguard Worker /// nullptr.
106*71db0c75SAndroid Build Coastguard Worker Node *find_best_fit(size_t size);
107*71db0c75SAndroid Build Coastguard Worker
108*71db0c75SAndroid Build Coastguard Worker private:
109*71db0c75SAndroid Build Coastguard Worker /// @returns Whether a node is the head of its containing freelist.
is_head(Node * node)110*71db0c75SAndroid Build Coastguard Worker bool is_head(Node *node) const { return node->parent || node == root; }
111*71db0c75SAndroid Build Coastguard Worker
112*71db0c75SAndroid Build Coastguard Worker /// Replaces references to one node with another (or nullptr) in all adjacent
113*71db0c75SAndroid Build Coastguard Worker /// parent and child nodes.
114*71db0c75SAndroid Build Coastguard Worker void replace_node(Node *node, Node *new_node);
115*71db0c75SAndroid Build Coastguard Worker
116*71db0c75SAndroid Build Coastguard Worker Node *root = nullptr;
117*71db0c75SAndroid Build Coastguard Worker SizeRange range;
118*71db0c75SAndroid Build Coastguard Worker };
119*71db0c75SAndroid Build Coastguard Worker
push(Block * block)120*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE void FreeTrie::push(Block *block) {
121*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT(block->inner_size_free() >= sizeof(Node) &&
122*71db0c75SAndroid Build Coastguard Worker "block too small to accomodate free trie node");
123*71db0c75SAndroid Build Coastguard Worker size_t size = block->inner_size();
124*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT(range.contains(size) && "requested size out of trie range");
125*71db0c75SAndroid Build Coastguard Worker
126*71db0c75SAndroid Build Coastguard Worker // Find the position in the tree to push to.
127*71db0c75SAndroid Build Coastguard Worker Node **cur = &root;
128*71db0c75SAndroid Build Coastguard Worker Node *parent = nullptr;
129*71db0c75SAndroid Build Coastguard Worker SizeRange cur_range = range;
130*71db0c75SAndroid Build Coastguard Worker while (*cur && (*cur)->size() != size) {
131*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT(cur_range.contains(size) && "requested size out of trie range");
132*71db0c75SAndroid Build Coastguard Worker parent = *cur;
133*71db0c75SAndroid Build Coastguard Worker if (size <= cur_range.lower().max()) {
134*71db0c75SAndroid Build Coastguard Worker cur = &(*cur)->lower;
135*71db0c75SAndroid Build Coastguard Worker cur_range = cur_range.lower();
136*71db0c75SAndroid Build Coastguard Worker } else {
137*71db0c75SAndroid Build Coastguard Worker cur = &(*cur)->upper;
138*71db0c75SAndroid Build Coastguard Worker cur_range = cur_range.upper();
139*71db0c75SAndroid Build Coastguard Worker }
140*71db0c75SAndroid Build Coastguard Worker }
141*71db0c75SAndroid Build Coastguard Worker
142*71db0c75SAndroid Build Coastguard Worker Node *node = new (block->usable_space()) Node;
143*71db0c75SAndroid Build Coastguard Worker FreeList list = *cur;
144*71db0c75SAndroid Build Coastguard Worker if (list.empty()) {
145*71db0c75SAndroid Build Coastguard Worker node->parent = parent;
146*71db0c75SAndroid Build Coastguard Worker node->lower = node->upper = nullptr;
147*71db0c75SAndroid Build Coastguard Worker } else {
148*71db0c75SAndroid Build Coastguard Worker node->parent = nullptr;
149*71db0c75SAndroid Build Coastguard Worker }
150*71db0c75SAndroid Build Coastguard Worker list.push(node);
151*71db0c75SAndroid Build Coastguard Worker *cur = static_cast<Node *>(list.begin());
152*71db0c75SAndroid Build Coastguard Worker }
153*71db0c75SAndroid Build Coastguard Worker
find_best_fit(size_t size)154*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE FreeTrie::Node *FreeTrie::find_best_fit(size_t size) {
155*71db0c75SAndroid Build Coastguard Worker if (empty() || range.max() < size)
156*71db0c75SAndroid Build Coastguard Worker return nullptr;
157*71db0c75SAndroid Build Coastguard Worker
158*71db0c75SAndroid Build Coastguard Worker Node *cur = root;
159*71db0c75SAndroid Build Coastguard Worker SizeRange cur_range = range;
160*71db0c75SAndroid Build Coastguard Worker Node *best_fit = nullptr;
161*71db0c75SAndroid Build Coastguard Worker Node *deferred_upper_trie = nullptr;
162*71db0c75SAndroid Build Coastguard Worker FreeTrie::SizeRange deferred_upper_range{0, 0};
163*71db0c75SAndroid Build Coastguard Worker
164*71db0c75SAndroid Build Coastguard Worker while (true) {
165*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT(cur_range.contains(cur->size()) &&
166*71db0c75SAndroid Build Coastguard Worker "trie node size out of range");
167*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT(cur_range.max() >= size &&
168*71db0c75SAndroid Build Coastguard Worker "range could not fit requested size");
169*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT((!best_fit || cur_range.min < best_fit->size()) &&
170*71db0c75SAndroid Build Coastguard Worker "range could not contain a best fit");
171*71db0c75SAndroid Build Coastguard Worker
172*71db0c75SAndroid Build Coastguard Worker // If the current node is an exact fit, it is a best fit.
173*71db0c75SAndroid Build Coastguard Worker if (cur->size() == size)
174*71db0c75SAndroid Build Coastguard Worker return cur;
175*71db0c75SAndroid Build Coastguard Worker
176*71db0c75SAndroid Build Coastguard Worker if (cur->size() > size && (!best_fit || cur->size() < best_fit->size())) {
177*71db0c75SAndroid Build Coastguard Worker // The current node is a better fit.
178*71db0c75SAndroid Build Coastguard Worker best_fit = cur;
179*71db0c75SAndroid Build Coastguard Worker
180*71db0c75SAndroid Build Coastguard Worker // If there is a deferred upper subtrie, then the current node is
181*71db0c75SAndroid Build Coastguard Worker // somewhere in its lower sibling subtrie. That means that the new best
182*71db0c75SAndroid Build Coastguard Worker // fit is better than the best fit in the deferred subtrie.
183*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT(
184*71db0c75SAndroid Build Coastguard Worker (!deferred_upper_trie ||
185*71db0c75SAndroid Build Coastguard Worker deferred_upper_range.min > best_fit->size()) &&
186*71db0c75SAndroid Build Coastguard Worker "deferred upper subtrie should be outclassed by new best fit");
187*71db0c75SAndroid Build Coastguard Worker deferred_upper_trie = nullptr;
188*71db0c75SAndroid Build Coastguard Worker }
189*71db0c75SAndroid Build Coastguard Worker
190*71db0c75SAndroid Build Coastguard Worker // Determine which subtries might contain the best fit.
191*71db0c75SAndroid Build Coastguard Worker bool lower_impossible = !cur->lower || cur_range.lower().max() < size;
192*71db0c75SAndroid Build Coastguard Worker bool upper_impossible =
193*71db0c75SAndroid Build Coastguard Worker !cur->upper ||
194*71db0c75SAndroid Build Coastguard Worker // If every node in the lower trie fits
195*71db0c75SAndroid Build Coastguard Worker (!lower_impossible && cur_range.min >= size) ||
196*71db0c75SAndroid Build Coastguard Worker // If every node in the upper trie is worse than the current best
197*71db0c75SAndroid Build Coastguard Worker (best_fit && cur_range.upper().min >= best_fit->size());
198*71db0c75SAndroid Build Coastguard Worker
199*71db0c75SAndroid Build Coastguard Worker if (lower_impossible && upper_impossible) {
200*71db0c75SAndroid Build Coastguard Worker if (!deferred_upper_trie)
201*71db0c75SAndroid Build Coastguard Worker return best_fit;
202*71db0c75SAndroid Build Coastguard Worker // Scan the deferred upper subtrie and consider whether any element within
203*71db0c75SAndroid Build Coastguard Worker // provides a better fit.
204*71db0c75SAndroid Build Coastguard Worker //
205*71db0c75SAndroid Build Coastguard Worker // This can only ever be reached once. In a deferred upper subtrie, every
206*71db0c75SAndroid Build Coastguard Worker // node fits, so the higher of two subtries can never contain a best fit.
207*71db0c75SAndroid Build Coastguard Worker cur = deferred_upper_trie;
208*71db0c75SAndroid Build Coastguard Worker cur_range = deferred_upper_range;
209*71db0c75SAndroid Build Coastguard Worker deferred_upper_trie = nullptr;
210*71db0c75SAndroid Build Coastguard Worker continue;
211*71db0c75SAndroid Build Coastguard Worker }
212*71db0c75SAndroid Build Coastguard Worker
213*71db0c75SAndroid Build Coastguard Worker if (lower_impossible) {
214*71db0c75SAndroid Build Coastguard Worker cur = cur->upper;
215*71db0c75SAndroid Build Coastguard Worker cur_range = cur_range.upper();
216*71db0c75SAndroid Build Coastguard Worker } else if (upper_impossible) {
217*71db0c75SAndroid Build Coastguard Worker cur = cur->lower;
218*71db0c75SAndroid Build Coastguard Worker cur_range = cur_range.lower();
219*71db0c75SAndroid Build Coastguard Worker } else {
220*71db0c75SAndroid Build Coastguard Worker // Both subtries might contain a better fit. Any fit in the lower subtrie
221*71db0c75SAndroid Build Coastguard Worker // is better than the any fit in the upper subtrie, so scan the lower
222*71db0c75SAndroid Build Coastguard Worker // and return to the upper only if no better fits were found. (Any better
223*71db0c75SAndroid Build Coastguard Worker // fit found clears the deferred upper subtrie.)
224*71db0c75SAndroid Build Coastguard Worker LIBC_ASSERT((!deferred_upper_trie ||
225*71db0c75SAndroid Build Coastguard Worker cur_range.upper().max() < deferred_upper_range.min) &&
226*71db0c75SAndroid Build Coastguard Worker "old deferred upper subtrie should be outclassed by new");
227*71db0c75SAndroid Build Coastguard Worker deferred_upper_trie = cur->upper;
228*71db0c75SAndroid Build Coastguard Worker deferred_upper_range = cur_range.upper();
229*71db0c75SAndroid Build Coastguard Worker cur = cur->lower;
230*71db0c75SAndroid Build Coastguard Worker cur_range = cur_range.lower();
231*71db0c75SAndroid Build Coastguard Worker }
232*71db0c75SAndroid Build Coastguard Worker }
233*71db0c75SAndroid Build Coastguard Worker }
234*71db0c75SAndroid Build Coastguard Worker
235*71db0c75SAndroid Build Coastguard Worker } // namespace LIBC_NAMESPACE_DECL
236*71db0c75SAndroid Build Coastguard Worker
237*71db0c75SAndroid Build Coastguard Worker #endif // LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
238