LCOV - code coverage report
Current view: top level - utilities/include/mcrl2/utilities - unordered_map.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 36 36 100.0 %
Date: 2024-04-19 03:43:27 Functions: 97 127 76.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Maurice Laveaux
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : 
       9             : #ifndef MCRL2_UTILITIES_UNORDERED_MAP_H
      10             : #define MCRL2_UTILITIES_UNORDERED_MAP_H
      11             : 
      12             : #include <utility>
      13             : #include <functional>
      14             : #include "mcrl2/utilities/unordered_set.h"
      15             : 
      16             : 
      17             : namespace mcrl2::utilities
      18             : {
      19             : 
      20             : /// \brief A class for a map of keys to values in T based using the simple hash table set implementation.
      21             : template<typename Key,
      22             :          typename T,
      23             :          typename Hash,
      24             :          typename KeyEqual,
      25             :          typename Allocator,
      26             :          bool ThreadSafe,
      27             :          bool Resize>
      28             : class unordered_map
      29             : {
      30             : public:
      31             :   using key_type = Key;
      32             :   using mapped_type = T;
      33             :   using value_type = std::pair<const Key, T>;
      34             :   typedef value_type node_type;
      35             :   using size_type = std::size_t;
      36             :   using difference_type = std::ptrdiff_t;
      37             : 
      38             :   using hasher = Hash;
      39             :   using key_equal = KeyEqual;
      40             :   using allocator_type = typename std::allocator_traits<Allocator>::template rebind_alloc<value_type>;
      41             : 
      42             :   using reference = value_type&;
      43             :   using const_reference = const value_type&;
      44             :   using pointer = typename std::allocator_traits<Allocator>::pointer;
      45             :   using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
      46             : 
      47             : private:
      48             :   /// \brief True iff the hash and equals functions allow transparent lookup,
      49             :   static constexpr bool allow_transparent = detail::is_transparent<Hash>() && detail::is_transparent<KeyEqual>();
      50             : 
      51             :   // Hashes only the keys of each pair.
      52             :   struct PairHash
      53             :   {
      54             :     using is_transparent = void;
      55             : 
      56             :     PairHash() = default;
      57             : 
      58       22515 :     explicit PairHash(const hasher& hash)
      59             :       : hash(hash)
      60       22515 :     {}
      61             : 
      62             :     hasher hash;
      63             : 
      64       19605 :     std::size_t operator()(const value_type& pair) const
      65             :     {
      66       19605 :       return hash(pair.first);
      67             :     }
      68             :         
      69             :     template<typename U, typename ...V, typename = std::enable_if_t<!std::is_same_v<U, std::pair<Key, T>>>>
      70      858105 :     std::size_t operator()(const U& key, const V&... /* args */) const 
      71             :     {
      72      858105 :       return hash(key);
      73             :     }
      74             :   };
      75             : 
      76             :   // Compares only the keys of each pair.
      77             :   struct PairEquals
      78             :   {
      79             :     using is_transparent = void;
      80             : 
      81             :     PairEquals() = default;
      82             : 
      83       22515 :     explicit PairEquals(const key_equal& equals)
      84             :       : equals(equals)
      85       22515 :     {}
      86             : 
      87             :     key_equal equals;
      88             : 
      89       10805 :     bool operator()(const value_type& first, const value_type& second) const
      90             :     {
      91       10805 :       return equals(first.first, second.first);
      92             :     }
      93             : 
      94             :     template <typename U, typename...V, typename = std::enable_if_t<!std::is_same_v<U, std::pair<Key, T>>>>
      95      585245 :     bool operator()(const value_type& first, const U& key, const V&... /* args */) const
      96             :     {
      97      585245 :       return equals(first.first, key);
      98             :     }
      99             :   };
     100             : 
     101             :   using Set = unordered_set<value_type, PairHash, PairEquals, allocator_type, ThreadSafe, Resize>;
     102             :   using bucket_type = typename Set::bucket_type;
     103             : 
     104             :   Set m_set; ///< The underlying set storing <key, value> pairs.
     105             : 
     106             : public:
     107             :   using iterator = typename Set::template unordered_set_iterator<bucket_type, false>;
     108             :   using const_iterator = typename Set::const_iterator;
     109             :   using local_iterator = typename bucket_type::iterator;
     110             :   using const_local_iterator = typename Set::const_local_iterator;
     111             :   typedef typename std::pair<unordered_map::iterator, bool> insert_return_type;
     112             : 
     113       22514 :   unordered_map()
     114       22514 :     : m_set(0, PairHash(hasher()), PairEquals(key_equal()))
     115       22514 :   {}
     116             : 
     117             :   /// \brief Constructs an unordered_map that can store initial_size number of elements before resizing.
     118           1 :   unordered_map(std::size_t initial_size,
     119             :     const hasher& hash = hasher(),
     120             :     const key_equal& equals = key_equal())
     121           1 :     : m_set(initial_size, PairHash(hash), PairEquals(equals))
     122           1 :   {}
     123             : 
     124             :   /// \returns A reference to the local node allocator.
     125             :   const allocator_type& get_allocator() const noexcept { return m_set.get_allocator(); }
     126             :   allocator_type& get_allocator() noexcept { return m_set.get_allocator(); }
     127             : 
     128         364 :   iterator begin() { return m_set.begin(); }
     129     1459170 :   iterator end() { return m_set.end(); }
     130             : 
     131         285 :   const_iterator begin() const { return m_set.begin(); }
     132       25630 :   const_iterator end() const { return m_set.end(); }
     133             : 
     134             :   const_iterator cbegin() const { return m_set.begin(); }
     135             :   const_iterator cend() const { return m_set.end(); }
     136             : 
     137             :   /// \returns True iff the set is empty.
     138       88648 :   bool empty() const noexcept { return m_set.empty(); }
     139             : 
     140             :   /// \returns The number of elements.
     141      106149 :   size_type size() const { return m_set.size(); }
     142             :   size_type max_size() const noexcept { return m_set.max_size(); }
     143             : 
     144             :   /// \brief Clears the content.
     145             :   void clear() { m_set.clear(); }
     146             : 
     147             :   /// \brief Inserts elements.
     148        4271 :   std::pair<iterator, bool> insert(const value_type& pair) { auto[x, y] = m_set.emplace(pair); return std::make_pair(iterator(x), y); }
     149             : 
     150             :   std::pair<iterator, bool> insert(const_iterator hint, const value_type& pair) { return insert(hint, pair);  }
     151             : 
     152             :   template<typename ...Args>
     153      101296 :   std::pair<iterator, bool> emplace(Args&&... args) { auto[x, y] = m_set.emplace(std::forward<Args>(args)...); return std::make_pair(iterator(x), y); }
     154             : 
     155             :   template<typename ...Args>
     156             :   iterator emplace_hint(const_iterator /*hint*/, Args&&... args) { return emplace(std::forward<Args>(args)...); }
     157             : 
     158             :   template<typename ...Args>
     159             :   std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args);
     160             : 
     161             :   template< class... Args >
     162             :   iterator try_emplace(const_iterator /*hint*/, const Key& k, Args&&... args) { return try_emplace(k, std::forward<Args>(args)...); }
     163             : 
     164             :   template< class... Args >
     165             :   iterator try_emplace(const_iterator /*hint*/, Key&& k, Args&&... args) { return try_emplace(std::forward<Key>(k), std::forward<Args>(args)...); }
     166             : 
     167             :   template <typename M>
     168             :   std::pair<iterator, bool> insert_or_assign(Key&& k, M&& obj)
     169             :   {
     170             :     auto it = find(k);
     171             :     if (it != end())
     172             :     {
     173             :       *it = obj;
     174             :       return std::make_pair(it, true);
     175             :     }
     176             :     else
     177             :     {
     178             :       return emplace(std::forward<Key>(obj), std::forward<M>(obj));
     179             :     }
     180             :   }
     181             : 
     182             :   template <typename M>
     183             :   std::pair<iterator, bool> insert_or_assign(const Key& k, M&& obj) { return insert_or_emplace(k, std::forward<M>(obj)); }
     184             : 
     185             :   template <typename M>
     186             :   std::pair<iterator, bool> insert_or_assign(const_iterator /* hint */, const Key& k, M&& obj) { return insert_or_emplace(k, std::forward<M>(obj)); }
     187             : 
     188             :   template <typename M>
     189             :   std::pair<iterator, bool> insert_or_assign(const_iterator /* hint */, Key&& k, M&& obj) { return insert_or_emplace(k, std::forward<M>(obj)); }
     190             : 
     191             :   /// \brief Erases elements.
     192             :   void erase(const key_type& key) { const_iterator it = m_set.find(key); m_set.erase(it); }
     193      172646 :   iterator erase(const_iterator it) { return m_set.erase(it); }
     194             : 
     195             :   /// \brief Provides access to the value associated with the given key.
     196             :   const T& at(const key_type& key) const;
     197             : 
     198             :   /// \brief Provides access to the value associated with the given key, constructs a default
     199             :   ///        value whenever the key was undefined.
     200             :   mapped_type& operator[](const key_type& key);
     201             : 
     202             :   /// \returns The number of elements matching the specified key.
     203             :   size_type count(const key_type& key) const { return m_set.count(key); }
     204             : 
     205             :   /// \returns Element with the specified key.
     206             :   template<typename ...Args>
     207     1458802 :   iterator find(const Args&... args) { return m_set.find(args...); }
     208             : 
     209             :   template<typename ...Args>
     210       25345 :   const_iterator find(const Args&... args) const { return m_set.find(args...); }
     211             : 
     212             :   /// \returns An iterator to the elements in the given bucket with index n.
     213             :   local_iterator begin(size_type n) { return m_set.begin(n); }
     214             :   local_iterator end(size_type n) { return m_set.end(n); }
     215             : 
     216             :   const_local_iterator begin(size_type n) const { return m_set.begin(n); }
     217             :   const_local_iterator end(size_type n) const { return m_set.end(n); }
     218             : 
     219             :   const_local_iterator cbegin(size_type n) const { return m_set.begin(n); }
     220             :   const_local_iterator cend(size_type n) const { return m_set.end(n); }
     221             : 
     222             :   /// \returns The number of buckets.
     223      207016 :   size_type bucket_count() const noexcept { return m_set.bucket_count(); }
     224             :   size_type max_bucket_count() const noexcept { return m_set.max_bucket_count(); }
     225             : 
     226             :   size_type bucket_size(size_type n) const noexcept { return m_set.bucket_size(n); }
     227             :   size_type bucket(const key_type& key) const noexcept { return m_set.bucket(key); }
     228             : 
     229      103508 :   float load_factor() const { return static_cast<float>(size()) / bucket_count(); }
     230      103508 :   float max_load_factor() const { return m_set.max_load_factor(); }
     231             :   void max_load_factor(float factor) { m_set.max_load_factor(factor); }
     232             : 
     233             :   /// \brief Resize the number buckets to at least number_of_buckets.
     234         547 :   void rehash(size_type number_of_buckets)
     235             :   {
     236         547 :     m_set.rehash(number_of_buckets);
     237         547 :   }
     238             : 
     239             :   /// \brief Resizes the set to the given number of elements.
     240             :   void reserve(size_type count) { rehash(std::ceil(static_cast<float>(count) / max_load_factor())); }
     241             : 
     242             :   hasher hash_function() const { return m_set.hash_function(); }
     243             :   key_equal key_eq() const { return m_set.key_eq(); }
     244             : 
     245             :   /// \brief Number of elements that can be stored before rehash.
     246             :   /// \details Nonstandard.
     247           1 :   size_type capacity() { return m_set.capacity(); }
     248             : };
     249             : 
     250             : /// \brief A specialization for large unordered maps that uses the block_allocator internally by default.
     251             : template<typename Key,
     252             :          typename T,
     253             :          typename Hash = std::hash<Key>,
     254             :          typename Equals = std::equal_to<Key>,
     255             :          typename Allocator = mcrl2::utilities::block_allocator<Key>,
     256             :          bool ThreadSafe = false,
     257             :          bool Resize = true>
     258             : using unordered_map_large = unordered_map<Key, T, Hash, Equals, Allocator, ThreadSafe, Resize>;
     259             : 
     260             : } // namespace mcrl2::utilities
     261             : 
     262             : #include "mcrl2/utilities/detail/unordered_map_implementation.h"
     263             : 
     264             : #endif // MCRL2_UTILITIES_UNORDERED_MAP_H

Generated by: LCOV version 1.14