diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 4d47228..516b044 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -3792,13 +3792,15 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std * [*Source breaking]: Removed previously deprecated `xxx_dont_splay` functions from splay containers, `splay_set_base_hook` and `splay_set_member_hook`from splay containers and `bool splay = true` - extra parameter is `splaytree_algorithms` functions. + extra parameter in `splaytree_algorithms` functions. * Fixed bugs: * [@https://svn.boost.org/trac/boost/ticket/8468 #8468: Compile error on visual studio 2010/2012 using vector with custom allocator and aligned types] * [@https://svn.boost.org/trac/boost/ticket/9332 #9332: ['"has_member_function_callable_with.hpp compile error on msvc-12.0"]]. + * [@https://svn.boost.org/trac/boost/ticket/9650 #9650: ['"intrusive list with stateful value traits"]]. * [@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/9948 #9948: remove use of const_cast in intrusive containers] * [@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] diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index ad3366a..ac3c566 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -1103,6 +1103,13 @@ class hashtable_impl typedef typename pointer_traits ::template rebind_pointer < bucket_type >::type bucket_ptr; + typedef typename pointer_traits + ::template rebind_pointer + < const bucket_type >::type const_bucket_ptr; + typedef typename pointer_traits + ::reference bucket_reference; + typedef typename pointer_traits + ::reference const_bucket_reference; typedef typename slist_impl::iterator siterator; typedef typename slist_impl::const_iterator const_siterator; typedef hashtable_iterator iterator; @@ -1115,6 +1122,10 @@ class hashtable_impl typedef typename pointer_traits ::template rebind_pointer < const node >::type const_node_ptr; + typedef typename pointer_traits + ::reference node_reference; + typedef typename pointer_traits + ::reference const_node_reference; typedef typename slist_impl::node_algorithms node_algorithms; static const bool stateful_value_traits = detail::is_stateful_value_traits::value; @@ -2145,7 +2156,9 @@ class hashtable_impl //! Throws: If the internal hash function throws. const_iterator iterator_to(const_reference value) const { - siterator sit = bucket_type::s_iterator_to(const_cast(this->priv_value_to_node(value))); + node_reference r = *pointer_traits::const_cast_from + (pointer_traits::pointer_to(this->priv_value_to_node(value))); + siterator sit = bucket_type::s_iterator_to(r); return const_iterator(sit, &this->get_bucket_value_traits()); } @@ -2183,7 +2196,9 @@ class hashtable_impl static const_local_iterator s_local_iterator_to(const_reference value) { BOOST_STATIC_ASSERT((!stateful_value_traits)); - siterator sit = bucket_type::s_iterator_to(((hashtable_impl*)0)->priv_value_to_node(const_cast(value))); + node_reference r = *pointer_traits::const_cast_from + (pointer_traits::pointer_to(((hashtable_impl*)0)->priv_value_to_node(value))); + siterator sit = bucket_type::s_iterator_to(r); return const_local_iterator(sit, const_value_traits_ptr()); } @@ -2213,8 +2228,9 @@ class hashtable_impl //! Throws: Nothing. const_local_iterator local_iterator_to(const_reference value) const { - siterator sit = bucket_type::s_iterator_to - (const_cast(this->priv_value_to_node(value))); + node_reference r = *pointer_traits::const_cast_from + (pointer_traits::pointer_to(this->priv_value_to_node(value))); + siterator sit = bucket_type::s_iterator_to(r); return const_local_iterator(sit, this->value_traits_ptr()); } @@ -2314,8 +2330,8 @@ class hashtable_impl //! containing all of the elements in the nth bucket. const_local_iterator cbegin(size_type n) const { - siterator sit = const_cast(this->priv_bucket_pointer()[n]).begin(); - return const_local_iterator(sit, this->value_traits_ptr()); + bucket_reference br = pointer_traits::const_cast_from(this->priv_bucket_pointer())[n]; + return const_local_iterator(br.begin(), this->value_traits_ptr()); } //! Requires: n is in the range [0, this->bucket_count()). @@ -2359,8 +2375,8 @@ class hashtable_impl //! containing all of the elements in the nth bucket. const_local_iterator cend(size_type n) const { - return const_local_iterator ( const_cast(this->priv_bucket_pointer()[n]).end() - , this->value_traits_ptr()); + bucket_reference br = pointer_traits::const_cast_from(this->priv_bucket_pointer())[n]; + return const_local_iterator ( br.end(), this->value_traits_ptr()); } //! Requires: new_bucket_traits can hold a pointer to a new bucket array diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index c9fdf58..36c29e7 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -1213,8 +1213,9 @@ class list_impl static const_iterator s_iterator_to(const_reference value) { BOOST_STATIC_ASSERT((!stateful_value_traits)); - BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::inited(value_traits::to_node_ptr(*pointer_traits::const_cast_from(pointer_traits::pointer_to(value))))); - return const_iterator(value_traits::to_node_ptr(*pointer_traits::const_cast_from(pointer_traits::pointer_to(value))), const_value_traits_ptr()); + reference r =*pointer_traits::const_cast_from(pointer_traits::pointer_to(value)); + BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::inited(value_traits::to_node_ptr(r))); + return const_iterator(value_traits::to_node_ptr(r), const_value_traits_ptr()); } //! Requires: value must be a reference to a value inserted in a list. @@ -1243,8 +1244,9 @@ class list_impl //! Note: Iterators and references are not invalidated. const_iterator iterator_to(const_reference value) const { - BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::inited(this->priv_value_traits().to_node_ptr(*pointer_traits::const_cast_from(pointer_traits::pointer_to(value))))); - return const_iterator(this->priv_value_traits().to_node_ptr(*pointer_traits::const_cast_from(pointer_traits::pointer_to(value))), value_traits_ptr()); + reference r = *pointer_traits::const_cast_from(pointer_traits::pointer_to(value)); + BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::inited(this->priv_value_traits().to_node_ptr(r))); + return const_iterator(this->priv_value_traits().to_node_ptr(r), value_traits_ptr()); } /// @cond diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index 6882ad2..a50838a 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -1685,7 +1685,8 @@ class slist_impl static const_iterator s_iterator_to(const_reference value) { BOOST_STATIC_ASSERT((!stateful_value_traits)); - return const_iterator(value_traits::to_node_ptr(*pointer_traits::const_cast_from(pointer_traits::pointer_to(value))), const_value_traits_ptr()); + reference r =*pointer_traits::const_cast_from(pointer_traits::pointer_to(value)); + return const_iterator(value_traits::to_node_ptr(r), const_value_traits_ptr()); } //! Requires: value must be a reference to a value inserted in a list. @@ -1714,8 +1715,9 @@ class slist_impl //! Note: Iterators and references are not invalidated. const_iterator iterator_to(const_reference value) const { - BOOST_INTRUSIVE_INVARIANT_ASSERT (linear || !node_algorithms::inited(this->priv_value_traits().to_node_ptr(*pointer_traits::const_cast_from(pointer_traits::pointer_to(value))))); - return const_iterator(this->priv_value_traits().to_node_ptr(*pointer_traits::const_cast_from(pointer_traits::pointer_to(value))), this->value_traits_ptr()); + reference r =*pointer_traits::const_cast_from(pointer_traits::pointer_to(value)); + BOOST_INTRUSIVE_INVARIANT_ASSERT (linear || !node_algorithms::inited(this->priv_value_traits().to_node_ptr(r))); + return const_iterator(this->priv_value_traits().to_node_ptr(r), this->value_traits_ptr()); } //! Returns: The iterator to the element before i in the list. diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index cfa6a7a..41c94b2 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -232,9 +232,6 @@ - - diff --git a/test/test_container.hpp b/test/test_container.hpp index f73e91b..2bacb16 100644 --- a/test/test_container.hpp +++ b/test/test_container.hpp @@ -90,6 +90,10 @@ void test_sequence_container(Container & c, Data & d) { typename Data::iterator i = d.begin(); c.insert( c.begin(), *i ); + BOOST_TEST( &*c.iterator_to(*c.begin()) == &*i ); + BOOST_TEST( &*c.iterator_to(*c.cbegin()) == &*i ); + BOOST_TEST( &*Container::s_iterator_to(*c.begin()) == &*i ); + BOOST_TEST( &*Container::s_iterator_to(*c.cbegin()) == &*i ); c.insert( c.end(), *(++i) ); } BOOST_TEST( c.size() == 2 ); @@ -230,6 +234,12 @@ void test_common_unordered_and_associative_container(Container & c, Data & d, bo assert( d.size() > 2 ); + c.clear(); + typename Container::reference r = *d.begin(); + c.insert(d.begin(), ++d.begin()); + BOOST_TEST( &*Container::s_iterator_to(*c.begin()) == &r ); + BOOST_TEST( &*Container::s_iterator_to(*c.cbegin()) == &r ); + c.clear(); c.insert(d.begin(), d.end()); @@ -259,7 +269,6 @@ void test_common_unordered_and_associative_container(Container & c, Data & d, bo BOOST_TEST( c.equal_range(*da, c.key_comp()).first == c.end() ); } - template< class Container, class Data > void test_common_unordered_and_associative_container(Container & c, Data & d) { @@ -267,6 +276,12 @@ void test_common_unordered_and_associative_container(Container & c, Data & d) { assert( d.size() > 2 ); + c.clear(); + typename Container::reference r = *d.begin(); + c.insert(d.begin(), ++d.begin()); + BOOST_TEST( &*c.iterator_to(*c.begin()) == &r ); + BOOST_TEST( &*c.iterator_to(*c.cbegin()) == &r ); + c.clear(); c.insert(d.begin(), d.end()); @@ -372,6 +387,9 @@ void test_unordered_associative_container_invariants(Container & c, Data & d) size_type bucket_elem = std::distance(c.begin(nb), c.end(nb)); BOOST_TEST( bucket_elem == c.bucket_size(nb) ); BOOST_TEST( &*c.local_iterator_to(*c.find(*di)) == &*i ); + BOOST_TEST( &*c.local_iterator_to(*const_cast(c).find(*di)) == &*i ); + BOOST_TEST( &*Container::s_local_iterator_to(*c.find(*di)) == &*i ); + BOOST_TEST( &*Container::s_local_iterator_to(*const_cast(c).find(*di)) == &*i ); std::pair er = c.equal_range(*di); size_type cnt = std::distance(er.first, er.second); BOOST_TEST( cnt == c.count(*di));