1 /////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2006-2012
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 // See http://www.boost.org/libs/intrusive for documentation.
11 /////////////////////////////////////////////////////////////////////////////
13 #ifndef BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP
14 #define BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP
16 #include <boost/intrusive/detail/config_begin.hpp>
17 #include <boost/intrusive/pointer_traits.hpp>
18 #include <boost/intrusive/detail/parent_from_member.hpp>
19 #include <boost/intrusive/detail/ebo_functor_holder.hpp>
20 #include <boost/intrusive/link_mode.hpp>
21 #include <boost/intrusive/detail/mpl.hpp>
22 #include <boost/intrusive/detail/assert.hpp>
23 #include <boost/intrusive/detail/is_stateful_value_traits.hpp>
24 #include <boost/intrusive/pointer_traits.hpp>
25 #include <boost/cstdint.hpp>
29 #include <boost/cstdint.hpp>
30 #include <boost/static_assert.hpp>
37 struct internal_member_value_traits
39 template <class U> static detail::one test(...);
40 template <class U> static detail::two test(typename U::member_value_traits* = 0);
41 static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
45 struct internal_base_hook_bool
48 struct two_or_three {one _[2 + Add];};
49 template <class U> static one test(...);
50 template <class U> static two_or_three<U::boost_intrusive_tags::is_base_hook> test (int);
51 static const std::size_t value = sizeof(test<T>(0));
55 struct internal_base_hook_bool_is_true
57 static const bool value = internal_base_hook_bool<T>::value > sizeof(one)*2;
61 struct internal_any_hook_bool
64 struct two_or_three {one _[2 + Add];};
65 template <class U> static one test(...);
66 template <class U> static two_or_three<U::is_any_hook> test (int);
67 static const std::size_t value = sizeof(test<T>(0));
71 struct internal_any_hook_bool_is_true
73 static const bool value = internal_any_hook_bool<T>::value > sizeof(one)*2;
78 struct external_value_traits_bool
81 struct two_or_three {one _[2 + Add];};
82 template <class U> static one test(...);
83 template <class U> static two_or_three<U::external_value_traits> test (int);
84 static const std::size_t value = sizeof(test<T>(0));
88 struct external_bucket_traits_bool
91 struct two_or_three {one _[2 + Add];};
92 template <class U> static one test(...);
93 template <class U> static two_or_three<U::external_bucket_traits> test (int);
94 static const std::size_t value = sizeof(test<T>(0));
98 struct external_value_traits_is_true
100 static const bool value = external_value_traits_bool<T>::value > sizeof(one)*2;
103 template<class Node, class Tag, link_mode_type LinkMode, int>
109 inline T* to_raw_pointer(T* p)
112 template <class Pointer>
113 inline typename boost::intrusive::pointer_traits<Pointer>::element_type*
114 to_raw_pointer(const Pointer &p)
115 { return boost::intrusive::detail::to_raw_pointer(p.operator->()); }
117 //This functor compares a stored value
118 //and the one passed as an argument
119 template<class ConstReference>
125 equal_to_value(ConstReference t)
129 bool operator()(ConstReference t)const
136 template <class Pointer>
137 void operator()(Pointer)
141 template<class NodeAlgorithms>
144 typedef typename NodeAlgorithms::node_ptr node_ptr;
147 void operator()(const node_ptr & p)
148 { NodeAlgorithms::init(p); }
151 template<bool ConstantSize, class SizeType>
154 static const bool constant_time_size = ConstantSize;
155 typedef SizeType size_type;
157 SizeType get_size() const
160 void set_size(SizeType size)
172 template<class SizeType>
173 struct size_holder<false, SizeType>
175 static const bool constant_time_size = false;
176 typedef SizeType size_type;
178 size_type get_size() const
181 void set_size(size_type)
191 template<class KeyValueCompare, class Container>
192 struct key_nodeptr_comp
193 : private detail::ebo_functor_holder<KeyValueCompare>
195 typedef typename Container::real_value_traits real_value_traits;
196 typedef typename Container::value_type value_type;
197 typedef typename real_value_traits::node_ptr node_ptr;
198 typedef typename real_value_traits::const_node_ptr const_node_ptr;
199 typedef detail::ebo_functor_holder<KeyValueCompare> base_t;
200 key_nodeptr_comp(KeyValueCompare kcomp, const Container *cont)
201 : base_t(kcomp), cont_(cont)
207 static const bool value = is_same<T, const_node_ptr>::value || is_same<T, node_ptr>::value;
211 const value_type & key_forward
212 (const T &node, typename enable_if_c<is_node_ptr<T>::value>::type * = 0) const
213 { return *cont_->get_real_value_traits().to_value_ptr(node); }
216 const T & key_forward(const T &key, typename enable_if_c<!is_node_ptr<T>::value>::type* = 0) const
220 template<class KeyType, class KeyType2>
221 bool operator()(const KeyType &key1, const KeyType2 &key2) const
222 { return base_t::get()(this->key_forward(key1), this->key_forward(key2)); }
224 const Container *cont_;
227 template<class F, class Container>
229 : private detail::ebo_functor_holder<F>
231 typedef typename Container::real_value_traits real_value_traits;
232 typedef typename Container::node_algorithms node_algorithms;
233 typedef typename real_value_traits::value_type value_type;
234 typedef typename real_value_traits::pointer pointer;
235 typedef typename real_value_traits::node_traits::node node;
236 typedef typename real_value_traits::node_ptr node_ptr;
237 typedef typename real_value_traits::const_node_ptr const_node_ptr;
238 typedef detail::ebo_functor_holder<F> base_t;
239 enum { safemode_or_autounlink =
240 (int)real_value_traits::link_mode == (int)auto_unlink ||
241 (int)real_value_traits::link_mode == (int)safe_link };
243 node_cloner(F f, const Container *cont)
244 : base_t(f), cont_(cont)
247 node_ptr operator()(const node_ptr & p)
248 { return this->operator()(*p); }
250 node_ptr operator()(const node &to_clone)
252 const value_type &v =
253 *cont_->get_real_value_traits().to_value_ptr
254 (pointer_traits<const_node_ptr>::pointer_to(to_clone));
255 node_ptr n = cont_->get_real_value_traits().to_node_ptr(*base_t::get()(v));
256 //Cloned node must be in default mode if the linking mode requires it
257 if(safemode_or_autounlink)
258 BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n));
262 const Container *cont_;
265 template<class F, class Container>
267 : private detail::ebo_functor_holder<F>
269 typedef typename Container::real_value_traits real_value_traits;
270 typedef typename real_value_traits::node_ptr node_ptr;
271 typedef detail::ebo_functor_holder<F> base_t;
272 typedef typename Container::node_algorithms node_algorithms;
273 enum { safemode_or_autounlink =
274 (int)real_value_traits::link_mode == (int)auto_unlink ||
275 (int)real_value_traits::link_mode == (int)safe_link };
277 node_disposer(F f, const Container *cont)
278 : base_t(f), cont_(cont)
281 void operator()(const node_ptr & p)
283 if(safemode_or_autounlink)
284 node_algorithms::init(p);
285 base_t::get()(cont_->get_real_value_traits().to_value_ptr(p));
287 const Container *cont_;
290 struct dummy_constptr
292 dummy_constptr(const void *)
295 const void *get_ptr() const
299 template<class VoidPointer>
302 typedef typename boost::intrusive::pointer_traits<VoidPointer>::
303 template rebind_pointer<const void>::type ConstVoidPtr;
305 constptr(const void *ptr)
306 : const_void_ptr_(ptr)
309 const void *get_ptr() const
310 { return boost::intrusive::detail::to_raw_pointer(const_void_ptr_); }
312 ConstVoidPtr const_void_ptr_;
315 template <class VoidPointer, bool store_ptr>
316 struct select_constptr
318 typedef typename detail::if_c
320 , constptr<VoidPointer>
325 template<class T, bool Add>
326 struct add_const_if_c
328 typedef typename detail::if_c
330 , typename detail::add_const<T>::type
335 template <link_mode_type LinkMode>
340 void destructor_impl(Hook &hook, detail::link_dispatch<safe_link>)
341 { //If this assertion raises, you might have destroyed an object
342 //while it was still inserted in a container that is alive.
343 //If so, remove the object from the container before destroying it.
344 (void)hook; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!hook.is_linked());
348 void destructor_impl(Hook &hook, detail::link_dispatch<auto_unlink>)
352 void destructor_impl(Hook &, detail::link_dispatch<normal_link>)
355 template<class T, class NodeTraits, link_mode_type LinkMode, class Tag, int HookType>
356 struct base_hook_traits
359 typedef detail::node_holder
360 <typename NodeTraits::node, Tag, LinkMode, HookType> node_holder;
361 typedef typename NodeTraits::node node;
362 typedef NodeTraits node_traits;
363 typedef T value_type;
364 typedef typename node_traits::node_ptr node_ptr;
365 typedef typename node_traits::const_node_ptr const_node_ptr;
366 typedef typename pointer_traits<node_ptr>::
367 template rebind_pointer<T>::type pointer;
368 typedef typename pointer_traits<node_ptr>::
369 template rebind_pointer<const T>::type const_pointer;
370 //typedef typename pointer_traits<pointer>::reference reference;
371 //typedef typename pointer_traits<const_pointer>::reference const_reference;
372 typedef T & reference;
373 typedef const T & const_reference;
374 typedef node_holder & node_holder_reference;
375 typedef const node_holder & const_node_holder_reference;
376 typedef node& node_reference;
377 typedef const node & const_node_reference;
379 static const link_mode_type link_mode = LinkMode;
381 static pointer to_value_ptr(const node_ptr & n)
383 return pointer_traits<pointer>::pointer_to
384 (static_cast<reference>(static_cast<node_holder_reference>(*n)));
387 static const_pointer to_value_ptr(const const_node_ptr & n)
389 return pointer_traits<const_pointer>::pointer_to
390 (static_cast<const_reference>(static_cast<const_node_holder_reference>(*n)));
393 static node_ptr to_node_ptr(reference value)
395 return pointer_traits<node_ptr>::pointer_to
396 (static_cast<node_reference>(static_cast<node_holder_reference>(value)));
399 static const_node_ptr to_node_ptr(const_reference value)
401 return pointer_traits<const_node_ptr>::pointer_to
402 (static_cast<const_node_reference>(static_cast<const_node_holder_reference>(value)));
406 template<class T, class Hook, Hook T::* P>
407 struct member_hook_traits
410 typedef Hook hook_type;
411 typedef typename hook_type::boost_intrusive_tags::node_traits node_traits;
412 typedef typename node_traits::node node;
413 typedef T value_type;
414 typedef typename node_traits::node_ptr node_ptr;
415 typedef typename node_traits::const_node_ptr const_node_ptr;
416 typedef typename pointer_traits<node_ptr>::
417 template rebind_pointer<T>::type pointer;
418 typedef typename pointer_traits<node_ptr>::
419 template rebind_pointer<const T>::type const_pointer;
420 typedef T & reference;
421 typedef const T & const_reference;
422 typedef node& node_reference;
423 typedef const node & const_node_reference;
424 typedef hook_type& hook_reference;
425 typedef const hook_type & const_hook_reference;
427 static const link_mode_type link_mode = Hook::boost_intrusive_tags::link_mode;
429 static node_ptr to_node_ptr(reference value)
431 return pointer_traits<node_ptr>::pointer_to
432 (static_cast<node_reference>(static_cast<hook_reference>(value.*P)));
435 static const_node_ptr to_node_ptr(const_reference value)
437 return pointer_traits<const_node_ptr>::pointer_to
438 (static_cast<const_node_reference>(static_cast<const_hook_reference>(value.*P)));
441 static pointer to_value_ptr(const node_ptr & n)
443 return pointer_traits<pointer>::pointer_to
444 (*detail::parent_from_member<T, Hook>
445 (static_cast<Hook*>(boost::intrusive::detail::to_raw_pointer(n)), P));
448 static const_pointer to_value_ptr(const const_node_ptr & n)
450 return pointer_traits<const_pointer>::pointer_to
451 (*detail::parent_from_member<T, Hook>
452 (static_cast<const Hook*>(boost::intrusive::detail::to_raw_pointer(n)), P));
456 template<class Functor>
457 struct function_hook_traits
460 typedef typename Functor::hook_type hook_type;
461 typedef typename Functor::hook_ptr hook_ptr;
462 typedef typename Functor::const_hook_ptr const_hook_ptr;
463 typedef typename hook_type::boost_intrusive_tags::node_traits node_traits;
464 typedef typename node_traits::node node;
465 typedef typename Functor::value_type value_type;
466 typedef typename node_traits::node_ptr node_ptr;
467 typedef typename node_traits::const_node_ptr const_node_ptr;
468 typedef typename pointer_traits<node_ptr>::
469 template rebind_pointer<value_type>::type pointer;
470 typedef typename pointer_traits<node_ptr>::
471 template rebind_pointer<const value_type>::type const_pointer;
472 typedef value_type & reference;
473 typedef const value_type & const_reference;
474 static const link_mode_type link_mode = hook_type::boost_intrusive_tags::link_mode;
476 static node_ptr to_node_ptr(reference value)
477 { return static_cast<node*>(boost::intrusive::detail::to_raw_pointer(Functor::to_hook_ptr(value))); }
479 static const_node_ptr to_node_ptr(const_reference value)
480 { return static_cast<const node*>(boost::intrusive::detail::to_raw_pointer(Functor::to_hook_ptr(value))); }
482 static pointer to_value_ptr(const node_ptr & n)
483 { return Functor::to_value_ptr(to_hook_ptr(n)); }
485 static const_pointer to_value_ptr(const const_node_ptr & n)
486 { return Functor::to_value_ptr(to_hook_ptr(n)); }
489 static hook_ptr to_hook_ptr(const node_ptr & n)
490 { return hook_ptr(&*static_cast<hook_type*>(&*n)); }
492 static const_hook_ptr to_hook_ptr(const const_node_ptr & n)
493 { return const_hook_ptr(&*static_cast<const hook_type*>(&*n)); }
497 //This function uses binary search to discover the
498 //highest set bit of the integer
499 inline std::size_t floor_log2 (std::size_t x)
501 const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT;
502 const bool Size_t_Bits_Power_2= !(Bits & (Bits-1));
503 BOOST_STATIC_ASSERT(Size_t_Bits_Power_2);
506 std::size_t log2 = 0;
508 for(std::size_t shift = Bits >> 1; shift; shift >>= 1){
509 std::size_t tmp = n >> shift;
511 log2 += shift, n = tmp;
517 inline float fast_log2 (float val)
526 boost::uint32_t x = caster.x;
527 const int log_2 = (int)(((x >> 23) & 255) - 128);
532 val = ((-1.0f/3.f) * val + 2.f) * val - (2.0f/3.f);
534 return (val + log_2);
537 inline std::size_t ceil_log2 (std::size_t x)
539 return ((x & (x-1))!= 0) + floor_log2(x);
542 template<class SizeType, std::size_t N>
545 static const bool value = sizeof(SizeType)*CHAR_BIT == N;
548 template<class SizeType, class Enabler = void >
549 struct sqrt2_pow_max;
551 template <class SizeType>
552 struct sqrt2_pow_max<SizeType, typename enable_if< numbits_eq<SizeType, 32> >::type>
554 static const boost::uint32_t value = 0xb504f334;
555 static const std::size_t pow = 31;
558 template <class SizeType>
559 struct sqrt2_pow_max<SizeType, typename enable_if< numbits_eq<SizeType, 64> >::type>
561 static const boost::uint64_t value = 0xb504f333f9de6484ull;
562 static const std::size_t pow = 63;
565 // Returns floor(pow(sqrt(2), x * 2 + 1)).
566 // Defined for X from 0 up to the number of bits in size_t minus 1.
567 inline std::size_t sqrt2_pow_2xplus1 (std::size_t x)
569 const std::size_t value = (std::size_t)sqrt2_pow_max<std::size_t>::value;
570 const std::size_t pow = (std::size_t)sqrt2_pow_max<std::size_t>::pow;
571 return (value >> (pow - x)) + 1;
574 template<class Container, class Disposer>
575 class exception_disposer
580 exception_disposer(const exception_disposer&);
581 exception_disposer &operator=(const exception_disposer&);
584 exception_disposer(Container &cont, Disposer &disp)
585 : cont_(&cont), disp_(disp)
591 ~exception_disposer()
594 cont_->clear_and_dispose(disp_);
599 template<class Container, class Disposer, class SizeType>
600 class exception_array_disposer
604 SizeType &constructed_;
606 exception_array_disposer(const exception_array_disposer&);
607 exception_array_disposer &operator=(const exception_array_disposer&);
611 exception_array_disposer
612 (Container &cont, Disposer &disp, SizeType &constructed)
613 : cont_(&cont), disp_(disp), constructed_(constructed)
619 ~exception_array_disposer()
621 SizeType n = constructed_;
624 cont_[n].clear_and_dispose(disp_);
630 template<class ValueTraits, bool ExternalValueTraits>
631 struct store_cont_ptr_on_it_impl
633 static const bool value = is_stateful_value_traits<ValueTraits>::value;
636 template<class ValueTraits>
637 struct store_cont_ptr_on_it_impl<ValueTraits, true>
639 static const bool value = true;
642 template <class Container>
643 struct store_cont_ptr_on_it
645 typedef typename Container::value_traits value_traits;
646 static const bool value = store_cont_ptr_on_it_impl
647 <value_traits, external_value_traits_is_true<value_traits>::value>::value;
650 template<class Container, bool IsConst>
652 : public detail::select_constptr
653 < typename pointer_traits
654 <typename Container::pointer>::template rebind_pointer<void>::type
655 , detail::store_cont_ptr_on_it<Container>::value
658 static const bool store_container_ptr =
659 detail::store_cont_ptr_on_it<Container>::value;
661 typedef typename Container::real_value_traits real_value_traits;
662 typedef typename real_value_traits::value_type value_type;
663 typedef typename detail::select_constptr
664 < typename pointer_traits
665 <typename Container::pointer>::template rebind_pointer<void>::type
666 , store_container_ptr >::type Base;
667 typedef typename real_value_traits::node_traits::node node;
668 typedef typename detail::add_const_if_c
669 <value_type, IsConst>::type vtype;
670 typedef typename detail::add_const_if_c
671 <node, IsConst>::type ntype;
672 typedef typename pointer_traits
673 <typename Container::pointer>::template rebind_pointer<ntype>::type npointer;
675 node_to_value(const Container *cont)
679 typedef vtype & result_type;
680 typedef ntype & first_argument_type;
682 const Container *get_container() const
684 if(store_container_ptr)
685 return static_cast<const Container*>(Base::get_ptr());
690 const real_value_traits *get_real_value_traits() const
692 if(store_container_ptr)
693 return &this->get_container()->get_real_value_traits();
698 result_type operator()(first_argument_type arg) const
700 return *(this->get_real_value_traits()->to_value_ptr
701 (pointer_traits<npointer>::pointer_to(arg)));
705 //This is not standard, but should work with all compilers
712 #ifdef BOOST_HAS_LONG_LONG
713 long long long_long_;
717 long double long_double_;
721 template<class T, std::size_t N>
722 class array_initializer
725 template<class CommonInitializer>
726 array_initializer(const CommonInitializer &init)
728 char *init_buf = (char*)rawbuf;
732 new(init_buf)T(init);
733 init_buf += sizeof(T);
738 init_buf -= sizeof(T);
739 ((T*)init_buf)->~T();
746 { return (T*)(rawbuf); }
748 operator const T*() const
749 { return (const T*)(rawbuf); }
753 char *init_buf = (char*)rawbuf + N*sizeof(T);
754 for(std::size_t i = 0; i != N; ++i){
755 init_buf -= sizeof(T);
756 ((T*)init_buf)->~T();
761 detail::max_align rawbuf[(N*sizeof(T)-1)/sizeof(detail::max_align)+1];
768 class reverse_iterator
769 : public std::iterator<
770 typename std::iterator_traits<It>::iterator_category,
771 typename std::iterator_traits<It>::value_type,
772 typename std::iterator_traits<It>::difference_type,
773 typename std::iterator_traits<It>::pointer,
774 typename std::iterator_traits<It>::reference>
777 typedef typename std::iterator_traits<It>::pointer pointer;
778 typedef typename std::iterator_traits<It>::reference reference;
779 typedef typename std::iterator_traits<It>::difference_type difference_type;
780 typedef It iterator_type;
784 explicit reverse_iterator(It r)
788 template<class OtherIt>
789 reverse_iterator(const reverse_iterator<OtherIt>& r)
790 : m_current(r.base())
794 { return m_current; }
796 reference operator*() const
797 { It temp(m_current); --temp; return *temp; }
799 pointer operator->() const
800 { It temp(m_current); --temp; return temp.operator->(); }
802 reference operator[](difference_type off) const
803 { return this->m_current[-off]; }
805 reverse_iterator& operator++()
806 { --m_current; return *this; }
808 reverse_iterator operator++(int)
810 reverse_iterator temp = *this;
815 reverse_iterator& operator--()
821 reverse_iterator operator--(int)
823 reverse_iterator temp(*this);
828 friend bool operator==(const reverse_iterator& l, const reverse_iterator& r)
829 { return l.m_current == r.m_current; }
831 friend bool operator!=(const reverse_iterator& l, const reverse_iterator& r)
832 { return l.m_current != r.m_current; }
834 friend bool operator<(const reverse_iterator& l, const reverse_iterator& r)
835 { return l.m_current < r.m_current; }
837 friend bool operator<=(const reverse_iterator& l, const reverse_iterator& r)
838 { return l.m_current <= r.m_current; }
840 friend bool operator>(const reverse_iterator& l, const reverse_iterator& r)
841 { return l.m_current > r.m_current; }
843 friend bool operator>=(const reverse_iterator& l, const reverse_iterator& r)
844 { return l.m_current >= r.m_current; }
846 reverse_iterator& operator+=(difference_type off)
847 { m_current -= off; return *this; }
849 friend reverse_iterator operator+(const reverse_iterator & l, difference_type off)
851 reverse_iterator tmp(l.m_current);
852 tmp.m_current -= off;
856 reverse_iterator& operator-=(difference_type off)
857 { m_current += off; return *this; }
859 friend reverse_iterator operator-(const reverse_iterator & l, difference_type off)
861 reverse_iterator tmp(l.m_current);
862 tmp.m_current += off;
866 friend difference_type operator-(const reverse_iterator& l, const reverse_iterator& r)
867 { return r.m_current - l.m_current; }
870 It m_current; // the wrapped iterator
874 } //namespace intrusive
877 #include <boost/intrusive/detail/config_end.hpp>
879 #endif //BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP