PageRenderTime 36ms CodeModel.GetById 12ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/asio/detail/hash_map.hpp

http://hadesmem.googlecode.com/
C++ Header | 331 lines | 245 code | 44 blank | 42 comment | 49 complexity | 1f7a87e8ce0eaccdd31a95622f7ede17 MD5 | raw file
  1//
  2// detail/hash_map.hpp
  3// ~~~~~~~~~~~~~~~~~~~
  4//
  5// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6//
  7// Distributed under the Boost Software License, Version 1.0. (See accompanying
  8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9//
 10
 11#ifndef BOOST_ASIO_DETAIL_HASH_MAP_HPP
 12#define BOOST_ASIO_DETAIL_HASH_MAP_HPP
 13
 14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
 15# pragma once
 16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 17
 18#include <boost/asio/detail/config.hpp>
 19#include <boost/assert.hpp>
 20#include <list>
 21#include <utility>
 22#include <boost/asio/detail/noncopyable.hpp>
 23
 24#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 25# include <boost/asio/detail/socket_types.hpp>
 26#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 27
 28#include <boost/asio/detail/push_options.hpp>
 29
 30namespace boost {
 31namespace asio {
 32namespace detail {
 33
 34inline std::size_t calculate_hash_value(int i)
 35{
 36  return static_cast<std::size_t>(i);
 37}
 38
 39inline std::size_t calculate_hash_value(void* p)
 40{
 41  return reinterpret_cast<std::size_t>(p)
 42    + (reinterpret_cast<std::size_t>(p) >> 3);
 43}
 44
 45#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 46inline std::size_t calculate_hash_value(SOCKET s)
 47{
 48  return static_cast<std::size_t>(s);
 49}
 50#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 51
 52// Note: assumes K and V are POD types.
 53template <typename K, typename V>
 54class hash_map
 55  : private noncopyable
 56{
 57public:
 58  // The type of a value in the map.
 59  typedef std::pair<K, V> value_type;
 60
 61  // The type of a non-const iterator over the hash map.
 62  typedef typename std::list<value_type>::iterator iterator;
 63
 64  // The type of a const iterator over the hash map.
 65  typedef typename std::list<value_type>::const_iterator const_iterator;
 66
 67  // Constructor.
 68  hash_map()
 69    : size_(0),
 70      buckets_(0),
 71      num_buckets_(0)
 72  {
 73  }
 74
 75  // Destructor.
 76  ~hash_map()
 77  {
 78    delete[] buckets_;
 79  }
 80
 81  // Get an iterator for the beginning of the map.
 82  iterator begin()
 83  {
 84    return values_.begin();
 85  }
 86
 87  // Get an iterator for the beginning of the map.
 88  const_iterator begin() const
 89  {
 90    return values_.begin();
 91  }
 92
 93  // Get an iterator for the end of the map.
 94  iterator end()
 95  {
 96    return values_.end();
 97  }
 98
 99  // Get an iterator for the end of the map.
100  const_iterator end() const
101  {
102    return values_.end();
103  }
104
105  // Check whether the map is empty.
106  bool empty() const
107  {
108    return values_.empty();
109  }
110
111  // Find an entry in the map.
112  iterator find(const K& k)
113  {
114    if (num_buckets_)
115    {
116      size_t bucket = calculate_hash_value(k) % num_buckets_;
117      iterator it = buckets_[bucket].first;
118      if (it == values_.end())
119        return values_.end();
120      iterator end_it = buckets_[bucket].last;
121      ++end_it;
122      while (it != end_it)
123      {
124        if (it->first == k)
125          return it;
126        ++it;
127      }
128    }
129    return values_.end();
130  }
131
132  // Find an entry in the map.
133  const_iterator find(const K& k) const
134  {
135    if (num_buckets_)
136    {
137      size_t bucket = calculate_hash_value(k) % num_buckets_;
138      const_iterator it = buckets_[bucket].first;
139      if (it == values_.end())
140        return it;
141      const_iterator end_it = buckets_[bucket].last;
142      ++end_it;
143      while (it != end_it)
144      {
145        if (it->first == k)
146          return it;
147        ++it;
148      }
149    }
150    return values_.end();
151  }
152
153  // Insert a new entry into the map.
154  std::pair<iterator, bool> insert(const value_type& v)
155  {
156    if (size_ + 1 >= num_buckets_)
157      rehash(hash_size(size_ + 1));
158    size_t bucket = calculate_hash_value(v.first) % num_buckets_;
159    iterator it = buckets_[bucket].first;
160    if (it == values_.end())
161    {
162      buckets_[bucket].first = buckets_[bucket].last =
163        values_insert(values_.end(), v);
164      ++size_;
165      return std::pair<iterator, bool>(buckets_[bucket].last, true);
166    }
167    iterator end_it = buckets_[bucket].last;
168    ++end_it;
169    while (it != end_it)
170    {
171      if (it->first == v.first)
172        return std::pair<iterator, bool>(it, false);
173      ++it;
174    }
175    buckets_[bucket].last = values_insert(end_it, v);
176    ++size_;
177    return std::pair<iterator, bool>(buckets_[bucket].last, true);
178  }
179
180  // Erase an entry from the map.
181  void erase(iterator it)
182  {
183    BOOST_ASSERT(it != values_.end());
184
185    size_t bucket = calculate_hash_value(it->first) % num_buckets_;
186    bool is_first = (it == buckets_[bucket].first);
187    bool is_last = (it == buckets_[bucket].last);
188    if (is_first && is_last)
189      buckets_[bucket].first = buckets_[bucket].last = values_.end();
190    else if (is_first)
191      ++buckets_[bucket].first;
192    else if (is_last)
193      --buckets_[bucket].last;
194
195    values_erase(it);
196    --size_;
197  }
198
199  // Erase a key from the map.
200  void erase(const K& k)
201  {
202    iterator it = find(k);
203    if (it != values_.end())
204      erase(it);
205  }
206
207  // Remove all entries from the map.
208  void clear()
209  {
210    // Clear the values.
211    values_.clear();
212    size_ = 0;
213
214    // Initialise all buckets to empty.
215    iterator end_it = values_.end();
216    for (size_t i = 0; i < num_buckets_; ++i)
217      buckets_[i].first = buckets_[i].last = end_it;
218  }
219
220private:
221  // Calculate the hash size for the specified number of elements.
222  static std::size_t hash_size(std::size_t num_elems)
223  {
224    static std::size_t sizes[] =
225    {
226#if defined(BOOST_ASIO_HASH_MAP_BUCKETS)
227      BOOST_ASIO_HASH_MAP_BUCKETS
228#else // BOOST_ASIO_HASH_MAP_BUCKETS
229      3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
230      49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
231      12582917, 25165843
232#endif // BOOST_ASIO_HASH_MAP_BUCKETS
233    };
234    const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1;
235    for (std::size_t i = 0; i < nth_size; ++i)
236      if (num_elems < sizes[i])
237        return sizes[i];
238    return sizes[nth_size];
239  }
240
241  // Re-initialise the hash from the values already contained in the list.
242  void rehash(std::size_t num_buckets)
243  {
244    if (num_buckets == num_buckets_)
245      return;
246    num_buckets_ = num_buckets;
247
248    iterator end_iter = values_.end();
249
250    // Update number of buckets and initialise all buckets to empty.
251    bucket_type* tmp = new bucket_type[num_buckets_];
252    delete[] buckets_;
253    buckets_ = tmp;
254    for (std::size_t i = 0; i < num_buckets_; ++i)
255      buckets_[i].first = buckets_[i].last = end_iter;
256
257    // Put all values back into the hash.
258    iterator iter = values_.begin();
259    while (iter != end_iter)
260    {
261      std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_;
262      if (buckets_[bucket].last == end_iter)
263      {
264        buckets_[bucket].first = buckets_[bucket].last = iter++;
265      }
266      else if (++buckets_[bucket].last == iter)
267      {
268        ++iter;
269      }
270      else
271      {
272        values_.splice(buckets_[bucket].last, values_, iter++);
273        --buckets_[bucket].last;
274      }
275    }
276  }
277
278  // Insert an element into the values list by splicing from the spares list,
279  // if a spare is available, and otherwise by inserting a new element.
280  iterator values_insert(iterator it, const value_type& v)
281  {
282    if (spares_.empty())
283    {
284      return values_.insert(it, v);
285    }
286    else
287    {
288      spares_.front() = v;
289      values_.splice(it, spares_, spares_.begin());
290      return --it;
291    }
292  }
293
294  // Erase an element from the values list by splicing it to the spares list.
295  void values_erase(iterator it)
296  {
297    *it = value_type();
298    spares_.splice(spares_.begin(), values_, it);
299  }
300
301  // The number of elements in the hash.
302  std::size_t size_;
303
304  // The list of all values in the hash map.
305  std::list<value_type> values_;
306
307  // The list of spare nodes waiting to be recycled. Assumes that POD types only
308  // are stored in the hash map.
309  std::list<value_type> spares_;
310
311  // The type for a bucket in the hash table.
312  struct bucket_type
313  {
314    iterator first;
315    iterator last;
316  };
317
318  // The buckets in the hash.
319  bucket_type* buckets_;
320
321  // The number of buckets in the hash.
322  std::size_t num_buckets_;
323};
324
325} // namespace detail
326} // namespace asio
327} // namespace boost
328
329#include <boost/asio/detail/pop_options.hpp>
330
331#endif // BOOST_ASIO_DETAIL_HASH_MAP_HPP