/3rd_party/llvm/include/llvm/ADT/ImmutableList.h

https://code.google.com/p/softart/ · C++ Header · 229 lines · 141 code · 46 blank · 42 comment · 11 complexity · 670cbf5c482f25c57f64eb3e7b96a2f5 MD5 · raw file

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