xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/orc/string_pool.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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