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