diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk
index a0cf973..4d47228 100644
--- a/doc/intrusive.qbk
+++ b/doc/intrusive.qbk
@@ -3800,6 +3800,7 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std
* [@https://svn.boost.org/trac/boost/ticket/9746 #9746: Modern Sun CC compiler detects error in intrusive library header]
* [@https://svn.boost.org/trac/boost/ticket/9940 #9940: bad bug in intrusive list with safe_link (or auto_unlink) hooks]
* [@https://svn.boost.org/trac/boost/ticket/9949 #9949: clear header node hooks upon intrusive container destruction]
+ * [@https://svn.boost.org/trac/boost/ticket/9961 #9961: tests for hooks not derived frorm generic_hook]
* Optimized tree rebalancing code to avoid redundant assignments.
diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj
index fc4e758..cfa6a7a 100644
--- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj
+++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj
@@ -318,6 +318,9 @@
+
+
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..a889a98
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,21 @@
+SRC_LIST = $(wildcard *.cpp)
+TGT_LIST = $(basename $(SRC_LIST))
+
+CPPFLAGS = -I${BOOST_INTRUSIVE}/include -I${BOOST}/include
+CXXFLAGS = -Wall -Wextra -pedantic -Wno-ignored-qualifiers -Wno-long-long -g3 -O0
+
+.PHONY: all run clean
+
+all: $(TGT_LIST)
+
+%: %.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $< -o $@
+
+run: $(TGT_LIST)
+ for f in $^; do \
+ echo "===== running: $$f"; \
+ ./$$f || break; \
+ done
+
+clean:
+ rm -f $(TGT_LIST)
diff --git a/test/avl_multiset_test.cpp b/test/avl_multiset_test.cpp
index ecad395..be6d3c2 100644
--- a/test/avl_multiset_test.cpp
+++ b/test/avl_multiset_test.cpp
@@ -55,6 +55,9 @@ struct hooks
typedef avl_set_member_hook
< link_mode
, void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< avltree_node_traits,
+ avltree_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -96,6 +99,13 @@ class test_main_template
>::type
, GetContainer
>::test_all();
+ test::test_generic_multiset < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainer
+ >::test_all();
return 0;
}
};
diff --git a/test/avl_set_test.cpp b/test/avl_set_test.cpp
index 8c04e46..36d0731 100644
--- a/test/avl_set_test.cpp
+++ b/test/avl_set_test.cpp
@@ -55,6 +55,9 @@ struct hooks
typedef avl_set_member_hook
< link_mode
, void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< avltree_node_traits,
+ avltree_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -96,6 +99,13 @@ class test_main_template
>::type
, GetContainer
>::test_all();
+ test::test_generic_set < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainer
+ >::test_all();
return 0;
}
};
diff --git a/test/itestvalue.hpp b/test/itestvalue.hpp
index 91bd182..4168501 100644
--- a/test/itestvalue.hpp
+++ b/test/itestvalue.hpp
@@ -16,6 +16,7 @@
#include
#include
#include
+#include "nonhook_node.hpp"
namespace boost{
namespace intrusive{
@@ -33,6 +34,7 @@ struct testvalue
{
typename Hooks::member_hook_type node_;
typename Hooks::auto_member_hook_type auto_node_;
+ typename Hooks::nonhook_node_member_type nhn_member_;
int value_;
static const bool constant_time_size = ConstantTimeSize;
@@ -56,6 +58,7 @@ struct testvalue
Hooks::auto_base_hook_type::operator=(static_cast(src));
this->node_ = src.node_;
this->auto_node_ = src.auto_node_;
+ this->nhn_member_ = src.nhn_member_;
value_ = src.value_;
return *this;
}
@@ -66,6 +69,7 @@ struct testvalue
Hooks::auto_base_hook_type::swap_nodes(static_cast(other));
node_.swap_nodes(other.node_);
auto_node_.swap_nodes(other.auto_node_);
+ nhn_member_.swap_nodes(other.nhn_member_);
}
bool is_linked() const
@@ -73,7 +77,8 @@ struct testvalue
return Hooks::base_hook_type::is_linked() ||
Hooks::auto_base_hook_type::is_linked() ||
node_.is_linked() ||
- auto_node_.is_linked();
+ auto_node_.is_linked() ||
+ nhn_member_.is_linked();
}
~testvalue()
diff --git a/test/list_test.cpp b/test/list_test.cpp
index 54d3061..7301dcf 100644
--- a/test/list_test.cpp
+++ b/test/list_test.cpp
@@ -34,6 +34,9 @@ struct hooks
typedef list_member_hook, tag > member_hook_type;
typedef list_member_hook< link_mode
, void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< list_node_traits< VoidPointer >,
+ circular_list_algorithms
+ > nonhook_node_member_type;
};
template
@@ -436,6 +439,12 @@ class test_main_template
>
>::type
>::test_all(data);
+ test_list < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >
+ >::test_all(data);
return 0;
}
};
diff --git a/test/multiset_test.cpp b/test/multiset_test.cpp
index ba503a2..dd52cfe 100644
--- a/test/multiset_test.cpp
+++ b/test/multiset_test.cpp
@@ -54,6 +54,9 @@ struct hooks
, optimize_size > member_hook_type;
typedef set_member_hook
, void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< rbtree_node_traits ,
+ rbtree_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -95,6 +98,13 @@ class test_main_template
>::type
, GetContainer
>::test_all();
+ test::test_generic_multiset < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainer
+ >::test_all();
return 0;
}
};
diff --git a/test/nonhook_node.hpp b/test/nonhook_node.hpp
new file mode 100644
index 0000000..06ba155
--- /dev/null
+++ b/test/nonhook_node.hpp
@@ -0,0 +1,120 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Matei David 2014-2014.
+// (C) Copyright Ion Gaztanaga 2014-2014.
+//
+// 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_DETAIL_NONHOOK_NODE_HPP
+#define BOOST_INTRUSIVE_DETAIL_NONHOOK_NODE_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+
+namespace boost{
+namespace intrusive{
+
+//This node will only be used in safe or auto unlink modes
+//so test it's been properly released
+template < typename Node_Traits, template class Node_Algorithms >
+struct nonhook_node_member : public Node_Traits::node
+{
+ typedef Node_Traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef typename node_traits::const_node_ptr const_node_ptr;
+ typedef Node_Algorithms< node_traits > node_algorithms;
+
+ nonhook_node_member()
+ {
+ node_algorithms::init(pointer_traits::pointer_to(static_cast< node& >(*this)));
+ }
+
+ nonhook_node_member(const nonhook_node_member& rhs)
+ {
+ BOOST_TEST(!rhs.is_linked());
+ *this = rhs;
+ }
+
+ nonhook_node_member& operator = (const nonhook_node_member& rhs)
+ {
+ BOOST_TEST(!this->is_linked() && !rhs.is_linked());
+ static_cast< node& >(*this) = rhs;
+ return *this;
+ }
+
+ ~nonhook_node_member()
+ {
+ BOOST_TEST(!this->is_linked());
+ node_algorithms::init(pointer_traits::pointer_to(static_cast< node& >(*this)));
+ }
+
+ void swap_nodes(nonhook_node_member& other)
+ {
+ node_algorithms::swap_nodes(pointer_traits::pointer_to(static_cast< node& >(*this)),
+ pointer_traits::pointer_to(static_cast< node& >(other)));
+ }
+
+ bool is_linked() const
+ {
+ return !node_algorithms::unique(pointer_traits::pointer_to(static_cast< const node& >(*this)));
+ }
+};
+
+template < typename T, typename NonHook_Member, NonHook_Member T::* P, link_mode_type Link_Mode >
+struct nonhook_node_member_value_traits
+{
+ typedef T value_type;
+ typedef typename NonHook_Member::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef typename node_traits::const_node_ptr const_node_ptr;
+ typedef typename pointer_traits::
+ template rebind_pointer::type pointer;
+ typedef typename pointer_traits::
+ template rebind_pointer::type const_pointer;
+ typedef T & reference;
+ typedef const T & const_reference;
+
+ static const link_mode_type link_mode = Link_Mode;
+
+ BOOST_STATIC_ASSERT((Link_Mode == safe_link || Link_Mode == auto_unlink));
+
+ static node_ptr to_node_ptr(reference value)
+ {
+ return pointer_traits::pointer_to(static_cast(value.*P));
+ }
+
+ static const_node_ptr to_node_ptr(const_reference value)
+ {
+ return pointer_traits::pointer_to(static_cast(value.*P));
+ }
+
+ static pointer to_value_ptr(node_ptr n)
+ {
+ return pointer_traits::pointer_to
+ (*detail::parent_from_member
+ (static_cast(boost::intrusive::detail::to_raw_pointer(n)), P));
+ }
+
+ static const_pointer to_value_ptr(const_node_ptr n)
+ {
+ return pointer_traits::pointer_to
+ (*detail::parent_from_member
+ (static_cast(boost::intrusive::detail::to_raw_pointer(n)), P));
+ }
+};
+
+}
+}
+
+#endif
diff --git a/test/set_test.cpp b/test/set_test.cpp
index 4e4e91d..8d5c490 100644
--- a/test/set_test.cpp
+++ b/test/set_test.cpp
@@ -55,6 +55,9 @@ struct hooks
, optimize_size > member_hook_type;
typedef set_member_hook
, void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< rbtree_node_traits ,
+ rbtree_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -96,6 +99,13 @@ class test_main_template
>::type
, GetContainer
>::test_all();
+ test::test_generic_set < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainer
+ >::test_all();
return 0;
}
};
diff --git a/test/sg_multiset_test.cpp b/test/sg_multiset_test.cpp
index 5accea7..4eee56c 100644
--- a/test/sg_multiset_test.cpp
+++ b/test/sg_multiset_test.cpp
@@ -66,6 +66,9 @@ struct hooks
struct auto_base_hook_type
: bs_set_base_hook, tag >
{};
+ typedef nonhook_node_member< tree_node_traits < VoidPointer >,
+ sgtree_algorithms
+ > nonhook_node_member_type;
};
@@ -139,6 +142,13 @@ class test_main_template
>::type
, GetContainerFixedAlpha
>::test_all();
+ test::test_generic_multiset < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainerFixedAlpha
+ >::test_all();
return 0;
}
};
diff --git a/test/sg_set_test.cpp b/test/sg_set_test.cpp
index f447425..00926e1 100644
--- a/test/sg_set_test.cpp
+++ b/test/sg_set_test.cpp
@@ -65,6 +65,9 @@ struct hooks
struct auto_base_hook_type
: bs_set_base_hook, tag >
{};
+ typedef nonhook_node_member< tree_node_traits < VoidPointer >,
+ sgtree_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -138,6 +141,13 @@ class test_main_template
>::type
, GetContainerFixedAlpha
>::test_all();
+ test::test_generic_set < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainerFixedAlpha
+ >::test_all();
return 0;
}
};
diff --git a/test/slist_test.cpp b/test/slist_test.cpp
index 0ea0c2b..cde9a31 100644
--- a/test/slist_test.cpp
+++ b/test/slist_test.cpp
@@ -35,6 +35,9 @@ struct hooks
typedef slist_member_hook, tag > member_hook_type;
typedef slist_member_hook< link_mode
, void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< slist_node_traits< VoidPointer >,
+ circular_slist_algorithms
+ > nonhook_node_member_type;
};
template
@@ -564,6 +567,14 @@ class test_main_template
, false
, false
>::test_all(data);
+ test_slist < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ false,
+ false
+ >::test_all(data);
//Now linear slists
test_slist < typename detail::get_base_value_traits
diff --git a/test/splay_multiset_test.cpp b/test/splay_multiset_test.cpp
index 7a21f07..c22706e 100644
--- a/test/splay_multiset_test.cpp
+++ b/test/splay_multiset_test.cpp
@@ -86,6 +86,9 @@ struct hooks
typedef bs_set_member_hook
< link_mode
, void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< tree_node_traits< VoidPointer >,
+ splaytree_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -127,6 +130,14 @@ class test_main_template
>::type
, GetContainer
>::test_all();
+ test::test_generic_multiset < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainer
+ >::test_all();
+
return 0;
}
};
diff --git a/test/splay_set_test.cpp b/test/splay_set_test.cpp
index 8e62f2c..7fc3fce 100644
--- a/test/splay_set_test.cpp
+++ b/test/splay_set_test.cpp
@@ -83,6 +83,9 @@ struct hooks
typedef bs_set_member_hook
< link_mode
, void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< tree_node_traits< VoidPointer >,
+ splaytree_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -124,6 +127,13 @@ class test_main_template
>::type
, GetContainer
>::test_all();
+ test::test_generic_set < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainer
+ >::test_all();
return 0;
}
};
diff --git a/test/treap_multiset_test.cpp b/test/treap_multiset_test.cpp
index 1982397..7918082 100644
--- a/test/treap_multiset_test.cpp
+++ b/test/treap_multiset_test.cpp
@@ -52,6 +52,9 @@ struct hooks
< void_pointer > member_hook_type;
typedef bs_set_member_hook
< void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< tree_node_traits< VoidPointer >,
+ treap_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -93,6 +96,13 @@ class test_main_template
>::type
, GetContainer
>::test_all();
+ test::test_generic_multiset < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainer
+ >::test_all();
return 0;
}
};
diff --git a/test/treap_set_test.cpp b/test/treap_set_test.cpp
index f0deb47..8d1cd49 100644
--- a/test/treap_set_test.cpp
+++ b/test/treap_set_test.cpp
@@ -67,6 +67,9 @@ struct hooks
< void_pointer > member_hook_type;
typedef bs_set_member_hook
< void_pointer > auto_member_hook_type;
+ typedef nonhook_node_member< tree_node_traits< VoidPointer >,
+ treap_algorithms
+ > nonhook_node_member_type;
};
template< class ValueType
@@ -108,6 +111,13 @@ class test_main_template
>::type
, GetContainer
>::test_all();
+ test::test_generic_set < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ GetContainer
+ >::test_all();
return 0;
}
};
diff --git a/test/unordered_multiset_test.cpp b/test/unordered_multiset_test.cpp
index a4da129..f0e8373 100644
--- a/test/unordered_multiset_test.cpp
+++ b/test/unordered_multiset_test.cpp
@@ -67,6 +67,9 @@ struct hooks
, store_hash
, optimize_multikey
> auto_member_hook_type;
+ typedef nonhook_node_member< unordered_node_traits< VoidPointer, true, true >,
+ unordered_algorithms
+ > nonhook_node_member_type;
};
static const std::size_t BucketSize = 8;
@@ -805,6 +808,15 @@ class test_main_template
, false
, Incremental
>::test_all(data);
+ test_unordered_multiset < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ false,
+ false,
+ Incremental
+ >::test_all(data);
return 0;
}
};
diff --git a/test/unordered_set_test.cpp b/test/unordered_set_test.cpp
index 4555405..0a60c5f 100644
--- a/test/unordered_set_test.cpp
+++ b/test/unordered_set_test.cpp
@@ -66,6 +66,9 @@ struct hooks
, store_hash
, optimize_multikey
> auto_member_hook_type;
+ typedef nonhook_node_member< unordered_node_traits< VoidPointer, true, true >,
+ unordered_algorithms
+ > nonhook_node_member_type;
};
static const std::size_t BucketSize = 8;
@@ -657,6 +660,15 @@ class test_main_template
, false
, incremental
>::test_all(data);
+ test_unordered_set < nonhook_node_member_value_traits< value_type,
+ typename hooks::nonhook_node_member_type,
+ &value_type::nhn_member_,
+ safe_link
+ >,
+ false,
+ false,
+ incremental
+ >::test_all(data);
return 0;
}