From b6f688321c11c99ba78ffe108ade2e92eec3f2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 7 Sep 2017 20:16:48 +0200 Subject: [PATCH 1/6] Fix outdated limitations in std containers. --- doc/intrusive.qbk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index a83c203..1b197a3 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -144,9 +144,11 @@ A non-intrusive container has some limitations: a size overhead for each allocation to store bookkeeping information and a synchronization to protected concurrent allocation from different threads. -* Only copies of objects are stored in non-intrusive containers. Hence copy - or move constructors and copy or move assignment operators are required. Non-copyable - and non-movable objects can't be stored in non-intrusive containers. +* Before C++11, only copies of objects could be stored in non-intrusive containers. Still + copy or move constructors and copy or move assignment operators are required + and non-copyable and non-movable objects can't be stored in some containers. In any case, + [*new] objects have to be created inside the container using constructors and the same + object can't be shared between two containers. * It's not possible to store a derived object in a STL-container while retaining its original type. @@ -156,6 +158,9 @@ Intrusive containers have some important advantages: * Operating with intrusive containers doesn't invoke any memory management at all. The time and size overhead associated with dynamic memory can be minimized. +* The same object can be inserted in more than one container at the same time with + a tiny overhead in the object size. + * Iterating an Intrusive container needs less memory accesses than the semantically equivalent container of pointers: iteration is faster. @@ -208,7 +213,7 @@ Intrusive containers have also downsides: [[Memory management] [External] [Internal through allocator]] [[Insertion/Erasure time] [Faster] [Slower]] [[Memory locality] [Better] [Worse]] - [[Can hold non-copyable and non-movable objects by value] [Yes] [No]] + [[Can insert the same object in more than one container] [Yes] [No]] [[Exception guarantees] [Better] [Worse]] [[Computation of iterator from value] [Constant] [Non-constant]] [[Insertion/erasure predictability] [High] [Low]] From 7f5caca12eac63ce3381493f3f8a861c35b03076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 7 Sep 2017 20:17:05 +0200 Subject: [PATCH 2/6] Extract BOOST_INTRUSIVE_HAS_TYPE trait --- include/boost/intrusive/detail/mpl.hpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/include/boost/intrusive/detail/mpl.hpp b/include/boost/intrusive/detail/mpl.hpp index 8d227a1..1523088 100644 --- a/include/boost/intrusive/detail/mpl.hpp +++ b/include/boost/intrusive/detail/mpl.hpp @@ -86,8 +86,8 @@ struct ls_zeros<1> // Infrastructure for providing a default type for T::TNAME if absent. #define BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(TNAME) \ - template \ - struct boost_intrusive_default_type_ ## TNAME \ + template \ + struct boost_intrusive_has_type_ ## TNAME \ { \ template \ static char test(int, typename X::TNAME*); \ @@ -95,13 +95,18 @@ struct ls_zeros<1> template \ static int test(...); \ \ - struct DefaultWrap { typedef DefaultType TNAME; }; \ - \ static const bool value = (1 == sizeof(test(0, 0))); \ + }; \ + \ + template \ + struct boost_intrusive_default_type_ ## TNAME \ + { \ + struct DefaultWrap { typedef DefaultType TNAME; }; \ \ typedef typename \ ::boost::intrusive::detail::if_c \ - ::type::TNAME type; \ + < boost_intrusive_has_type_ ## TNAME::value \ + , T, DefaultWrap>::type::TNAME type; \ }; \ // @@ -110,6 +115,11 @@ struct ls_zeros<1> boost_intrusive_default_type_ ## TNAME< T, TIMPL >::type \ // +#define BOOST_INTRUSIVE_HAS_TYPE(INSTANTIATION_NS_PREFIX, T, TNAME) \ + INSTANTIATION_NS_PREFIX \ + boost_intrusive_has_type_ ## TNAME< T >::value \ +// + #define BOOST_INTRUSIVE_INSTANTIATE_EVAL_DEFAULT_TYPE_TMPLT(TNAME)\ template \ struct boost_intrusive_eval_default_type_ ## TNAME \ From 972e9871ba1ad74b3579ca9d41a9d6348b7d776a Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 11 Oct 2017 11:33:09 +0900 Subject: [PATCH 3/6] Fix typo in documentation for the Node Algorithm concept --- doc/intrusive.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 1b197a3..fbd6a93 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -2424,7 +2424,7 @@ This section will expand the explanation of previously presented basic concepts before explaining the customization options of [*Boost.Intrusive]. * [*Node Algorithms]: A set of static functions that implement basic operations - on a group of nodes: initialize a node, link_mode_type a node to a group of nodes, + on a group of nodes: initialize a node, link a node to a group of nodes, unlink a node from another group of nodes, etc. For example, a circular singly linked list is a group of nodes, where each node has a pointer to the next node. [*Node Algorithms] just require a [*NodeTraits] From a10de1bd6088b90efe9147ce6b489e3818e33d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 14 Oct 2017 12:06:21 +0200 Subject: [PATCH 4/6] Closes #25 in GitHub ("Document the behavior of move constructor for slist") --- include/boost/intrusive/bstree.hpp | 11 +++++++++-- include/boost/intrusive/hashtable.hpp | 11 +++++++++-- include/boost/intrusive/list.hpp | 11 +++++++++-- include/boost/intrusive/slist.hpp | 11 +++++++++-- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/include/boost/intrusive/bstree.hpp b/include/boost/intrusive/bstree.hpp index ac67e86..410eedf 100644 --- a/include/boost/intrusive/bstree.hpp +++ b/include/boost/intrusive/bstree.hpp @@ -725,15 +725,22 @@ class bstree_impl this->insert_equal(b, e); } - //! Effects: to-do + //! Effects: Constructs a container moving resources from another container. + //! Internal comparison object and value traits are move constructed and + //! nodes belonging to x (except the node representing the "end") are linked to *this. //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node's + //! move constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the move constructor of the comparison objet throws. bstree_impl(BOOST_RV_REF(bstree_impl) x) : data_type(::boost::move(x.comp()), ::boost::move(x.get_value_traits())) { this->swap(x); } - //! Effects: to-do + //! Effects: Equivalent to swap //! BOOST_INTRUSIVE_FORCEINLINE bstree_impl& operator=(BOOST_RV_REF(bstree_impl) x) { this->swap(x); return *this; } diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index bae9d52..35ba774 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -1798,8 +1798,15 @@ class hashtable_impl this->insert_equal(b, e); } - //! Effects: to-do + //! Effects: Constructs a container moving resources from another container. + //! Internal value traits, bucket traits, hasher and comparison are move constructed and + //! nodes belonging to x are linked to *this. //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node's + //! move constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the move constructor of value traits, bucket traits, hasher or comparison throws. hashtable_impl(BOOST_RV_REF(hashtable_impl) x) : internal_type( ::boost::move(x.priv_value_traits()) , ::boost::move(x.priv_bucket_traits()) @@ -1815,7 +1822,7 @@ class hashtable_impl x.priv_split_traits().set_size(size_type(0)); } - //! Effects: to-do + //! Effects: Equivalnet to swap. //! hashtable_impl& operator=(BOOST_RV_REF(hashtable_impl) x) { this->swap(x); return *this; } diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index a955c44..71eac5c 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -215,8 +215,15 @@ class list_impl this->insert(this->cend(), b, e); } - //! Effects: to-do + //! Effects: Constructs a container moving resources from another container. + //! Internal value traits are move constructed and + //! nodes belonging to x (except the node representing the "end") are linked to *this. //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node's + //! move constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the move constructor of value traits throws. list_impl(BOOST_RV_REF(list_impl) x) : data_(::boost::move(x.priv_value_traits())) { @@ -226,7 +233,7 @@ class list_impl this->swap(x); } - //! Effects: to-do + //! Effects: Equivalent to swap //! list_impl& operator=(BOOST_RV_REF(list_impl) x) { this->swap(x); return *this; } diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index f34350d..1f7ace1 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -338,8 +338,15 @@ class slist_impl this->insert_after(this->cbefore_begin(), b, e); } - //! Effects: to-do + //! Effects: Constructs a container moving resources from another container. + //! Internal value traits are move constructed and + //! nodes belonging to x (except the node representing the "end") are linked to *this. //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node's + //! move constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the move constructor of value traits throws. slist_impl(BOOST_RV_REF(slist_impl) x) : data_(::boost::move(x.priv_value_traits())) { @@ -348,7 +355,7 @@ class slist_impl this->swap(x); } - //! Effects: to-do + //! Effects: Equivalent to swap //! slist_impl& operator=(BOOST_RV_REF(slist_impl) x) { this->swap(x); return *this; } From 80c22df9dcc496a2d4e3d22e8284525366a0941d Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 16 Oct 2017 09:18:13 +0900 Subject: [PATCH 5/6] [hashtable] Fix typo in documentation --- include/boost/intrusive/hashtable.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index 35ba774..6b1d5dd 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -1822,7 +1822,7 @@ class hashtable_impl x.priv_split_traits().set_size(size_type(0)); } - //! Effects: Equivalnet to swap. + //! Effects: Equivalent to swap. //! hashtable_impl& operator=(BOOST_RV_REF(hashtable_impl) x) { this->swap(x); return *this; } From f4047cd759fcfa20bce3b7d2e383676c2707a416 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Tue, 31 Oct 2017 15:54:01 +0100 Subject: [PATCH 6/6] fix null_node construction form default ctor - NVCC fails parsing null_node((node_ptr())) --- include/boost/intrusive/circular_list_algorithms.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/intrusive/circular_list_algorithms.hpp b/include/boost/intrusive/circular_list_algorithms.hpp index 72eae32..0bc4d9d 100644 --- a/include/boost/intrusive/circular_list_algorithms.hpp +++ b/include/boost/intrusive/circular_list_algorithms.hpp @@ -69,7 +69,7 @@ class circular_list_algorithms //! Throws: Nothing. BOOST_INTRUSIVE_FORCEINLINE static void init(const node_ptr &this_node) { - const node_ptr null_node((node_ptr())); + const node_ptr null_node = node_ptr(); NodeTraits::set_next(this_node, null_node); NodeTraits::set_previous(this_node, null_node); }