blob: df44e709eb8dd42bfd42d243cc7ba45a034c98cb [file] [log] [blame]
Jeff Thompsona28eed82013-08-22 16:21:10 -07001
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_MANAGER_HPP_INCLUDED
8#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
9
10#if defined(_MSC_VER) && (_MSC_VER >= 1020)
11# pragma once
12#endif
13
14#include <ndnboost/unordered/detail/util.hpp>
15#include <ndnboost/unordered/detail/allocate.hpp>
16#include <ndnboost/type_traits/aligned_storage.hpp>
17#include <ndnboost/type_traits/alignment_of.hpp>
18#include <ndnboost/type_traits/is_nothrow_move_constructible.hpp>
19#include <ndnboost/type_traits/is_nothrow_move_assignable.hpp>
20#include <ndnboost/swap.hpp>
21#include <ndnboost/assert.hpp>
22#include <ndnboost/limits.hpp>
23#include <ndnboost/iterator.hpp>
24
25namespace ndnboost { namespace unordered { namespace detail {
26
27 template <typename Types> struct table;
28 template <typename NodePointer> struct bucket;
29 struct ptr_bucket;
30 template <typename Types> struct table_impl;
31 template <typename Types> struct grouped_table_impl;
32
33}}}
34
35namespace ndnboost { namespace unordered { namespace iterator_detail {
36
37 ////////////////////////////////////////////////////////////////////////////
38 // Iterators
39 //
40 // all no throw
41
42 template <typename Node> struct iterator;
43 template <typename Node, typename ConstNodePointer> struct c_iterator;
44 template <typename Node, typename Policy> struct l_iterator;
45 template <typename Node, typename ConstNodePointer, typename Policy>
46 struct cl_iterator;
47
48 // Local Iterators
49 //
50 // all no throw
51
52 template <typename Node, typename Policy>
53 struct l_iterator
54 : public ndnboost::iterator<
55 std::forward_iterator_tag,
56 typename Node::value_type,
57 std::ptrdiff_t,
58 typename Node::node_pointer,
59 typename Node::value_type&>
60 {
61#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
62 template <typename Node2, typename ConstNodePointer, typename Policy2>
63 friend struct ndnboost::unordered::iterator_detail::cl_iterator;
64 private:
65#endif
66 typedef typename Node::node_pointer node_pointer;
67 typedef ndnboost::unordered::iterator_detail::iterator<Node> iterator;
68 node_pointer ptr_;
69 std::size_t bucket_;
70 std::size_t bucket_count_;
71
72 public:
73
74 typedef typename Node::value_type value_type;
75
76 l_iterator() : ptr_() {}
77
78 l_iterator(iterator x, std::size_t b, std::size_t c)
79 : ptr_(x.node_), bucket_(b), bucket_count_(c) {}
80
81 value_type& operator*() const {
82 return ptr_->value();
83 }
84
85 value_type* operator->() const {
86 return ptr_->value_ptr();
87 }
88
89 l_iterator& operator++() {
90 ptr_ = static_cast<node_pointer>(ptr_->next_);
91 if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_)
92 != bucket_)
93 ptr_ = node_pointer();
94 return *this;
95 }
96
97 l_iterator operator++(int) {
98 l_iterator tmp(*this);
99 ++(*this);
100 return tmp;
101 }
102
103 bool operator==(l_iterator x) const {
104 return ptr_ == x.ptr_;
105 }
106
107 bool operator!=(l_iterator x) const {
108 return ptr_ != x.ptr_;
109 }
110 };
111
112 template <typename Node, typename ConstNodePointer, typename Policy>
113 struct cl_iterator
114 : public ndnboost::iterator<
115 std::forward_iterator_tag,
116 typename Node::value_type,
117 std::ptrdiff_t,
118 ConstNodePointer,
119 typename Node::value_type const&>
120 {
121 friend struct ndnboost::unordered::iterator_detail::l_iterator
122 <Node, Policy>;
123 private:
124
125 typedef typename Node::node_pointer node_pointer;
126 typedef ndnboost::unordered::iterator_detail::iterator<Node> iterator;
127 node_pointer ptr_;
128 std::size_t bucket_;
129 std::size_t bucket_count_;
130
131 public:
132
133 typedef typename Node::value_type value_type;
134
135 cl_iterator() : ptr_() {}
136
137 cl_iterator(iterator x, std::size_t b, std::size_t c) :
138 ptr_(x.node_), bucket_(b), bucket_count_(c) {}
139
140 cl_iterator(ndnboost::unordered::iterator_detail::l_iterator<
141 Node, Policy> const& x) :
142 ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
143 {}
144
145 value_type const& operator*() const {
146 return ptr_->value();
147 }
148
149 value_type const* operator->() const {
150 return ptr_->value_ptr();
151 }
152
153 cl_iterator& operator++() {
154 ptr_ = static_cast<node_pointer>(ptr_->next_);
155 if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_)
156 != bucket_)
157 ptr_ = node_pointer();
158 return *this;
159 }
160
161 cl_iterator operator++(int) {
162 cl_iterator tmp(*this);
163 ++(*this);
164 return tmp;
165 }
166
167 friend bool operator==(cl_iterator const& x, cl_iterator const& y) {
168 return x.ptr_ == y.ptr_;
169 }
170
171 friend bool operator!=(cl_iterator const& x, cl_iterator const& y) {
172 return x.ptr_ != y.ptr_;
173 }
174 };
175
176 template <typename Node>
177 struct iterator
178 : public ndnboost::iterator<
179 std::forward_iterator_tag,
180 typename Node::value_type,
181 std::ptrdiff_t,
182 typename Node::node_pointer,
183 typename Node::value_type&>
184 {
185#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
186 template <typename, typename>
187 friend struct ndnboost::unordered::iterator_detail::c_iterator;
188 template <typename, typename>
189 friend struct ndnboost::unordered::iterator_detail::l_iterator;
190 template <typename, typename, typename>
191 friend struct ndnboost::unordered::iterator_detail::cl_iterator;
192 template <typename>
193 friend struct ndnboost::unordered::detail::table;
194 template <typename>
195 friend struct ndnboost::unordered::detail::table_impl;
196 template <typename>
197 friend struct ndnboost::unordered::detail::grouped_table_impl;
198 private:
199#endif
200 typedef typename Node::node_pointer node_pointer;
201 node_pointer node_;
202
203 public:
204
205 typedef typename Node::value_type value_type;
206
207 iterator() : node_() {}
208
209 explicit iterator(typename Node::link_pointer x) :
210 node_(static_cast<node_pointer>(x)) {}
211
212 value_type& operator*() const {
213 return node_->value();
214 }
215
216 value_type* operator->() const {
217 return &node_->value();
218 }
219
220 iterator& operator++() {
221 node_ = static_cast<node_pointer>(node_->next_);
222 return *this;
223 }
224
225 iterator operator++(int) {
226 iterator tmp(node_);
227 node_ = static_cast<node_pointer>(node_->next_);
228 return tmp;
229 }
230
231 bool operator==(iterator const& x) const {
232 return node_ == x.node_;
233 }
234
235 bool operator!=(iterator const& x) const {
236 return node_ != x.node_;
237 }
238 };
239
240 template <typename Node, typename ConstNodePointer>
241 struct c_iterator
242 : public ndnboost::iterator<
243 std::forward_iterator_tag,
244 typename Node::value_type,
245 std::ptrdiff_t,
246 ConstNodePointer,
247 typename Node::value_type const&>
248 {
249 friend struct ndnboost::unordered::iterator_detail::iterator<Node>;
250
251#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
252 template <typename>
253 friend struct ndnboost::unordered::detail::table;
254 template <typename>
255 friend struct ndnboost::unordered::detail::table_impl;
256 template <typename>
257 friend struct ndnboost::unordered::detail::grouped_table_impl;
258
259 private:
260#endif
261 typedef typename Node::node_pointer node_pointer;
262 typedef ndnboost::unordered::iterator_detail::iterator<Node> iterator;
263 node_pointer node_;
264
265 public:
266
267 typedef typename Node::value_type value_type;
268
269 c_iterator() : node_() {}
270
271 explicit c_iterator(typename Node::link_pointer x) :
272 node_(static_cast<node_pointer>(x)) {}
273
274 c_iterator(iterator const& x) : node_(x.node_) {}
275
276 value_type const& operator*() const {
277 return node_->value();
278 }
279
280 value_type const* operator->() const {
281 return &node_->value();
282 }
283
284 c_iterator& operator++() {
285 node_ = static_cast<node_pointer>(node_->next_);
286 return *this;
287 }
288
289 c_iterator operator++(int) {
290 c_iterator tmp(node_);
291 node_ = static_cast<node_pointer>(node_->next_);
292 return tmp;
293 }
294
295 friend bool operator==(c_iterator const& x, c_iterator const& y) {
296 return x.node_ == y.node_;
297 }
298
299 friend bool operator!=(c_iterator const& x, c_iterator const& y) {
300 return x.node_ != y.node_;
301 }
302 };
303}}}
304
305namespace ndnboost { namespace unordered { namespace detail {
306
307 ///////////////////////////////////////////////////////////////////
308 //
309 // Node construction
310
311 template <typename NodeAlloc>
312 struct node_constructor
313 {
314 private:
315
316 typedef NodeAlloc node_allocator;
317 typedef ndnboost::unordered::detail::allocator_traits<NodeAlloc>
318 node_allocator_traits;
319 typedef typename node_allocator_traits::value_type node;
320 typedef typename node_allocator_traits::pointer node_pointer;
321 typedef typename node::value_type value_type;
322
323 protected:
324
325 node_allocator& alloc_;
326 node_pointer node_;
327 bool node_constructed_;
328 bool value_constructed_;
329
330 public:
331
332 node_constructor(node_allocator& n) :
333 alloc_(n),
334 node_(),
335 node_constructed_(false),
336 value_constructed_(false)
337 {
338 }
339
340 ~node_constructor();
341
342 void construct();
343
344 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
345 void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS)
346 {
347 construct();
348 ndnboost::unordered::detail::construct_value_impl(
349 alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
350 value_constructed_ = true;
351 }
352
353 template <typename A0>
354 void construct_with_value2(BOOST_FWD_REF(A0) a0)
355 {
356 construct();
357 ndnboost::unordered::detail::construct_value_impl(
358 alloc_, node_->value_ptr(),
359 BOOST_UNORDERED_EMPLACE_ARGS1(ndnboost::forward<A0>(a0)));
360 value_constructed_ = true;
361 }
362
363 value_type const& value() const {
364 BOOST_ASSERT(node_ && node_constructed_ && value_constructed_);
365 return node_->value();
366 }
367
368 // no throw
369 node_pointer release()
370 {
371 BOOST_ASSERT(node_ && node_constructed_);
372 node_pointer p = node_;
373 node_ = node_pointer();
374 return p;
375 }
376
377 private:
378 node_constructor(node_constructor const&);
379 node_constructor& operator=(node_constructor const&);
380 };
381
382 template <typename Alloc>
383 node_constructor<Alloc>::~node_constructor()
384 {
385 if (node_) {
386 if (value_constructed_) {
387 ndnboost::unordered::detail::destroy_value_impl(alloc_,
388 node_->value_ptr());
389 }
390
391 if (node_constructed_) {
392 node_allocator_traits::destroy(alloc_,
393 ndnboost::addressof(*node_));
394 }
395
396 node_allocator_traits::deallocate(alloc_, node_, 1);
397 }
398 }
399
400 template <typename Alloc>
401 void node_constructor<Alloc>::construct()
402 {
403 if(!node_) {
404 node_constructed_ = false;
405 value_constructed_ = false;
406
407 node_ = node_allocator_traits::allocate(alloc_, 1);
408
409 node_allocator_traits::construct(alloc_,
410 ndnboost::addressof(*node_), node());
411 node_->init(node_);
412 node_constructed_ = true;
413 }
414 else {
415 BOOST_ASSERT(node_constructed_);
416
417 if (value_constructed_)
418 {
419 ndnboost::unordered::detail::destroy_value_impl(alloc_,
420 node_->value_ptr());
421 value_constructed_ = false;
422 }
423 }
424 }
425
426 ///////////////////////////////////////////////////////////////////
427 //
428 // Node Holder
429 //
430 // Temporary store for nodes. Deletes any that aren't used.
431
432 template <typename NodeAlloc>
433 struct node_holder : private node_constructor<NodeAlloc>
434 {
435 private:
436 typedef node_constructor<NodeAlloc> base;
437
438 typedef NodeAlloc node_allocator;
439 typedef ndnboost::unordered::detail::allocator_traits<NodeAlloc>
440 node_allocator_traits;
441 typedef typename node_allocator_traits::value_type node;
442 typedef typename node_allocator_traits::pointer node_pointer;
443 typedef typename node::value_type value_type;
444 typedef typename node::link_pointer link_pointer;
445 typedef ndnboost::unordered::iterator_detail::iterator<node> iterator;
446
447 node_pointer nodes_;
448
449 public:
450
451 template <typename Table>
452 explicit node_holder(Table& b) :
453 base(b.node_alloc()),
454 nodes_()
455 {
456 if (b.size_) {
457 typename Table::link_pointer prev = b.get_previous_start();
458 nodes_ = static_cast<node_pointer>(prev->next_);
459 prev->next_ = link_pointer();
460 b.size_ = 0;
461 }
462 }
463
464 ~node_holder();
465
466 void node_for_assignment()
467 {
468 if (!this->node_ && nodes_) {
469 this->node_ = nodes_;
470 nodes_ = static_cast<node_pointer>(nodes_->next_);
471 this->node_->init(this->node_);
472 this->node_->next_ = link_pointer();
473
474 this->node_constructed_ = true;
475 this->value_constructed_ = true;
476 }
477 }
478
479 template <typename T>
480 inline void assign_impl(T const& v) {
481 if (this->node_ && this->value_constructed_) {
482 this->node_->value() = v;
483 }
484 else {
485 this->construct_with_value2(v);
486 }
487 }
488
489 template <typename T1, typename T2>
490 inline void assign_impl(std::pair<T1 const, T2> const& v) {
491 this->construct_with_value2(v);
492 }
493
494 template <typename T>
495 inline void move_assign_impl(T& v) {
496 if (this->node_ && this->value_constructed_) {
497 this->node_->value() = ndnboost::move(v);
498 }
499 else {
500 this->construct_with_value2(ndnboost::move(v));
501 }
502 }
503
504 template <typename T1, typename T2>
505 inline void move_assign_impl(std::pair<T1 const, T2>& v) {
506 this->construct_with_value2(ndnboost::move(v));
507 }
508
509 node_pointer copy_of(value_type const& v)
510 {
511 node_for_assignment();
512 assign_impl(v);
513 return base::release();
514 }
515
516 node_pointer move_copy_of(value_type& v)
517 {
518 node_for_assignment();
519 move_assign_impl(v);
520 return base::release();
521 }
522
523 iterator begin() const
524 {
525 return iterator(nodes_);
526 }
527 };
528
529 template <typename Alloc>
530 node_holder<Alloc>::~node_holder()
531 {
532 while (nodes_) {
533 node_pointer p = nodes_;
534 nodes_ = static_cast<node_pointer>(p->next_);
535
536 ndnboost::unordered::detail::destroy_value_impl(this->alloc_,
537 p->value_ptr());
538 node_allocator_traits::destroy(this->alloc_, ndnboost::addressof(*p));
539 node_allocator_traits::deallocate(this->alloc_, p, 1);
540 }
541 }
542
543 ///////////////////////////////////////////////////////////////////
544 //
545 // Bucket
546
547 template <typename NodePointer>
548 struct bucket
549 {
550 typedef NodePointer link_pointer;
551 link_pointer next_;
552
553 bucket() : next_() {}
554
555 link_pointer first_from_start()
556 {
557 return next_;
558 }
559
560 enum { extra_node = true };
561 };
562
563 struct ptr_bucket
564 {
565 typedef ptr_bucket* link_pointer;
566 link_pointer next_;
567
568 ptr_bucket() : next_(0) {}
569
570 link_pointer first_from_start()
571 {
572 return this;
573 }
574
575 enum { extra_node = false };
576 };
577
578 ///////////////////////////////////////////////////////////////////
579 //
580 // Hash Policy
581
582 template <typename SizeT>
583 struct prime_policy
584 {
585 template <typename Hash, typename T>
586 static inline SizeT apply_hash(Hash const& hf, T const& x) {
587 return hf(x);
588 }
589
590 static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) {
591 return hash % bucket_count;
592 }
593
594 static inline SizeT new_bucket_count(SizeT min) {
595 return ndnboost::unordered::detail::next_prime(min);
596 }
597
598 static inline SizeT prev_bucket_count(SizeT max) {
599 return ndnboost::unordered::detail::prev_prime(max);
600 }
601 };
602
603 template <typename SizeT>
604 struct mix64_policy
605 {
606 template <typename Hash, typename T>
607 static inline SizeT apply_hash(Hash const& hf, T const& x) {
608 SizeT key = hf(x);
609 key = (~key) + (key << 21); // key = (key << 21) - key - 1;
610 key = key ^ (key >> 24);
611 key = (key + (key << 3)) + (key << 8); // key * 265
612 key = key ^ (key >> 14);
613 key = (key + (key << 2)) + (key << 4); // key * 21
614 key = key ^ (key >> 28);
615 key = key + (key << 31);
616 return key;
617 }
618
619 static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) {
620 return hash & (bucket_count - 1);
621 }
622
623 static inline SizeT new_bucket_count(SizeT min) {
624 if (min <= 4) return 4;
625 --min;
626 min |= min >> 1;
627 min |= min >> 2;
628 min |= min >> 4;
629 min |= min >> 8;
630 min |= min >> 16;
631 min |= min >> 32;
632 return min + 1;
633 }
634
635 static inline SizeT prev_bucket_count(SizeT max) {
636 max |= max >> 1;
637 max |= max >> 2;
638 max |= max >> 4;
639 max |= max >> 8;
640 max |= max >> 16;
641 max |= max >> 32;
642 return (max >> 1) + 1;
643 }
644 };
645
646 template <int digits, int radix>
647 struct pick_policy_impl {
648 typedef prime_policy<std::size_t> type;
649 };
650
651 template <>
652 struct pick_policy_impl<64, 2> {
653 typedef mix64_policy<std::size_t> type;
654 };
655
656 struct pick_policy :
657 pick_policy_impl<
658 std::numeric_limits<std::size_t>::digits,
659 std::numeric_limits<std::size_t>::radix> {};
660
661 ////////////////////////////////////////////////////////////////////////////
662 // Functions
663
664 // Assigning and swapping the equality and hash function objects
665 // needs strong exception safety. To implement that normally we'd
666 // require one of them to be known to not throw and the other to
667 // guarantee strong exception safety. Unfortunately they both only
668 // have basic exception safety. So to acheive strong exception
669 // safety we have storage space for two copies, and assign the new
670 // copies to the unused space. Then switch to using that to use
671 // them. This is implemented in 'set_hash_functions' which
672 // atomically assigns the new function objects in a strongly
673 // exception safe manner.
674
675 template <class H, class P, bool NoThrowMoveAssign>
676 class set_hash_functions;
677
678 template <class H, class P>
679 class functions
680 {
681 public:
682 static const bool nothrow_move_assignable =
683 ndnboost::is_nothrow_move_assignable<H>::value &&
684 ndnboost::is_nothrow_move_assignable<P>::value;
685 static const bool nothrow_move_constructible =
686 ndnboost::is_nothrow_move_constructible<H>::value &&
687 ndnboost::is_nothrow_move_constructible<P>::value;
688
689 private:
690 friend class ndnboost::unordered::detail::set_hash_functions<H, P,
691 nothrow_move_assignable>;
692 functions& operator=(functions const&);
693
694 typedef compressed<H, P> function_pair;
695
696 typedef typename ndnboost::aligned_storage<
697 sizeof(function_pair),
698 ndnboost::alignment_of<function_pair>::value>::type aligned_function;
699
700 bool current_; // The currently active functions.
701 aligned_function funcs_[2];
702
703 function_pair const& current() const {
704 return *static_cast<function_pair const*>(
705 static_cast<void const*>(&funcs_[current_]));
706 }
707
708 function_pair& current() {
709 return *static_cast<function_pair*>(
710 static_cast<void*>(&funcs_[current_]));
711 }
712
713 void construct(bool which, H const& hf, P const& eq)
714 {
715 new((void*) &funcs_[which]) function_pair(hf, eq);
716 }
717
718 void construct(bool which, function_pair const& f)
719 {
720 new((void*) &funcs_[which]) function_pair(f);
721 }
722
723 void construct(bool which, function_pair& f,
724 ndnboost::unordered::detail::move_tag m)
725 {
726 new((void*) &funcs_[which]) function_pair(f, m);
727 }
728
729 void destroy(bool which)
730 {
731 ndnboost::unordered::detail::destroy((function_pair*)(&funcs_[which]));
732 }
733
734 public:
735
736 typedef ndnboost::unordered::detail::set_hash_functions<H, P,
737 nothrow_move_assignable> set_hash_functions;
738
739 functions(H const& hf, P const& eq)
740 : current_(false)
741 {
742 construct(current_, hf, eq);
743 }
744
745 functions(functions const& bf)
746 : current_(false)
747 {
748 construct(current_, bf.current());
749 }
750
751 functions(functions& bf, ndnboost::unordered::detail::move_tag m)
752 : current_(false)
753 {
754 if (nothrow_move_constructible) {
755 construct(current_, bf.current(), m);
756 }
757 else {
758 construct(current_, bf.current());
759 }
760 }
761
762 ~functions() {
763 this->destroy(current_);
764 }
765
766 H const& hash_function() const {
767 return current().first();
768 }
769
770 P const& key_eq() const {
771 return current().second();
772 }
773 };
774
775 template <class H, class P>
776 class set_hash_functions<H, P, false>
777 {
778 set_hash_functions(set_hash_functions const&);
779 set_hash_functions& operator=(set_hash_functions const&);
780
781 typedef functions<H, P> functions_type;
782
783 functions_type& functions_;
784 bool tmp_functions_;
785
786 public:
787
788 set_hash_functions(functions_type& f, H const& h, P const& p)
789 : functions_(f),
790 tmp_functions_(!f.current_)
791 {
792 f.construct(tmp_functions_, h, p);
793 }
794
795 set_hash_functions(functions_type& f, functions_type const& other)
796 : functions_(f),
797 tmp_functions_(!f.current_)
798 {
799 f.construct(tmp_functions_, other.current());
800 }
801
802 ~set_hash_functions()
803 {
804 functions_.destroy(tmp_functions_);
805 }
806
807 void commit()
808 {
809 functions_.current_ = tmp_functions_;
810 tmp_functions_ = !tmp_functions_;
811 }
812 };
813
814 template <class H, class P>
815 class set_hash_functions<H, P, true>
816 {
817 set_hash_functions(set_hash_functions const&);
818 set_hash_functions& operator=(set_hash_functions const&);
819
820 typedef functions<H, P> functions_type;
821
822 functions_type& functions_;
823 H hash_;
824 P pred_;
825
826 public:
827
828 set_hash_functions(functions_type& f, H const& h, P const& p) :
829 functions_(f),
830 hash_(h),
831 pred_(p) {}
832
833 set_hash_functions(functions_type& f, functions_type const& other) :
834 functions_(f),
835 hash_(other.hash_function()),
836 pred_(other.key_eq()) {}
837
838 void commit()
839 {
840 functions_.current().first() = ndnboost::move(hash_);
841 functions_.current().second() = ndnboost::move(pred_);
842 }
843 };
844
845 ////////////////////////////////////////////////////////////////////////////
846 // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
847 // e.g. for int
848
849#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
850# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
851#else
852 struct please_ignore_this_overload {
853 typedef please_ignore_this_overload type;
854 };
855
856 template <typename T>
857 struct rv_ref_impl {
858 typedef BOOST_RV_REF(T) type;
859 };
860
861 template <typename T>
862 struct rv_ref :
863 ndnboost::detail::if_true<
864 ndnboost::is_class<T>::value
865 >::BOOST_NESTED_TEMPLATE then <
866 ndnboost::unordered::detail::rv_ref_impl<T>,
867 please_ignore_this_overload
868 >::type
869 {};
870
871# define BOOST_UNORDERED_RV_REF(T) \
872 typename ndnboost::unordered::detail::rv_ref<T>::type
873#endif
874}}}
875
876#endif