You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
433 lines
15 KiB
433 lines
15 KiB
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// (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
|
|
|