From: Ted Kremenek Date: Mon, 30 Jun 2008 18:07:38 +0000 (+0000) Subject: Added ImmutableList, a companion ADT to ImmutableSet and ImmutableMap that is used... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3771902e922796f506dfda5955d7d80b61104696;p=oota-llvm.git Added ImmutableList, a companion ADT to ImmutableSet and ImmutableMap that is used to represent a purely functional list. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@52911 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/ADT/ImmutableList.h b/include/llvm/ADT/ImmutableList.h new file mode 100644 index 00000000000..2490f0c49ef --- /dev/null +++ b/include/llvm/ADT/ImmutableList.h @@ -0,0 +1,175 @@ +//==--- ImmutableList.h - Immutable (functional) list interface --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ImmutableList class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_IMLIST_H +#define LLVM_ADT_IMLIST_H + +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { + +template class ImmutableListFactory; + +template +class ImmutableListImpl : public FoldingSetNode { + T Head; + ImmutableListImpl* Tail; + + ImmutableListImpl(const T& head, ImmutableListImpl* tail = 0) + : Head(head), Tail(tail) {} + + friend class ImmutableListFactory; + + // Do not implement. + void operator=(const ImmutableListImpl&); + ImmutableListImpl(const ImmutableListImpl&); + +public: + const T& getHead() const { return Head; } + ImmutableListImpl* getTail() const { return Tail; } + + static inline void Profile(FoldingSetNodeID& ID, const T& H, + ImmutableListImpl* L){ + ID.AddPointer(L); + ID.Add(H); + } + + void Profile(FoldingSetNodeID& ID) { + Profile(ID, Head, Tail); + } +}; + +/// ImmutableList - This class represents an immutable (functional) list. +/// It is implemented as a smart pointer (wraps ImmutableListImpl), so it +/// it is intended to always be copied by value as if it were a pointer. +/// This interface matches ImmutableSet and ImmutableMap. ImmutableList +/// objects should almost never be created directly, and instead should +/// be created by ImmutableListFactory objects that manage the lifetime +/// of a group of lists. When the factory object is reclaimed, all lists +/// created by that factory are released as well. +template +class ImmutableList { +public: + typedef T value_type; + typedef ImmutableListFactory Factory; + +private: + ImmutableListImpl* X; + +public: + // This constructor should normally only be called by ImmutableListFactory. + // There may be cases, however, when one needs to extract the internal pointer + // and reconstruct a list object from that pointer. + ImmutableList(ImmutableListImpl* x) : X(x) {} + + ImmutableListImpl* getInternalPointer() const { + return X; + } + + class iterator { + ImmutableListImpl* L; + public: + iterator() : L(0) {} + iterator(ImmutableList l) : L(l.getInternalPointer()) {} + + iterator& operator++() { L = L->Tail; } + bool operator==(const iterator& I) const { return L == I.L; } + ImmutableList operator*() const { return L; } + }; + + iterator begin() const { return iterator(X); } + iterator end() const { return iterator(); } + + bool isEmpty() const { return !X; } + + bool isEqual(const ImmutableList& L) const { return X == L.X; } + bool operator==(const ImmutableList& L) const { return isEqual(L); } + + const T& getHead() { + assert (!isEmpty() && "Cannot get the head of an empty list."); + return X->getHead(); + } + + ImmutableList getTail() { + return X ? X->getTail() : 0; + } +}; + +template +class ImmutableListFactory { + typedef ImmutableListImpl ListTy; + typedef FoldingSet CacheTy; + + CacheTy Cache; + uintptr_t Allocator; + + bool ownsAllocator() const { + return Allocator & 0x1 ? false : true; + } + + BumpPtrAllocator& getAllocator() const { + return *reinterpret_cast(Allocator & ~0x1); + } + +public: + ImmutableListFactory() + : Allocator(reinterpret_cast(new BumpPtrAllocator())) {} + + ImmutableListFactory(BumpPtrAllocator& Alloc) + : Allocator(reinterpret_cast(&Alloc) | 0x1) {} + + ~ImmutableListFactory() { + if (ownsAllocator()) delete &getAllocator(); + } + + ImmutableList Concat(const T& Head, ImmutableList Tail) { + // Profile the new list to see if it already exists in our cache. + FoldingSetNodeID ID; + void* InsertPos; + + ListTy* TailImpl = Tail.getInternalPointer(); + ListTy::Profile(ID, Head, TailImpl); + ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos); + + if (!L) { + // The list does not exist in our cache. Create it. + BumpPtrAllocator& A = getAllocator(); + L = (ListTy*) A.Allocate(); + new (L) ListTy(Head, TailImpl); + + // Insert the new list into the cache. + Cache.InsertNode(L, InsertPos); + } + + return L; + } + + ImmutableList Add(const T& D, ImmutableList L) { + return Concat(D, L); + } + + ImmutableList GetEmptyList() const { + return ImmutableList(0); + } + + ImmutableList Create(const T& X) { + return Concat(X, GetEmptyList()); + } +}; + +} // end llvm namespace + +#endif