9#include <unordered_map>
16template<
typename T,
typename Pool,
bool CanBeNone = false>
20template<
typename T,
typename Hash = std::hash<T>,
typename KeyEqual = std::equal_to<T>,
typename Copy = std::
identity,
21 bool ThreadSafe = false>
24 using counter_type = std::conditional_t<ThreadSafe, std::atomic<uint32_t>, uint32_t>;
25 using table_type = std::unordered_map<T, counter_type, Hash, KeyEqual>;
33 template<
typename,
typename,
bool>
51 for (
auto& [_, count] :
table_)
52 M_insist(count == 0,
"deleting would create a dangling reference to pooled object");
70 template<
bool CanBeNone>
74 template<
bool CanBeNone>
79template<
typename T,
typename Hash = std::hash<T>,
typename KeyEqual = std::equal_to<T>,
bool ThreadSafe = false>
98 template<
typename U,
typename V>
99 auto operator()(
U &&first, V &&second)
const {
return KeyEqual{}(*first, *second); }
102 using counter_type = std::conditional_t<ThreadSafe, std::atomic<uint32_t>, uint32_t>;
110 template<
typename,
typename,
bool>
125 Pool(std::size_t initial_capacity) :
table_(initial_capacity) { }
129 while (not
table_.empty()) {
130 typename table_type::node_type nh =
table_.extract(
table_.begin());
131 M_insist(nh.mapped() == 0,
"deleting would create a dangling reference to pooled object");
146 requires std::derived_from<U, T>
151 template<
typename U,
bool CanBeNone>
152 requires std::derived_from<U, T>
156 template<
typename U,
bool CanBeNone>
166template<
typename T,
typename Pool,
bool CanBeNone>
178 template<
typename,
typename,
bool>
196 if constexpr (CanBeNone) {
223 if (not other.has_value())
231 if (not other.has_value())
233 return std::exchange(other.ref_,
nullptr);
254 M_insist(
ref_->second > 0,
"underflow reference count");
255 if (--
ref_->second == 0)
264 explicit operator const T & ()
const {
return Pool::Get(*
this); }
275 requires std::is_polymorphic_v<typename Pool::pooled_type>
and (std::derived_from<U, T> or std::derived_from<T, U>)
287 requires std::is_polymorphic_v<typename Pool::pooled_type>
and std::derived_from<T, U>
297 template<
typename U,
bool _CanBeNone>
298 requires std::is_polymorphic_v<typename Pool::pooled_type>
and std::derived_from<U, T>
307 template<
typename U,
bool _CanBeNone>
309 template<
typename U,
bool _CanBeNone>
318 return out << *pooled;
320 return out <<
"Pooled<" <<
typeid(
T).name() <<
">";
323 void dump(std::ostream &out)
const {
326 <<
" count: " << this->
count() << std::endl;
331template<
typename T,
typename Hash,
typename KeyEqual,
typename Copy,
bool ThreadSafe>
335 if constexpr (ThreadSafe) {
337 typename table_type::iterator it;
341 if (it != table_.end())
343 }
while (not lock.upgrade());
345 it = table_.emplace_hint(it, Copy{}(std::forward<U>(u)), 0);
348 auto it = table_.find(u);
349 if (it == table_.end())
350 it = table_.emplace_hint(it, Copy{}(std::forward<U>(u)), 0);
355template<
typename T,
typename Hash,
typename KeyEqual,
typename Copy,
bool ThreadSafe>
356template<
bool CanBeNone>
359 M_insist(pooled.
ref_,
"cannot erase w/o valid reference");
360 if constexpr (ThreadSafe) {
362 if (pooled.
ref_->second != 0)
return false;
363 table_.erase(pooled.
ref_->first);
366 M_insist(pooled.
ref_->second == 0,
"reference count must be 0 to erase");
367 table_.erase(pooled.
ref_->first);
372template<
typename T,
typename Hash,
typename KeyEqual,
typename Copy,
bool ThreadSafe>
373template<
bool CanBeNone>
377 return pooled.
ref_->first;
380template<
typename T,
typename Hash,
typename KeyEqual,
bool ThreadSafe>
382requires std::derived_from<U, T>
385 if constexpr (ThreadSafe) {
387 typename table_type::iterator it;
390 it = table_.find(&u);
391 if (it != table_.end())
393 }
while (not lock.upgrade());
395 it = table_.emplace_hint(it, as<T>(std::make_unique<U>(std::forward<U>(u))), 0);
398 auto it = table_.find(&u);
399 if (it == table_.end())
400 it = table_.emplace_hint(it, as<T>(std::make_unique<U>(std::forward<U>(u))), 0);
405template<
typename T,
typename Hash,
typename KeyEqual,
bool ThreadSafe>
406template<
typename U,
bool CanBeNone>
409 M_insist(pooled.
ref_,
"cannot erase w/o valid reference");
410 if constexpr (ThreadSafe) {
412 if (pooled.
ref_->second != 0)
return false;
413 table_.erase(pooled.
ref_->first);
416 M_insist(pooled.
ref_->second == 0,
"reference count must be 0 to erase");
417 table_.erase(pooled.
ref_->first);
422template<
typename T,
typename Hash,
typename KeyEqual,
bool ThreadSafe>
423template<
typename U,
bool CanBeNone>
424requires std::derived_from<U, T>
428 return as<U>(*pooled.
ref_->first);
431template<
typename T,
typename Hash = std::hash<T>,
typename KeyEqual = std::equal_to<T>,
typename Copy = std::
identity>
433template<
typename T,
typename Hash = std::hash<T>,
typename KeyEqual = std::equal_to<T>>
445template<
bool ThreadSafe = false>
456 for (
const auto& [str, _] : *
this)
475template<
typename T,
typename Pool,
bool CanBeNone>
476struct std::hash<
m::Pooled<T, Pool, CanBeNone>>
479 return std::hash<const T*>{}(&*pooled);
ThreadSafeStringPool::proxy_type ThreadSafePooledString
and arithmetic< U > and same_signedness< T, U > U
ThreadSafeStringPool::proxy_optional_type ThreadSafePooledOptionalString
The PODPool implements an implicitly garbage-collected set of pooled (or internalized) POD struct ent...
PODPool(std::size_t initial_capacity)
static constexpr bool is_thread_safe
const_iterator cbegin() const
OptField< ThreadSafe, reader_writer_mutex > table_mutex_
std::unordered_map< T, counter_type, Hash, KeyEqual > table_type
bool erase(const Pooled< T, PODPool, CanBeNone > &pooled)
Erases the pooled entity from the pool.
table_type::const_iterator const_iterator
proxy_type operator()(U &&u)
Returns the pooled.
static const T & Get(const Pooled< T, PODPool, CanBeNone > &pooled)
Returns a reference to the value referenced by.
const_iterator cend() const
std::conditional_t< ThreadSafe, std::atomic< uint32_t >, uint32_t > counter_type
std::size_t size() const
Returns the number of elements in the pool.
auto operator()(U &&first, V &&second) const
void is_transparent
Mark this callable as transparent, allowing for comparing various types that are interoperable.
void is_transparent
Mark this callable as transparent, allowing for computing the hash of various types that are interop...
auto operator()(U &&u) const
A pool implements an implicitly garbage-collected set of instances of a class hierarchy.
std::size_t size() const
Returns the number of elements in the pool.
OptField< ThreadSafe, reader_writer_mutex > table_mutex_
const_iterator cend() const
std::conditional_t< ThreadSafe, std::atomic< uint32_t >, uint32_t > counter_type
Pooled< U, Pool, false > operator()(U &&u)
Returns the pooled.
table_type::const_iterator const_iterator
static constexpr bool is_thread_safe
Pool(std::size_t initial_capacity)
static const U & Get(const Pooled< U, Pool, CanBeNone > &pooled)
Returns a reference to the value referenced by.
std::unordered_map< std::unique_ptr< T >, counter_type, dereference_hash, dereference_equal_to > table_type
const_iterator cbegin() const
bool erase(const Pooled< U, Pool, CanBeNone > &pooled)
Erases the pooled entity from the pool.
A data type representing a pooled (or internalized) object.
Pooled(Pooled< T, Pool, true > &&other)
Move-constructs a non-optional Pooled from an optional one. Can only be used if value is present.
Pooled< T, Pool, false > assert_not_none() const
bool operator!=(Pooled< U, Pool, _CanBeNone > other) const
friend std::ostream & operator<<(std::ostream &out, const Pooled &pooled)
Pooled & operator=(Pooled other)
friend struct Pooled
Access privilege for conversion between optional and non-optional Pooled instances.
bool operator==(const U *other) const
static constexpr bool can_be_none
Can this Pooled not reference an object?
and(std::derived_from< U, T > or std::derived_from< T, U >) Pooled< U
Explicitly casts this Pooled<T> to Pooled<U>.
Pooled(Pool *pool, value_type *value)
Constucts a fresh Pooled from a pooled.
const T * operator->() const
void dump(std::ostream &out) const
Pooled(const Pooled< T, Pool, false > &other)
Constructs an optional Pooled with a present value from a non-optional one.
bool operator!=(const U *other) const
friend void swap(Pooled &first, Pooled &second)
bool operator==(Pooled< U, Pool, _CanBeNone > other) const
Pooled(Pooled< T, Pool, false > &&other)
Move-constructs an optional Pooled with a present value from a non-optional one.
and std::derived_from< U, T > Pooled & operator=(Pooled< U, Pool, _CanBeNone > other)
Assigns a Pooled<U> to this Pooled<T>.
typename Pool::table_type::value_type value_type
const T & operator*() const
Pool * pool_
The pool holding this value. Can only be nullptr if CanBeNone or if the Pooled instance is moved.
uint32_t count() const
Returns the number of references to the pooled object or 0 if this Pooled CanBeNone and does not hold...
Pooled(const Pooled< T, Pool, true > &other)
Constructs a non-optional Pooled from an optional one. Can only be used if value is present.
value_type * ref_
The pointer to the pooled object. Can only be nullptr if CanBeNone or if the Pooled instance is move...
const char * operator()(const char *str) const
const char * operator()(std::string_view sv) const
Explicit specialization of PODPool for strings (const char *).
_StringPool(std::size_t initial_capacity)
Signals that an argument to a function of method was invalid.
This is a helper class that helps managing reader and writer locks claimed from reader_writer_mutex.
void lock_read()
Acquire a read lock.
uint64_t operator()(const m::Pooled< T, Pool, CanBeNone > &pooled) const