StringPool.h revision 208954
1249261Sdim//===-- StringPool.h - Interned string pool ---------------------*- C++ -*-===//
2249261Sdim//
3353358Sdim//                     The LLVM Compiler Infrastructure
4353358Sdim//
5353358Sdim// This file is distributed under the University of Illinois Open Source
6249261Sdim// License. See LICENSE.TXT for details.
7249261Sdim//
8249261Sdim//===----------------------------------------------------------------------===//
9341825Sdim//
10249261Sdim// This file declares an interned string pool, which helps reduce the cost of
11249261Sdim// strings by using the same storage for identical strings.
12249261Sdim//
13276479Sdim// To intern a string:
14261991Sdim//
15261991Sdim//   StringPool Pool;
16249261Sdim//   PooledStringPtr Str = Pool.intern("wakka wakka");
17321369Sdim//
18261991Sdim// To use the value of an interned string, use operator bool and operator*:
19261991Sdim//
20296417Sdim//   if (Str)
21249261Sdim//     cerr << "the string is" << *Str << "\n";
22249261Sdim//
23249261Sdim// Pooled strings are immutable, but you can change a PooledStringPtr to point
24249261Sdim// to another instance. So that interned strings can eventually be freed,
25249261Sdim// strings in the string pool are reference-counted (automatically).
26249261Sdim//
27309124Sdim//===----------------------------------------------------------------------===//
28309124Sdim
29309124Sdim#ifndef LLVM_SUPPORT_STRINGPOOL_H
30309124Sdim#define LLVM_SUPPORT_STRINGPOOL_H
31309124Sdim
32309124Sdim#include "llvm/ADT/StringMap.h"
33309124Sdim#include <new>
34309124Sdim#include <cassert>
35309124Sdim
36309124Sdimnamespace llvm {
37309124Sdim
38309124Sdim  class PooledStringPtr;
39309124Sdim
40309124Sdim  /// StringPool - An interned string pool. Use the intern method to add a
41314564Sdim  /// string. Strings are removed automatically as PooledStringPtrs are
42314564Sdim  /// destroyed.
43353358Sdim  class StringPool {
44353358Sdim    /// PooledString - This is the value of an entry in the pool's interning
45309124Sdim    /// table.
46309124Sdim    struct PooledString {
47353358Sdim      StringPool *Pool;  ///< So the string can remove itself.
48309124Sdim      unsigned Refcount; ///< Number of referencing PooledStringPtrs.
49309124Sdim
50353358Sdim    public:
51309124Sdim      PooledString() : Pool(0), Refcount(0) { }
52309124Sdim    };
53353358Sdim
54353358Sdim    friend class PooledStringPtr;
55309124Sdim
56353358Sdim    typedef StringMap<PooledString> table_t;
57353358Sdim    typedef StringMapEntry<PooledString> entry_t;
58309124Sdim    table_t InternTable;
59309124Sdim
60309124Sdim  public:
61309124Sdim    StringPool();
62309124Sdim    ~StringPool();
63309124Sdim
64309124Sdim    /// intern - Adds a string to the pool and returns a reference-counted
65309124Sdim    /// pointer to it. No additional memory is allocated if the string already
66309124Sdim    /// exists in the pool.
67309124Sdim    PooledStringPtr intern(const StringRef &Str);
68309124Sdim
69309124Sdim    /// empty - Checks whether the pool is empty. Returns true if so.
70309124Sdim    ///
71309124Sdim    inline bool empty() const { return InternTable.empty(); }
72309124Sdim  };
73309124Sdim
74309124Sdim  /// PooledStringPtr - A pointer to an interned string. Use operator bool to
75309124Sdim  /// test whether the pointer is valid, and operator * to get the string if so.
76309124Sdim  /// This is a lightweight value class with storage requirements equivalent to
77309124Sdim  /// a single pointer, but it does have reference-counting overhead when
78309124Sdim  /// copied.
79309124Sdim  class PooledStringPtr {
80309124Sdim    typedef StringPool::entry_t entry_t;
81309124Sdim    entry_t *S;
82353358Sdim
83309124Sdim  public:
84309124Sdim    PooledStringPtr() : S(0) {}
85309124Sdim
86341825Sdim    explicit PooledStringPtr(entry_t *E) : S(E) {
87280031Sdim      if (S) ++S->getValue().Refcount;
88280031Sdim    }
89280031Sdim
90309124Sdim    PooledStringPtr(const PooledStringPtr &That) : S(That.S) {
91341825Sdim      if (S) ++S->getValue().Refcount;
92341825Sdim    }
93353358Sdim
94341825Sdim    PooledStringPtr &operator=(const PooledStringPtr &That) {
95341825Sdim      if (S != That.S) {
96341825Sdim        clear();
97341825Sdim        S = That.S;
98341825Sdim        if (S) ++S->getValue().Refcount;
99341825Sdim      }
100341825Sdim      return *this;
101341825Sdim    }
102341825Sdim
103341825Sdim    void clear() {
104341825Sdim      if (!S)
105341825Sdim        return;
106341825Sdim      if (--S->getValue().Refcount == 0) {
107341825Sdim        S->getValue().Pool->InternTable.remove(S);
108341825Sdim        S->Destroy();
109341825Sdim      }
110341825Sdim      S = 0;
111341825Sdim    }
112341825Sdim
113341825Sdim    ~PooledStringPtr() { clear(); }
114341825Sdim
115341825Sdim    inline const char *begin() const {
116341825Sdim      assert(*this && "Attempt to dereference empty PooledStringPtr!");
117341825Sdim      return S->getKeyData();
118341825Sdim    }
119341825Sdim
120341825Sdim    inline const char *end() const {
121341825Sdim      assert(*this && "Attempt to dereference empty PooledStringPtr!");
122341825Sdim      return S->getKeyData() + S->getKeyLength();
123341825Sdim    }
124341825Sdim
125341825Sdim    inline unsigned size() const {
126341825Sdim      assert(*this && "Attempt to dereference empty PooledStringPtr!");
127341825Sdim      return S->getKeyLength();
128341825Sdim    }
129341825Sdim
130341825Sdim    inline const char *operator*() const { return begin(); }
131341825Sdim    inline operator bool() const { return S != 0; }
132341825Sdim
133341825Sdim    inline bool operator==(const PooledStringPtr &That) { return S == That.S; }
134341825Sdim    inline bool operator!=(const PooledStringPtr &That) { return S != That.S; }
135309124Sdim  };
136341825Sdim
137309124Sdim} // End llvm namespace
138276479Sdim
139309124Sdim#endif
140309124Sdim