1 //==--- ImmutableList.h - Immutable (functional) list interface --*- C++ -*-==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines the ImmutableList class. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_ADT_IMLIST_H 15 #define LLVM_ADT_IMLIST_H 16 17 #include "llvm/Support/Allocator.h" 18 #include "llvm/ADT/FoldingSet.h" 19 #include "llvm/Support/DataTypes.h" 20 #include <cassert> 21 22 namespace llvm { 23 24 template <typename T> class ImmutableListFactory; 25 26 template <typename T> 27 class ImmutableListImpl : public FoldingSetNode { 28 T Head; 29 const ImmutableListImpl* Tail; 30 31 ImmutableListImpl(const T& head, const ImmutableListImpl* tail = 0) Head(head)32 : Head(head), Tail(tail) {} 33 34 friend class ImmutableListFactory<T>; 35 36 // Do not implement. 37 void operator=(const ImmutableListImpl&); 38 ImmutableListImpl(const ImmutableListImpl&); 39 40 public: getHead()41 const T& getHead() const { return Head; } getTail()42 const ImmutableListImpl* getTail() const { return Tail; } 43 Profile(FoldingSetNodeID & ID,const T & H,const ImmutableListImpl * L)44 static inline void Profile(FoldingSetNodeID& ID, const T& H, 45 const ImmutableListImpl* L){ 46 ID.AddPointer(L); 47 ID.Add(H); 48 } 49 Profile(FoldingSetNodeID & ID)50 void Profile(FoldingSetNodeID& ID) { 51 Profile(ID, Head, Tail); 52 } 53 }; 54 55 /// ImmutableList - This class represents an immutable (functional) list. 56 /// It is implemented as a smart pointer (wraps ImmutableListImpl), so it 57 /// it is intended to always be copied by value as if it were a pointer. 58 /// This interface matches ImmutableSet and ImmutableMap. ImmutableList 59 /// objects should almost never be created directly, and instead should 60 /// be created by ImmutableListFactory objects that manage the lifetime 61 /// of a group of lists. When the factory object is reclaimed, all lists 62 /// created by that factory are released as well. 63 template <typename T> 64 class ImmutableList { 65 public: 66 typedef T value_type; 67 typedef ImmutableListFactory<T> Factory; 68 69 private: 70 const ImmutableListImpl<T>* X; 71 72 public: 73 // This constructor should normally only be called by ImmutableListFactory<T>. 74 // There may be cases, however, when one needs to extract the internal pointer 75 // and reconstruct a list object from that pointer. X(x)76 ImmutableList(const ImmutableListImpl<T>* x = 0) : X(x) {} 77 getInternalPointer()78 const ImmutableListImpl<T>* getInternalPointer() const { 79 return X; 80 } 81 82 class iterator { 83 const ImmutableListImpl<T>* L; 84 public: iterator()85 iterator() : L(0) {} iterator(ImmutableList l)86 iterator(ImmutableList l) : L(l.getInternalPointer()) {} 87 88 iterator& operator++() { L = L->getTail(); return *this; } 89 bool operator==(const iterator& I) const { return L == I.L; } 90 bool operator!=(const iterator& I) const { return L != I.L; } 91 const value_type& operator*() const { return L->getHead(); } getList()92 ImmutableList getList() const { return L; } 93 }; 94 95 /// begin - Returns an iterator referring to the head of the list, or 96 /// an iterator denoting the end of the list if the list is empty. begin()97 iterator begin() const { return iterator(X); } 98 99 /// end - Returns an iterator denoting the end of the list. This iterator 100 /// does not refer to a valid list element. end()101 iterator end() const { return iterator(); } 102 103 /// isEmpty - Returns true if the list is empty. isEmpty()104 bool isEmpty() const { return !X; } 105 contains(const T & V)106 bool contains(const T& V) const { 107 for (iterator I = begin(), E = end(); I != E; ++I) { 108 if (*I == V) 109 return true; 110 } 111 return false; 112 } 113 114 /// isEqual - Returns true if two lists are equal. Because all lists created 115 /// from the same ImmutableListFactory are uniqued, this has O(1) complexity 116 /// because it the contents of the list do not need to be compared. Note 117 /// that you should only compare two lists created from the same 118 /// ImmutableListFactory. isEqual(const ImmutableList & L)119 bool isEqual(const ImmutableList& L) const { return X == L.X; } 120 121 bool operator==(const ImmutableList& L) const { return isEqual(L); } 122 123 /// getHead - Returns the head of the list. getHead()124 const T& getHead() { 125 assert (!isEmpty() && "Cannot get the head of an empty list."); 126 return X->getHead(); 127 } 128 129 /// getTail - Returns the tail of the list, which is another (possibly empty) 130 /// ImmutableList. getTail()131 ImmutableList getTail() { 132 return X ? X->getTail() : 0; 133 } 134 Profile(FoldingSetNodeID & ID)135 void Profile(FoldingSetNodeID& ID) const { 136 ID.AddPointer(X); 137 } 138 }; 139 140 template <typename T> 141 class ImmutableListFactory { 142 typedef ImmutableListImpl<T> ListTy; 143 typedef FoldingSet<ListTy> CacheTy; 144 145 CacheTy Cache; 146 uintptr_t Allocator; 147 ownsAllocator()148 bool ownsAllocator() const { 149 return Allocator & 0x1 ? false : true; 150 } 151 getAllocator()152 BumpPtrAllocator& getAllocator() const { 153 return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1); 154 } 155 156 public: ImmutableListFactory()157 ImmutableListFactory() 158 : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {} 159 ImmutableListFactory(BumpPtrAllocator & Alloc)160 ImmutableListFactory(BumpPtrAllocator& Alloc) 161 : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {} 162 ~ImmutableListFactory()163 ~ImmutableListFactory() { 164 if (ownsAllocator()) delete &getAllocator(); 165 } 166 concat(const T & Head,ImmutableList<T> Tail)167 ImmutableList<T> concat(const T& Head, ImmutableList<T> Tail) { 168 // Profile the new list to see if it already exists in our cache. 169 FoldingSetNodeID ID; 170 void* InsertPos; 171 172 const ListTy* TailImpl = Tail.getInternalPointer(); 173 ListTy::Profile(ID, Head, TailImpl); 174 ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos); 175 176 if (!L) { 177 // The list does not exist in our cache. Create it. 178 BumpPtrAllocator& A = getAllocator(); 179 L = (ListTy*) A.Allocate<ListTy>(); 180 new (L) ListTy(Head, TailImpl); 181 182 // Insert the new list into the cache. 183 Cache.InsertNode(L, InsertPos); 184 } 185 186 return L; 187 } 188 add(const T & D,ImmutableList<T> L)189 ImmutableList<T> add(const T& D, ImmutableList<T> L) { 190 return concat(D, L); 191 } 192 getEmptyList()193 ImmutableList<T> getEmptyList() const { 194 return ImmutableList<T>(0); 195 } 196 create(const T & X)197 ImmutableList<T> create(const T& X) { 198 return Concat(X, getEmptyList()); 199 } 200 }; 201 202 //===----------------------------------------------------------------------===// 203 // Partially-specialized Traits. 204 //===----------------------------------------------------------------------===// 205 206 template<typename T> struct DenseMapInfo; 207 template<typename T> struct DenseMapInfo<ImmutableList<T> > { 208 static inline ImmutableList<T> getEmptyKey() { 209 return reinterpret_cast<ImmutableListImpl<T>*>(-1); 210 } 211 static inline ImmutableList<T> getTombstoneKey() { 212 return reinterpret_cast<ImmutableListImpl<T>*>(-2); 213 } 214 static unsigned getHashValue(ImmutableList<T> X) { 215 uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer()); 216 return (unsigned((uintptr_t)PtrVal) >> 4) ^ 217 (unsigned((uintptr_t)PtrVal) >> 9); 218 } 219 static bool isEqual(ImmutableList<T> X1, ImmutableList<T> X2) { 220 return X1 == X2; 221 } 222 }; 223 224 template <typename T> struct isPodLike; 225 template <typename T> 226 struct isPodLike<ImmutableList<T> > { static const bool value = true; }; 227 228 } // end llvm namespace 229 230 #endif 231