5 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_DETAIL_HASH_MAP_HPP
12 #define BOOST_ASIO_DETAIL_HASH_MAP_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/push_options.hpp>
20 #include <boost/asio/detail/push_options.hpp>
25 #include <boost/functional/hash.hpp>
26 #include <boost/asio/detail/pop_options.hpp>
28 #include <boost/asio/detail/noncopyable.hpp>
29 #include <boost/asio/detail/socket_types.hpp>
36 inline std::size_t calculate_hash_value(const T
& t
)
38 return boost::hash_value(t
);
42 inline std::size_t calculate_hash_value(SOCKET s
)
44 return static_cast<std::size_t>(s
);
46 #endif // defined(_WIN64)
48 // Note: assumes K and V are POD types.
49 template <typename K
, typename V
>
54 // The type of a value in the map.
55 typedef std::pair
<K
, V
> value_type
;
57 // The type of a non-const iterator over the hash map.
58 typedef typename
std::list
<value_type
>::iterator iterator
;
60 // The type of a const iterator over the hash map.
61 typedef typename
std::list
<value_type
>::const_iterator const_iterator
;
70 // Get an iterator for the beginning of the map.
73 return values_
.begin();
76 // Get an iterator for the beginning of the map.
77 const_iterator
begin() const
79 return values_
.begin();
82 // Get an iterator for the end of the map.
88 // Get an iterator for the end of the map.
89 const_iterator
end() const
94 // Check whether the map is empty.
97 return values_
.empty();
100 // Find an entry in the map.
101 iterator
find(const K
& k
)
103 size_t bucket
= calculate_hash_value(k
) % buckets_
.size();
104 iterator it
= buckets_
[bucket
].first
;
105 if (it
== values_
.end())
106 return values_
.end();
107 iterator end
= buckets_
[bucket
].last
;
115 return values_
.end();
118 // Find an entry in the map.
119 const_iterator
find(const K
& k
) const
121 size_t bucket
= calculate_hash_value(k
) % buckets_
.size();
122 const_iterator it
= buckets_
[bucket
].first
;
123 if (it
== values_
.end())
125 const_iterator end
= buckets_
[bucket
].last
;
133 return values_
.end();
136 // Insert a new entry into the map.
137 std::pair
<iterator
, bool> insert(const value_type
& v
)
139 if (size_
+ 1 >= buckets_
.size())
140 rehash(hash_size(size_
+ 1));
141 size_t bucket
= calculate_hash_value(v
.first
) % buckets_
.size();
142 iterator it
= buckets_
[bucket
].first
;
143 if (it
== values_
.end())
145 buckets_
[bucket
].first
= buckets_
[bucket
].last
=
146 values_insert(values_
.end(), v
);
148 return std::pair
<iterator
, bool>(buckets_
[bucket
].last
, true);
150 iterator end
= buckets_
[bucket
].last
;
154 if (it
->first
== v
.first
)
155 return std::pair
<iterator
, bool>(it
, false);
158 buckets_
[bucket
].last
= values_insert(end
, v
);
160 return std::pair
<iterator
, bool>(buckets_
[bucket
].last
, true);
163 // Erase an entry from the map.
164 void erase(iterator it
)
166 assert(it
!= values_
.end());
168 size_t bucket
= calculate_hash_value(it
->first
) % buckets_
.size();
169 bool is_first
= (it
== buckets_
[bucket
].first
);
170 bool is_last
= (it
== buckets_
[bucket
].last
);
171 if (is_first
&& is_last
)
172 buckets_
[bucket
].first
= buckets_
[bucket
].last
= values_
.end();
174 ++buckets_
[bucket
].first
;
176 --buckets_
[bucket
].last
;
182 // Remove all entries from the map.
189 // Initialise all buckets to empty.
190 for (size_t i
= 0; i
< buckets_
.size(); ++i
)
191 buckets_
[i
].first
= buckets_
[i
].last
= values_
.end();
195 // Calculate the hash size for the specified number of elements.
196 static std::size_t hash_size(std::size_t num_elems
)
198 static std::size_t sizes
[] =
200 #if defined(BOOST_ASIO_HASH_MAP_BUCKETS)
201 BOOST_ASIO_HASH_MAP_BUCKETS
202 #else // BOOST_ASIO_HASH_MAP_BUCKETS
203 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
204 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
206 #endif // BOOST_ASIO_HASH_MAP_BUCKETS
208 const std::size_t nth_size
= sizeof(sizes
) / sizeof(std::size_t) - 1;
209 for (std::size_t i
= 0; i
< nth_size
; ++i
)
210 if (num_elems
< sizes
[i
])
212 return sizes
[nth_size
];
215 // Re-initialise the hash from the values already contained in the list.
216 void rehash(std::size_t num_buckets
)
218 iterator end
= values_
.end();
220 // Update number of buckets and initialise all buckets to empty.
221 buckets_
.resize(num_buckets
);
222 for (std::size_t i
= 0; i
< buckets_
.size(); ++i
)
223 buckets_
[i
].first
= buckets_
[i
].last
= end
;
225 // Put all values back into the hash.
226 iterator iter
= values_
.begin();
229 std::size_t bucket
= calculate_hash_value(iter
->first
) % buckets_
.size();
230 if (buckets_
[bucket
].last
== end
)
232 buckets_
[bucket
].first
= buckets_
[bucket
].last
= iter
++;
236 values_
.splice(++buckets_
[bucket
].last
, values_
, iter
++);
237 --buckets_
[bucket
].last
;
242 // Insert an element into the values list by splicing from the spares list,
243 // if a spare is available, and otherwise by inserting a new element.
244 iterator
values_insert(iterator it
, const value_type
& v
)
248 return values_
.insert(it
, v
);
253 values_
.splice(it
, spares_
, spares_
.begin());
258 // Erase an element from the values list by splicing it to the spares list.
259 void values_erase(iterator it
)
262 spares_
.splice(spares_
.begin(), values_
, it
);
265 // The number of elements in the hash.
268 // The list of all values in the hash map.
269 std::list
<value_type
> values_
;
271 // The list of spare nodes waiting to be recycled. Assumes that POD types only
272 // are stored in the hash map.
273 std::list
<value_type
> spares_
;
275 // The type for a bucket in the hash table.
282 // The buckets in the hash.
283 std::vector
<bucket_type
> buckets_
;
286 } // namespace detail
290 #include <boost/asio/detail/pop_options.hpp>
292 #endif // BOOST_ASIO_DETAIL_HASH_MAP_HPP