Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:39

0001 //
0002 // detail/hash_map.hpp
0003 // ~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_HASH_MAP_HPP
0012 #define BOOST_ASIO_DETAIL_HASH_MAP_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <list>
0020 #include <utility>
0021 #include <boost/asio/detail/assert.hpp>
0022 #include <boost/asio/detail/noncopyable.hpp>
0023 
0024 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0025 # include <boost/asio/detail/socket_types.hpp>
0026 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0027 
0028 #include <boost/asio/detail/push_options.hpp>
0029 
0030 namespace boost {
0031 namespace asio {
0032 namespace detail {
0033 
0034 inline std::size_t calculate_hash_value(int i)
0035 {
0036   return static_cast<std::size_t>(i);
0037 }
0038 
0039 inline std::size_t calculate_hash_value(void* p)
0040 {
0041   return reinterpret_cast<std::size_t>(p)
0042     + (reinterpret_cast<std::size_t>(p) >> 3);
0043 }
0044 
0045 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0046 inline std::size_t calculate_hash_value(SOCKET s)
0047 {
0048   return static_cast<std::size_t>(s);
0049 }
0050 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0051 
0052 // Note: assumes K and V are POD types.
0053 template <typename K, typename V>
0054 class hash_map
0055   : private noncopyable
0056 {
0057 public:
0058   // The type of a value in the map.
0059   typedef std::pair<K, V> value_type;
0060 
0061   // The type of a non-const iterator over the hash map.
0062   typedef typename std::list<value_type>::iterator iterator;
0063 
0064   // The type of a const iterator over the hash map.
0065   typedef typename std::list<value_type>::const_iterator const_iterator;
0066 
0067   // Constructor.
0068   hash_map()
0069     : size_(0),
0070       buckets_(0),
0071       num_buckets_(0)
0072   {
0073   }
0074 
0075   // Destructor.
0076   ~hash_map()
0077   {
0078     delete[] buckets_;
0079   }
0080 
0081   // Get an iterator for the beginning of the map.
0082   iterator begin()
0083   {
0084     return values_.begin();
0085   }
0086 
0087   // Get an iterator for the beginning of the map.
0088   const_iterator begin() const
0089   {
0090     return values_.begin();
0091   }
0092 
0093   // Get an iterator for the end of the map.
0094   iterator end()
0095   {
0096     return values_.end();
0097   }
0098 
0099   // Get an iterator for the end of the map.
0100   const_iterator end() const
0101   {
0102     return values_.end();
0103   }
0104 
0105   // Check whether the map is empty.
0106   bool empty() const
0107   {
0108     return values_.empty();
0109   }
0110 
0111   // Find an entry in the map.
0112   iterator find(const K& k)
0113   {
0114     if (num_buckets_)
0115     {
0116       size_t bucket = calculate_hash_value(k) % num_buckets_;
0117       iterator it = buckets_[bucket].first;
0118       if (it == values_.end())
0119         return values_.end();
0120       iterator end_it = buckets_[bucket].last;
0121       ++end_it;
0122       while (it != end_it)
0123       {
0124         if (it->first == k)
0125           return it;
0126         ++it;
0127       }
0128     }
0129     return values_.end();
0130   }
0131 
0132   // Find an entry in the map.
0133   const_iterator find(const K& k) const
0134   {
0135     if (num_buckets_)
0136     {
0137       size_t bucket = calculate_hash_value(k) % num_buckets_;
0138       const_iterator it = buckets_[bucket].first;
0139       if (it == values_.end())
0140         return it;
0141       const_iterator end_it = buckets_[bucket].last;
0142       ++end_it;
0143       while (it != end_it)
0144       {
0145         if (it->first == k)
0146           return it;
0147         ++it;
0148       }
0149     }
0150     return values_.end();
0151   }
0152 
0153   // Insert a new entry into the map.
0154   std::pair<iterator, bool> insert(const value_type& v)
0155   {
0156     if (size_ + 1 >= num_buckets_)
0157       rehash(hash_size(size_ + 1));
0158     size_t bucket = calculate_hash_value(v.first) % num_buckets_;
0159     iterator it = buckets_[bucket].first;
0160     if (it == values_.end())
0161     {
0162       buckets_[bucket].first = buckets_[bucket].last =
0163         values_insert(values_.end(), v);
0164       ++size_;
0165       return std::pair<iterator, bool>(buckets_[bucket].last, true);
0166     }
0167     iterator end_it = buckets_[bucket].last;
0168     ++end_it;
0169     while (it != end_it)
0170     {
0171       if (it->first == v.first)
0172         return std::pair<iterator, bool>(it, false);
0173       ++it;
0174     }
0175     buckets_[bucket].last = values_insert(end_it, v);
0176     ++size_;
0177     return std::pair<iterator, bool>(buckets_[bucket].last, true);
0178   }
0179 
0180   // Erase an entry from the map.
0181   void erase(iterator it)
0182   {
0183     BOOST_ASIO_ASSERT(it != values_.end());
0184     BOOST_ASIO_ASSERT(num_buckets_ != 0);
0185 
0186     size_t bucket = calculate_hash_value(it->first) % num_buckets_;
0187     bool is_first = (it == buckets_[bucket].first);
0188     bool is_last = (it == buckets_[bucket].last);
0189     if (is_first && is_last)
0190       buckets_[bucket].first = buckets_[bucket].last = values_.end();
0191     else if (is_first)
0192       ++buckets_[bucket].first;
0193     else if (is_last)
0194       --buckets_[bucket].last;
0195 
0196     values_erase(it);
0197     --size_;
0198   }
0199 
0200   // Erase a key from the map.
0201   void erase(const K& k)
0202   {
0203     iterator it = find(k);
0204     if (it != values_.end())
0205       erase(it);
0206   }
0207 
0208   // Remove all entries from the map.
0209   void clear()
0210   {
0211     // Clear the values.
0212     values_.clear();
0213     size_ = 0;
0214 
0215     // Initialise all buckets to empty.
0216     iterator end_it = values_.end();
0217     for (size_t i = 0; i < num_buckets_; ++i)
0218       buckets_[i].first = buckets_[i].last = end_it;
0219   }
0220 
0221 private:
0222   // Calculate the hash size for the specified number of elements.
0223   static std::size_t hash_size(std::size_t num_elems)
0224   {
0225     static std::size_t sizes[] =
0226     {
0227 #if defined(BOOST_ASIO_HASH_MAP_BUCKETS)
0228       BOOST_ASIO_HASH_MAP_BUCKETS
0229 #else // BOOST_ASIO_HASH_MAP_BUCKETS
0230       3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
0231       49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
0232       12582917, 25165843
0233 #endif // BOOST_ASIO_HASH_MAP_BUCKETS
0234     };
0235     const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1;
0236     for (std::size_t i = 0; i < nth_size; ++i)
0237       if (num_elems < sizes[i])
0238         return sizes[i];
0239     return sizes[nth_size];
0240   }
0241 
0242   // Re-initialise the hash from the values already contained in the list.
0243   void rehash(std::size_t num_buckets)
0244   {
0245     if (num_buckets == num_buckets_)
0246       return;
0247     BOOST_ASIO_ASSERT(num_buckets != 0);
0248 
0249     iterator end_iter = values_.end();
0250 
0251     // Update number of buckets and initialise all buckets to empty.
0252     bucket_type* tmp = new bucket_type[num_buckets];
0253     delete[] buckets_;
0254     buckets_ = tmp;
0255     num_buckets_ = num_buckets;
0256     for (std::size_t i = 0; i < num_buckets_; ++i)
0257       buckets_[i].first = buckets_[i].last = end_iter;
0258 
0259     // Put all values back into the hash.
0260     iterator iter = values_.begin();
0261     while (iter != end_iter)
0262     {
0263       std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_;
0264       if (buckets_[bucket].last == end_iter)
0265       {
0266         buckets_[bucket].first = buckets_[bucket].last = iter++;
0267       }
0268       else if (++buckets_[bucket].last == iter)
0269       {
0270         ++iter;
0271       }
0272       else
0273       {
0274         values_.splice(buckets_[bucket].last, values_, iter++);
0275         --buckets_[bucket].last;
0276       }
0277     }
0278   }
0279 
0280   // Insert an element into the values list by splicing from the spares list,
0281   // if a spare is available, and otherwise by inserting a new element.
0282   iterator values_insert(iterator it, const value_type& v)
0283   {
0284     if (spares_.empty())
0285     {
0286       return values_.insert(it, v);
0287     }
0288     else
0289     {
0290       spares_.front() = v;
0291       values_.splice(it, spares_, spares_.begin());
0292       return --it;
0293     }
0294   }
0295 
0296   // Erase an element from the values list by splicing it to the spares list.
0297   void values_erase(iterator it)
0298   {
0299     *it = value_type();
0300     spares_.splice(spares_.begin(), values_, it);
0301   }
0302 
0303   // The number of elements in the hash.
0304   std::size_t size_;
0305 
0306   // The list of all values in the hash map.
0307   std::list<value_type> values_;
0308 
0309   // The list of spare nodes waiting to be recycled. Assumes that POD types only
0310   // are stored in the hash map.
0311   std::list<value_type> spares_;
0312 
0313   // The type for a bucket in the hash table.
0314   struct bucket_type
0315   {
0316     iterator first;
0317     iterator last;
0318   };
0319 
0320   // The buckets in the hash.
0321   bucket_type* buckets_;
0322 
0323   // The number of buckets in the hash.
0324   std::size_t num_buckets_;
0325 };
0326 
0327 } // namespace detail
0328 } // namespace asio
0329 } // namespace boost
0330 
0331 #include <boost/asio/detail/pop_options.hpp>
0332 
0333 #endif // BOOST_ASIO_DETAIL_HASH_MAP_HPP