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