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