LLVM API Documentation
00001 //==--- ImmutableList.h - Immutable (functional) list interface --*- C++ -*-==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines the ImmutableList class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #ifndef LLVM_ADT_IMMUTABLELIST_H 00015 #define LLVM_ADT_IMMUTABLELIST_H 00016 00017 #include "llvm/ADT/FoldingSet.h" 00018 #include "llvm/Support/Allocator.h" 00019 #include "llvm/Support/DataTypes.h" 00020 #include <cassert> 00021 00022 namespace llvm { 00023 00024 template <typename T> class ImmutableListFactory; 00025 00026 template <typename T> 00027 class ImmutableListImpl : public FoldingSetNode { 00028 T Head; 00029 const ImmutableListImpl* Tail; 00030 00031 ImmutableListImpl(const T& head, const ImmutableListImpl* tail = 0) 00032 : Head(head), Tail(tail) {} 00033 00034 friend class ImmutableListFactory<T>; 00035 00036 void operator=(const ImmutableListImpl&) LLVM_DELETED_FUNCTION; 00037 ImmutableListImpl(const ImmutableListImpl&) LLVM_DELETED_FUNCTION; 00038 00039 public: 00040 const T& getHead() const { return Head; } 00041 const ImmutableListImpl* getTail() const { return Tail; } 00042 00043 static inline void Profile(FoldingSetNodeID& ID, const T& H, 00044 const ImmutableListImpl* L){ 00045 ID.AddPointer(L); 00046 ID.Add(H); 00047 } 00048 00049 void Profile(FoldingSetNodeID& ID) { 00050 Profile(ID, Head, Tail); 00051 } 00052 }; 00053 00054 /// ImmutableList - This class represents an immutable (functional) list. 00055 /// It is implemented as a smart pointer (wraps ImmutableListImpl), so it 00056 /// it is intended to always be copied by value as if it were a pointer. 00057 /// This interface matches ImmutableSet and ImmutableMap. ImmutableList 00058 /// objects should almost never be created directly, and instead should 00059 /// be created by ImmutableListFactory objects that manage the lifetime 00060 /// of a group of lists. When the factory object is reclaimed, all lists 00061 /// created by that factory are released as well. 00062 template <typename T> 00063 class ImmutableList { 00064 public: 00065 typedef T value_type; 00066 typedef ImmutableListFactory<T> Factory; 00067 00068 private: 00069 const ImmutableListImpl<T>* X; 00070 00071 public: 00072 // This constructor should normally only be called by ImmutableListFactory<T>. 00073 // There may be cases, however, when one needs to extract the internal pointer 00074 // and reconstruct a list object from that pointer. 00075 ImmutableList(const ImmutableListImpl<T>* x = 0) : X(x) {} 00076 00077 const ImmutableListImpl<T>* getInternalPointer() const { 00078 return X; 00079 } 00080 00081 class iterator { 00082 const ImmutableListImpl<T>* L; 00083 public: 00084 iterator() : L(0) {} 00085 iterator(ImmutableList l) : L(l.getInternalPointer()) {} 00086 00087 iterator& operator++() { L = L->getTail(); return *this; } 00088 bool operator==(const iterator& I) const { return L == I.L; } 00089 bool operator!=(const iterator& I) const { return L != I.L; } 00090 const value_type& operator*() const { return L->getHead(); } 00091 ImmutableList getList() const { return L; } 00092 }; 00093 00094 /// begin - Returns an iterator referring to the head of the list, or 00095 /// an iterator denoting the end of the list if the list is empty. 00096 iterator begin() const { return iterator(X); } 00097 00098 /// end - Returns an iterator denoting the end of the list. This iterator 00099 /// does not refer to a valid list element. 00100 iterator end() const { return iterator(); } 00101 00102 /// isEmpty - Returns true if the list is empty. 00103 bool isEmpty() const { return !X; } 00104 00105 bool contains(const T& V) const { 00106 for (iterator I = begin(), E = end(); I != E; ++I) { 00107 if (*I == V) 00108 return true; 00109 } 00110 return false; 00111 } 00112 00113 /// isEqual - Returns true if two lists are equal. Because all lists created 00114 /// from the same ImmutableListFactory are uniqued, this has O(1) complexity 00115 /// because it the contents of the list do not need to be compared. Note 00116 /// that you should only compare two lists created from the same 00117 /// ImmutableListFactory. 00118 bool isEqual(const ImmutableList& L) const { return X == L.X; } 00119 00120 bool operator==(const ImmutableList& L) const { return isEqual(L); } 00121 00122 /// getHead - Returns the head of the list. 00123 const T& getHead() { 00124 assert (!isEmpty() && "Cannot get the head of an empty list."); 00125 return X->getHead(); 00126 } 00127 00128 /// getTail - Returns the tail of the list, which is another (possibly empty) 00129 /// ImmutableList. 00130 ImmutableList getTail() { 00131 return X ? X->getTail() : 0; 00132 } 00133 00134 void Profile(FoldingSetNodeID& ID) const { 00135 ID.AddPointer(X); 00136 } 00137 }; 00138 00139 template <typename T> 00140 class ImmutableListFactory { 00141 typedef ImmutableListImpl<T> ListTy; 00142 typedef FoldingSet<ListTy> CacheTy; 00143 00144 CacheTy Cache; 00145 uintptr_t Allocator; 00146 00147 bool ownsAllocator() const { 00148 return Allocator & 0x1 ? false : true; 00149 } 00150 00151 BumpPtrAllocator& getAllocator() const { 00152 return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1); 00153 } 00154 00155 public: 00156 ImmutableListFactory() 00157 : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {} 00158 00159 ImmutableListFactory(BumpPtrAllocator& Alloc) 00160 : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {} 00161 00162 ~ImmutableListFactory() { 00163 if (ownsAllocator()) delete &getAllocator(); 00164 } 00165 00166 ImmutableList<T> concat(const T& Head, ImmutableList<T> Tail) { 00167 // Profile the new list to see if it already exists in our cache. 00168 FoldingSetNodeID ID; 00169 void* InsertPos; 00170 00171 const ListTy* TailImpl = Tail.getInternalPointer(); 00172 ListTy::Profile(ID, Head, TailImpl); 00173 ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos); 00174 00175 if (!L) { 00176 // The list does not exist in our cache. Create it. 00177 BumpPtrAllocator& A = getAllocator(); 00178 L = (ListTy*) A.Allocate<ListTy>(); 00179 new (L) ListTy(Head, TailImpl); 00180 00181 // Insert the new list into the cache. 00182 Cache.InsertNode(L, InsertPos); 00183 } 00184 00185 return L; 00186 } 00187 00188 ImmutableList<T> add(const T& D, ImmutableList<T> L) { 00189 return concat(D, L); 00190 } 00191 00192 ImmutableList<T> getEmptyList() const { 00193 return ImmutableList<T>(0); 00194 } 00195 00196 ImmutableList<T> create(const T& X) { 00197 return Concat(X, getEmptyList()); 00198 } 00199 }; 00200 00201 //===----------------------------------------------------------------------===// 00202 // Partially-specialized Traits. 00203 //===----------------------------------------------------------------------===// 00204 00205 template<typename T> struct DenseMapInfo; 00206 template<typename T> struct DenseMapInfo<ImmutableList<T> > { 00207 static inline ImmutableList<T> getEmptyKey() { 00208 return reinterpret_cast<ImmutableListImpl<T>*>(-1); 00209 } 00210 static inline ImmutableList<T> getTombstoneKey() { 00211 return reinterpret_cast<ImmutableListImpl<T>*>(-2); 00212 } 00213 static unsigned getHashValue(ImmutableList<T> X) { 00214 uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer()); 00215 return (unsigned((uintptr_t)PtrVal) >> 4) ^ 00216 (unsigned((uintptr_t)PtrVal) >> 9); 00217 } 00218 static bool isEqual(ImmutableList<T> X1, ImmutableList<T> X2) { 00219 return X1 == X2; 00220 } 00221 }; 00222 00223 template <typename T> struct isPodLike; 00224 template <typename T> 00225 struct isPodLike<ImmutableList<T> > { static const bool value = true; }; 00226 00227 } // end llvm namespace 00228 00229 #endif