Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:06

0001 //==--- ImmutableList.h - Immutable (functional) list interface --*- C++ -*-==//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// This file defines the ImmutableList class.
0011 ///
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_ADT_IMMUTABLELIST_H
0015 #define LLVM_ADT_IMMUTABLELIST_H
0016 
0017 #include "llvm/ADT/FoldingSet.h"
0018 #include "llvm/Support/Allocator.h"
0019 #include <cassert>
0020 #include <cstdint>
0021 #include <new>
0022 
0023 namespace llvm {
0024 
0025 template <typename T> class ImmutableListFactory;
0026 
0027 template <typename T>
0028 class ImmutableListImpl : public FoldingSetNode {
0029   friend class ImmutableListFactory<T>;
0030 
0031   T Head;
0032   const ImmutableListImpl* Tail;
0033 
0034   template <typename ElemT>
0035   ImmutableListImpl(ElemT &&head, const ImmutableListImpl *tail = nullptr)
0036     : Head(std::forward<ElemT>(head)), Tail(tail) {}
0037 
0038 public:
0039   ImmutableListImpl(const ImmutableListImpl &) = delete;
0040   ImmutableListImpl &operator=(const ImmutableListImpl &) = delete;
0041 
0042   const T& getHead() const { return Head; }
0043   const ImmutableListImpl* getTail() const { return Tail; }
0044 
0045   static inline void Profile(FoldingSetNodeID& ID, const T& H,
0046                              const ImmutableListImpl* L){
0047     ID.AddPointer(L);
0048     ID.Add(H);
0049   }
0050 
0051   void Profile(FoldingSetNodeID& ID) {
0052     Profile(ID, Head, Tail);
0053   }
0054 };
0055 
0056 /// ImmutableList - This class represents an immutable (functional) list.
0057 ///  It is implemented as a smart pointer (wraps ImmutableListImpl), so it
0058 ///  it is intended to always be copied by value as if it were a pointer.
0059 ///  This interface matches ImmutableSet and ImmutableMap.  ImmutableList
0060 ///  objects should almost never be created directly, and instead should
0061 ///  be created by ImmutableListFactory objects that manage the lifetime
0062 ///  of a group of lists.  When the factory object is reclaimed, all lists
0063 ///  created by that factory are released as well.
0064 template <typename T>
0065 class ImmutableList {
0066 public:
0067   using value_type = T;
0068   using Factory = ImmutableListFactory<T>;
0069 
0070   static_assert(std::is_trivially_destructible<T>::value,
0071                 "T must be trivially destructible!");
0072 
0073 private:
0074   const ImmutableListImpl<T>* X;
0075 
0076 public:
0077   // This constructor should normally only be called by ImmutableListFactory<T>.
0078   // There may be cases, however, when one needs to extract the internal pointer
0079   // and reconstruct a list object from that pointer.
0080   ImmutableList(const ImmutableListImpl<T>* x = nullptr) : X(x) {}
0081 
0082   const ImmutableListImpl<T>* getInternalPointer() const {
0083     return X;
0084   }
0085 
0086   class iterator {
0087     const ImmutableListImpl<T>* L = nullptr;
0088 
0089   public:
0090     iterator() = default;
0091     iterator(ImmutableList l) : L(l.getInternalPointer()) {}
0092 
0093     iterator& operator++() { L = L->getTail(); return *this; }
0094     bool operator==(const iterator& I) const { return L == I.L; }
0095     bool operator!=(const iterator& I) const { return L != I.L; }
0096     const value_type& operator*() const { return L->getHead(); }
0097     const std::remove_reference_t<value_type> *operator->() const {
0098       return &L->getHead();
0099     }
0100 
0101     ImmutableList getList() const { return L; }
0102   };
0103 
0104   /// begin - Returns an iterator referring to the head of the list, or
0105   ///  an iterator denoting the end of the list if the list is empty.
0106   iterator begin() const { return iterator(X); }
0107 
0108   /// end - Returns an iterator denoting the end of the list.  This iterator
0109   ///  does not refer to a valid list element.
0110   iterator end() const { return iterator(); }
0111 
0112   /// isEmpty - Returns true if the list is empty.
0113   bool isEmpty() const { return !X; }
0114 
0115   bool contains(const T& V) const {
0116     for (iterator I = begin(), E = end(); I != E; ++I) {
0117       if (*I == V)
0118         return true;
0119     }
0120     return false;
0121   }
0122 
0123   /// isEqual - Returns true if two lists are equal.  Because all lists created
0124   ///  from the same ImmutableListFactory are uniqued, this has O(1) complexity
0125   ///  because it the contents of the list do not need to be compared.  Note
0126   ///  that you should only compare two lists created from the same
0127   ///  ImmutableListFactory.
0128   bool isEqual(const ImmutableList& L) const { return X == L.X; }
0129 
0130   bool operator==(const ImmutableList& L) const { return isEqual(L); }
0131 
0132   /// getHead - Returns the head of the list.
0133   const T& getHead() const {
0134     assert(!isEmpty() && "Cannot get the head of an empty list.");
0135     return X->getHead();
0136   }
0137 
0138   /// getTail - Returns the tail of the list, which is another (possibly empty)
0139   ///  ImmutableList.
0140   ImmutableList getTail() const {
0141     return X ? X->getTail() : nullptr;
0142   }
0143 
0144   void Profile(FoldingSetNodeID& ID) const {
0145     ID.AddPointer(X);
0146   }
0147 };
0148 
0149 template <typename T>
0150 class ImmutableListFactory {
0151   using ListTy = ImmutableListImpl<T>;
0152   using CacheTy = FoldingSet<ListTy>;
0153 
0154   CacheTy Cache;
0155   uintptr_t Allocator;
0156 
0157   bool ownsAllocator() const {
0158     return (Allocator & 0x1) == 0;
0159   }
0160 
0161   BumpPtrAllocator& getAllocator() const {
0162     return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1);
0163   }
0164 
0165 public:
0166   ImmutableListFactory()
0167     : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {}
0168 
0169   ImmutableListFactory(BumpPtrAllocator& Alloc)
0170   : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {}
0171 
0172   ~ImmutableListFactory() {
0173     if (ownsAllocator()) delete &getAllocator();
0174   }
0175 
0176   template <typename ElemT>
0177   [[nodiscard]] ImmutableList<T> concat(ElemT &&Head, ImmutableList<T> Tail) {
0178     // Profile the new list to see if it already exists in our cache.
0179     FoldingSetNodeID ID;
0180     void* InsertPos;
0181 
0182     const ListTy* TailImpl = Tail.getInternalPointer();
0183     ListTy::Profile(ID, Head, TailImpl);
0184     ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos);
0185 
0186     if (!L) {
0187       // The list does not exist in our cache.  Create it.
0188       BumpPtrAllocator& A = getAllocator();
0189       L = (ListTy*) A.Allocate<ListTy>();
0190       new (L) ListTy(std::forward<ElemT>(Head), TailImpl);
0191 
0192       // Insert the new list into the cache.
0193       Cache.InsertNode(L, InsertPos);
0194     }
0195 
0196     return L;
0197   }
0198 
0199   template <typename ElemT>
0200   [[nodiscard]] ImmutableList<T> add(ElemT &&Data, ImmutableList<T> L) {
0201     return concat(std::forward<ElemT>(Data), L);
0202   }
0203 
0204   template <typename... CtorArgs>
0205   [[nodiscard]] ImmutableList<T> emplace(ImmutableList<T> Tail,
0206                                          CtorArgs &&...Args) {
0207     return concat(T(std::forward<CtorArgs>(Args)...), Tail);
0208   }
0209 
0210   ImmutableList<T> getEmptyList() const {
0211     return ImmutableList<T>(nullptr);
0212   }
0213 
0214   template <typename ElemT>
0215   ImmutableList<T> create(ElemT &&Data) {
0216     return concat(std::forward<ElemT>(Data), getEmptyList());
0217   }
0218 };
0219 
0220 //===----------------------------------------------------------------------===//
0221 // Partially-specialized Traits.
0222 //===----------------------------------------------------------------------===//
0223 
0224 template <typename T> struct DenseMapInfo<ImmutableList<T>, void> {
0225   static inline ImmutableList<T> getEmptyKey() {
0226     return reinterpret_cast<ImmutableListImpl<T>*>(-1);
0227   }
0228 
0229   static inline ImmutableList<T> getTombstoneKey() {
0230     return reinterpret_cast<ImmutableListImpl<T>*>(-2);
0231   }
0232 
0233   static unsigned getHashValue(ImmutableList<T> X) {
0234     uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer());
0235     return (unsigned((uintptr_t)PtrVal) >> 4) ^
0236            (unsigned((uintptr_t)PtrVal) >> 9);
0237   }
0238 
0239   static bool isEqual(ImmutableList<T> X1, ImmutableList<T> X2) {
0240     return X1 == X2;
0241   }
0242 };
0243 
0244 } // end namespace llvm
0245 
0246 #endif // LLVM_ADT_IMMUTABLELIST_H