LLVM 23.0.0git
ImmutableList.h
Go to the documentation of this file.
1//==--- ImmutableList.h - Immutable (functional) list interface --*- 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/// \file
10/// This file defines the ImmutableList class.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_ADT_IMMUTABLELIST_H
15#define LLVM_ADT_IMMUTABLELIST_H
16
17#include "llvm/ADT/FoldingSet.h"
19#include <cassert>
20#include <cstdint>
21#include <new>
22
23namespace llvm {
24
25template <typename T> class ImmutableListFactory;
26
27template <typename T>
28class ImmutableListImpl : public FoldingSetNode {
29 friend class ImmutableListFactory<T>;
30
31 T Head;
32 const ImmutableListImpl* Tail;
33
34 template <typename ElemT>
35 ImmutableListImpl(ElemT &&head, const ImmutableListImpl *tail = nullptr)
36 : Head(std::forward<ElemT>(head)), Tail(tail) {}
37
38public:
39 ImmutableListImpl(const ImmutableListImpl &) = delete;
40 ImmutableListImpl &operator=(const ImmutableListImpl &) = delete;
41
42 const T& getHead() const { return Head; }
43 const ImmutableListImpl* getTail() const { return Tail; }
44
45 static inline void Profile(FoldingSetNodeID& ID, const T& H,
46 const ImmutableListImpl* L){
47 ID.AddPointer(L);
48 ID.Add(H);
49 }
50
52 Profile(ID, Head, Tail);
53 }
54};
55
56/// This class represents an immutable (functional) list. It is implemented as a
57/// smart pointer (wraps ImmutableListImpl), so it is intended to always be
58/// copied by value as if it were a pointer. This interface matches ImmutableSet
59/// and ImmutableMap. ImmutableList objects should almost never be created
60/// directly, and instead should be created by ImmutableListFactory objects that
61/// manage the lifetime of a group of lists. When the factory object is
62/// reclaimed, all lists created by that factory are released as well.
63template <typename T>
65public:
66 using value_type = T;
68
69 static_assert(std::is_trivially_destructible<T>::value,
70 "T must be trivially destructible!");
71
72private:
73 const ImmutableListImpl<T>* X;
74
75public:
76 // This constructor should normally only be called by ImmutableListFactory<T>.
77 // There may be cases, however, when one needs to extract the internal pointer
78 // and reconstruct a list object from that pointer.
79 ImmutableList(const ImmutableListImpl<T>* x = nullptr) : X(x) {}
80
82 return X;
83 }
84
85 class iterator {
86 const ImmutableListImpl<T>* L = nullptr;
87
88 public:
89 iterator() = default;
91
92 iterator& operator++() { L = L->getTail(); return *this; }
93 bool operator==(const iterator& I) const { return L == I.L; }
94 bool operator!=(const iterator& I) const { return L != I.L; }
95 const value_type& operator*() const { return L->getHead(); }
96 const std::remove_reference_t<value_type> *operator->() const {
97 return &L->getHead();
98 }
99
100 ImmutableList getList() const { return L; }
101 };
102
103 /// Returns an iterator referring to the head of the list, or an iterator
104 /// denoting the end of the list if the list is empty.
105 iterator begin() const { return iterator(X); }
106
107 /// Returns an iterator denoting the end of the list. This iterator does not
108 /// refer to a valid list element.
109 iterator end() const { return iterator(); }
110
111 /// Returns true if the list is empty.
112 bool isEmpty() const { return !X; }
113
114 bool contains(const T& V) const {
115 for (iterator I = begin(), E = end(); I != E; ++I) {
116 if (*I == V)
117 return true;
118 }
119 return false;
120 }
121
122 /// Returns true if two lists are equal. Because all lists created from the
123 /// same ImmutableListFactory are uniqued, this has O(1) complexity because it
124 /// the contents of the list do not need to be compared. Note that you should
125 /// only compare two lists created from the same ImmutableListFactory.
126 bool isEqual(const ImmutableList& L) const { return X == L.X; }
127
128 bool operator==(const ImmutableList& L) const { return isEqual(L); }
129
130 /// Returns the head of the list.
131 const T& getHead() const {
132 assert(!isEmpty() && "Cannot get the head of an empty list.");
133 return X->getHead();
134 }
135
136 /// Returns the tail of the list, which is another (possibly empty)
137 /// ImmutableList.
139 return X ? X->getTail() : nullptr;
140 }
141
143 ID.AddPointer(X);
144 }
145};
146
147template <typename T>
149 using ListTy = ImmutableListImpl<T>;
150 using CacheTy = FoldingSet<ListTy>;
151
152 CacheTy Cache;
153 uintptr_t Allocator;
154
155 bool ownsAllocator() const {
156 return (Allocator & 0x1) == 0;
157 }
158
159 BumpPtrAllocator& getAllocator() const {
160 return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1);
161 }
162
163public:
165 : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {}
166
168 : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {}
169
171 if (ownsAllocator()) delete &getAllocator();
172 }
173
174 template <typename ElemT>
175 [[nodiscard]] ImmutableList<T> concat(ElemT &&Head, ImmutableList<T> Tail) {
176 // Profile the new list to see if it already exists in our cache.
178 void* InsertPos;
179
180 const ListTy* TailImpl = Tail.getInternalPointer();
181 ListTy::Profile(ID, Head, TailImpl);
182 ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos);
183
184 if (!L) {
185 // The list does not exist in our cache. Create it.
186 BumpPtrAllocator& A = getAllocator();
187 L = (ListTy*) A.Allocate<ListTy>();
188 new (L) ListTy(std::forward<ElemT>(Head), TailImpl);
189
190 // Insert the new list into the cache.
191 Cache.InsertNode(L, InsertPos);
192 }
193
194 return L;
195 }
196
197 template <typename ElemT>
198 [[nodiscard]] ImmutableList<T> add(ElemT &&Data, ImmutableList<T> L) {
199 return concat(std::forward<ElemT>(Data), L);
200 }
201
202 template <typename... CtorArgs>
204 CtorArgs &&...Args) {
205 return concat(T(std::forward<CtorArgs>(Args)...), Tail);
206 }
207
209 return ImmutableList<T>(nullptr);
210 }
211
212 template <typename ElemT>
214 return concat(std::forward<ElemT>(Data), getEmptyList());
215 }
216};
217
218//===----------------------------------------------------------------------===//
219// Partially-specialized Traits.
220//===----------------------------------------------------------------------===//
221
222template <typename T> struct DenseMapInfo<ImmutableList<T>, void> {
224 return reinterpret_cast<ImmutableListImpl<T>*>(-1);
225 }
226
228 return reinterpret_cast<ImmutableListImpl<T>*>(-2);
229 }
230
231 static unsigned getHashValue(ImmutableList<T> X) {
232 uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer());
233 return (unsigned((uintptr_t)PtrVal) >> 4) ^
234 (unsigned((uintptr_t)PtrVal) >> 9);
235 }
236
238 return X1 == X2;
239 }
240};
241
242} // end namespace llvm
243
244#endif // LLVM_ADT_IMMUTABLELIST_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the BumpPtrAllocator interface.
#define X(NUM, ENUM, NAME)
Definition ELF.h:851
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines a hash set that can be used to remove duplication of nodes in a graph.
#define I(x, y, z)
Definition MD5.cpp:57
#define H(x, y, z)
Definition MD5.cpp:56
Load MIR Sample Profile
#define T
This class is used to gather all the unique data bits of a node.
Definition FoldingSet.h:208
This template class is used to instantiate a specialized implementation of the folding set to the nod...
Definition FoldingSet.h:529
ImmutableListFactory(BumpPtrAllocator &Alloc)
ImmutableList< T > create(ElemT &&Data)
ImmutableList< T > add(ElemT &&Data, ImmutableList< T > L)
ImmutableList< T > getEmptyList() const
ImmutableList< T > concat(ElemT &&Head, ImmutableList< T > Tail)
ImmutableList< T > emplace(ImmutableList< T > Tail, CtorArgs &&...Args)
static void Profile(FoldingSetNodeID &ID, const T &H, const ImmutableListImpl *L)
ImmutableListImpl & operator=(const ImmutableListImpl &)=delete
const T & getHead() const
ImmutableListImpl(const ImmutableListImpl &)=delete
const ImmutableListImpl * getTail() const
void Profile(FoldingSetNodeID &ID)
bool operator==(const iterator &I) const
const std::remove_reference_t< value_type > * operator->() const
const value_type & operator*() const
ImmutableList getList() const
bool operator!=(const iterator &I) const
This class represents an immutable (functional) list.
ImmutableListFactory< T > Factory
bool isEmpty() const
Returns true if the list is empty.
iterator end() const
Returns an iterator denoting the end of the list.
const T & getHead() const
Returns the head of the list.
ImmutableList getTail() const
Returns the tail of the list, which is another (possibly empty) ImmutableList.
const ImmutableListImpl< T > * getInternalPointer() const
void Profile(FoldingSetNodeID &ID) const
bool contains(const T &V) const
bool operator==(const ImmutableList &L) const
ImmutableList(const ImmutableListImpl< T > *x=nullptr)
iterator begin() const
Returns an iterator referring to the head of the list, or an iterator denoting the end of the list if...
bool isEqual(const ImmutableList &L) const
Returns true if two lists are equal.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
Definition CallingConv.h:76
This is an optimization pass for GlobalISel generic memory operations.
FoldingSetBase::Node FoldingSetNode
Definition FoldingSet.h:404
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:383
static unsigned getHashValue(ImmutableList< T > X)
static bool isEqual(ImmutableList< T > X1, ImmutableList< T > X2)
An information struct used to provide DenseMap with the various necessary components for a given valu...