Path: blob/main/contrib/llvm-project/libc/src/__support/freestore.h
213766 views
//===-- Interface for freestore ------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLVM_LIBC_SRC___SUPPORT_FREESTORE_H9#define LLVM_LIBC_SRC___SUPPORT_FREESTORE_H1011#include "freetrie.h"1213namespace LIBC_NAMESPACE_DECL {1415/// A best-fit store of variously-sized free blocks. Blocks can be inserted and16/// removed in logarithmic time.17class FreeStore {18public:19FreeStore() = default;20FreeStore(const FreeStore &other) = delete;21FreeStore &operator=(const FreeStore &other) = delete;2223/// Sets the range of possible block sizes. This can only be called when the24/// trie is empty.25LIBC_INLINE void set_range(FreeTrie::SizeRange range) {26large_trie.set_range(range);27}2829/// Insert a free block. If the block is too small to be tracked, nothing30/// happens.31void insert(Block *block);3233/// Remove a free block. If the block is too small to be tracked, nothing34/// happens.35void remove(Block *block);3637/// Remove a best-fit free block that can contain the given size when38/// allocated. Returns nullptr if there is no such block.39Block *remove_best_fit(size_t size);4041private:42static constexpr size_t MIN_OUTER_SIZE =43align_up(sizeof(Block) + sizeof(FreeList::Node), alignof(max_align_t));44static constexpr size_t MIN_LARGE_OUTER_SIZE =45align_up(sizeof(Block) + sizeof(FreeTrie::Node), alignof(max_align_t));46static constexpr size_t NUM_SMALL_SIZES =47(MIN_LARGE_OUTER_SIZE - MIN_OUTER_SIZE) / alignof(max_align_t);4849LIBC_INLINE static bool too_small(Block *block) {50return block->outer_size() < MIN_OUTER_SIZE;51}52LIBC_INLINE static bool is_small(Block *block) {53return block->outer_size() < MIN_LARGE_OUTER_SIZE;54}5556FreeList &small_list(Block *block);57FreeList *find_best_small_fit(size_t size);5859cpp::array<FreeList, NUM_SMALL_SIZES> small_lists;60FreeTrie large_trie;61};6263LIBC_INLINE void FreeStore::insert(Block *block) {64if (too_small(block))65return;66if (is_small(block))67small_list(block).push(block);68else69large_trie.push(block);70}7172LIBC_INLINE void FreeStore::remove(Block *block) {73if (too_small(block))74return;75if (is_small(block)) {76small_list(block).remove(77reinterpret_cast<FreeList::Node *>(block->usable_space()));78} else {79large_trie.remove(80reinterpret_cast<FreeTrie::Node *>(block->usable_space()));81}82}8384LIBC_INLINE Block *FreeStore::remove_best_fit(size_t size) {85if (FreeList *list = find_best_small_fit(size)) {86Block *block = list->front();87list->pop();88return block;89}90if (FreeTrie::Node *best_fit = large_trie.find_best_fit(size)) {91Block *block = best_fit->block();92large_trie.remove(best_fit);93return block;94}95return nullptr;96}9798LIBC_INLINE FreeList &FreeStore::small_list(Block *block) {99LIBC_ASSERT(is_small(block) && "only legal for small blocks");100return small_lists[(block->outer_size() - MIN_OUTER_SIZE) /101alignof(max_align_t)];102}103104LIBC_INLINE FreeList *FreeStore::find_best_small_fit(size_t size) {105for (FreeList &list : small_lists)106if (!list.empty() && list.size() >= size)107return &list;108return nullptr;109}110111} // namespace LIBC_NAMESPACE_DECL112113#endif // LLVM_LIBC_SRC___SUPPORT_FREESTORE_H114115116