9#ifndef MCRL2_UTILITIES_UNORDERED_SET_IMPLEMENTATION_H
10#define MCRL2_UTILITIES_UNORDERED_SET_IMPLEMENTATION_H
13#define MCRL2_UNORDERED_SET_TEMPLATES template<typename Key, typename Hash, typename Equals, typename Allocator, bool ThreadSafe, bool Resize>
14#define MCRL2_UNORDERED_SET_CLASS unordered_set<Key, Hash, Equals, Allocator, ThreadSafe, Resize>
29 return static_cast<float>(bytes) / (1024.0f * 1024.0f);
33MCRL2_UNORDERED_SET_CLASS::unordered_set(
const unordered_set& set)
37 for (
auto& element : set)
49 for (
auto& element : set)
58MCRL2_UNORDERED_SET_CLASS::~unordered_set()
61 if (m_buckets.size() > 0)
68void MCRL2_UNORDERED_SET_CLASS::clear()
70 assert(m_buckets.size() != 0);
73 for (
auto it = begin(); it != end(); )
78 assert(std::all_of(m_buckets.begin(), m_buckets.end(), [](
const bucket_type& bucket) { return bucket.empty(); }));
79 assert(m_number_of_elements == 0);
80 assert(m_buckets.size() != 0);
84template<
typename ...Args>
85auto MCRL2_UNORDERED_SET_CLASS::emplace(Args&&... args) -> std::pair<iterator, bool>
87 if constexpr (Resize) { rehash_if_needed(); }
89 size_type bucket_index;
93 if constexpr (allow_transparent)
96 bucket_index = find_bucket_index(std::forward<Args>(args)...);
97 it = find_impl(bucket_index, std::forward<Args>(args)...);
102 Key object(std::forward<Args>(args)...);
103 bucket_index = find_bucket_index(
object);
104 it = find_impl(bucket_index,
object);
109 return std::make_pair(it,
false);
113 return emplace_impl(bucket_index, std::forward<Args>(args)...);
118auto MCRL2_UNORDERED_SET_CLASS::erase(
typename MCRL2_UNORDERED_SET_CLASS::const_iterator it) -> iterator
121 bucket_type& bucket =
const_cast<bucket_type&
>(*it.get_bucket_it());
124 --m_number_of_elements;
127 iterator result_it(it.get_bucket_it(), m_buckets.end(), it.key_before_it(), bucket.erase_after(m_allocator, it.key_before_it()));
130 result_it.goto_next_bucket();
135template<
typename ...Args>
136std::size_t MCRL2_UNORDERED_SET_CLASS::count(
const Args&... args)
const
138 if constexpr (allow_transparent)
140 return find(args...) != end();
144 return find(Key(args...)) != end();
149template<
typename ...Args>
150void MCRL2_UNORDERED_SET_CLASS::erase(
const Args&... args)
152 if constexpr (allow_transparent)
158 erase_impl(Key(args...));
163template<
typename ...Args>
164auto MCRL2_UNORDERED_SET_CLASS::find(
const Args&... args)
const -> const_iterator
166 if constexpr (allow_transparent)
168 return find_impl(find_bucket_index(args...), args...);
172 Key element(args...);
173 return find_impl(find_bucket_index(element), element);
178template<
typename ...Args>
179auto MCRL2_UNORDERED_SET_CLASS::find(
const Args&... args) -> iterator
181 if constexpr (allow_transparent)
183 return find_impl(find_bucket_index(args...), args...);
187 Key element(args...);
188 return find_impl(find_bucket_index(element), element);
193void MCRL2_UNORDERED_SET_CLASS::rehash(std::size_t number_of_buckets)
200 if (number_of_buckets <= bucket_count())
208 m_bucket_mutexes = std::vector<std::mutex>(std::max(number_of_buckets /
BucketsPerMutex, 1ul));
212 bucket_type old_keys;
213 for (
auto&& bucket : m_buckets)
215 old_keys.splice_after(old_keys.before_begin(), bucket);
218 assert(std::distance(old_keys.begin(), old_keys.end()) ==
static_cast<long>(m_number_of_elements));
223 std::vector<bucket_type>().swap(m_buckets);
225 m_buckets.resize(number_of_buckets);
226 m_buckets_mask = m_buckets.size() - 1;
229 while (!old_keys.empty())
232 bucket_type& bucket = m_buckets[find_bucket_index(old_keys.front())];
233 bucket.splice_front(bucket.before_begin(), old_keys);
241 std::vector<std::size_t> histogram;
247 histogram.resize(std::max(histogram.size(), bucket_length + 1));
248 ++histogram[bucket_length];
253 for (std::size_t i = 0; i < histogram.size(); ++i)
262template<
typename ...Args>
263auto MCRL2_UNORDERED_SET_CLASS::emplace_impl(size_type bucket_index, Args&&... args) -> std::pair<iterator, bool>
265 bucket_type& bucket = m_buckets[bucket_index];
267 if constexpr (ThreadSafe)
272 auto [key_it, added] = bucket.emplace_front_unique(m_allocator, m_equals, std::forward<Args>(args)...);
273 iterator it(m_buckets.begin() + bucket_index, m_buckets.end(), bucket.before_begin(), key_it);
277 m_number_of_elements.fetch_add(1, std::memory_order_relaxed);
280 return std::make_pair(it, added);
285 std::lock_guard g(m_bucket_mutexes[bucket_index % m_bucket_mutexes.size()]);
287 iterator it = find_impl(bucket_index, std::forward<Args>(args)...);
291 return std::make_pair(it,
false);
296 bucket.emplace_front(m_allocator, std::forward<Args>(args)...);
299 m_number_of_elements.fetch_add(1, std::memory_order_relaxed);
300 iterator it(m_buckets.begin() + bucket_index, m_buckets.end(), bucket.before_begin(), bucket.begin());
301 return std::make_pair(it,
true);
309 bucket.emplace_front(m_allocator, std::forward<Args>(args)...);
310 ++m_number_of_elements;
313 iterator it(m_buckets.begin() + bucket_index, m_buckets.end(), bucket.before_begin(), bucket.begin());
314 return std::make_pair(it,
true);
320template<
typename ...Args>
321void MCRL2_UNORDERED_SET_CLASS::erase_impl(
const Args&... args)
323 bucket_type& bucket = m_buckets[find_bucket_index(args...)];
326 typename bucket_type::const_iterator before_it = bucket.before_begin();
327 for (
typename bucket_type::iterator it = bucket.begin(); it != bucket.end();)
329 if (m_equals(*it, args...))
332 --m_number_of_elements;
333 it = bucket.erase_after(m_allocator, before_it);
347template<
typename ...Args>
348std::size_t MCRL2_UNORDERED_SET_CLASS::find_bucket_index(
const Args&... args)
const
350 std::size_t
hash = m_hash(args...);
352 assert(m_buckets_mask == m_buckets.size() - 1);
353 std::size_t index =
hash & m_buckets_mask;
354 assert(index < m_buckets.size());
359template<
typename ...Args>
360auto MCRL2_UNORDERED_SET_CLASS::find_impl(size_type bucket_index,
const Args&... args)
const -> const_iterator
362 const auto& bucket = m_buckets[bucket_index];
365 auto before_it = bucket.before_begin();
366 for(
auto it = bucket.begin(); it != bucket.end(); ++it)
369 if (m_equals(key, args...))
371 return const_iterator(m_buckets.begin() + bucket_index, m_buckets.end(), before_it, it);
381void MCRL2_UNORDERED_SET_CLASS::rehash_if_needed()
383 if (load_factor() >= max_load_factor())
385 rehash(m_buckets.size() * 2);
389#undef MCRL2_UNORDERED_SET_CLASS
390#undef MCRL2_UNORDERED_SET_TEMPLATES
A unordered_set with a subset of the interface of std::unordered_set that only stores a single pointe...
size_type bucket_count() const noexcept
size_type size() const noexcept
size_type bucket_size(size_type n) const noexcept
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
float bytes_to_megabytes(std::size_t bytes)
static constexpr std::size_t minimum_size
static constexpr long BucketsPerMutex
Number of buckets per mutex.
static T round_up_to_power_of_two(T value)
static constexpr bool EnableLockfreeInsertion
Enables lockfree implementation of emplace.
void print_performance_statistics(const T &unordered_set)
Prints various information for unordered_set like data structures.
#define MCRL2_UNORDERED_SET_CLASS
#define MCRL2_UNORDERED_SET_TEMPLATES