Path: blob/main/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/ArrayList.h
35291 views
//===- ArrayList.h ----------------------------------------------*- C++ -*-===//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_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H9#define LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H1011#include "llvm/Support/PerThreadBumpPtrAllocator.h"12#include <atomic>1314namespace llvm {15namespace dwarf_linker {16namespace parallel {1718/// This class is a simple list of T structures. It keeps elements as19/// pre-allocated groups to save memory for each element's next pointer.20/// It allocates internal data using specified per-thread BumpPtrAllocator.21/// Method add() can be called asynchronously.22template <typename T, size_t ItemsGroupSize = 512> class ArrayList {23public:24ArrayList(llvm::parallel::PerThreadBumpPtrAllocator *Allocator)25: Allocator(Allocator) {}2627/// Add specified \p Item to the list.28T &add(const T &Item) {29assert(Allocator);3031// Allocate head group if it is not allocated yet.32while (!LastGroup) {33if (allocateNewGroup(GroupsHead))34LastGroup = GroupsHead.load();35}3637ItemsGroup *CurGroup;38size_t CurItemsCount;39do {40CurGroup = LastGroup;41CurItemsCount = CurGroup->ItemsCount.fetch_add(1);4243// Check whether current group is full.44if (CurItemsCount < ItemsGroupSize)45break;4647// Allocate next group if necessary.48if (!CurGroup->Next)49allocateNewGroup(CurGroup->Next);5051LastGroup.compare_exchange_weak(CurGroup, CurGroup->Next);52} while (true);5354// Store item into the current group.55CurGroup->Items[CurItemsCount] = Item;56return CurGroup->Items[CurItemsCount];57}5859using ItemHandlerTy = function_ref<void(T &)>;6061/// Enumerate all items and apply specified \p Handler to each.62void forEach(ItemHandlerTy Handler) {63for (ItemsGroup *CurGroup = GroupsHead; CurGroup;64CurGroup = CurGroup->Next) {65for (T &Item : *CurGroup)66Handler(Item);67}68}6970/// Check whether list is empty.71bool empty() { return !GroupsHead; }7273/// Erase list.74void erase() {75GroupsHead = nullptr;76LastGroup = nullptr;77}7879void sort(function_ref<bool(const T &LHS, const T &RHS)> Comparator) {80SmallVector<T> SortedItems;81forEach([&](T &Item) { SortedItems.push_back(Item); });8283if (SortedItems.size()) {84std::sort(SortedItems.begin(), SortedItems.end(), Comparator);8586size_t SortedItemIdx = 0;87forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; });88assert(SortedItemIdx == SortedItems.size());89}90}9192size_t size() {93size_t Result = 0;9495for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr;96CurGroup = CurGroup->Next)97Result += CurGroup->getItemsCount();9899return Result;100}101102protected:103struct ItemsGroup {104using ArrayTy = std::array<T, ItemsGroupSize>;105106// Array of items kept by this group.107ArrayTy Items;108109// Pointer to the next items group.110std::atomic<ItemsGroup *> Next = nullptr;111112// Number of items in this group.113// NOTE: ItemsCount could be inaccurate as it might be incremented by114// several threads. Use getItemsCount() method to get real number of items115// inside ItemsGroup.116std::atomic<size_t> ItemsCount = 0;117118size_t getItemsCount() const {119return std::min(ItemsCount.load(), ItemsGroupSize);120}121122typename ArrayTy::iterator begin() { return Items.begin(); }123typename ArrayTy::iterator end() { return Items.begin() + getItemsCount(); }124};125126// Allocate new group. Put allocated group into the \p AtomicGroup if127// it is empty. If \p AtomicGroup is filled by another thread then128// put allocated group into the end of groups list.129// \returns true if allocated group is put into the \p AtomicGroup.130bool allocateNewGroup(std::atomic<ItemsGroup *> &AtomicGroup) {131ItemsGroup *CurGroup = nullptr;132133// Allocate new group.134ItemsGroup *NewGroup = Allocator->Allocate<ItemsGroup>();135NewGroup->ItemsCount = 0;136NewGroup->Next = nullptr;137138// Try to replace current group with allocated one.139if (AtomicGroup.compare_exchange_weak(CurGroup, NewGroup))140return true;141142// Put allocated group as last group.143while (CurGroup) {144ItemsGroup *NextGroup = CurGroup->Next;145146if (!NextGroup) {147if (CurGroup->Next.compare_exchange_weak(NextGroup, NewGroup))148break;149}150151CurGroup = NextGroup;152}153154return false;155}156157std::atomic<ItemsGroup *> GroupsHead = nullptr;158std::atomic<ItemsGroup *> LastGroup = nullptr;159llvm::parallel::PerThreadBumpPtrAllocator *Allocator = nullptr;160};161162} // end of namespace parallel163} // end of namespace dwarf_linker164} // end of namespace llvm165166#endif // LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H167168169