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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Contains a thread-safe string pool. Strings are ref-counted, but not
10// automatically deallocated. Unused entries can be cleared by calling
11// StringPool::clearDeadEntries.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef ORC_RT_STRING_POOL_H
16#define ORC_RT_STRING_POOL_H
17
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(a&: S, b&: 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(a&: S, b&: 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 NDEBUG
132 clearDeadEntries();
133 assert(Pool.empty() && "Dangling references at pool destruction time");
134#endif // NDEBUG
135}
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(args&: I, args&: Added) = Pool.try_emplace(k: std::move(t&: S), args: 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(position: Tmp);
151 }
152}
153
154inline bool StringPool::empty() const {
155 std::lock_guard<std::mutex> Lock(PoolMutex);
156 return Pool.empty();
157}
158
159} // end namespace __orc_rt
160
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 std
171
172#endif // ORC_RT_REF_COUNTED_STRING_POOL_H
173

source code of compiler-rt/lib/orc/string_pool.h