1*bdd1243dSDimitry Andric //===------- string_pool.h - Thread-safe pool for strings -------*- C++ -*-===// 2*bdd1243dSDimitry Andric // 3*bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*bdd1243dSDimitry Andric // 7*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8*bdd1243dSDimitry Andric // 9*bdd1243dSDimitry Andric // Contains a thread-safe string pool. Strings are ref-counted, but not 10*bdd1243dSDimitry Andric // automatically deallocated. Unused entries can be cleared by calling 11*bdd1243dSDimitry Andric // StringPool::clearDeadEntries. 12*bdd1243dSDimitry Andric // 13*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 14*bdd1243dSDimitry Andric 15*bdd1243dSDimitry Andric #ifndef ORC_RT_STRING_POOL_H 16*bdd1243dSDimitry Andric #define ORC_RT_STRING_POOL_H 17*bdd1243dSDimitry Andric 18*bdd1243dSDimitry Andric #include <atomic> 19*bdd1243dSDimitry Andric #include <cassert> 20*bdd1243dSDimitry Andric #include <functional> 21*bdd1243dSDimitry Andric #include <mutex> 22*bdd1243dSDimitry Andric #include <string> 23*bdd1243dSDimitry Andric #include <unordered_map> 24*bdd1243dSDimitry Andric 25*bdd1243dSDimitry Andric namespace __orc_rt { 26*bdd1243dSDimitry Andric 27*bdd1243dSDimitry Andric class PooledStringPtr; 28*bdd1243dSDimitry Andric 29*bdd1243dSDimitry Andric /// String pool for strings names used by the ORC runtime. 30*bdd1243dSDimitry Andric class StringPool { 31*bdd1243dSDimitry Andric friend class PooledStringPtr; 32*bdd1243dSDimitry Andric 33*bdd1243dSDimitry Andric public: 34*bdd1243dSDimitry Andric /// Destroy a StringPool. 35*bdd1243dSDimitry Andric ~StringPool(); 36*bdd1243dSDimitry Andric 37*bdd1243dSDimitry Andric /// Create a string pointer from the given string. 38*bdd1243dSDimitry Andric PooledStringPtr intern(std::string S); 39*bdd1243dSDimitry Andric 40*bdd1243dSDimitry Andric /// Remove from the pool any entries that are no longer referenced. 41*bdd1243dSDimitry Andric void clearDeadEntries(); 42*bdd1243dSDimitry Andric 43*bdd1243dSDimitry Andric /// Returns true if the pool is empty. 44*bdd1243dSDimitry Andric bool empty() const; 45*bdd1243dSDimitry Andric 46*bdd1243dSDimitry Andric private: 47*bdd1243dSDimitry Andric using RefCountType = std::atomic<size_t>; 48*bdd1243dSDimitry Andric using PoolMap = std::unordered_map<std::string, RefCountType>; 49*bdd1243dSDimitry Andric using PoolMapEntry = PoolMap::value_type; 50*bdd1243dSDimitry Andric mutable std::mutex PoolMutex; 51*bdd1243dSDimitry Andric PoolMap Pool; 52*bdd1243dSDimitry Andric }; 53*bdd1243dSDimitry Andric 54*bdd1243dSDimitry Andric /// Pointer to a pooled string. 55*bdd1243dSDimitry Andric class PooledStringPtr { 56*bdd1243dSDimitry Andric friend class StringPool; 57*bdd1243dSDimitry Andric friend struct std::hash<PooledStringPtr>; 58*bdd1243dSDimitry Andric 59*bdd1243dSDimitry Andric public: 60*bdd1243dSDimitry Andric PooledStringPtr() = default; 61*bdd1243dSDimitry Andric PooledStringPtr(std::nullptr_t) {} 62*bdd1243dSDimitry Andric PooledStringPtr(const PooledStringPtr &Other) : S(Other.S) { 63*bdd1243dSDimitry Andric if (S) 64*bdd1243dSDimitry Andric ++S->second; 65*bdd1243dSDimitry Andric } 66*bdd1243dSDimitry Andric 67*bdd1243dSDimitry Andric PooledStringPtr &operator=(const PooledStringPtr &Other) { 68*bdd1243dSDimitry Andric if (S) { 69*bdd1243dSDimitry Andric assert(S->second && "Releasing PooledStringPtr with zero ref count"); 70*bdd1243dSDimitry Andric --S->second; 71*bdd1243dSDimitry Andric } 72*bdd1243dSDimitry Andric S = Other.S; 73*bdd1243dSDimitry Andric if (S) 74*bdd1243dSDimitry Andric ++S->second; 75*bdd1243dSDimitry Andric return *this; 76*bdd1243dSDimitry Andric } 77*bdd1243dSDimitry Andric 78*bdd1243dSDimitry Andric PooledStringPtr(PooledStringPtr &&Other) : S(nullptr) { 79*bdd1243dSDimitry Andric std::swap(S, Other.S); 80*bdd1243dSDimitry Andric } 81*bdd1243dSDimitry Andric 82*bdd1243dSDimitry Andric PooledStringPtr &operator=(PooledStringPtr &&Other) { 83*bdd1243dSDimitry Andric if (S) { 84*bdd1243dSDimitry Andric assert(S->second && "Releasing PooledStringPtr with zero ref count"); 85*bdd1243dSDimitry Andric --S->second; 86*bdd1243dSDimitry Andric } 87*bdd1243dSDimitry Andric S = nullptr; 88*bdd1243dSDimitry Andric std::swap(S, Other.S); 89*bdd1243dSDimitry Andric return *this; 90*bdd1243dSDimitry Andric } 91*bdd1243dSDimitry Andric 92*bdd1243dSDimitry Andric ~PooledStringPtr() { 93*bdd1243dSDimitry Andric if (S) { 94*bdd1243dSDimitry Andric assert(S->second && "Releasing PooledStringPtr with zero ref count"); 95*bdd1243dSDimitry Andric --S->second; 96*bdd1243dSDimitry Andric } 97*bdd1243dSDimitry Andric } 98*bdd1243dSDimitry Andric 99*bdd1243dSDimitry Andric explicit operator bool() const { return S; } 100*bdd1243dSDimitry Andric 101*bdd1243dSDimitry Andric const std::string &operator*() const { return S->first; } 102*bdd1243dSDimitry Andric 103*bdd1243dSDimitry Andric friend bool operator==(const PooledStringPtr &LHS, 104*bdd1243dSDimitry Andric const PooledStringPtr &RHS) { 105*bdd1243dSDimitry Andric return LHS.S == RHS.S; 106*bdd1243dSDimitry Andric } 107*bdd1243dSDimitry Andric 108*bdd1243dSDimitry Andric friend bool operator!=(const PooledStringPtr &LHS, 109*bdd1243dSDimitry Andric const PooledStringPtr &RHS) { 110*bdd1243dSDimitry Andric return !(LHS == RHS); 111*bdd1243dSDimitry Andric } 112*bdd1243dSDimitry Andric 113*bdd1243dSDimitry Andric friend bool operator<(const PooledStringPtr &LHS, 114*bdd1243dSDimitry Andric const PooledStringPtr &RHS) { 115*bdd1243dSDimitry Andric return LHS.S < RHS.S; 116*bdd1243dSDimitry Andric } 117*bdd1243dSDimitry Andric 118*bdd1243dSDimitry Andric private: 119*bdd1243dSDimitry Andric using PoolEntry = StringPool::PoolMapEntry; 120*bdd1243dSDimitry Andric using PoolEntryPtr = PoolEntry *; 121*bdd1243dSDimitry Andric 122*bdd1243dSDimitry Andric PooledStringPtr(StringPool::PoolMapEntry *S) : S(S) { 123*bdd1243dSDimitry Andric if (S) 124*bdd1243dSDimitry Andric ++S->second; 125*bdd1243dSDimitry Andric } 126*bdd1243dSDimitry Andric 127*bdd1243dSDimitry Andric PoolEntryPtr S = nullptr; 128*bdd1243dSDimitry Andric }; 129*bdd1243dSDimitry Andric 130*bdd1243dSDimitry Andric inline StringPool::~StringPool() { 131*bdd1243dSDimitry Andric #ifndef NDEBUG 132*bdd1243dSDimitry Andric clearDeadEntries(); 133*bdd1243dSDimitry Andric assert(Pool.empty() && "Dangling references at pool destruction time"); 134*bdd1243dSDimitry Andric #endif // NDEBUG 135*bdd1243dSDimitry Andric } 136*bdd1243dSDimitry Andric 137*bdd1243dSDimitry Andric inline PooledStringPtr StringPool::intern(std::string S) { 138*bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(PoolMutex); 139*bdd1243dSDimitry Andric PoolMap::iterator I; 140*bdd1243dSDimitry Andric bool Added; 141*bdd1243dSDimitry Andric std::tie(I, Added) = Pool.try_emplace(std::move(S), 0); 142*bdd1243dSDimitry Andric return PooledStringPtr(&*I); 143*bdd1243dSDimitry Andric } 144*bdd1243dSDimitry Andric 145*bdd1243dSDimitry Andric inline void StringPool::clearDeadEntries() { 146*bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(PoolMutex); 147*bdd1243dSDimitry Andric for (auto I = Pool.begin(), E = Pool.end(); I != E;) { 148*bdd1243dSDimitry Andric auto Tmp = I++; 149*bdd1243dSDimitry Andric if (Tmp->second == 0) 150*bdd1243dSDimitry Andric Pool.erase(Tmp); 151*bdd1243dSDimitry Andric } 152*bdd1243dSDimitry Andric } 153*bdd1243dSDimitry Andric 154*bdd1243dSDimitry Andric inline bool StringPool::empty() const { 155*bdd1243dSDimitry Andric std::lock_guard<std::mutex> Lock(PoolMutex); 156*bdd1243dSDimitry Andric return Pool.empty(); 157*bdd1243dSDimitry Andric } 158*bdd1243dSDimitry Andric 159*bdd1243dSDimitry Andric } // end namespace __orc_rt 160*bdd1243dSDimitry Andric 161*bdd1243dSDimitry Andric namespace std { 162*bdd1243dSDimitry Andric 163*bdd1243dSDimitry Andric // Make PooledStringPtrs hashable. 164*bdd1243dSDimitry Andric template <> struct hash<__orc_rt::PooledStringPtr> { 165*bdd1243dSDimitry Andric size_t operator()(const __orc_rt::PooledStringPtr &A) const { 166*bdd1243dSDimitry Andric return hash<__orc_rt::PooledStringPtr::PoolEntryPtr>()(A.S); 167*bdd1243dSDimitry Andric } 168*bdd1243dSDimitry Andric }; 169*bdd1243dSDimitry Andric 170*bdd1243dSDimitry Andric } // namespace std 171*bdd1243dSDimitry Andric 172*bdd1243dSDimitry Andric #endif // ORC_RT_REF_COUNTED_STRING_POOL_H 173