File indexing completed on 2026-05-10 08:43:06
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_ADT_IMMUTABLELIST_H
0015 #define LLVM_ADT_IMMUTABLELIST_H
0016
0017 #include "llvm/ADT/FoldingSet.h"
0018 #include "llvm/Support/Allocator.h"
0019 #include <cassert>
0020 #include <cstdint>
0021 #include <new>
0022
0023 namespace llvm {
0024
0025 template <typename T> class ImmutableListFactory;
0026
0027 template <typename T>
0028 class ImmutableListImpl : public FoldingSetNode {
0029 friend class ImmutableListFactory<T>;
0030
0031 T Head;
0032 const ImmutableListImpl* Tail;
0033
0034 template <typename ElemT>
0035 ImmutableListImpl(ElemT &&head, const ImmutableListImpl *tail = nullptr)
0036 : Head(std::forward<ElemT>(head)), Tail(tail) {}
0037
0038 public:
0039 ImmutableListImpl(const ImmutableListImpl &) = delete;
0040 ImmutableListImpl &operator=(const ImmutableListImpl &) = delete;
0041
0042 const T& getHead() const { return Head; }
0043 const ImmutableListImpl* getTail() const { return Tail; }
0044
0045 static inline void Profile(FoldingSetNodeID& ID, const T& H,
0046 const ImmutableListImpl* L){
0047 ID.AddPointer(L);
0048 ID.Add(H);
0049 }
0050
0051 void Profile(FoldingSetNodeID& ID) {
0052 Profile(ID, Head, Tail);
0053 }
0054 };
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 template <typename T>
0065 class ImmutableList {
0066 public:
0067 using value_type = T;
0068 using Factory = ImmutableListFactory<T>;
0069
0070 static_assert(std::is_trivially_destructible<T>::value,
0071 "T must be trivially destructible!");
0072
0073 private:
0074 const ImmutableListImpl<T>* X;
0075
0076 public:
0077
0078
0079
0080 ImmutableList(const ImmutableListImpl<T>* x = nullptr) : X(x) {}
0081
0082 const ImmutableListImpl<T>* getInternalPointer() const {
0083 return X;
0084 }
0085
0086 class iterator {
0087 const ImmutableListImpl<T>* L = nullptr;
0088
0089 public:
0090 iterator() = default;
0091 iterator(ImmutableList l) : L(l.getInternalPointer()) {}
0092
0093 iterator& operator++() { L = L->getTail(); return *this; }
0094 bool operator==(const iterator& I) const { return L == I.L; }
0095 bool operator!=(const iterator& I) const { return L != I.L; }
0096 const value_type& operator*() const { return L->getHead(); }
0097 const std::remove_reference_t<value_type> *operator->() const {
0098 return &L->getHead();
0099 }
0100
0101 ImmutableList getList() const { return L; }
0102 };
0103
0104
0105
0106 iterator begin() const { return iterator(X); }
0107
0108
0109
0110 iterator end() const { return iterator(); }
0111
0112
0113 bool isEmpty() const { return !X; }
0114
0115 bool contains(const T& V) const {
0116 for (iterator I = begin(), E = end(); I != E; ++I) {
0117 if (*I == V)
0118 return true;
0119 }
0120 return false;
0121 }
0122
0123
0124
0125
0126
0127
0128 bool isEqual(const ImmutableList& L) const { return X == L.X; }
0129
0130 bool operator==(const ImmutableList& L) const { return isEqual(L); }
0131
0132
0133 const T& getHead() const {
0134 assert(!isEmpty() && "Cannot get the head of an empty list.");
0135 return X->getHead();
0136 }
0137
0138
0139
0140 ImmutableList getTail() const {
0141 return X ? X->getTail() : nullptr;
0142 }
0143
0144 void Profile(FoldingSetNodeID& ID) const {
0145 ID.AddPointer(X);
0146 }
0147 };
0148
0149 template <typename T>
0150 class ImmutableListFactory {
0151 using ListTy = ImmutableListImpl<T>;
0152 using CacheTy = FoldingSet<ListTy>;
0153
0154 CacheTy Cache;
0155 uintptr_t Allocator;
0156
0157 bool ownsAllocator() const {
0158 return (Allocator & 0x1) == 0;
0159 }
0160
0161 BumpPtrAllocator& getAllocator() const {
0162 return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1);
0163 }
0164
0165 public:
0166 ImmutableListFactory()
0167 : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {}
0168
0169 ImmutableListFactory(BumpPtrAllocator& Alloc)
0170 : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {}
0171
0172 ~ImmutableListFactory() {
0173 if (ownsAllocator()) delete &getAllocator();
0174 }
0175
0176 template <typename ElemT>
0177 [[nodiscard]] ImmutableList<T> concat(ElemT &&Head, ImmutableList<T> Tail) {
0178
0179 FoldingSetNodeID ID;
0180 void* InsertPos;
0181
0182 const ListTy* TailImpl = Tail.getInternalPointer();
0183 ListTy::Profile(ID, Head, TailImpl);
0184 ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos);
0185
0186 if (!L) {
0187
0188 BumpPtrAllocator& A = getAllocator();
0189 L = (ListTy*) A.Allocate<ListTy>();
0190 new (L) ListTy(std::forward<ElemT>(Head), TailImpl);
0191
0192
0193 Cache.InsertNode(L, InsertPos);
0194 }
0195
0196 return L;
0197 }
0198
0199 template <typename ElemT>
0200 [[nodiscard]] ImmutableList<T> add(ElemT &&Data, ImmutableList<T> L) {
0201 return concat(std::forward<ElemT>(Data), L);
0202 }
0203
0204 template <typename... CtorArgs>
0205 [[nodiscard]] ImmutableList<T> emplace(ImmutableList<T> Tail,
0206 CtorArgs &&...Args) {
0207 return concat(T(std::forward<CtorArgs>(Args)...), Tail);
0208 }
0209
0210 ImmutableList<T> getEmptyList() const {
0211 return ImmutableList<T>(nullptr);
0212 }
0213
0214 template <typename ElemT>
0215 ImmutableList<T> create(ElemT &&Data) {
0216 return concat(std::forward<ElemT>(Data), getEmptyList());
0217 }
0218 };
0219
0220
0221
0222
0223
0224 template <typename T> struct DenseMapInfo<ImmutableList<T>, void> {
0225 static inline ImmutableList<T> getEmptyKey() {
0226 return reinterpret_cast<ImmutableListImpl<T>*>(-1);
0227 }
0228
0229 static inline ImmutableList<T> getTombstoneKey() {
0230 return reinterpret_cast<ImmutableListImpl<T>*>(-2);
0231 }
0232
0233 static unsigned getHashValue(ImmutableList<T> X) {
0234 uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer());
0235 return (unsigned((uintptr_t)PtrVal) >> 4) ^
0236 (unsigned((uintptr_t)PtrVal) >> 9);
0237 }
0238
0239 static bool isEqual(ImmutableList<T> X1, ImmutableList<T> X2) {
0240 return X1 == X2;
0241 }
0242 };
0243
0244 }
0245
0246 #endif