ImmutableMap.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===--- ImmutableMap.h - Immutable (functional) map interface --*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. ///
  14. /// \file
  15. /// This file defines the ImmutableMap class.
  16. ///
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_ADT_IMMUTABLEMAP_H
  19. #define LLVM_ADT_IMMUTABLEMAP_H
  20. #include "llvm/ADT/FoldingSet.h"
  21. #include "llvm/ADT/ImmutableSet.h"
  22. #include "llvm/Support/Allocator.h"
  23. #include <utility>
  24. namespace llvm {
  25. /// ImutKeyValueInfo -Traits class used by ImmutableMap. While both the first
  26. /// and second elements in a pair are used to generate profile information,
  27. /// only the first element (the key) is used by isEqual and isLess.
  28. template <typename T, typename S>
  29. struct ImutKeyValueInfo {
  30. using value_type = const std::pair<T,S>;
  31. using value_type_ref = const value_type&;
  32. using key_type = const T;
  33. using key_type_ref = const T&;
  34. using data_type = const S;
  35. using data_type_ref = const S&;
  36. static inline key_type_ref KeyOfValue(value_type_ref V) {
  37. return V.first;
  38. }
  39. static inline data_type_ref DataOfValue(value_type_ref V) {
  40. return V.second;
  41. }
  42. static inline bool isEqual(key_type_ref L, key_type_ref R) {
  43. return ImutContainerInfo<T>::isEqual(L,R);
  44. }
  45. static inline bool isLess(key_type_ref L, key_type_ref R) {
  46. return ImutContainerInfo<T>::isLess(L,R);
  47. }
  48. static inline bool isDataEqual(data_type_ref L, data_type_ref R) {
  49. return ImutContainerInfo<S>::isEqual(L,R);
  50. }
  51. static inline void Profile(FoldingSetNodeID& ID, value_type_ref V) {
  52. ImutContainerInfo<T>::Profile(ID, V.first);
  53. ImutContainerInfo<S>::Profile(ID, V.second);
  54. }
  55. };
  56. template <typename KeyT, typename ValT,
  57. typename ValInfo = ImutKeyValueInfo<KeyT,ValT>>
  58. class ImmutableMap {
  59. public:
  60. using value_type = typename ValInfo::value_type;
  61. using value_type_ref = typename ValInfo::value_type_ref;
  62. using key_type = typename ValInfo::key_type;
  63. using key_type_ref = typename ValInfo::key_type_ref;
  64. using data_type = typename ValInfo::data_type;
  65. using data_type_ref = typename ValInfo::data_type_ref;
  66. using TreeTy = ImutAVLTree<ValInfo>;
  67. protected:
  68. IntrusiveRefCntPtr<TreeTy> Root;
  69. public:
  70. /// Constructs a map from a pointer to a tree root. In general one
  71. /// should use a Factory object to create maps instead of directly
  72. /// invoking the constructor, but there are cases where make this
  73. /// constructor public is useful.
  74. explicit ImmutableMap(const TreeTy *R) : Root(const_cast<TreeTy *>(R)) {}
  75. class Factory {
  76. typename TreeTy::Factory F;
  77. const bool Canonicalize;
  78. public:
  79. Factory(bool canonicalize = true) : Canonicalize(canonicalize) {}
  80. Factory(BumpPtrAllocator &Alloc, bool canonicalize = true)
  81. : F(Alloc), Canonicalize(canonicalize) {}
  82. Factory(const Factory &) = delete;
  83. Factory &operator=(const Factory &) = delete;
  84. ImmutableMap getEmptyMap() { return ImmutableMap(F.getEmptyTree()); }
  85. [[nodiscard]] ImmutableMap add(ImmutableMap Old, key_type_ref K,
  86. data_type_ref D) {
  87. TreeTy *T = F.add(Old.Root.get(), std::pair<key_type, data_type>(K, D));
  88. return ImmutableMap(Canonicalize ? F.getCanonicalTree(T): T);
  89. }
  90. [[nodiscard]] ImmutableMap remove(ImmutableMap Old, key_type_ref K) {
  91. TreeTy *T = F.remove(Old.Root.get(), K);
  92. return ImmutableMap(Canonicalize ? F.getCanonicalTree(T): T);
  93. }
  94. typename TreeTy::Factory *getTreeFactory() const {
  95. return const_cast<typename TreeTy::Factory *>(&F);
  96. }
  97. };
  98. bool contains(key_type_ref K) const {
  99. return Root ? Root->contains(K) : false;
  100. }
  101. bool operator==(const ImmutableMap &RHS) const {
  102. return Root && RHS.Root ? Root->isEqual(*RHS.Root.get()) : Root == RHS.Root;
  103. }
  104. bool operator!=(const ImmutableMap &RHS) const {
  105. return Root && RHS.Root ? Root->isNotEqual(*RHS.Root.get())
  106. : Root != RHS.Root;
  107. }
  108. TreeTy *getRoot() const {
  109. if (Root) { Root->retain(); }
  110. return Root.get();
  111. }
  112. TreeTy *getRootWithoutRetain() const { return Root.get(); }
  113. void manualRetain() {
  114. if (Root) Root->retain();
  115. }
  116. void manualRelease() {
  117. if (Root) Root->release();
  118. }
  119. bool isEmpty() const { return !Root; }
  120. public:
  121. //===--------------------------------------------------===//
  122. // For testing.
  123. //===--------------------------------------------------===//
  124. void verify() const { if (Root) Root->verify(); }
  125. //===--------------------------------------------------===//
  126. // Iterators.
  127. //===--------------------------------------------------===//
  128. class iterator : public ImutAVLValueIterator<ImmutableMap> {
  129. friend class ImmutableMap;
  130. iterator() = default;
  131. explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
  132. public:
  133. key_type_ref getKey() const { return (*this)->first; }
  134. data_type_ref getData() const { return (*this)->second; }
  135. };
  136. iterator begin() const { return iterator(Root.get()); }
  137. iterator end() const { return iterator(); }
  138. data_type* lookup(key_type_ref K) const {
  139. if (Root) {
  140. TreeTy* T = Root->find(K);
  141. if (T) return &T->getValue().second;
  142. }
  143. return nullptr;
  144. }
  145. /// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
  146. /// which key is the highest in the ordering of keys in the map. This
  147. /// method returns NULL if the map is empty.
  148. value_type* getMaxElement() const {
  149. return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
  150. }
  151. //===--------------------------------------------------===//
  152. // Utility methods.
  153. //===--------------------------------------------------===//
  154. unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
  155. static inline void Profile(FoldingSetNodeID& ID, const ImmutableMap& M) {
  156. ID.AddPointer(M.Root.get());
  157. }
  158. inline void Profile(FoldingSetNodeID& ID) const {
  159. return Profile(ID,*this);
  160. }
  161. };
  162. // NOTE: This will possibly become the new implementation of ImmutableMap some day.
  163. template <typename KeyT, typename ValT,
  164. typename ValInfo = ImutKeyValueInfo<KeyT,ValT>>
  165. class ImmutableMapRef {
  166. public:
  167. using value_type = typename ValInfo::value_type;
  168. using value_type_ref = typename ValInfo::value_type_ref;
  169. using key_type = typename ValInfo::key_type;
  170. using key_type_ref = typename ValInfo::key_type_ref;
  171. using data_type = typename ValInfo::data_type;
  172. using data_type_ref = typename ValInfo::data_type_ref;
  173. using TreeTy = ImutAVLTree<ValInfo>;
  174. using FactoryTy = typename TreeTy::Factory;
  175. protected:
  176. IntrusiveRefCntPtr<TreeTy> Root;
  177. FactoryTy *Factory;
  178. public:
  179. /// Constructs a map from a pointer to a tree root. In general one
  180. /// should use a Factory object to create maps instead of directly
  181. /// invoking the constructor, but there are cases where make this
  182. /// constructor public is useful.
  183. ImmutableMapRef(const TreeTy *R, FactoryTy *F)
  184. : Root(const_cast<TreeTy *>(R)), Factory(F) {}
  185. ImmutableMapRef(const ImmutableMap<KeyT, ValT> &X,
  186. typename ImmutableMap<KeyT, ValT>::Factory &F)
  187. : Root(X.getRootWithoutRetain()), Factory(F.getTreeFactory()) {}
  188. static inline ImmutableMapRef getEmptyMap(FactoryTy *F) {
  189. return ImmutableMapRef(nullptr, F);
  190. }
  191. void manualRetain() {
  192. if (Root) Root->retain();
  193. }
  194. void manualRelease() {
  195. if (Root) Root->release();
  196. }
  197. ImmutableMapRef add(key_type_ref K, data_type_ref D) const {
  198. TreeTy *NewT =
  199. Factory->add(Root.get(), std::pair<key_type, data_type>(K, D));
  200. return ImmutableMapRef(NewT, Factory);
  201. }
  202. ImmutableMapRef remove(key_type_ref K) const {
  203. TreeTy *NewT = Factory->remove(Root.get(), K);
  204. return ImmutableMapRef(NewT, Factory);
  205. }
  206. bool contains(key_type_ref K) const {
  207. return Root ? Root->contains(K) : false;
  208. }
  209. ImmutableMap<KeyT, ValT> asImmutableMap() const {
  210. return ImmutableMap<KeyT, ValT>(Factory->getCanonicalTree(Root.get()));
  211. }
  212. bool operator==(const ImmutableMapRef &RHS) const {
  213. return Root && RHS.Root ? Root->isEqual(*RHS.Root.get()) : Root == RHS.Root;
  214. }
  215. bool operator!=(const ImmutableMapRef &RHS) const {
  216. return Root && RHS.Root ? Root->isNotEqual(*RHS.Root.get())
  217. : Root != RHS.Root;
  218. }
  219. bool isEmpty() const { return !Root; }
  220. //===--------------------------------------------------===//
  221. // For testing.
  222. //===--------------------------------------------------===//
  223. void verify() const {
  224. if (Root)
  225. Root->verify();
  226. }
  227. //===--------------------------------------------------===//
  228. // Iterators.
  229. //===--------------------------------------------------===//
  230. class iterator : public ImutAVLValueIterator<ImmutableMapRef> {
  231. friend class ImmutableMapRef;
  232. iterator() = default;
  233. explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
  234. public:
  235. key_type_ref getKey() const { return (*this)->first; }
  236. data_type_ref getData() const { return (*this)->second; }
  237. };
  238. iterator begin() const { return iterator(Root.get()); }
  239. iterator end() const { return iterator(); }
  240. data_type *lookup(key_type_ref K) const {
  241. if (Root) {
  242. TreeTy* T = Root->find(K);
  243. if (T) return &T->getValue().second;
  244. }
  245. return nullptr;
  246. }
  247. /// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
  248. /// which key is the highest in the ordering of keys in the map. This
  249. /// method returns NULL if the map is empty.
  250. value_type* getMaxElement() const {
  251. return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
  252. }
  253. //===--------------------------------------------------===//
  254. // Utility methods.
  255. //===--------------------------------------------------===//
  256. unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
  257. static inline void Profile(FoldingSetNodeID &ID, const ImmutableMapRef &M) {
  258. ID.AddPointer(M.Root.get());
  259. }
  260. inline void Profile(FoldingSetNodeID &ID) const { return Profile(ID, *this); }
  261. };
  262. } // end namespace llvm
  263. #endif // LLVM_ADT_IMMUTABLEMAP_H
  264. #ifdef __GNUC__
  265. #pragma GCC diagnostic pop
  266. #endif