LLVM 24.0.0git
ArrayList.h
Go to the documentation of this file.
1//===- ArrayList.h ----------------------------------------------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H
10#define LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H
11
14#include <atomic>
15
16namespace llvm {
17namespace dwarf_linker {
18namespace parallel {
19
20/// This class is a simple list of T structures. It keeps elements as
21/// pre-allocated groups to save memory for each element's next pointer.
22/// It allocates internal data using specified per-thread BumpPtrAllocator.
23/// Method add() can be called asynchronously.
24template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
25public:
28
29 /// Add specified \p Item to the list.
30 T &add(const T &Item) {
32
33 // Allocate head group if it is not allocated yet.
34 while (!LastGroup) {
36 LastGroup = GroupsHead.load();
37 }
38
39 ItemsGroup *CurGroup;
40 size_t CurItemsCount;
41 do {
42 CurGroup = LastGroup;
43 CurItemsCount = CurGroup->ItemsCount.fetch_add(1);
44
45 // Check whether current group is full.
46 if (CurItemsCount < ItemsGroupSize)
47 break;
48
49 // Allocate next group if necessary.
50 if (!CurGroup->Next)
51 allocateNewGroup(CurGroup->Next);
52
53 LastGroup.compare_exchange_weak(CurGroup, CurGroup->Next);
54 } while (true);
55
56 // Store item into the current group.
57 CurGroup->Items[CurItemsCount] = Item;
58 return CurGroup->Items[CurItemsCount];
59 }
60
61 using ItemHandlerTy = function_ref<void(T &)>;
62
63 /// Enumerate all items and apply specified \p Handler to each.
64 void forEach(ItemHandlerTy Handler) {
65 for (ItemsGroup *CurGroup = GroupsHead; CurGroup;
66 CurGroup = CurGroup->Next) {
67 for (T &Item : *CurGroup)
68 Handler(Item);
69 }
70 }
71
72 /// Check whether list is empty.
73 bool empty() { return !GroupsHead; }
74
75 /// Erase list.
76 void erase() {
77 GroupsHead = nullptr;
78 LastGroup = nullptr;
79 }
80
81 void sort(function_ref<bool(const T &LHS, const T &RHS)> Comparator,
82 bool Parallel = false) {
83 SmallVector<T> SortedItems;
84 forEach([&](T &Item) { SortedItems.push_back(Item); });
85
86 if (SortedItems.size()) {
87 if (Parallel)
88 parallelSort(SortedItems, Comparator);
89 else
90 std::sort(SortedItems.begin(), SortedItems.end(), Comparator);
91
92 size_t SortedItemIdx = 0;
93 forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; });
94 assert(SortedItemIdx == SortedItems.size());
95 }
96 }
97
98 size_t size() {
99 size_t Result = 0;
100
101 for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr;
102 CurGroup = CurGroup->Next)
103 Result += CurGroup->getItemsCount();
104
105 return Result;
106 }
107
108protected:
109 struct ItemsGroup {
110 using ArrayTy = std::array<T, ItemsGroupSize>;
111
112 // Array of items kept by this group.
114
115 // Pointer to the next items group.
116 std::atomic<ItemsGroup *> Next = nullptr;
117
118 // Number of items in this group.
119 // NOTE: ItemsCount could be inaccurate as it might be incremented by
120 // several threads. Use getItemsCount() method to get real number of items
121 // inside ItemsGroup.
122 std::atomic<size_t> ItemsCount = 0;
123
124 size_t getItemsCount() const {
125 return std::min(ItemsCount.load(), ItemsGroupSize);
126 }
127
128 typename ArrayTy::iterator begin() { return Items.begin(); }
129 typename ArrayTy::iterator end() { return Items.begin() + getItemsCount(); }
130 };
131
132 // Allocate new group. Put allocated group into the \p AtomicGroup if
133 // it is empty. If \p AtomicGroup is filled by another thread then
134 // put allocated group into the end of groups list.
135 // \returns true if allocated group is put into the \p AtomicGroup.
136 bool allocateNewGroup(std::atomic<ItemsGroup *> &AtomicGroup) {
137 ItemsGroup *CurGroup = nullptr;
138
139 // Allocate new group.
140 ItemsGroup *NewGroup = Allocator->Allocate<ItemsGroup>();
141 NewGroup->ItemsCount = 0;
142 NewGroup->Next = nullptr;
143
144 // Try to replace current group with allocated one.
145 if (AtomicGroup.compare_exchange_strong(CurGroup, NewGroup))
146 return true;
147
148 // Put allocated group as last group.
149 while (CurGroup) {
150 ItemsGroup *NextGroup = CurGroup->Next;
151
152 if (!NextGroup) {
153 if (CurGroup->Next.compare_exchange_weak(NextGroup, NewGroup))
154 break;
155 }
156
157 CurGroup = NextGroup;
158 }
159
160 return false;
161 }
162
163 std::atomic<ItemsGroup *> GroupsHead = nullptr;
164 std::atomic<ItemsGroup *> LastGroup = nullptr;
166};
167
168} // end of namespace parallel
169} // end of namespace dwarf_linker
170} // end of namespace llvm
171
172#endif // LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define T
Value * RHS
Value * LHS
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
void sort(function_ref< bool(const T &LHS, const T &RHS)> Comparator, bool Parallel=false)
Definition ArrayList.h:81
T & add(const T &Item)
Add specified Item to the list.
Definition ArrayList.h:30
std::atomic< ItemsGroup * > LastGroup
Definition ArrayList.h:164
bool empty()
Check whether list is empty.
Definition ArrayList.h:73
llvm::parallel::PerThreadBumpPtrAllocator * Allocator
Definition ArrayList.h:165
bool allocateNewGroup(std::atomic< ItemsGroup * > &AtomicGroup)
Definition ArrayList.h:136
void forEach(ItemHandlerTy Handler)
Enumerate all items and apply specified Handler to each.
Definition ArrayList.h:64
std::atomic< ItemsGroup * > GroupsHead
Definition ArrayList.h:163
function_ref< void(T &)> ItemHandlerTy
Definition ArrayList.h:61
ArrayList(llvm::parallel::PerThreadBumpPtrAllocator *Allocator)
Definition ArrayList.h:26
An efficient, type-erasing, non-owning reference to a callable.
PerThreadAllocator< BumpPtrAllocator > PerThreadBumpPtrAllocator
This is an optimization pass for GlobalISel generic memory operations.
void parallelSort(RandomAccessIterator Start, RandomAccessIterator End, const Comparator &Comp=Comparator())
Definition Parallel.h:194
std::array< T, ItemsGroupSize > ArrayTy
Definition ArrayList.h:110