forked from OSchip/llvm-project
173 lines
4.2 KiB
C++
173 lines
4.2 KiB
C++
//===------- string_pool.h - Thread-safe pool for strings -------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Contains a thread-safe string pool. Strings are ref-counted, but not
|
|
// automatically deallocated. Unused entries can be cleared by calling
|
|
// StringPool::clearDeadEntries.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef ORC_RT_STRING_POOL_H
|
|
#define ORC_RT_STRING_POOL_H
|
|
|
|
#include <atomic>
|
|
#include <cassert>
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
namespace __orc_rt {
|
|
|
|
class PooledStringPtr;
|
|
|
|
/// String pool for strings names used by the ORC runtime.
|
|
class StringPool {
|
|
friend class PooledStringPtr;
|
|
|
|
public:
|
|
/// Destroy a StringPool.
|
|
~StringPool();
|
|
|
|
/// Create a string pointer from the given string.
|
|
PooledStringPtr intern(std::string S);
|
|
|
|
/// Remove from the pool any entries that are no longer referenced.
|
|
void clearDeadEntries();
|
|
|
|
/// Returns true if the pool is empty.
|
|
bool empty() const;
|
|
|
|
private:
|
|
using RefCountType = std::atomic<size_t>;
|
|
using PoolMap = std::unordered_map<std::string, RefCountType>;
|
|
using PoolMapEntry = PoolMap::value_type;
|
|
mutable std::mutex PoolMutex;
|
|
PoolMap Pool;
|
|
};
|
|
|
|
/// Pointer to a pooled string.
|
|
class PooledStringPtr {
|
|
friend class StringPool;
|
|
friend struct std::hash<PooledStringPtr>;
|
|
|
|
public:
|
|
PooledStringPtr() = default;
|
|
PooledStringPtr(std::nullptr_t) {}
|
|
PooledStringPtr(const PooledStringPtr &Other) : S(Other.S) {
|
|
if (S)
|
|
++S->second;
|
|
}
|
|
|
|
PooledStringPtr &operator=(const PooledStringPtr &Other) {
|
|
if (S) {
|
|
assert(S->second && "Releasing PooledStringPtr with zero ref count");
|
|
--S->second;
|
|
}
|
|
S = Other.S;
|
|
if (S)
|
|
++S->second;
|
|
return *this;
|
|
}
|
|
|
|
PooledStringPtr(PooledStringPtr &&Other) : S(nullptr) {
|
|
std::swap(S, Other.S);
|
|
}
|
|
|
|
PooledStringPtr &operator=(PooledStringPtr &&Other) {
|
|
if (S) {
|
|
assert(S->second && "Releasing PooledStringPtr with zero ref count");
|
|
--S->second;
|
|
}
|
|
S = nullptr;
|
|
std::swap(S, Other.S);
|
|
return *this;
|
|
}
|
|
|
|
~PooledStringPtr() {
|
|
if (S) {
|
|
assert(S->second && "Releasing PooledStringPtr with zero ref count");
|
|
--S->second;
|
|
}
|
|
}
|
|
|
|
explicit operator bool() const { return S; }
|
|
|
|
const std::string &operator*() const { return S->first; }
|
|
|
|
friend bool operator==(const PooledStringPtr &LHS,
|
|
const PooledStringPtr &RHS) {
|
|
return LHS.S == RHS.S;
|
|
}
|
|
|
|
friend bool operator!=(const PooledStringPtr &LHS,
|
|
const PooledStringPtr &RHS) {
|
|
return !(LHS == RHS);
|
|
}
|
|
|
|
friend bool operator<(const PooledStringPtr &LHS,
|
|
const PooledStringPtr &RHS) {
|
|
return LHS.S < RHS.S;
|
|
}
|
|
|
|
private:
|
|
using PoolEntry = StringPool::PoolMapEntry;
|
|
using PoolEntryPtr = PoolEntry *;
|
|
|
|
PooledStringPtr(StringPool::PoolMapEntry *S) : S(S) {
|
|
if (S)
|
|
++S->second;
|
|
}
|
|
|
|
PoolEntryPtr S = nullptr;
|
|
};
|
|
|
|
inline StringPool::~StringPool() {
|
|
#ifndef NDEBUG
|
|
clearDeadEntries();
|
|
assert(Pool.empty() && "Dangling references at pool destruction time");
|
|
#endif // NDEBUG
|
|
}
|
|
|
|
inline PooledStringPtr StringPool::intern(std::string S) {
|
|
std::lock_guard<std::mutex> Lock(PoolMutex);
|
|
PoolMap::iterator I;
|
|
bool Added;
|
|
std::tie(I, Added) = Pool.try_emplace(std::move(S), 0);
|
|
return PooledStringPtr(&*I);
|
|
}
|
|
|
|
inline void StringPool::clearDeadEntries() {
|
|
std::lock_guard<std::mutex> Lock(PoolMutex);
|
|
for (auto I = Pool.begin(), E = Pool.end(); I != E;) {
|
|
auto Tmp = I++;
|
|
if (Tmp->second == 0)
|
|
Pool.erase(Tmp);
|
|
}
|
|
}
|
|
|
|
inline bool StringPool::empty() const {
|
|
std::lock_guard<std::mutex> Lock(PoolMutex);
|
|
return Pool.empty();
|
|
}
|
|
|
|
} // end namespace __orc_rt
|
|
|
|
namespace std {
|
|
|
|
// Make PooledStringPtrs hashable.
|
|
template <> struct hash<__orc_rt::PooledStringPtr> {
|
|
size_t operator()(const __orc_rt::PooledStringPtr &A) const {
|
|
return hash<__orc_rt::PooledStringPtr::PoolEntryPtr>()(A.S);
|
|
}
|
|
};
|
|
|
|
} // namespace std
|
|
|
|
#endif // ORC_RT_REF_COUNTED_STRING_POOL_H
|