Home | History | Annotate | Download | only in ADT
      1 //===--- ImmutableMap.h - Immutable (functional) map 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 ImmutableMap class.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_ADT_IMMUTABLEMAP_H
     15 #define LLVM_ADT_IMMUTABLEMAP_H
     16 
     17 #include "llvm/ADT/ImmutableSet.h"
     18 
     19 namespace llvm {
     20 
     21 /// ImutKeyValueInfo -Traits class used by ImmutableMap.  While both the first
     22 /// and second elements in a pair are used to generate profile information,
     23 /// only the first element (the key) is used by isEqual and isLess.
     24 template <typename T, typename S>
     25 struct ImutKeyValueInfo {
     26   typedef const std::pair<T,S> value_type;
     27   typedef const value_type& value_type_ref;
     28   typedef const T   key_type;
     29   typedef const T&  key_type_ref;
     30   typedef const S   data_type;
     31   typedef const S&  data_type_ref;
     32 
     33   static inline key_type_ref KeyOfValue(value_type_ref V) {
     34     return V.first;
     35   }
     36 
     37   static inline data_type_ref DataOfValue(value_type_ref V) {
     38     return V.second;
     39   }
     40 
     41   static inline bool isEqual(key_type_ref L, key_type_ref R) {
     42     return ImutContainerInfo<T>::isEqual(L,R);
     43   }
     44   static inline bool isLess(key_type_ref L, key_type_ref R) {
     45     return ImutContainerInfo<T>::isLess(L,R);
     46   }
     47 
     48   static inline bool isDataEqual(data_type_ref L, data_type_ref R) {
     49     return ImutContainerInfo<S>::isEqual(L,R);
     50   }
     51 
     52   static inline void Profile(FoldingSetNodeID& ID, value_type_ref V) {
     53     ImutContainerInfo<T>::Profile(ID, V.first);
     54     ImutContainerInfo<S>::Profile(ID, V.second);
     55   }
     56 };
     57 
     58 
     59 template <typename KeyT, typename ValT,
     60           typename ValInfo = ImutKeyValueInfo<KeyT,ValT> >
     61 class ImmutableMap {
     62 public:
     63   typedef typename ValInfo::value_type      value_type;
     64   typedef typename ValInfo::value_type_ref  value_type_ref;
     65   typedef typename ValInfo::key_type        key_type;
     66   typedef typename ValInfo::key_type_ref    key_type_ref;
     67   typedef typename ValInfo::data_type       data_type;
     68   typedef typename ValInfo::data_type_ref   data_type_ref;
     69   typedef ImutAVLTree<ValInfo>              TreeTy;
     70 
     71 protected:
     72   TreeTy* Root;
     73 
     74 public:
     75   /// Constructs a map from a pointer to a tree root.  In general one
     76   /// should use a Factory object to create maps instead of directly
     77   /// invoking the constructor, but there are cases where make this
     78   /// constructor public is useful.
     79   explicit ImmutableMap(const TreeTy* R) : Root(const_cast<TreeTy*>(R)) {
     80     if (Root) { Root->retain(); }
     81   }
     82   ImmutableMap(const ImmutableMap &X) : Root(X.Root) {
     83     if (Root) { Root->retain(); }
     84   }
     85   ImmutableMap &operator=(const ImmutableMap &X) {
     86     if (Root != X.Root) {
     87       if (X.Root) { X.Root->retain(); }
     88       if (Root) { Root->release(); }
     89       Root = X.Root;
     90     }
     91     return *this;
     92   }
     93   ~ImmutableMap() {
     94     if (Root) { Root->release(); }
     95   }
     96 
     97   class Factory {
     98     typename TreeTy::Factory F;
     99     const bool Canonicalize;
    100 
    101   public:
    102     Factory(bool canonicalize = true)
    103       : Canonicalize(canonicalize) {}
    104 
    105     Factory(BumpPtrAllocator& Alloc, bool canonicalize = true)
    106       : F(Alloc), Canonicalize(canonicalize) {}
    107 
    108     ImmutableMap getEmptyMap() { return ImmutableMap(F.getEmptyTree()); }
    109 
    110     ImmutableMap add(ImmutableMap Old, key_type_ref K, data_type_ref D) {
    111       TreeTy *T = F.add(Old.Root, std::pair<key_type,data_type>(K,D));
    112       return ImmutableMap(Canonicalize ? F.getCanonicalTree(T): T);
    113     }
    114 
    115     ImmutableMap remove(ImmutableMap Old, key_type_ref K) {
    116       TreeTy *T = F.remove(Old.Root,K);
    117       return ImmutableMap(Canonicalize ? F.getCanonicalTree(T): T);
    118     }
    119 
    120     typename TreeTy::Factory *getTreeFactory() const {
    121       return const_cast<typename TreeTy::Factory *>(&F);
    122     }
    123 
    124   private:
    125     Factory(const Factory& RHS) = delete;
    126     void operator=(const Factory& RHS) = delete;
    127   };
    128 
    129   bool contains(key_type_ref K) const {
    130     return Root ? Root->contains(K) : false;
    131   }
    132 
    133   bool operator==(const ImmutableMap &RHS) const {
    134     return Root && RHS.Root ? Root->isEqual(*RHS.Root) : Root == RHS.Root;
    135   }
    136 
    137   bool operator!=(const ImmutableMap &RHS) const {
    138     return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
    139   }
    140 
    141   TreeTy *getRoot() const {
    142     if (Root) { Root->retain(); }
    143     return Root;
    144   }
    145 
    146   TreeTy *getRootWithoutRetain() const {
    147     return Root;
    148   }
    149 
    150   void manualRetain() {
    151     if (Root) Root->retain();
    152   }
    153 
    154   void manualRelease() {
    155     if (Root) Root->release();
    156   }
    157 
    158   bool isEmpty() const { return !Root; }
    159 
    160   //===--------------------------------------------------===//
    161   // Foreach - A limited form of map iteration.
    162   //===--------------------------------------------------===//
    163 
    164 private:
    165   template <typename Callback>
    166   struct CBWrapper {
    167     Callback C;
    168     void operator()(value_type_ref V) { C(V.first,V.second); }
    169   };
    170 
    171   template <typename Callback>
    172   struct CBWrapperRef {
    173     Callback &C;
    174     CBWrapperRef(Callback& c) : C(c) {}
    175 
    176     void operator()(value_type_ref V) { C(V.first,V.second); }
    177   };
    178 
    179 public:
    180   template <typename Callback>
    181   void foreach(Callback& C) {
    182     if (Root) {
    183       CBWrapperRef<Callback> CB(C);
    184       Root->foreach(CB);
    185     }
    186   }
    187 
    188   template <typename Callback>
    189   void foreach() {
    190     if (Root) {
    191       CBWrapper<Callback> CB;
    192       Root->foreach(CB);
    193     }
    194   }
    195 
    196   //===--------------------------------------------------===//
    197   // For testing.
    198   //===--------------------------------------------------===//
    199 
    200   void verify() const { if (Root) Root->verify(); }
    201 
    202   //===--------------------------------------------------===//
    203   // Iterators.
    204   //===--------------------------------------------------===//
    205 
    206   class iterator : public ImutAVLValueIterator<ImmutableMap> {
    207     iterator() = default;
    208     explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
    209     friend class ImmutableMap;
    210 
    211   public:
    212     key_type_ref getKey() const { return (*this)->first; }
    213     data_type_ref getData() const { return (*this)->second; }
    214   };
    215 
    216   iterator begin() const { return iterator(Root); }
    217   iterator end() const { return iterator(); }
    218 
    219   data_type* lookup(key_type_ref K) const {
    220     if (Root) {
    221       TreeTy* T = Root->find(K);
    222       if (T) return &T->getValue().second;
    223     }
    224 
    225     return nullptr;
    226   }
    227 
    228   /// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
    229   ///  which key is the highest in the ordering of keys in the map.  This
    230   ///  method returns NULL if the map is empty.
    231   value_type* getMaxElement() const {
    232     return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
    233   }
    234 
    235   //===--------------------------------------------------===//
    236   // Utility methods.
    237   //===--------------------------------------------------===//
    238 
    239   unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
    240 
    241   static inline void Profile(FoldingSetNodeID& ID, const ImmutableMap& M) {
    242     ID.AddPointer(M.Root);
    243   }
    244 
    245   inline void Profile(FoldingSetNodeID& ID) const {
    246     return Profile(ID,*this);
    247   }
    248 };
    249 
    250 // NOTE: This will possibly become the new implementation of ImmutableMap some day.
    251 template <typename KeyT, typename ValT,
    252 typename ValInfo = ImutKeyValueInfo<KeyT,ValT> >
    253 class ImmutableMapRef {
    254 public:
    255   typedef typename ValInfo::value_type      value_type;
    256   typedef typename ValInfo::value_type_ref  value_type_ref;
    257   typedef typename ValInfo::key_type        key_type;
    258   typedef typename ValInfo::key_type_ref    key_type_ref;
    259   typedef typename ValInfo::data_type       data_type;
    260   typedef typename ValInfo::data_type_ref   data_type_ref;
    261   typedef ImutAVLTree<ValInfo>              TreeTy;
    262   typedef typename TreeTy::Factory          FactoryTy;
    263 
    264 protected:
    265   TreeTy *Root;
    266   FactoryTy *Factory;
    267 
    268 public:
    269   /// Constructs a map from a pointer to a tree root.  In general one
    270   /// should use a Factory object to create maps instead of directly
    271   /// invoking the constructor, but there are cases where make this
    272   /// constructor public is useful.
    273   explicit ImmutableMapRef(const TreeTy* R, FactoryTy *F)
    274     : Root(const_cast<TreeTy*>(R)),
    275       Factory(F) {
    276     if (Root) { Root->retain(); }
    277   }
    278 
    279   explicit ImmutableMapRef(const ImmutableMap<KeyT, ValT> &X,
    280                            typename ImmutableMap<KeyT, ValT>::Factory &F)
    281     : Root(X.getRootWithoutRetain()),
    282       Factory(F.getTreeFactory()) {
    283     if (Root) { Root->retain(); }
    284   }
    285 
    286   ImmutableMapRef(const ImmutableMapRef &X)
    287     : Root(X.Root),
    288       Factory(X.Factory) {
    289     if (Root) { Root->retain(); }
    290   }
    291 
    292   ImmutableMapRef &operator=(const ImmutableMapRef &X) {
    293     if (Root != X.Root) {
    294       if (X.Root)
    295         X.Root->retain();
    296 
    297       if (Root)
    298         Root->release();
    299 
    300       Root = X.Root;
    301       Factory = X.Factory;
    302     }
    303     return *this;
    304   }
    305 
    306   ~ImmutableMapRef() {
    307     if (Root)
    308       Root->release();
    309   }
    310 
    311   static inline ImmutableMapRef getEmptyMap(FactoryTy *F) {
    312     return ImmutableMapRef(0, F);
    313   }
    314 
    315   void manualRetain() {
    316     if (Root) Root->retain();
    317   }
    318 
    319   void manualRelease() {
    320     if (Root) Root->release();
    321   }
    322 
    323   ImmutableMapRef add(key_type_ref K, data_type_ref D) const {
    324     TreeTy *NewT = Factory->add(Root, std::pair<key_type, data_type>(K, D));
    325     return ImmutableMapRef(NewT, Factory);
    326   }
    327 
    328   ImmutableMapRef remove(key_type_ref K) const {
    329     TreeTy *NewT = Factory->remove(Root, K);
    330     return ImmutableMapRef(NewT, Factory);
    331   }
    332 
    333   bool contains(key_type_ref K) const {
    334     return Root ? Root->contains(K) : false;
    335   }
    336 
    337   ImmutableMap<KeyT, ValT> asImmutableMap() const {
    338     return ImmutableMap<KeyT, ValT>(Factory->getCanonicalTree(Root));
    339   }
    340 
    341   bool operator==(const ImmutableMapRef &RHS) const {
    342     return Root && RHS.Root ? Root->isEqual(*RHS.Root) : Root == RHS.Root;
    343   }
    344 
    345   bool operator!=(const ImmutableMapRef &RHS) const {
    346     return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
    347   }
    348 
    349   bool isEmpty() const { return !Root; }
    350 
    351   //===--------------------------------------------------===//
    352   // For testing.
    353   //===--------------------------------------------------===//
    354 
    355   void verify() const { if (Root) Root->verify(); }
    356 
    357   //===--------------------------------------------------===//
    358   // Iterators.
    359   //===--------------------------------------------------===//
    360 
    361   class iterator : public ImutAVLValueIterator<ImmutableMapRef> {
    362     iterator() = default;
    363     explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
    364     friend class ImmutableMapRef;
    365 
    366   public:
    367     key_type_ref getKey() const { return (*this)->first; }
    368     data_type_ref getData() const { return (*this)->second; }
    369   };
    370 
    371   iterator begin() const { return iterator(Root); }
    372   iterator end() const { return iterator(); }
    373 
    374   data_type* lookup(key_type_ref K) const {
    375     if (Root) {
    376       TreeTy* T = Root->find(K);
    377       if (T) return &T->getValue().second;
    378     }
    379 
    380     return 0;
    381   }
    382 
    383   /// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
    384   ///  which key is the highest in the ordering of keys in the map.  This
    385   ///  method returns NULL if the map is empty.
    386   value_type* getMaxElement() const {
    387     return Root ? &(Root->getMaxElement()->getValue()) : 0;
    388   }
    389 
    390   //===--------------------------------------------------===//
    391   // Utility methods.
    392   //===--------------------------------------------------===//
    393 
    394   unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
    395 
    396   static inline void Profile(FoldingSetNodeID& ID, const ImmutableMapRef &M) {
    397     ID.AddPointer(M.Root);
    398   }
    399 
    400   inline void Profile(FoldingSetNodeID& ID) const {
    401     return Profile(ID, *this);
    402   }
    403 };
    404 
    405 } // end namespace llvm
    406 
    407 #endif
    408