1321369Sdim//===- StringPool.h - Interned string pool ----------------------*- C++ -*-===// 2193323Sed// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6193323Sed// 7193323Sed//===----------------------------------------------------------------------===// 8193323Sed// 9193323Sed// This file declares an interned string pool, which helps reduce the cost of 10193323Sed// strings by using the same storage for identical strings. 11193323Sed// 12193323Sed// To intern a string: 13193323Sed// 14193323Sed// StringPool Pool; 15193323Sed// PooledStringPtr Str = Pool.intern("wakka wakka"); 16193323Sed// 17193323Sed// To use the value of an interned string, use operator bool and operator*: 18193323Sed// 19193323Sed// if (Str) 20193323Sed// cerr << "the string is" << *Str << "\n"; 21193323Sed// 22193323Sed// Pooled strings are immutable, but you can change a PooledStringPtr to point 23193323Sed// to another instance. So that interned strings can eventually be freed, 24193323Sed// strings in the string pool are reference-counted (automatically). 25193323Sed// 26193323Sed//===----------------------------------------------------------------------===// 27193323Sed 28193323Sed#ifndef LLVM_SUPPORT_STRINGPOOL_H 29193323Sed#define LLVM_SUPPORT_STRINGPOOL_H 30193323Sed 31280031Sdim#include "llvm/ADT/StringMap.h" 32321369Sdim#include "llvm/ADT/StringRef.h" 33249423Sdim#include <cassert> 34193323Sed 35193323Sednamespace llvm { 36193323Sed 37193323Sed class PooledStringPtr; 38193323Sed 39193323Sed /// StringPool - An interned string pool. Use the intern method to add a 40193323Sed /// string. Strings are removed automatically as PooledStringPtrs are 41193323Sed /// destroyed. 42193323Sed class StringPool { 43193323Sed /// PooledString - This is the value of an entry in the pool's interning 44193323Sed /// table. 45193323Sed struct PooledString { 46321369Sdim StringPool *Pool = nullptr; ///< So the string can remove itself. 47321369Sdim unsigned Refcount = 0; ///< Number of referencing PooledStringPtrs. 48193323Sed 49193323Sed public: 50321369Sdim PooledString() = default; 51193323Sed }; 52193323Sed 53193323Sed friend class PooledStringPtr; 54193323Sed 55321369Sdim using table_t = StringMap<PooledString>; 56321369Sdim using entry_t = StringMapEntry<PooledString>; 57193323Sed table_t InternTable; 58193323Sed 59193323Sed public: 60193323Sed StringPool(); 61193323Sed ~StringPool(); 62193323Sed 63193323Sed /// intern - Adds a string to the pool and returns a reference-counted 64193323Sed /// pointer to it. No additional memory is allocated if the string already 65193323Sed /// exists in the pool. 66210299Sed PooledStringPtr intern(StringRef Str); 67193323Sed 68193323Sed /// empty - Checks whether the pool is empty. Returns true if so. 69193323Sed /// 70193323Sed inline bool empty() const { return InternTable.empty(); } 71193323Sed }; 72193323Sed 73193323Sed /// PooledStringPtr - A pointer to an interned string. Use operator bool to 74193323Sed /// test whether the pointer is valid, and operator * to get the string if so. 75193323Sed /// This is a lightweight value class with storage requirements equivalent to 76193323Sed /// a single pointer, but it does have reference-counting overhead when 77193323Sed /// copied. 78193323Sed class PooledStringPtr { 79321369Sdim using entry_t = StringPool::entry_t; 80193323Sed 81321369Sdim entry_t *S = nullptr; 82321369Sdim 83193323Sed public: 84321369Sdim PooledStringPtr() = default; 85193323Sed 86193323Sed explicit PooledStringPtr(entry_t *E) : S(E) { 87193323Sed if (S) ++S->getValue().Refcount; 88193323Sed } 89193323Sed 90193323Sed PooledStringPtr(const PooledStringPtr &That) : S(That.S) { 91193323Sed if (S) ++S->getValue().Refcount; 92193323Sed } 93193323Sed 94193323Sed PooledStringPtr &operator=(const PooledStringPtr &That) { 95193323Sed if (S != That.S) { 96193323Sed clear(); 97193323Sed S = That.S; 98193323Sed if (S) ++S->getValue().Refcount; 99193323Sed } 100193323Sed return *this; 101193323Sed } 102193323Sed 103193323Sed void clear() { 104193323Sed if (!S) 105193323Sed return; 106193323Sed if (--S->getValue().Refcount == 0) { 107193323Sed S->getValue().Pool->InternTable.remove(S); 108193323Sed S->Destroy(); 109193323Sed } 110276479Sdim S = nullptr; 111193323Sed } 112193323Sed 113193323Sed ~PooledStringPtr() { clear(); } 114193323Sed 115193323Sed inline const char *begin() const { 116193323Sed assert(*this && "Attempt to dereference empty PooledStringPtr!"); 117193323Sed return S->getKeyData(); 118193323Sed } 119193323Sed 120193323Sed inline const char *end() const { 121193323Sed assert(*this && "Attempt to dereference empty PooledStringPtr!"); 122193323Sed return S->getKeyData() + S->getKeyLength(); 123193323Sed } 124193323Sed 125193323Sed inline unsigned size() const { 126193323Sed assert(*this && "Attempt to dereference empty PooledStringPtr!"); 127193323Sed return S->getKeyLength(); 128193323Sed } 129193323Sed 130193323Sed inline const char *operator*() const { return begin(); } 131288943Sdim inline explicit operator bool() const { return S != nullptr; } 132193323Sed 133276479Sdim inline bool operator==(const PooledStringPtr &That) const { return S == That.S; } 134276479Sdim inline bool operator!=(const PooledStringPtr &That) const { return S != That.S; } 135193323Sed }; 136193323Sed 137321369Sdim} // end namespace llvm 138193323Sed 139321369Sdim#endif // LLVM_SUPPORT_STRINGPOOL_H 140