ImmutableList.h revision 1f6efa3996dd1929fbc129203ce5009b620e6969
13771902e922796f506dfda5955d7d80b61104696Ted Kremenek//==--- ImmutableList.h - Immutable (functional) list interface --*- C++ -*-==//
23771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
33771902e922796f506dfda5955d7d80b61104696Ted Kremenek//                     The LLVM Compiler Infrastructure
43771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
53771902e922796f506dfda5955d7d80b61104696Ted Kremenek// This file is distributed under the University of Illinois Open Source
63771902e922796f506dfda5955d7d80b61104696Ted Kremenek// License. See LICENSE.TXT for details.
73771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
83771902e922796f506dfda5955d7d80b61104696Ted Kremenek//===----------------------------------------------------------------------===//
93771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
103771902e922796f506dfda5955d7d80b61104696Ted Kremenek// This file defines the ImmutableList class.
113771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
123771902e922796f506dfda5955d7d80b61104696Ted Kremenek//===----------------------------------------------------------------------===//
133771902e922796f506dfda5955d7d80b61104696Ted Kremenek
143771902e922796f506dfda5955d7d80b61104696Ted Kremenek#ifndef LLVM_ADT_IMLIST_H
153771902e922796f506dfda5955d7d80b61104696Ted Kremenek#define LLVM_ADT_IMLIST_H
163771902e922796f506dfda5955d7d80b61104696Ted Kremenek
173771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include "llvm/Support/Allocator.h"
183771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include "llvm/ADT/FoldingSet.h"
191f6efa3996dd1929fbc129203ce5009b620e6969Michael J. Spencer#include "llvm/Support/DataTypes.h"
203771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include <cassert>
213771902e922796f506dfda5955d7d80b61104696Ted Kremenek
223771902e922796f506dfda5955d7d80b61104696Ted Kremeneknamespace llvm {
233771902e922796f506dfda5955d7d80b61104696Ted Kremenek
243771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T> class ImmutableListFactory;
253a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
263771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T>
273771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableListImpl : public FoldingSetNode {
283771902e922796f506dfda5955d7d80b61104696Ted Kremenek  T Head;
29e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  const ImmutableListImpl* Tail;
303771902e922796f506dfda5955d7d80b61104696Ted Kremenek
31e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  ImmutableListImpl(const T& head, const ImmutableListImpl* tail = 0)
323771902e922796f506dfda5955d7d80b61104696Ted Kremenek    : Head(head), Tail(tail) {}
333a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
343771902e922796f506dfda5955d7d80b61104696Ted Kremenek  friend class ImmutableListFactory<T>;
353a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
363771902e922796f506dfda5955d7d80b61104696Ted Kremenek  // Do not implement.
373771902e922796f506dfda5955d7d80b61104696Ted Kremenek  void operator=(const ImmutableListImpl&);
383771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ImmutableListImpl(const ImmutableListImpl&);
393a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
403771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic:
413771902e922796f506dfda5955d7d80b61104696Ted Kremenek  const T& getHead() const { return Head; }
42e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  const ImmutableListImpl* getTail() const { return Tail; }
433a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
443771902e922796f506dfda5955d7d80b61104696Ted Kremenek  static inline void Profile(FoldingSetNodeID& ID, const T& H,
45e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek                             const ImmutableListImpl* L){
463771902e922796f506dfda5955d7d80b61104696Ted Kremenek    ID.AddPointer(L);
473771902e922796f506dfda5955d7d80b61104696Ted Kremenek    ID.Add(H);
483771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
493a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
503771902e922796f506dfda5955d7d80b61104696Ted Kremenek  void Profile(FoldingSetNodeID& ID) {
513771902e922796f506dfda5955d7d80b61104696Ted Kremenek    Profile(ID, Head, Tail);
523771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
533771902e922796f506dfda5955d7d80b61104696Ted Kremenek};
543a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
553771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// ImmutableList - This class represents an immutable (functional) list.
563771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  It is implemented as a smart pointer (wraps ImmutableListImpl), so it
573771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  it is intended to always be copied by value as if it were a pointer.
583771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  This interface matches ImmutableSet and ImmutableMap.  ImmutableList
593771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  objects should almost never be created directly, and instead should
603771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  be created by ImmutableListFactory objects that manage the lifetime
613771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  of a group of lists.  When the factory object is reclaimed, all lists
623771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  created by that factory are released as well.
633771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T>
643771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableList {
653771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic:
663771902e922796f506dfda5955d7d80b61104696Ted Kremenek  typedef T value_type;
673771902e922796f506dfda5955d7d80b61104696Ted Kremenek  typedef ImmutableListFactory<T> Factory;
683771902e922796f506dfda5955d7d80b61104696Ted Kremenek
693771902e922796f506dfda5955d7d80b61104696Ted Kremenekprivate:
70e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  const ImmutableListImpl<T>* X;
713771902e922796f506dfda5955d7d80b61104696Ted Kremenek
723771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic:
733771902e922796f506dfda5955d7d80b61104696Ted Kremenek  // This constructor should normally only be called by ImmutableListFactory<T>.
743771902e922796f506dfda5955d7d80b61104696Ted Kremenek  // There may be cases, however, when one needs to extract the internal pointer
753771902e922796f506dfda5955d7d80b61104696Ted Kremenek  // and reconstruct a list object from that pointer.
76e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  ImmutableList(const ImmutableListImpl<T>* x = 0) : X(x) {}
773771902e922796f506dfda5955d7d80b61104696Ted Kremenek
78e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  const ImmutableListImpl<T>* getInternalPointer() const {
793771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return X;
803771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
813a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
823771902e922796f506dfda5955d7d80b61104696Ted Kremenek  class iterator {
83e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek    const ImmutableListImpl<T>* L;
843771902e922796f506dfda5955d7d80b61104696Ted Kremenek  public:
853771902e922796f506dfda5955d7d80b61104696Ted Kremenek    iterator() : L(0) {}
863771902e922796f506dfda5955d7d80b61104696Ted Kremenek    iterator(ImmutableList l) : L(l.getInternalPointer()) {}
873a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
88445723bfb0d3c4cb7ecebb60710c669cf3dd2c8dTed Kremenek    iterator& operator++() { L = L->getTail(); return *this; }
893771902e922796f506dfda5955d7d80b61104696Ted Kremenek    bool operator==(const iterator& I) const { return L == I.L; }
90445723bfb0d3c4cb7ecebb60710c669cf3dd2c8dTed Kremenek    bool operator!=(const iterator& I) const { return L != I.L; }
913a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman    const value_type& operator*() const { return L->getHead(); }
923a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman    ImmutableList getList() const { return L; }
933771902e922796f506dfda5955d7d80b61104696Ted Kremenek  };
943771902e922796f506dfda5955d7d80b61104696Ted Kremenek
9530389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// begin - Returns an iterator referring to the head of the list, or
9630389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  an iterator denoting the end of the list if the list is empty.
973771902e922796f506dfda5955d7d80b61104696Ted Kremenek  iterator begin() const { return iterator(X); }
983a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
9930389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// end - Returns an iterator denoting the end of the list.  This iterator
10030389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  does not refer to a valid list element.
1013771902e922796f506dfda5955d7d80b61104696Ted Kremenek  iterator end() const { return iterator(); }
1023771902e922796f506dfda5955d7d80b61104696Ted Kremenek
10330389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// isEmpty - Returns true if the list is empty.
1043771902e922796f506dfda5955d7d80b61104696Ted Kremenek  bool isEmpty() const { return !X; }
1053a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
10630389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// isEqual - Returns true if two lists are equal.  Because all lists created
10730389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  from the same ImmutableListFactory are uniqued, this has O(1) complexity
10830389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  because it the contents of the list do not need to be compared.  Note
10930389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  that you should only compare two lists created from the same
11030389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  ImmutableListFactory.
1113a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  bool isEqual(const ImmutableList& L) const { return X == L.X; }
11230389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek
1133771902e922796f506dfda5955d7d80b61104696Ted Kremenek  bool operator==(const ImmutableList& L) const { return isEqual(L); }
1143771902e922796f506dfda5955d7d80b61104696Ted Kremenek
11530389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// getHead - Returns the head of the list.
1163771902e922796f506dfda5955d7d80b61104696Ted Kremenek  const T& getHead() {
1173771902e922796f506dfda5955d7d80b61104696Ted Kremenek    assert (!isEmpty() && "Cannot get the head of an empty list.");
1183771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return X->getHead();
1193771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1203a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
12130389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// getTail - Returns the tail of the list, which is another (possibly empty)
12230389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  ImmutableList.
1233771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ImmutableList getTail() {
1243771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return X ? X->getTail() : 0;
1253a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  }
1262ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu
1272ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu  void Profile(FoldingSetNodeID& ID) const {
1282ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu    ID.AddPointer(X);
1292ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu  }
1303771902e922796f506dfda5955d7d80b61104696Ted Kremenek};
1313a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1323771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T>
1333771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableListFactory {
1343a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  typedef ImmutableListImpl<T> ListTy;
1353771902e922796f506dfda5955d7d80b61104696Ted Kremenek  typedef FoldingSet<ListTy>   CacheTy;
1363a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1373771902e922796f506dfda5955d7d80b61104696Ted Kremenek  CacheTy Cache;
1383771902e922796f506dfda5955d7d80b61104696Ted Kremenek  uintptr_t Allocator;
1393a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1403771902e922796f506dfda5955d7d80b61104696Ted Kremenek  bool ownsAllocator() const {
1413771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return Allocator & 0x1 ? false : true;
1423771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1433a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1443a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  BumpPtrAllocator& getAllocator() const {
1453771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1);
1463a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  }
1473771902e922796f506dfda5955d7d80b61104696Ted Kremenek
1483771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic:
1493771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ImmutableListFactory()
1503771902e922796f506dfda5955d7d80b61104696Ted Kremenek    : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {}
1513a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1523771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ImmutableListFactory(BumpPtrAllocator& Alloc)
1533771902e922796f506dfda5955d7d80b61104696Ted Kremenek  : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {}
1543a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1553771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ~ImmutableListFactory() {
1563771902e922796f506dfda5955d7d80b61104696Ted Kremenek    if (ownsAllocator()) delete &getAllocator();
1573771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1583a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1599c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek  ImmutableList<T> concat(const T& Head, ImmutableList<T> Tail) {
1603771902e922796f506dfda5955d7d80b61104696Ted Kremenek    // Profile the new list to see if it already exists in our cache.
1613771902e922796f506dfda5955d7d80b61104696Ted Kremenek    FoldingSetNodeID ID;
1623771902e922796f506dfda5955d7d80b61104696Ted Kremenek    void* InsertPos;
1633a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
164e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek    const ListTy* TailImpl = Tail.getInternalPointer();
1653771902e922796f506dfda5955d7d80b61104696Ted Kremenek    ListTy::Profile(ID, Head, TailImpl);
1663771902e922796f506dfda5955d7d80b61104696Ted Kremenek    ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos);
1673a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1683771902e922796f506dfda5955d7d80b61104696Ted Kremenek    if (!L) {
1693771902e922796f506dfda5955d7d80b61104696Ted Kremenek      // The list does not exist in our cache.  Create it.
1703771902e922796f506dfda5955d7d80b61104696Ted Kremenek      BumpPtrAllocator& A = getAllocator();
1713771902e922796f506dfda5955d7d80b61104696Ted Kremenek      L = (ListTy*) A.Allocate<ListTy>();
1723771902e922796f506dfda5955d7d80b61104696Ted Kremenek      new (L) ListTy(Head, TailImpl);
1733a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1743771902e922796f506dfda5955d7d80b61104696Ted Kremenek      // Insert the new list into the cache.
1753771902e922796f506dfda5955d7d80b61104696Ted Kremenek      Cache.InsertNode(L, InsertPos);
1763771902e922796f506dfda5955d7d80b61104696Ted Kremenek    }
1773a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1783771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return L;
1793771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1803a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1819c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek  ImmutableList<T> add(const T& D, ImmutableList<T> L) {
1829c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek    return concat(D, L);
1833771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1843a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1859c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek  ImmutableList<T> getEmptyList() const {
1863771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return ImmutableList<T>(0);
1873771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1883a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1899c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek  ImmutableList<T> create(const T& X) {
1909c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek    return Concat(X, getEmptyList());
1913771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1923771902e922796f506dfda5955d7d80b61104696Ted Kremenek};
1933a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1942c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu//===----------------------------------------------------------------------===//
195eca64f0980e3f686a36007c53272780119635337Ted Kremenek// Partially-specialized Traits.
1962c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu//===----------------------------------------------------------------------===//
1972c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu
198eca64f0980e3f686a36007c53272780119635337Ted Kremenektemplate<typename T> struct DenseMapInfo;
199eca64f0980e3f686a36007c53272780119635337Ted Kremenektemplate<typename T> struct DenseMapInfo<ImmutableList<T> > {
200eca64f0980e3f686a36007c53272780119635337Ted Kremenek  static inline ImmutableList<T> getEmptyKey() {
201eca64f0980e3f686a36007c53272780119635337Ted Kremenek    return reinterpret_cast<ImmutableListImpl<T>*>(-1);
202eca64f0980e3f686a36007c53272780119635337Ted Kremenek  }
203eca64f0980e3f686a36007c53272780119635337Ted Kremenek  static inline ImmutableList<T> getTombstoneKey() {
204eca64f0980e3f686a36007c53272780119635337Ted Kremenek    return reinterpret_cast<ImmutableListImpl<T>*>(-2);
205eca64f0980e3f686a36007c53272780119635337Ted Kremenek  }
206eca64f0980e3f686a36007c53272780119635337Ted Kremenek  static unsigned getHashValue(ImmutableList<T> X) {
207eca64f0980e3f686a36007c53272780119635337Ted Kremenek    uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer());
2083a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman    return (unsigned((uintptr_t)PtrVal) >> 4) ^
209eca64f0980e3f686a36007c53272780119635337Ted Kremenek           (unsigned((uintptr_t)PtrVal) >> 9);
210eca64f0980e3f686a36007c53272780119635337Ted Kremenek  }
211eca64f0980e3f686a36007c53272780119635337Ted Kremenek  static bool isEqual(ImmutableList<T> X1, ImmutableList<T> X2) {
212eca64f0980e3f686a36007c53272780119635337Ted Kremenek    return X1 == X2;
213eca64f0980e3f686a36007c53272780119635337Ted Kremenek  }
214eca64f0980e3f686a36007c53272780119635337Ted Kremenek};
2153a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
2164bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnertemplate <typename T> struct isPodLike;
2174bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnertemplate <typename T>
2184bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnerstruct isPodLike<ImmutableList<T> > { static const bool value = true; };
2194bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattner
2203771902e922796f506dfda5955d7d80b61104696Ted Kremenek} // end llvm namespace
2213771902e922796f506dfda5955d7d80b61104696Ted Kremenek
2223771902e922796f506dfda5955d7d80b61104696Ted Kremenek#endif
223