Chris@16
|
1
|
Chris@16
|
2 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
Chris@16
|
3 // Copyright (C) 2005-2011 Daniel James
|
Chris@16
|
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6
|
Chris@16
|
7 #ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
Chris@16
|
8 #define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
Chris@16
|
9
|
Chris@16
|
10 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
Chris@16
|
11 # pragma once
|
Chris@16
|
12 #endif
|
Chris@16
|
13
|
Chris@16
|
14 #include <boost/unordered/detail/table.hpp>
|
Chris@16
|
15 #include <boost/unordered/detail/extract_key.hpp>
|
Chris@16
|
16 #include <boost/throw_exception.hpp>
|
Chris@16
|
17 #include <stdexcept>
|
Chris@16
|
18
|
Chris@16
|
19 namespace boost { namespace unordered { namespace detail {
|
Chris@16
|
20
|
Chris@16
|
21 template <typename A, typename T> struct unique_node;
|
Chris@16
|
22 template <typename T> struct ptr_node;
|
Chris@16
|
23 template <typename Types> struct table_impl;
|
Chris@16
|
24
|
Chris@16
|
25 template <typename A, typename T>
|
Chris@16
|
26 struct unique_node :
|
Chris@16
|
27 boost::unordered::detail::value_base<T>
|
Chris@16
|
28 {
|
Chris@16
|
29 typedef typename ::boost::unordered::detail::rebind_wrap<
|
Chris@16
|
30 A, unique_node<A, T> >::type::pointer node_pointer;
|
Chris@16
|
31 typedef node_pointer link_pointer;
|
Chris@16
|
32
|
Chris@16
|
33 link_pointer next_;
|
Chris@16
|
34 std::size_t hash_;
|
Chris@16
|
35
|
Chris@16
|
36 unique_node() :
|
Chris@16
|
37 next_(),
|
Chris@16
|
38 hash_(0)
|
Chris@16
|
39 {}
|
Chris@16
|
40
|
Chris@16
|
41 void init(node_pointer)
|
Chris@16
|
42 {
|
Chris@16
|
43 }
|
Chris@16
|
44
|
Chris@16
|
45 private:
|
Chris@16
|
46 unique_node& operator=(unique_node const&);
|
Chris@16
|
47 };
|
Chris@16
|
48
|
Chris@16
|
49 template <typename T>
|
Chris@16
|
50 struct ptr_node :
|
Chris@16
|
51 boost::unordered::detail::value_base<T>,
|
Chris@16
|
52 boost::unordered::detail::ptr_bucket
|
Chris@16
|
53 {
|
Chris@16
|
54 typedef boost::unordered::detail::ptr_bucket bucket_base;
|
Chris@16
|
55 typedef ptr_node<T>* node_pointer;
|
Chris@16
|
56 typedef ptr_bucket* link_pointer;
|
Chris@16
|
57
|
Chris@16
|
58 std::size_t hash_;
|
Chris@16
|
59
|
Chris@16
|
60 ptr_node() :
|
Chris@16
|
61 bucket_base(),
|
Chris@16
|
62 hash_(0)
|
Chris@16
|
63 {}
|
Chris@16
|
64
|
Chris@16
|
65 void init(node_pointer)
|
Chris@16
|
66 {
|
Chris@16
|
67 }
|
Chris@16
|
68
|
Chris@16
|
69 private:
|
Chris@16
|
70 ptr_node& operator=(ptr_node const&);
|
Chris@16
|
71 };
|
Chris@16
|
72
|
Chris@16
|
73 // If the allocator uses raw pointers use ptr_node
|
Chris@16
|
74 // Otherwise use node.
|
Chris@16
|
75
|
Chris@16
|
76 template <typename A, typename T, typename NodePtr, typename BucketPtr>
|
Chris@16
|
77 struct pick_node2
|
Chris@16
|
78 {
|
Chris@16
|
79 typedef boost::unordered::detail::unique_node<A, T> node;
|
Chris@16
|
80
|
Chris@16
|
81 typedef typename boost::unordered::detail::allocator_traits<
|
Chris@16
|
82 typename boost::unordered::detail::rebind_wrap<A, node>::type
|
Chris@16
|
83 >::pointer node_pointer;
|
Chris@16
|
84
|
Chris@16
|
85 typedef boost::unordered::detail::bucket<node_pointer> bucket;
|
Chris@16
|
86 typedef node_pointer link_pointer;
|
Chris@16
|
87 };
|
Chris@16
|
88
|
Chris@16
|
89 template <typename A, typename T>
|
Chris@16
|
90 struct pick_node2<A, T,
|
Chris@16
|
91 boost::unordered::detail::ptr_node<T>*,
|
Chris@16
|
92 boost::unordered::detail::ptr_bucket*>
|
Chris@16
|
93 {
|
Chris@16
|
94 typedef boost::unordered::detail::ptr_node<T> node;
|
Chris@16
|
95 typedef boost::unordered::detail::ptr_bucket bucket;
|
Chris@16
|
96 typedef bucket* link_pointer;
|
Chris@16
|
97 };
|
Chris@16
|
98
|
Chris@16
|
99 template <typename A, typename T>
|
Chris@16
|
100 struct pick_node
|
Chris@16
|
101 {
|
Chris@16
|
102 typedef boost::unordered::detail::allocator_traits<
|
Chris@16
|
103 typename boost::unordered::detail::rebind_wrap<A,
|
Chris@16
|
104 boost::unordered::detail::ptr_node<T> >::type
|
Chris@16
|
105 > tentative_node_traits;
|
Chris@16
|
106
|
Chris@16
|
107 typedef boost::unordered::detail::allocator_traits<
|
Chris@16
|
108 typename boost::unordered::detail::rebind_wrap<A,
|
Chris@16
|
109 boost::unordered::detail::ptr_bucket >::type
|
Chris@16
|
110 > tentative_bucket_traits;
|
Chris@16
|
111
|
Chris@16
|
112 typedef pick_node2<A, T,
|
Chris@16
|
113 typename tentative_node_traits::pointer,
|
Chris@16
|
114 typename tentative_bucket_traits::pointer> pick;
|
Chris@16
|
115
|
Chris@16
|
116 typedef typename pick::node node;
|
Chris@16
|
117 typedef typename pick::bucket bucket;
|
Chris@16
|
118 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
119 };
|
Chris@16
|
120
|
Chris@16
|
121 template <typename A, typename T, typename H, typename P>
|
Chris@16
|
122 struct set
|
Chris@16
|
123 {
|
Chris@16
|
124 typedef boost::unordered::detail::set<A, T, H, P> types;
|
Chris@16
|
125
|
Chris@16
|
126 typedef A allocator;
|
Chris@16
|
127 typedef T value_type;
|
Chris@16
|
128 typedef H hasher;
|
Chris@16
|
129 typedef P key_equal;
|
Chris@16
|
130 typedef T key_type;
|
Chris@16
|
131
|
Chris@16
|
132 typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
Chris@16
|
133 typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
|
Chris@16
|
134 typedef typename pick::node node;
|
Chris@16
|
135 typedef typename pick::bucket bucket;
|
Chris@16
|
136 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
137
|
Chris@16
|
138 typedef boost::unordered::detail::table_impl<types> table;
|
Chris@16
|
139 typedef boost::unordered::detail::set_extractor<value_type> extractor;
|
Chris@16
|
140
|
Chris@16
|
141 typedef boost::unordered::detail::pick_policy::type policy;
|
Chris@16
|
142 };
|
Chris@16
|
143
|
Chris@16
|
144 template <typename A, typename K, typename M, typename H, typename P>
|
Chris@16
|
145 struct map
|
Chris@16
|
146 {
|
Chris@16
|
147 typedef boost::unordered::detail::map<A, K, M, H, P> types;
|
Chris@16
|
148
|
Chris@16
|
149 typedef A allocator;
|
Chris@16
|
150 typedef std::pair<K const, M> value_type;
|
Chris@16
|
151 typedef H hasher;
|
Chris@16
|
152 typedef P key_equal;
|
Chris@16
|
153 typedef K key_type;
|
Chris@16
|
154
|
Chris@16
|
155 typedef boost::unordered::detail::allocator_traits<allocator>
|
Chris@16
|
156 traits;
|
Chris@16
|
157 typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
|
Chris@16
|
158 typedef typename pick::node node;
|
Chris@16
|
159 typedef typename pick::bucket bucket;
|
Chris@16
|
160 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
161
|
Chris@16
|
162 typedef boost::unordered::detail::table_impl<types> table;
|
Chris@16
|
163 typedef boost::unordered::detail::map_extractor<key_type, value_type>
|
Chris@16
|
164 extractor;
|
Chris@16
|
165
|
Chris@16
|
166 typedef boost::unordered::detail::pick_policy::type policy;
|
Chris@16
|
167 };
|
Chris@16
|
168
|
Chris@16
|
169 template <typename Types>
|
Chris@16
|
170 struct table_impl : boost::unordered::detail::table<Types>
|
Chris@16
|
171 {
|
Chris@16
|
172 typedef boost::unordered::detail::table<Types> table;
|
Chris@16
|
173 typedef typename table::value_type value_type;
|
Chris@16
|
174 typedef typename table::bucket bucket;
|
Chris@16
|
175 typedef typename table::policy policy;
|
Chris@16
|
176 typedef typename table::node_pointer node_pointer;
|
Chris@16
|
177 typedef typename table::node_allocator node_allocator;
|
Chris@16
|
178 typedef typename table::node_allocator_traits node_allocator_traits;
|
Chris@16
|
179 typedef typename table::bucket_pointer bucket_pointer;
|
Chris@16
|
180 typedef typename table::link_pointer link_pointer;
|
Chris@16
|
181 typedef typename table::hasher hasher;
|
Chris@16
|
182 typedef typename table::key_equal key_equal;
|
Chris@16
|
183 typedef typename table::key_type key_type;
|
Chris@16
|
184 typedef typename table::node_constructor node_constructor;
|
Chris@16
|
185 typedef typename table::extractor extractor;
|
Chris@16
|
186 typedef typename table::iterator iterator;
|
Chris@16
|
187 typedef typename table::c_iterator c_iterator;
|
Chris@16
|
188
|
Chris@16
|
189 typedef std::pair<iterator, bool> emplace_return;
|
Chris@16
|
190
|
Chris@16
|
191 // Constructors
|
Chris@16
|
192
|
Chris@16
|
193 table_impl(std::size_t n,
|
Chris@16
|
194 hasher const& hf,
|
Chris@16
|
195 key_equal const& eq,
|
Chris@16
|
196 node_allocator const& a)
|
Chris@16
|
197 : table(n, hf, eq, a)
|
Chris@16
|
198 {}
|
Chris@16
|
199
|
Chris@16
|
200 table_impl(table_impl const& x)
|
Chris@16
|
201 : table(x, node_allocator_traits::
|
Chris@16
|
202 select_on_container_copy_construction(x.node_alloc()))
|
Chris@16
|
203 {
|
Chris@16
|
204 this->init(x);
|
Chris@16
|
205 }
|
Chris@16
|
206
|
Chris@16
|
207 table_impl(table_impl const& x,
|
Chris@16
|
208 node_allocator const& a)
|
Chris@16
|
209 : table(x, a)
|
Chris@16
|
210 {
|
Chris@16
|
211 this->init(x);
|
Chris@16
|
212 }
|
Chris@16
|
213
|
Chris@16
|
214 table_impl(table_impl& x,
|
Chris@16
|
215 boost::unordered::detail::move_tag m)
|
Chris@16
|
216 : table(x, m)
|
Chris@16
|
217 {}
|
Chris@16
|
218
|
Chris@16
|
219 table_impl(table_impl& x,
|
Chris@16
|
220 node_allocator const& a,
|
Chris@16
|
221 boost::unordered::detail::move_tag m)
|
Chris@16
|
222 : table(x, a, m)
|
Chris@16
|
223 {
|
Chris@16
|
224 this->move_init(x);
|
Chris@16
|
225 }
|
Chris@16
|
226
|
Chris@16
|
227 // Accessors
|
Chris@16
|
228
|
Chris@16
|
229 template <class Key, class Pred>
|
Chris@16
|
230 iterator find_node_impl(
|
Chris@16
|
231 std::size_t key_hash,
|
Chris@16
|
232 Key const& k,
|
Chris@16
|
233 Pred const& eq) const
|
Chris@16
|
234 {
|
Chris@16
|
235 std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
Chris@16
|
236 iterator n = this->begin(bucket_index);
|
Chris@16
|
237
|
Chris@16
|
238 for (;;)
|
Chris@16
|
239 {
|
Chris@16
|
240 if (!n.node_) return n;
|
Chris@16
|
241
|
Chris@16
|
242 std::size_t node_hash = n.node_->hash_;
|
Chris@16
|
243 if (key_hash == node_hash)
|
Chris@16
|
244 {
|
Chris@16
|
245 if (eq(k, this->get_key(*n)))
|
Chris@16
|
246 return n;
|
Chris@16
|
247 }
|
Chris@16
|
248 else
|
Chris@16
|
249 {
|
Chris@16
|
250 if (this->hash_to_bucket(node_hash) != bucket_index)
|
Chris@16
|
251 return iterator();
|
Chris@16
|
252 }
|
Chris@16
|
253
|
Chris@16
|
254 ++n;
|
Chris@16
|
255 }
|
Chris@16
|
256 }
|
Chris@16
|
257
|
Chris@16
|
258 std::size_t count(key_type const& k) const
|
Chris@16
|
259 {
|
Chris@16
|
260 return this->find_node(k).node_ ? 1 : 0;
|
Chris@16
|
261 }
|
Chris@16
|
262
|
Chris@16
|
263 value_type& at(key_type const& k) const
|
Chris@16
|
264 {
|
Chris@16
|
265 if (this->size_) {
|
Chris@16
|
266 iterator it = this->find_node(k);
|
Chris@16
|
267 if (it.node_) return *it;
|
Chris@16
|
268 }
|
Chris@16
|
269
|
Chris@16
|
270 boost::throw_exception(
|
Chris@16
|
271 std::out_of_range("Unable to find key in unordered_map."));
|
Chris@16
|
272 }
|
Chris@16
|
273
|
Chris@16
|
274 std::pair<iterator, iterator>
|
Chris@16
|
275 equal_range(key_type const& k) const
|
Chris@16
|
276 {
|
Chris@16
|
277 iterator n = this->find_node(k);
|
Chris@16
|
278 iterator n2 = n;
|
Chris@16
|
279 if (n2.node_) ++n2;
|
Chris@16
|
280 return std::make_pair(n, n2);
|
Chris@16
|
281 }
|
Chris@16
|
282
|
Chris@16
|
283 // equals
|
Chris@16
|
284
|
Chris@16
|
285 bool equals(table_impl const& other) const
|
Chris@16
|
286 {
|
Chris@16
|
287 if(this->size_ != other.size_) return false;
|
Chris@16
|
288
|
Chris@16
|
289 for(iterator n1 = this->begin(); n1.node_; ++n1)
|
Chris@16
|
290 {
|
Chris@16
|
291 iterator n2 = other.find_matching_node(n1);
|
Chris@16
|
292
|
Chris@16
|
293 if (!n2.node_ || *n1 != *n2)
|
Chris@16
|
294 return false;
|
Chris@16
|
295 }
|
Chris@16
|
296
|
Chris@16
|
297 return true;
|
Chris@16
|
298 }
|
Chris@16
|
299
|
Chris@16
|
300 // Emplace/Insert
|
Chris@16
|
301
|
Chris@16
|
302 inline iterator add_node(
|
Chris@16
|
303 node_constructor& a,
|
Chris@16
|
304 std::size_t key_hash)
|
Chris@16
|
305 {
|
Chris@16
|
306 node_pointer n = a.release();
|
Chris@16
|
307 n->hash_ = key_hash;
|
Chris@16
|
308
|
Chris@16
|
309 bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash));
|
Chris@16
|
310
|
Chris@16
|
311 if (!b->next_)
|
Chris@16
|
312 {
|
Chris@16
|
313 link_pointer start_node = this->get_previous_start();
|
Chris@16
|
314
|
Chris@16
|
315 if (start_node->next_) {
|
Chris@16
|
316 this->get_bucket(this->hash_to_bucket(
|
Chris@16
|
317 static_cast<node_pointer>(start_node->next_)->hash_)
|
Chris@16
|
318 )->next_ = n;
|
Chris@16
|
319 }
|
Chris@16
|
320
|
Chris@16
|
321 b->next_ = start_node;
|
Chris@16
|
322 n->next_ = start_node->next_;
|
Chris@16
|
323 start_node->next_ = n;
|
Chris@16
|
324 }
|
Chris@16
|
325 else
|
Chris@16
|
326 {
|
Chris@16
|
327 n->next_ = b->next_->next_;
|
Chris@16
|
328 b->next_->next_ = n;
|
Chris@16
|
329 }
|
Chris@16
|
330
|
Chris@16
|
331 ++this->size_;
|
Chris@16
|
332 return iterator(n);
|
Chris@16
|
333 }
|
Chris@16
|
334
|
Chris@16
|
335 value_type& operator[](key_type const& k)
|
Chris@16
|
336 {
|
Chris@16
|
337 std::size_t key_hash = this->hash(k);
|
Chris@16
|
338 iterator pos = this->find_node(key_hash, k);
|
Chris@16
|
339
|
Chris@16
|
340 if (pos.node_) return *pos;
|
Chris@16
|
341
|
Chris@16
|
342 // Create the node before rehashing in case it throws an
|
Chris@16
|
343 // exception (need strong safety in such a case).
|
Chris@16
|
344 node_constructor a(this->node_alloc());
|
Chris@16
|
345 a.construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS3(
|
Chris@16
|
346 boost::unordered::piecewise_construct,
|
Chris@16
|
347 boost::make_tuple(k),
|
Chris@16
|
348 boost::make_tuple()));
|
Chris@16
|
349
|
Chris@16
|
350 this->reserve_for_insert(this->size_ + 1);
|
Chris@16
|
351 return *add_node(a, key_hash);
|
Chris@16
|
352 }
|
Chris@16
|
353
|
Chris@16
|
354 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@16
|
355 # if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
356 emplace_return emplace(boost::unordered::detail::emplace_args1<
|
Chris@16
|
357 boost::unordered::detail::please_ignore_this_overload> const&)
|
Chris@16
|
358 {
|
Chris@16
|
359 BOOST_ASSERT(false);
|
Chris@16
|
360 return emplace_return(this->begin(), false);
|
Chris@16
|
361 }
|
Chris@16
|
362 # else
|
Chris@16
|
363 emplace_return emplace(
|
Chris@16
|
364 boost::unordered::detail::please_ignore_this_overload const&)
|
Chris@16
|
365 {
|
Chris@16
|
366 BOOST_ASSERT(false);
|
Chris@16
|
367 return emplace_return(this->begin(), false);
|
Chris@16
|
368 }
|
Chris@16
|
369 # endif
|
Chris@16
|
370 #endif
|
Chris@16
|
371
|
Chris@16
|
372 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
Chris@16
|
373 emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS)
|
Chris@16
|
374 {
|
Chris@16
|
375 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
376 return emplace_impl(
|
Chris@16
|
377 extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
|
Chris@16
|
378 BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
379 #else
|
Chris@16
|
380 return emplace_impl(
|
Chris@16
|
381 extractor::extract(args.a0, args.a1),
|
Chris@16
|
382 BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
383 #endif
|
Chris@16
|
384 }
|
Chris@16
|
385
|
Chris@16
|
386 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
387 template <typename A0>
|
Chris@16
|
388 emplace_return emplace(
|
Chris@16
|
389 boost::unordered::detail::emplace_args1<A0> const& args)
|
Chris@16
|
390 {
|
Chris@16
|
391 return emplace_impl(extractor::extract(args.a0), args);
|
Chris@16
|
392 }
|
Chris@16
|
393 #endif
|
Chris@16
|
394
|
Chris@16
|
395 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
Chris@16
|
396 emplace_return emplace_impl(key_type const& k,
|
Chris@16
|
397 BOOST_UNORDERED_EMPLACE_ARGS)
|
Chris@16
|
398 {
|
Chris@16
|
399 std::size_t key_hash = this->hash(k);
|
Chris@16
|
400 iterator pos = this->find_node(key_hash, k);
|
Chris@16
|
401
|
Chris@16
|
402 if (pos.node_) return emplace_return(pos, false);
|
Chris@16
|
403
|
Chris@16
|
404 // Create the node before rehashing in case it throws an
|
Chris@16
|
405 // exception (need strong safety in such a case).
|
Chris@16
|
406 node_constructor a(this->node_alloc());
|
Chris@16
|
407 a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
408
|
Chris@16
|
409 // reserve has basic exception safety if the hash function
|
Chris@16
|
410 // throws, strong otherwise.
|
Chris@16
|
411 this->reserve_for_insert(this->size_ + 1);
|
Chris@16
|
412 return emplace_return(this->add_node(a, key_hash), true);
|
Chris@16
|
413 }
|
Chris@16
|
414
|
Chris@16
|
415 emplace_return emplace_impl_with_node(node_constructor& a)
|
Chris@16
|
416 {
|
Chris@16
|
417 key_type const& k = this->get_key(a.value());
|
Chris@16
|
418 std::size_t key_hash = this->hash(k);
|
Chris@16
|
419 iterator pos = this->find_node(key_hash, k);
|
Chris@16
|
420
|
Chris@16
|
421 if (pos.node_) return emplace_return(pos, false);
|
Chris@16
|
422
|
Chris@16
|
423 // reserve has basic exception safety if the hash function
|
Chris@16
|
424 // throws, strong otherwise.
|
Chris@16
|
425 this->reserve_for_insert(this->size_ + 1);
|
Chris@16
|
426 return emplace_return(this->add_node(a, key_hash), true);
|
Chris@16
|
427 }
|
Chris@16
|
428
|
Chris@16
|
429 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
Chris@16
|
430 emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
|
Chris@16
|
431 {
|
Chris@16
|
432 // Don't have a key, so construct the node first in order
|
Chris@16
|
433 // to be able to lookup the position.
|
Chris@16
|
434 node_constructor a(this->node_alloc());
|
Chris@16
|
435 a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
436 return emplace_impl_with_node(a);
|
Chris@16
|
437 }
|
Chris@16
|
438
|
Chris@16
|
439 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
440 // Insert range methods
|
Chris@16
|
441 //
|
Chris@16
|
442 // if hash function throws, or inserting > 1 element, basic exception
|
Chris@16
|
443 // safety strong otherwise
|
Chris@16
|
444
|
Chris@16
|
445 template <class InputIt>
|
Chris@16
|
446 void insert_range(InputIt i, InputIt j)
|
Chris@16
|
447 {
|
Chris@16
|
448 if(i != j)
|
Chris@16
|
449 return insert_range_impl(extractor::extract(*i), i, j);
|
Chris@16
|
450 }
|
Chris@16
|
451
|
Chris@16
|
452 template <class InputIt>
|
Chris@16
|
453 void insert_range_impl(key_type const& k, InputIt i, InputIt j)
|
Chris@16
|
454 {
|
Chris@16
|
455 node_constructor a(this->node_alloc());
|
Chris@16
|
456
|
Chris@16
|
457 insert_range_impl2(a, k, i, j);
|
Chris@16
|
458
|
Chris@16
|
459 while(++i != j) {
|
Chris@16
|
460 // Note: can't use get_key as '*i' might not be value_type - it
|
Chris@16
|
461 // could be a pair with first_types as key_type without const or
|
Chris@16
|
462 // a different second_type.
|
Chris@16
|
463 //
|
Chris@16
|
464 // TODO: Might be worth storing the value_type instead of the
|
Chris@16
|
465 // key here. Could be more efficient if '*i' is expensive. Could
|
Chris@16
|
466 // be less efficient if copying the full value_type is
|
Chris@16
|
467 // expensive.
|
Chris@16
|
468 insert_range_impl2(a, extractor::extract(*i), i, j);
|
Chris@16
|
469 }
|
Chris@16
|
470 }
|
Chris@16
|
471
|
Chris@16
|
472 template <class InputIt>
|
Chris@16
|
473 void insert_range_impl2(node_constructor& a, key_type const& k,
|
Chris@16
|
474 InputIt i, InputIt j)
|
Chris@16
|
475 {
|
Chris@16
|
476 // No side effects in this initial code
|
Chris@16
|
477 std::size_t key_hash = this->hash(k);
|
Chris@16
|
478 iterator pos = this->find_node(key_hash, k);
|
Chris@16
|
479
|
Chris@16
|
480 if (!pos.node_) {
|
Chris@16
|
481 a.construct_with_value2(*i);
|
Chris@16
|
482 if(this->size_ + 1 > this->max_load_)
|
Chris@16
|
483 this->reserve_for_insert(this->size_ +
|
Chris@16
|
484 boost::unordered::detail::insert_size(i, j));
|
Chris@16
|
485
|
Chris@16
|
486 // Nothing after this point can throw.
|
Chris@16
|
487 this->add_node(a, key_hash);
|
Chris@16
|
488 }
|
Chris@16
|
489 }
|
Chris@16
|
490
|
Chris@16
|
491 template <class InputIt>
|
Chris@16
|
492 void insert_range_impl(no_key, InputIt i, InputIt j)
|
Chris@16
|
493 {
|
Chris@16
|
494 node_constructor a(this->node_alloc());
|
Chris@16
|
495
|
Chris@16
|
496 do {
|
Chris@16
|
497 a.construct_with_value2(*i);
|
Chris@16
|
498 emplace_impl_with_node(a);
|
Chris@16
|
499 } while(++i != j);
|
Chris@16
|
500 }
|
Chris@16
|
501
|
Chris@16
|
502 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
503 // Erase
|
Chris@16
|
504 //
|
Chris@16
|
505 // no throw
|
Chris@16
|
506
|
Chris@16
|
507 std::size_t erase_key(key_type const& k)
|
Chris@16
|
508 {
|
Chris@16
|
509 if(!this->size_) return 0;
|
Chris@16
|
510
|
Chris@16
|
511 std::size_t key_hash = this->hash(k);
|
Chris@16
|
512 std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
Chris@16
|
513 link_pointer prev = this->get_previous_start(bucket_index);
|
Chris@16
|
514 if (!prev) return 0;
|
Chris@16
|
515
|
Chris@16
|
516 for (;;)
|
Chris@16
|
517 {
|
Chris@16
|
518 if (!prev->next_) return 0;
|
Chris@16
|
519 std::size_t node_hash =
|
Chris@16
|
520 static_cast<node_pointer>(prev->next_)->hash_;
|
Chris@16
|
521 if (this->hash_to_bucket(node_hash) != bucket_index)
|
Chris@16
|
522 return 0;
|
Chris@16
|
523 if (node_hash == key_hash &&
|
Chris@16
|
524 this->key_eq()(k, this->get_key(
|
Chris@16
|
525 static_cast<node_pointer>(prev->next_)->value())))
|
Chris@16
|
526 break;
|
Chris@16
|
527 prev = prev->next_;
|
Chris@16
|
528 }
|
Chris@16
|
529
|
Chris@16
|
530 link_pointer end = static_cast<node_pointer>(prev->next_)->next_;
|
Chris@16
|
531
|
Chris@16
|
532 std::size_t count = this->delete_nodes(prev, end);
|
Chris@16
|
533 this->fix_bucket(bucket_index, prev);
|
Chris@16
|
534 return count;
|
Chris@16
|
535 }
|
Chris@16
|
536
|
Chris@16
|
537 iterator erase(c_iterator r)
|
Chris@16
|
538 {
|
Chris@16
|
539 BOOST_ASSERT(r.node_);
|
Chris@16
|
540 iterator next(r.node_);
|
Chris@16
|
541 ++next;
|
Chris@16
|
542 erase_nodes(r.node_, next.node_);
|
Chris@16
|
543 return next;
|
Chris@16
|
544 }
|
Chris@16
|
545
|
Chris@16
|
546 iterator erase_range(c_iterator r1, c_iterator r2)
|
Chris@16
|
547 {
|
Chris@16
|
548 if (r1 == r2) return iterator(r2.node_);
|
Chris@16
|
549 erase_nodes(r1.node_, r2.node_);
|
Chris@16
|
550 return iterator(r2.node_);
|
Chris@16
|
551 }
|
Chris@16
|
552
|
Chris@16
|
553 void erase_nodes(node_pointer begin, node_pointer end)
|
Chris@16
|
554 {
|
Chris@16
|
555 std::size_t bucket_index = this->hash_to_bucket(begin->hash_);
|
Chris@16
|
556
|
Chris@16
|
557 // Find the node before begin.
|
Chris@16
|
558 link_pointer prev = this->get_previous_start(bucket_index);
|
Chris@16
|
559 while(prev->next_ != begin) prev = prev->next_;
|
Chris@16
|
560
|
Chris@16
|
561 // Delete the nodes.
|
Chris@16
|
562 do {
|
Chris@16
|
563 this->delete_node(prev);
|
Chris@16
|
564 bucket_index = this->fix_bucket(bucket_index, prev);
|
Chris@16
|
565 } while (prev->next_ != end);
|
Chris@16
|
566 }
|
Chris@16
|
567
|
Chris@16
|
568 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
569 // fill_buckets
|
Chris@16
|
570
|
Chris@16
|
571 template <class NodeCreator>
|
Chris@16
|
572 static void fill_buckets(iterator n, table& dst,
|
Chris@16
|
573 NodeCreator& creator)
|
Chris@16
|
574 {
|
Chris@16
|
575 link_pointer prev = dst.get_previous_start();
|
Chris@16
|
576
|
Chris@16
|
577 while (n.node_) {
|
Chris@16
|
578 node_pointer node = creator.create(*n);
|
Chris@16
|
579 node->hash_ = n.node_->hash_;
|
Chris@16
|
580 prev->next_ = node;
|
Chris@16
|
581 ++dst.size_;
|
Chris@16
|
582 ++n;
|
Chris@16
|
583
|
Chris@16
|
584 prev = place_in_bucket(dst, prev);
|
Chris@16
|
585 }
|
Chris@16
|
586 }
|
Chris@16
|
587
|
Chris@16
|
588 // strong otherwise exception safety
|
Chris@16
|
589 void rehash_impl(std::size_t num_buckets)
|
Chris@16
|
590 {
|
Chris@16
|
591 BOOST_ASSERT(this->buckets_);
|
Chris@16
|
592
|
Chris@16
|
593 this->create_buckets(num_buckets);
|
Chris@16
|
594 link_pointer prev = this->get_previous_start();
|
Chris@16
|
595 while (prev->next_)
|
Chris@16
|
596 prev = place_in_bucket(*this, prev);
|
Chris@16
|
597 }
|
Chris@16
|
598
|
Chris@16
|
599 // Iterate through the nodes placing them in the correct buckets.
|
Chris@16
|
600 // pre: prev->next_ is not null.
|
Chris@16
|
601 static link_pointer place_in_bucket(table& dst, link_pointer prev)
|
Chris@16
|
602 {
|
Chris@16
|
603 node_pointer n = static_cast<node_pointer>(prev->next_);
|
Chris@16
|
604 bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_));
|
Chris@16
|
605
|
Chris@16
|
606 if (!b->next_) {
|
Chris@16
|
607 b->next_ = prev;
|
Chris@16
|
608 return n;
|
Chris@16
|
609 }
|
Chris@16
|
610 else {
|
Chris@16
|
611 prev->next_ = n->next_;
|
Chris@16
|
612 n->next_ = b->next_->next_;
|
Chris@16
|
613 b->next_->next_ = n;
|
Chris@16
|
614 return prev;
|
Chris@16
|
615 }
|
Chris@16
|
616 }
|
Chris@16
|
617 };
|
Chris@16
|
618 }}}
|
Chris@16
|
619
|
Chris@16
|
620 #endif
|