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 <cstddef>
21#include <cstdint>
22#include <iterator>
23#include <new>
24
25namespace llvm {
26
27template <typename T> class ImmutableListFactory;
28
29template <typename T>
30class ImmutableListImpl : public FoldingSetNode {
31 friend class ImmutableListFactory<T>;
32
33 T Head;
34 const ImmutableListImpl* Tail;
35
36 template <typename ElemT>
37 ImmutableListImpl(ElemT &&head, const ImmutableListImpl *tail = nullptr)
38 : Head(std::forward<ElemT>(head)), Tail(tail) {}
39
40public:
41 ImmutableListImpl(const ImmutableListImpl &) = delete;
42 ImmutableListImpl &operator=(const ImmutableListImpl &) = delete;
43
44 const T& getHead() const { return Head; }
45 const ImmutableListImpl* getTail() const { return Tail; }
46
47 static inline void Profile(FoldingSetNodeID& ID, const T& H,
48 const ImmutableListImpl* L){
49 ID.AddPointer(L);
50 ID.Add(H);
51 }
52
54 Profile(ID, Head, Tail);
55 }
56};
57
58/// This class represents an immutable (functional) list. It is implemented as a
59/// smart pointer (wraps ImmutableListImpl), so it is intended to always be
60/// copied by value as if it were a pointer. This interface matches ImmutableSet
61/// and ImmutableMap. ImmutableList objects should almost never be created
62/// directly, and instead should be created by ImmutableListFactory objects that
63/// manage the lifetime of a group of lists. When the factory object is
64/// reclaimed, all lists created by that factory are released as well.
65template <typename T>
67public:
68 using value_type = T;
70
71 static_assert(std::is_trivially_destructible<T>::value,
72 "T must be trivially destructible!");
73
74private:
75 const ImmutableListImpl<T>* X;
76
77public:
78 // This constructor should normally only be called by ImmutableListFactory<T>.
79 // There may be cases, however, when one needs to extract the internal pointer
80 // and reconstruct a list object from that pointer.
81 ImmutableList(const ImmutableListImpl<T>* x = nullptr) : X(x) {}
82
84 return X;
85 }
86
87 class iterator {
88 const ImmutableListImpl<T>* L = nullptr;
89
90 public:
91 using iterator_category = std::forward_iterator_tag;
92 using value_type = std::remove_reference_t<T>;
93 using difference_type = std::ptrdiff_t;
94 using pointer = const value_type *;
95 using reference = const value_type &;
96
97 iterator() = default;
99
100 iterator& operator++() { L = L->getTail(); return *this; }
102 iterator Tmp = *this;
103 ++*this;
104 return Tmp;
105 }
106 bool operator==(const iterator& I) const { return L == I.L; }
107 bool operator!=(const iterator& I) const { return L != I.L; }
108 const value_type& operator*() const { return L->getHead(); }
109 const std::remove_reference_t<value_type> *operator->() const {
110 return &L->getHead();
111 }
112
113 ImmutableList getList() const { return L; }
114 };
115
116 /// Returns an iterator referring to the head of the list, or an iterator
117 /// denoting the end of the list if the list is empty.
118 iterator begin() const { return iterator(X); }
119
120 /// Returns an iterator denoting the end of the list. This iterator does not
121 /// refer to a valid list element.
122 iterator end() const { return iterator(); }
123
124 /// Returns true if the list is empty.
125 bool isEmpty() const { return !X; }
126
127 bool contains(const T& V) const {
128 for (iterator I = begin(), E = end(); I != E; ++I) {
129 if (*I == V)
130 return true;
131 }
132 return false;
133 }
134
135 /// Returns true if two lists are equal. Because all lists created from the
136 /// same ImmutableListFactory are uniqued, this has O(1) complexity because it
137 /// the contents of the list do not need to be compared. Note that you should
138 /// only compare two lists created from the same ImmutableListFactory.
139 bool isEqual(const ImmutableList& L) const { return X == L.X; }
140
141 bool operator==(const ImmutableList& L) const { return isEqual(L); }
142
143 /// Returns the head of the list.
144 const T& getHead() const {
145 assert(!isEmpty() && "Cannot get the head of an empty list.");
146 return X->getHead();
147 }
148
149 /// Returns the tail of the list, which is another (possibly empty)
150 /// ImmutableList.
152 return X ? X->getTail() : nullptr;
153 }
154
156 ID.AddPointer(X);
157 }
158};
159
160template <typename T>
162 using ListTy = ImmutableListImpl<T>;
163 using CacheTy = FoldingSet<ListTy>;
164
165 CacheTy Cache;
166 uintptr_t Allocator;
167
168 bool ownsAllocator() const {
169 return (Allocator & 0x1) == 0;
170 }
171
172 BumpPtrAllocator& getAllocator() const {
173 return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1);
174 }
175
176public:
178 : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {}
179
181 : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {}
182
184 if (ownsAllocator()) delete &getAllocator();
185 }
186
187 template <typename ElemT>
188 [[nodiscard]] ImmutableList<T> concat(ElemT &&Head, ImmutableList<T> Tail) {
189 // Profile the new list to see if it already exists in our cache.
191 void* InsertPos;
192
193 const ListTy* TailImpl = Tail.getInternalPointer();
194 ListTy::Profile(ID, Head, TailImpl);
195 ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos);
196
197 if (!L) {
198 // The list does not exist in our cache. Create it.
199 BumpPtrAllocator& A = getAllocator();
200 L = (ListTy*) A.Allocate<ListTy>();
201 new (L) ListTy(std::forward<ElemT>(Head), TailImpl);
202
203 // Insert the new list into the cache.
204 Cache.InsertNode(L, InsertPos);
205 }
206
207 return L;
208 }
209
210 template <typename ElemT>
211 [[nodiscard]] ImmutableList<T> add(ElemT &&Data, ImmutableList<T> L) {
212 return concat(std::forward<ElemT>(Data), L);
213 }
214
215 template <typename... CtorArgs>
217 CtorArgs &&...Args) {
218 return concat(T(std::forward<CtorArgs>(Args)...), Tail);
219 }
220
222 return ImmutableList<T>(nullptr);
223 }
224
225 template <typename ElemT>
227 return concat(std::forward<ElemT>(Data), getEmptyList());
228 }
229};
230
231//===----------------------------------------------------------------------===//
232// Partially-specialized Traits.
233//===----------------------------------------------------------------------===//
234
235template <typename T> struct DenseMapInfo<ImmutableList<T>, void> {
236 static unsigned getHashValue(ImmutableList<T> X) {
237 return DenseMapInfo<const void *>::getHashValue(X.getInternalPointer());
238 }
239
241 return X1 == X2;
242 }
243};
244
245} // end namespace llvm
246
247#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:853
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
std::remove_reference_t< T > value_type
const std::remove_reference_t< value_type > * operator->() const
const value_type & reference
const value_type & operator*() const
ImmutableList getList() const
bool operator!=(const iterator &I) const
std::forward_iterator_tag iterator_category
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...