diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 1357b01..166b39d 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -3831,6 +3831,23 @@ all the objects to be inserted in intrusive containers in containers like `std:: [section:release_notes Release Notes] +[section:release_notes_boost_1_47_00 Boost 1.47 Release] + +* Fixed bugs + [@https://svn.boost.org/trac/boost/ticket/4797 #4797], + [@https://svn.boost.org/trac/boost/ticket/5165 #5165], + [@https://svn.boost.org/trac/boost/ticket/5183 #5183], + [@https://svn.boost.org/trac/boost/ticket/5191 #5191]. + +[endsect] + +[section:release_notes_boost_1_46_00 Boost 1.46 Release] + +* Fixed bug + [@https://svn.boost.org/trac/boost/ticket/4980 #4980], + +[endsect] + [section:release_notes_boost_1_45_00 Boost 1.45 Release] * Added `function_hook` option. diff --git a/example/doc_offset_ptr.cpp b/example/doc_offset_ptr.cpp index 064ee6e..7fb2414 100644 --- a/example/doc_offset_ptr.cpp +++ b/example/doc_offset_ptr.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2009 +// (C) Copyright Ion Gaztanaga 2006-2011 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -51,7 +51,7 @@ class shared_memory_data #include //Definition of the shared memory friendly intrusive list -typedef ip::list shm_list_t; +typedef list intrusive_list_t; int main() { @@ -80,12 +80,14 @@ int main() for(int i = 0; i < MaxElem; ++i) (*pshm_vect)[i].set(i); //Now create the shared memory intrusive list - shm_list_t *plist = shm.construct(ip::anonymous_instance)(); + intrusive_list_t *plist = shm.construct(ip::anonymous_instance)(); + + //Insert objects stored in shared memory vector in the intrusive list plist->insert(plist->end(), pshm_vect->begin(), pshm_vect->end()); //Check all the inserted nodes int checker = 0; - for( shm_list_t::const_iterator it = plist->begin(), itend(plist->end()) + for( intrusive_list_t::const_iterator it = plist->begin(), itend(plist->end()) ; it != itend; ++it, ++checker){ if(it->get() != checker) return false; } diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index d7f2673..773b3f3 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -291,18 +291,18 @@ + + + + + + - - - - - - diff --git a/proj/vc7ide/to-do.txt b/proj/vc7ide/to-do.txt index 4a5777f..c5e713d 100644 --- a/proj/vc7ide/to-do.txt +++ b/proj/vc7ide/to-do.txt @@ -15,3 +15,15 @@ -> Document incremental<> option better -> Assure stable order for optimize_multikey and inverse order otherwise -> add an option to unordered containers to get O(1) traversal and begin()/end() even with very low load factors + + +The article explains it quite well: Linear Hashing The cost of hash table expansion is spread out across each hash table insertion operation, as opposed to being incurred all at once. Linear hashing is therefore well suited for interactive applications. + +Linear hashing typically requires power of two length for bucket arrays, but those buckets are not fully used from the beginning, as it is when using non-linear hashing (which typically requires prime bucket length). Although the bucket array hash, say, has 16 buckets, the implementation uses first just one or two, then when after incremental rehashing uses three, etc.. incrementally, until it fills those 16 buckets. Then for a new incremental rehash, it allocates a new bucket array with length 32, but starts using only 17, and continues with incremental hashing. I think Dinkum STL used this incremental rehashing. The key is that in each incremental hashing, not all elements are rehashed, but just elements of a single bucket, distributing hashing impact in all allocations. + +For more information on hashing alternatives see the original standard hashing container proposal (chapter Control of Hash Resizing): + +http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1456.html + +Now, intrusive containers don't allocate memory at all, so incremental rehashing must be trigered by the user using +"incremental_rehash(bool)" (use an additional bucket, that is, incremental rehash) and "incremental_rehash(bucket_traits)" (to update the new bucket array with an array that should be twice/half the size of the previous one). I admit that this is not explained at all with an example, so I will note this issue in my to do list. diff --git a/test/test_container.hpp b/test/test_container.hpp index c900a6b..262872c 100644 --- a/test/test_container.hpp +++ b/test/test_container.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007-2009 +// (C) Copyright Ion Gaztanaga 2007-2011 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -15,6 +15,7 @@ #include #include +#include namespace boost { namespace intrusive { @@ -78,55 +79,67 @@ template< class Container, class Data > void test_sequence_container(Container & c, Data & d) { assert( d.size() > 2 ); - - c.clear(); - - BOOST_TEST( c.size() == 0 ); - BOOST_TEST( c.empty() ); - - { - typename Data::iterator i = d.begin(); - c.insert( c.begin(), *i ); - c.insert( c.end(), *(++i) ); + c.clear(); + + BOOST_TEST( c.size() == 0 ); + BOOST_TEST( c.empty() ); + + + { + typename Data::iterator i = d.begin(); + c.insert( c.begin(), *i ); + c.insert( c.end(), *(++i) ); + } + + BOOST_TEST( c.size() == 2 ); + BOOST_TEST( !c.empty() ); + + typename Container::iterator i; + i = c.erase( c.begin() ); + + BOOST_TEST( c.size() == 1 ); + + { + typename Data::iterator i = d.begin(); + ++++i; + c.insert( c.begin(), *(i) ); + } + + i = c.erase( c.begin(), c.end() ); + BOOST_TEST( i == c.end() ); + + BOOST_TEST( c.empty() ); + + c.insert( c.begin(), *d.begin() ); + + BOOST_TEST( c.size() == 1 ); + + BOOST_TEST( c.begin() != c.end() ); + + i = c.erase_and_dispose( c.begin(), detail::null_disposer() ); + BOOST_TEST( i == c.begin() ); + + c.assign(d.begin(), d.end()); + + BOOST_TEST( c.size() == d.size() ); + + c.clear(); + + BOOST_TEST( c.size() == 0 ); + BOOST_TEST( c.empty() ); } - - BOOST_TEST( c.size() == 2 ); - BOOST_TEST( !c.empty() ); - - typename Container::iterator i; - i = c.erase( c.begin() ); - - BOOST_TEST( c.size() == 1 ); - { - typename Data::iterator i = d.begin(); - ++++i; - c.insert( c.begin(), *(i) ); + c.clear(); + c.insert( c.begin(), d.begin(), d.end() ); + Container move_c(::boost::move(c)); + BOOST_TEST( move_c.size() == d.size() ); + BOOST_TEST( c.empty()); + + c = ::boost::move(move_c); + BOOST_TEST( c.size() == d.size() ); + BOOST_TEST( move_c.empty()); } - - i = c.erase( c.begin(), c.end() ); - BOOST_TEST( i == c.end() ); - - BOOST_TEST( c.empty() ); - - c.insert( c.begin(), *d.begin() ); - - BOOST_TEST( c.size() == 1 ); - - BOOST_TEST( c.begin() != c.end() ); - - i = c.erase_and_dispose( c.begin(), detail::null_disposer() ); - BOOST_TEST( i == c.begin() ); - - c.assign(d.begin(), d.end()); - - BOOST_TEST( c.size() == d.size() ); - - c.clear(); - - BOOST_TEST( c.size() == 0 ); - BOOST_TEST( c.empty() ); } template< class Container, class Data > @@ -212,42 +225,55 @@ void test_common_unordered_and_associative_container(Container & c, Data & d, bo template< class Container, class Data > void test_common_unordered_and_associative_container(Container & c, Data & d) { - { typedef typename Container::size_type size_type; - - assert( d.size() > 2 ); - - c.clear(); - c.insert(d.begin(), d.end()); - - for( typename Data::const_iterator di = d.begin(), de = d.end(); - di != de; ++di ) { - BOOST_TEST( c.find(*di) != c.end() ); + assert( d.size() > 2 ); + + c.clear(); + c.insert(d.begin(), d.end()); + + for( typename Data::const_iterator di = d.begin(), de = d.end(); + di != de; ++di ) + { + BOOST_TEST( c.find(*di) != c.end() ); + } + + typename Data::const_iterator db = d.begin(); + typename Data::const_iterator da = db++; + + size_type old_size = c.size(); + + c.erase(*da); + BOOST_TEST( c.size() == old_size-1 ); + //This should erase nothing + size_type second_erase = c.erase_and_dispose( *da, detail::null_disposer() ); + BOOST_TEST( second_erase == 0 ); + + BOOST_TEST( c.count(*da) == 0 ); + BOOST_TEST( c.count(*db) != 0 ); + + BOOST_TEST( c.find(*da) == c.end() ); + BOOST_TEST( c.find(*db) != c.end() ); + + BOOST_TEST( c.equal_range(*db).first != c.end() ); + BOOST_TEST( c.equal_range(*da).first == c.equal_range(*da).second ); } + { + c.clear(); + c.insert( d.begin(), d.end() ); + size_type orig_size = c.size(); + Container move_c(::boost::move(c)); + BOOST_TEST(orig_size == move_c.size()); + BOOST_TEST( c.empty()); + for( typename Data::const_iterator di = d.begin(), de = d.end(); + di != de; ++di ) + { BOOST_TEST( move_c.find(*di) != move_c.end() ); } - typename Data::const_iterator db = d.begin(); - typename Data::const_iterator da = db++; - - size_type old_size = c.size(); - - c.erase(*da); - BOOST_TEST( c.size() == old_size-1 ); - //This should not eras anyone - size_type second_erase = c.erase_and_dispose( *da, detail::null_disposer() ); - BOOST_TEST( second_erase == 0 ); - - BOOST_TEST( c.count(*da) == 0 ); - BOOST_TEST( c.count(*db) != 0 ); - - BOOST_TEST( c.find(*da) == c.end() ); - BOOST_TEST( c.find(*db) != c.end() ); - - BOOST_TEST( c.equal_range(*db).first != c.end() ); - - c.clear(); - - BOOST_TEST( c.equal_range(*da).first == c.end() ); + c = ::boost::move(move_c); + for( typename Data::const_iterator di = d.begin(), de = d.end(); + di != de; ++di ) + { BOOST_TEST( c.find(*di) != c.end() ); } + BOOST_TEST( move_c.empty()); } typedef detail::bool_::value> enabler; test_common_unordered_and_associative_container(c, d, enabler());