| ///////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Olaf Krzikalla 2004-2006. |
| // (C) Copyright Ion Gaztanaga 2006-2009 |
| // |
| // Distributed under the Boost Software License, Version 1.0. |
| // (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| // See http://www.boost.org/libs/intrusive for documentation. |
| // |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| #ifndef BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP |
| #define BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP |
| |
| #include <boost/intrusive/detail/config_begin.hpp> |
| #include <boost/intrusive/intrusive_fwd.hpp> |
| #include <boost/pointer_cast.hpp> |
| #include <boost/intrusive/detail/utilities.hpp> |
| #include <boost/intrusive/detail/pointer_to_other.hpp> |
| #include <boost/intrusive/slist_hook.hpp> |
| #include <boost/intrusive/options.hpp> |
| #include <boost/intrusive/detail/generic_hook.hpp> |
| |
| namespace boost { |
| namespace intrusive { |
| |
| /// @cond |
| |
| template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey> |
| struct unordered_node |
| : public slist_node<VoidPointer> |
| { |
| typedef typename boost::pointer_to_other |
| < VoidPointer |
| , unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> |
| >::type node_ptr; |
| node_ptr prev_in_group_; |
| std::size_t hash_; |
| }; |
| |
| template<class VoidPointer> |
| struct unordered_node<VoidPointer, false, true> |
| : public slist_node<VoidPointer> |
| { |
| typedef typename boost::pointer_to_other |
| < VoidPointer |
| , unordered_node<VoidPointer, false, true> |
| >::type node_ptr; |
| node_ptr prev_in_group_; |
| }; |
| |
| template<class VoidPointer> |
| struct unordered_node<VoidPointer, true, false> |
| : public slist_node<VoidPointer> |
| { |
| typedef typename boost::pointer_to_other |
| < VoidPointer |
| , unordered_node<VoidPointer, true, false> |
| >::type node_ptr; |
| std::size_t hash_; |
| }; |
| |
| template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey> |
| struct unordered_node_traits |
| : public slist_node_traits<VoidPointer> |
| { |
| typedef slist_node_traits<VoidPointer> reduced_slist_node_traits; |
| typedef unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> node; |
| typedef typename boost::pointer_to_other |
| <VoidPointer, node>::type node_ptr; |
| typedef typename boost::pointer_to_other |
| <VoidPointer, const node>::type const_node_ptr; |
| |
| static const bool store_hash = StoreHash; |
| static const bool optimize_multikey = OptimizeMultiKey; |
| |
| static node_ptr get_next(const_node_ptr n) |
| { |
| // This still fails in gcc < 4.4 so forget about it |
| // using ::boost::static_pointer_cast; |
| // return static_pointer_cast<node>(n->next_); |
| return node_ptr(&static_cast<node&>(*n->next_)); |
| } |
| |
| static void set_next(node_ptr n, node_ptr next) |
| { n->next_ = next; } |
| |
| static node_ptr get_prev_in_group(const_node_ptr n) |
| { return n->prev_in_group_; } |
| |
| static void set_prev_in_group(node_ptr n, node_ptr prev) |
| { n->prev_in_group_ = prev; } |
| |
| static std::size_t get_hash(const_node_ptr n) |
| { return n->hash_; } |
| |
| static void set_hash(node_ptr n, std::size_t h) |
| { n->hash_ = h; } |
| }; |
| |
| template<class NodeTraits> |
| struct unordered_group_adapter |
| { |
| typedef typename NodeTraits::node node; |
| typedef typename NodeTraits::node_ptr node_ptr; |
| typedef typename NodeTraits::const_node_ptr const_node_ptr; |
| |
| static node_ptr get_next(const_node_ptr n) |
| { return NodeTraits::get_prev_in_group(n); } |
| |
| static void set_next(node_ptr n, node_ptr next) |
| { NodeTraits::set_prev_in_group(n, next); } |
| }; |
| |
| template<class NodeTraits> |
| struct unordered_algorithms |
| : public circular_slist_algorithms<NodeTraits> |
| { |
| typedef circular_slist_algorithms<NodeTraits> base_type; |
| typedef unordered_group_adapter<NodeTraits> group_traits; |
| typedef circular_slist_algorithms<group_traits> group_algorithms; |
| |
| static void init(typename base_type::node_ptr n) |
| { |
| base_type::init(n); |
| group_algorithms::init(n); |
| } |
| |
| static void init_header(typename base_type::node_ptr n) |
| { |
| base_type::init_header(n); |
| group_algorithms::init_header(n); |
| } |
| |
| static void unlink(typename base_type::node_ptr n) |
| { |
| base_type::unlink(n); |
| group_algorithms::unlink(n); |
| } |
| }; |
| |
| template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey> |
| struct get_uset_node_algo |
| { |
| typedef typename detail::if_c |
| < (StoreHash || OptimizeMultiKey) |
| , unordered_node_traits<VoidPointer, StoreHash, OptimizeMultiKey> |
| , slist_node_traits<VoidPointer> |
| >::type node_traits_type; |
| typedef typename detail::if_c |
| < OptimizeMultiKey |
| , unordered_algorithms<node_traits_type> |
| , circular_slist_algorithms<node_traits_type> |
| >::type type; |
| }; |
| /// @endcond |
| |
| //! Helper metafunction to define a \c unordered_set_base_hook that yields to the same |
| //! type when the same options (either explicitly or implicitly) are used. |
| #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) |
| template<class ...Options> |
| #else |
| template<class O1 = none, class O2 = none, class O3 = none, class O4 = none> |
| #endif |
| struct make_unordered_set_base_hook |
| { |
| /// @cond |
| typedef typename pack_options |
| < hook_defaults, |
| #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) |
| O1, O2, O3, O4 |
| #else |
| Options... |
| #endif |
| >::type packed_options; |
| |
| typedef detail::generic_hook |
| < get_uset_node_algo<typename packed_options::void_pointer |
| , packed_options::store_hash |
| , packed_options::optimize_multikey |
| > |
| , typename packed_options::tag |
| , packed_options::link_mode |
| , detail::UsetBaseHook |
| > implementation_defined; |
| /// @endcond |
| typedef implementation_defined type; |
| }; |
| |
| //! Derive a class from unordered_set_base_hook in order to store objects in |
| //! in an unordered_set/unordered_multi_set. unordered_set_base_hook holds the data necessary to maintain |
| //! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set. |
| //! |
| //! The hook admits the following options: \c tag<>, \c void_pointer<>, |
| //! \c link_mode<>, \c store_hash<> and \c optimize_multikey<>. |
| //! |
| //! \c tag<> defines a tag to identify the node. |
| //! The same tag value can be used in different classes, but if a class is |
| //! derived from more than one \c list_base_hook, then each \c list_base_hook needs its |
| //! unique tag. |
| //! |
| //! \c void_pointer<> is the pointer type that will be used internally in the hook |
| //! and the the container configured to use this hook. |
| //! |
| //! \c link_mode<> will specify the linking mode of the hook (\c normal_link, |
| //! \c auto_unlink or \c safe_link). |
| //! |
| //! \c store_hash<> will tell the hook to store the hash of the value |
| //! to speed up rehashings. |
| //! |
| //! \c optimize_multikey<> will tell the hook to store a link to form a group |
| //! with other value with the same value to speed up searches and insertions |
| //! in unordered_multisets with a great number of with equivalent keys. |
| #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) |
| template<class ...Options> |
| #else |
| template<class O1, class O2, class O3, class O4> |
| #endif |
| class unordered_set_base_hook |
| : public make_unordered_set_base_hook< |
| #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) |
| O1, O2, O3, O4 |
| #else |
| Options... |
| #endif |
| >::type |
| { |
| #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) |
| public: |
| //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link |
| //! initializes the node to an unlinked state. |
| //! |
| //! <b>Throws</b>: Nothing. |
| unordered_set_base_hook(); |
| |
| //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link |
| //! initializes the node to an unlinked state. The argument is ignored. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Rationale</b>: Providing a copy-constructor |
| //! makes classes using the hook STL-compliant without forcing the |
| //! user to do some additional work. \c swap can be used to emulate |
| //! move-semantics. |
| unordered_set_base_hook(const unordered_set_base_hook& ); |
| |
| //! <b>Effects</b>: Empty function. The argument is ignored. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Rationale</b>: Providing an assignment operator |
| //! makes classes using the hook STL-compliant without forcing the |
| //! user to do some additional work. \c swap can be used to emulate |
| //! move-semantics. |
| unordered_set_base_hook& operator=(const unordered_set_base_hook& ); |
| |
| //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does |
| //! nothing (ie. no code is generated). If link_mode is \c safe_link and the |
| //! object is stored in an unordered_set an assertion is raised. If link_mode is |
| //! \c auto_unlink and \c is_linked() is true, the node is unlinked. |
| //! |
| //! <b>Throws</b>: Nothing. |
| ~unordered_set_base_hook(); |
| |
| //! <b>Effects</b>: Swapping two nodes swaps the position of the elements |
| //! related to those nodes in one or two containers. That is, if the node |
| //! this is part of the element e1, the node x is part of the element e2 |
| //! and both elements are included in the containers s1 and s2, then after |
| //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 |
| //! at the position of e1. If one element is not in a container, then |
| //! after the swap-operation the other element is not in a container. |
| //! Iterators to e1 and e2 related to those nodes are invalidated. |
| //! |
| //! <b>Complexity</b>: Constant |
| //! |
| //! <b>Throws</b>: Nothing. |
| void swap_nodes(unordered_set_base_hook &other); |
| |
| //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink. |
| //! |
| //! <b>Returns</b>: true, if the node belongs to a container, false |
| //! otherwise. This function can be used to test whether \c unordered_set::iterator_to |
| //! will return a valid iterator. |
| //! |
| //! <b>Complexity</b>: Constant |
| bool is_linked() const; |
| |
| //! <b>Effects</b>: Removes the node if it's inserted in a container. |
| //! This function is only allowed if link_mode is \c auto_unlink. |
| //! |
| //! <b>Throws</b>: Nothing. |
| void unlink(); |
| #endif |
| }; |
| |
| |
| //! Helper metafunction to define a \c unordered_set_member_hook that yields to the same |
| //! type when the same options (either explicitly or implicitly) are used. |
| #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) |
| template<class ...Options> |
| #else |
| template<class O1 = none, class O2 = none, class O3 = none, class O4 = none> |
| #endif |
| struct make_unordered_set_member_hook |
| { |
| /// @cond |
| typedef typename pack_options |
| < hook_defaults, |
| #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) |
| O1, O2, O3, O4 |
| #else |
| Options... |
| #endif |
| >::type packed_options; |
| |
| typedef detail::generic_hook |
| < get_uset_node_algo< typename packed_options::void_pointer |
| , packed_options::store_hash |
| , packed_options::optimize_multikey |
| > |
| , member_tag |
| , packed_options::link_mode |
| , detail::NoBaseHook |
| > implementation_defined; |
| /// @endcond |
| typedef implementation_defined type; |
| }; |
| |
| //! Put a public data member unordered_set_member_hook in order to store objects of this class in |
| //! an unordered_set/unordered_multi_set. unordered_set_member_hook holds the data necessary for maintaining the |
| //! unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set. |
| //! |
| //! The hook admits the following options: \c void_pointer<>, |
| //! \c link_mode<> and \c store_hash<>. |
| //! |
| //! \c void_pointer<> is the pointer type that will be used internally in the hook |
| //! and the the container configured to use this hook. |
| //! |
| //! \c link_mode<> will specify the linking mode of the hook (\c normal_link, |
| //! \c auto_unlink or \c safe_link). |
| //! |
| //! \c store_hash<> will tell the hook to store the hash of the value |
| //! to speed up rehashings. |
| #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) |
| template<class ...Options> |
| #else |
| template<class O1, class O2, class O3, class O4> |
| #endif |
| class unordered_set_member_hook |
| : public make_unordered_set_member_hook< |
| #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) |
| O1, O2, O3, O4 |
| #else |
| Options... |
| #endif |
| >::type |
| { |
| #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) |
| public: |
| //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link |
| //! initializes the node to an unlinked state. |
| //! |
| //! <b>Throws</b>: Nothing. |
| unordered_set_member_hook(); |
| |
| //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link |
| //! initializes the node to an unlinked state. The argument is ignored. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Rationale</b>: Providing a copy-constructor |
| //! makes classes using the hook STL-compliant without forcing the |
| //! user to do some additional work. \c swap can be used to emulate |
| //! move-semantics. |
| unordered_set_member_hook(const unordered_set_member_hook& ); |
| |
| //! <b>Effects</b>: Empty function. The argument is ignored. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Rationale</b>: Providing an assignment operator |
| //! makes classes using the hook STL-compliant without forcing the |
| //! user to do some additional work. \c swap can be used to emulate |
| //! move-semantics. |
| unordered_set_member_hook& operator=(const unordered_set_member_hook& ); |
| |
| //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does |
| //! nothing (ie. no code is generated). If link_mode is \c safe_link and the |
| //! object is stored in an unordered_set an assertion is raised. If link_mode is |
| //! \c auto_unlink and \c is_linked() is true, the node is unlinked. |
| //! |
| //! <b>Throws</b>: Nothing. |
| ~unordered_set_member_hook(); |
| |
| //! <b>Effects</b>: Swapping two nodes swaps the position of the elements |
| //! related to those nodes in one or two containers. That is, if the node |
| //! this is part of the element e1, the node x is part of the element e2 |
| //! and both elements are included in the containers s1 and s2, then after |
| //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 |
| //! at the position of e1. If one element is not in a container, then |
| //! after the swap-operation the other element is not in a container. |
| //! Iterators to e1 and e2 related to those nodes are invalidated. |
| //! |
| //! <b>Complexity</b>: Constant |
| //! |
| //! <b>Throws</b>: Nothing. |
| void swap_nodes(unordered_set_member_hook &other); |
| |
| //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink. |
| //! |
| //! <b>Returns</b>: true, if the node belongs to a container, false |
| //! otherwise. This function can be used to test whether \c unordered_set::iterator_to |
| //! will return a valid iterator. |
| //! |
| //! <b>Complexity</b>: Constant |
| bool is_linked() const; |
| |
| //! <b>Effects</b>: Removes the node if it's inserted in a container. |
| //! This function is only allowed if link_mode is \c auto_unlink. |
| //! |
| //! <b>Throws</b>: Nothing. |
| void unlink(); |
| #endif |
| }; |
| |
| } //namespace intrusive |
| } //namespace boost |
| |
| #include <boost/intrusive/detail/config_end.hpp> |
| |
| #endif //BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP |