template <typename T> classImmutableList { public: using value_type = T; using Factory = ImmutableListFactory<T>;
static_assert(std::is_trivially_destructible<T>::value, "T must be trivially destructible!");
private: const ImmutableListImpl<T>* X;
public: // This constructor should normally only be called by ImmutableListFactory<T>. // There may be cases, however, when one needs to extract the internal pointer // and reconstruct a list object from that pointer. ImmutableList(const ImmutableListImpl<T>* x = nullptr) : X(x) {}
const ImmutableListImpl<T>* getInternalPointer()const{ return X; } ...... boolcontains(const T& V)const{ for (iterator I = begin(), E = end(); I != E; ++I) { if (*I == V) returntrue; } returnfalse; }
/// isEqual - Returns true if two lists are equal. Because all lists created /// from the same ImmutableListFactory are uniqued, this has O(1) complexity /// because it the contents of the list do not need to be compared. Note /// that you should only compare two lists created from the same /// ImmutableListFactory. boolisEqual(const ImmutableList& L)const{ return X == L.X; }
/// getHead - Returns the head of the list. const T& getHead()const{ assert(!isEmpty() && "Cannot get the head of an empty list."); return X->getHead(); }
/// getTail - Returns the tail of the list, which is another (possibly empty) /// ImmutableList. ImmutableList getTail()const{ return X ? X->getTail() : nullptr; }
// This constructor should normally only be called by ImmutableListFactory<T>. // There may be cases, however, when one needs to extract the internal pointer // and reconstruct a list object from that pointer. ImmutableList(const ImmutableListImpl<T>* x = nullptr) : X(x) {}
~ImmutableListFactory() { if (ownsAllocator()) delete &getAllocator(); }
template <typename ElemT> LLVM_NODISCARD ImmutableList<T> concat(ElemT &&Head, ImmutableList<T> Tail){ // Profile the new list to see if it already exists in our cache. FoldingSetNodeID ID; void* InsertPos;
if (!L) { // The list does not exist in our cache. Create it. BumpPtrAllocator& A = getAllocator(); L = (ListTy*) A.Allocate<ListTy>(); new (L) ListTy(std::forward<ElemT>(Head), TailImpl);
// Insert the new list into the cache. Cache.InsertNode(L, InsertPos); }
FoldingSet - This template class is used to instantiate a specialized implementation of the folding set to the node class T. T must be a subclass of FoldingSetNode and implement a Profile function.
template <typename ElemT> LLVM_NODISCARD ImmutableList<T> concat(ElemT &&Head, ImmutableList<T> Tail){ // Profile the new list to see if it already exists in our cache. FoldingSetNodeID ID; void* InsertPos;
if (!L) { // The list does not exist in our cache. Create it. BumpPtrAllocator& A = getAllocator(); L = (ListTy*) A.Allocate<ListTy>(); new (L) ListTy(std::forward<ElemT>(Head), TailImpl);
// Insert the new list into the cache. Cache.InsertNode(L, InsertPos); }