From 1ca8dabff8072a71140286786a6166586a9fe934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 22 Jul 2007 14:19:19 +0000 Subject: [PATCH] New Intrusive version [SVN r38273] --- doc/Jamfile.v2 | 14 +- doc/intrusive.qbk | 109 ++++- example/doc_advanced_value_traits2.cpp | 95 +++++ example/doc_offset_ptr.cpp | 2 +- example/doc_value_traits.cpp | 1 + .../vc7ide/_intrusivelib/_intrusivelib.vcproj | 17 +- proj/vc7ide/list/list.vcproj | 2 + proj/vc7ide/multiset/multiset.vcproj | 264 ++++++------ proj/vc7ide/set/set.vcproj | 264 ++++++------ proj/vc7ide/slist/slist.vcproj | 264 ++++++------ .../unordered_multiset.vcproj | 2 + .../vc7ide/unordered_set/unordered_set.vcproj | 264 ++++++------ test/list_test.cpp | 20 +- test/multiset_test.cpp | 19 + test/set_test.cpp | 19 + test/slist_test.cpp | 12 + test/test_container.hpp | 384 ++++++++++-------- test/test_intrusive_associative_container.hpp | 0 test/test_intrusive_sequence_container.hpp | 0 test/test_intrusive_unordered_container.hpp | 0 test/unordered_multiset_test.cpp | 22 + test/unordered_set_test.cpp | 22 + 22 files changed, 1061 insertions(+), 735 deletions(-) create mode 100644 example/doc_advanced_value_traits2.cpp create mode 100644 test/test_intrusive_associative_container.hpp create mode 100644 test/test_intrusive_sequence_container.hpp create mode 100644 test/test_intrusive_unordered_container.hpp diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index ab523ad..ce5b6c6 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -8,12 +8,10 @@ # See http://www.boost.org/libs/intrusive for documentation. -project boost/intrusive/doc ; - -import boostbook : boostbook ; +import doxygen ; import quickbook ; -doxygen intrusive_doxygen +doxygen autodoc : [ glob ../../../boost/intrusive/*.hpp ] : @@ -26,15 +24,15 @@ doxygen intrusive_doxygen SEARCH_INCLUDES=YES ; -xml intrusive_xml : intrusive.qbk ; +xml intrusive : intrusive.qbk ; -boostbook intrusive +boostbook standalone : - intrusive_xml - intrusive_doxygen + intrusive : boost.root=../../../.. boost.libraries=../../../../libs/libraries.htm generate.section.toc.level=3 chunk.first.sections=1 + autodoc ; diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 2165789..c50fbf4 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -1,8 +1,16 @@ +[/ + / Copyright (c) 2007 Ion Gaztanaga + / + / 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) + /] + [library Boost.Intrusive [quickbook 1.3] - [version 2007-06-23] [authors [Krzikalla, Olaf], [Gaztañaga, Ion]] [copyright 2005 Olaf Krzikalla, 2006-2007 Ion Gaztañaga] + [id intrusive] + [dirname intrusive] [purpose Intrusive containers] [license Distributed under the Boost Software License, Version 1.0. @@ -17,7 +25,7 @@ [*Boost.Intrusive] is a library presenting some intrusive containers to the world of C++. Intrusive containers are special containers -that offer [link boost_intrusive.performance better performance] +that offer [link intrusive.performance better performance] and exception safety guarantees than non-intrusive containers (like STL containers). The performance benefits of intrusive containers makes them ideal as a building @@ -190,7 +198,7 @@ Intrusive containers have also downsides: swapping can be used to implement move-capabilities. To ease the implementation of copy constructors and assignment operators of classes storing [*Boost.Intrusive] containers, [*Boost.Intrusive] offers special cloning functions. See - [link boost_intrusive.clone_from Cloning [*Boost.Intrusive] containers] section for more information. + [link intrusive.clone_from Cloning [*Boost.Intrusive] containers] section for more information. * Analyzing thread-safety of a program that uses containers is harder with intrusive containers, becuase the container might be modified indirectly without an explicitly call to a container member. @@ -214,7 +222,7 @@ Intrusive containers have also downsides: ] For a performance comparison between Intrusive and Non-intrusive containers see -[link boost_intrusive.performance Performance] section. +[link intrusive.performance Performance] section. [endsect] @@ -259,11 +267,11 @@ three template arguments: * The second template argument controls the linking policy. [*Boost.Intrusive] currently supports 3 policies: `normal_link`, `safe_link`, `auto_unlink`. More about these in the sections - [link boost_intrusive.safe_hook Safe hooks] and [link boost_intrusive.auto_unlink_hooks Auto-unlink hooks] + [link intrusive.safe_hook Safe hooks] and [link intrusive.auto_unlink_hooks Auto-unlink hooks] * The third template argument is the pointer type to be used internally in the hook. The default value is `void *`, which means that raw pointers will be used in the hook. - More about this in the section titled [link boost_intrusive.using_smart_pointers Using smart pointers with Boost.Intrusive containers] + More about this in the section titled [link intrusive.using_smart_pointers Using smart pointers with Boost.Intrusive containers] Example: @@ -591,13 +599,13 @@ the user. See [@http://www.boost.org/libs/utility/assert.html] for more information about `BOOST_ASSERT`. `BOOST_ASSERT` is globally configured for all the libraries, so the user might -want to redefine safe-mode assertions without modifying `BOOST_ASSERT`. This can -be achieved redefining the following macros: +want to redefine intrusive safe-mode assertions without modifying the global +`BOOST_ASSERT`. This can be achieved redefining the following macros: -* `BOOST_INTRUSIVE_SAFE_MODE_CONTAINER_INSERTION_ASSERT`: This assertion will be +* `BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT`: This assertion will be used in insertion functions of the intrusive containers to check that the hook of the value to be inserted is default constructed. -* `BOOST_INTRUSIVE_SAFE_MODE_HOOK_DESTRUCTOR_ASSERT`: This assertion will be +* `BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT`: This assertion will be used in hooks' destructors to check that the hook is in a default state. If any of these macros is not redefined, it will be defaulted to `BOOST_ASSERT`. @@ -620,7 +628,7 @@ If any of these macros is not redefined, it will be defaulted to `BOOST_ASSERT`. These hooks have exactly the same size overhead as their analogue non auto-unlinking hooks, but they have a restriction: they can only be used with -[link boost_intrusive.presenting_containers non-constant time containers]. +[link intrusive.presenting_containers non-constant time containers]. There is a reason for this: * Auto-unlink hooks don't store any reference to the container where they are inserted. @@ -1594,7 +1602,7 @@ before explaining the customization options of [*Boost.Intrusive]. [section:node_algorithms Node algorithms with custom NodeTraits] -As explained in the [link boost_intrusive.concepts Concepts] section, [*Boost.Intrusive] +As explained in the [link intrusive.concepts Concepts] section, [*Boost.Intrusive] containers are implemented using node algorithms that work on generic nodes. Sometimes, the use of intrusive containers is expensive for some environments @@ -1775,7 +1783,7 @@ For a complete rbtree of functions see [section:value_traits Containers with custom ValueTraits] -As explained in the [link boost_intrusive.concepts Concepts] section, [*Boost.Intrusive] +As explained in the [link intrusive.concepts Concepts] section, [*Boost.Intrusive] containers are templatized using a `ValueTraits` parameter. This parameter contains all the information to glue the `value_type` of the containers and the node to be used in node algorithms, since these types can be different. Apart from this, @@ -1819,7 +1827,7 @@ Let's explain each type and function: * ['node_traits]: The node configuration that it's needed by node algorithms. These node traits and algorithms are - described in the previous chapter: [link boost_intrusive.node_algorithms Nodes Algorithms]. + described in the previous chapter: [link intrusive.node_algorithms Nodes Algorithms]. * If my_value_traits is meant to be used with [classref boost::intrusive::slist slist], `node_traits` should follow @@ -1912,6 +1920,21 @@ we'll define a ValueTraits class that will configure [*Boost.Intrusive] containe [doc_value_traits_value_traits] +Defining a value traits class that just defines `value_type` as +`legacy_node_traits::node` is a common approach when defining customized +intrusive containers, so [*Boost.Intrusive] offers a templatized +[classref boost::intrusive::trivial_value_traits trivial_value_traits] class +that does exactly what we want: + +[c++] + + #include + + //Now we can define legacy_value_traits just with a single line + using namespace boost::intrusive; + typedef trivial_value_traits legacy_value_traits; + + Now we can just define the containers that will store the legacy abi objects and write a little test: @@ -1955,6 +1978,40 @@ share the same list algorithms. [endsect] +[section:simplifying_value_traits Simplifying value traits definition] + +The previous example can be further simplified using +[classref boost::intrusive::derivation_value_traits derivation_value_traits] +class to define a value traits class with a value that stores the +`simple_node` as a base class: + +[c++] + + #include + + //value_1, value_2, simple_node and simple_node_traits are defined + //as in the previous example... + //... + + using namespace boost::intrusive; + + //Now define the needed value traits using + typedef derivation_value_traits ValueTraits1; + typedef derivation_value_traits ValueTraits2; + + //Now define the containers + typedef list Value1List; + typedef list Value2List; + +We can even choose to store `simple_node` as a member of `value_1` and `value_2` +classes and use [classref boost::intrusive::member_value_traits member_value_traits] +to define the needed value traits classes: + +[import ../example/doc_advanced_value_traits2.cpp] +[doc_advanced_value_traits2_value_traits] + +[endsect] + [endsect] [section:thread_safety Thread safety guarantees] @@ -2108,7 +2165,7 @@ and also derives from `test_class`. You can find the full test code code in the [@../../perf/perf_list.cpp perf_list.cpp] source file. -[section:performance_results_push_back Back insertions and destruction] +[section:performance_results_push_back Back insertion and destruction] The first test will measure the benefits we can obtain with intrusive containers avoiding memory allocations and deallocations . All the objects to be @@ -2171,7 +2228,7 @@ These are the times in microseconds for each case, and the normalized time: The results are logical: intrusive lists just need one allocation. The destruction time of the `normal_link` intrusive container is trivial (complexity: `O(1)`), -whereas `safe_link` and `auto_unlink` intrusive containers need to the hook of +whereas `safe_link` and `auto_unlink` intrusive containers need to put the hook of erased values' in the default state (complexity: `O(NumElements)`). That's why `normal_link` intrusive list shines in this test. @@ -2187,7 +2244,7 @@ a good operating system memory allocator is the reason for this good results. [section:performance_results_reversing Reversing] -The next test measures the time needed to complete calss to the member function `reverse()`. +The next test measures the time needed to complete calls to the member function `reverse()`. Values (`test_class` and `itest_class`) and lists are created like explained in the previous section. @@ -2405,6 +2462,21 @@ all the objects to be inserted in intrusive containers in containers like `std:: [endsect] +[section:disabling_exceptions Disabling exceptions support] + +[*Boost.Intrusive] might be useful in environments where exceptions are not available +or recommendable (like embedded or real-time systems). [*Boost.Intrusive] uses the +global Boost mechanism to disable exception handling, so that if the compiler +configuration disables exceptions, `BOOST_NO_EXCEPTIONS` is defined and exception +handling is disabled. + +This mechanism is a global mechanism to disable exceptions. If for any reason, +the user wants to disable exception handling [*only] in [*Boost.Intrusive], +`BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING` can be defined to disable +exception handling in the library. + +[endsect] + [section:tested_compilers Tested compilers] [*Boost.Intrusive] has been tested in the following compilers/platforms: @@ -2418,6 +2490,7 @@ all the objects to be inserted in intrusive containers in containers like `std:: * Codewarrior 9.4/WinXP * GCC 3.4.3/Solaris 11 * GCC 4.0/Mac Os 10.4.1 +* SunCC 5.8/Solaris 11 [endsect] @@ -2448,7 +2521,7 @@ helpful discussions. [endsect] -[xinclude intrusive_doxygen.xml] +[xinclude autodoc.xml] [section:license_notices License notices] diff --git a/example/doc_advanced_value_traits2.cpp b/example/doc_advanced_value_traits2.cpp new file mode 100644 index 0000000..bfc852a --- /dev/null +++ b/example/doc_advanced_value_traits2.cpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007 +// +// 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. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +struct simple_node +{ + simple_node *prev_; + simple_node *next_; +}; + +//Define the node traits. A single node_traits will be enough. +struct simple_node_traits +{ + typedef simple_node node; + typedef node * node_ptr; + typedef const node * const_node_ptr; + static node *get_next(const node *n) { return n->next_; } + static void set_next(node *n, node *next) { n->next_ = next; } + static node *get_previous(const node *n) { return n->prev_; } + static void set_previous(node *n, node *prev) { n->prev_ = prev; } +}; + +//[doc_advanced_value_traits2_value_traits +class base_1{}; +class base_2{}; + +struct value_1 : public base_1, public simple_node +{ + int id_; + simple_node node_; +}; + +struct value_2 : public base_1, public base_2, public simple_node +{ + simple_node node_; + float id_; +}; + +using namespace boost::intrusive; + +typedef member_value_traits + ValueTraits1; +typedef member_value_traits + ValueTraits2; + +//Now define two intrusive lists. Both lists will use the same algorithms: +// circular_list_algorithms +typedef boost::intrusive::list Value1List; +typedef boost::intrusive::list Value2List; +//] + +//[doc_advanced_value_traits2_test +int main() +{ + typedef std::vector Vect1; + typedef std::vector Vect2; + + //Create values, with a different internal number + Vect1 values1; + Vect2 values2; + for(int i = 0; i < 100; ++i){ + value_1 v1; v1.id_ = i; values1.push_back(v1); + value_2 v2; v2.id_ = (float)i; values2.push_back(v2); + } + + //Create the lists with the objects + Value1List list1(values1.begin(), values1.end()); + Value2List list2(values2.begin(), values2.end()); + + //Now test both lists + Value1List::const_iterator bit1(list1.begin()), bitend1(list1.end()); + Value2List::const_iterator bit2(list2.begin()), bitend2(list2.end()); + + Vect1::const_iterator it1(values1.begin()), itend1(values1.end()); + Vect2::const_iterator it2(values2.begin()), itend2(values2.end()); + + //Test the objects inserted in our lists + for(; it1 != itend1; ++it1, ++bit1, ++it2, ++bit2){ + if(&*bit1 != &*it1 || &*bit2 != &*it2) return false; + } + return 0; +} +//] diff --git a/example/doc_offset_ptr.cpp b/example/doc_offset_ptr.cpp index c20d58d..ddaaa8c 100644 --- a/example/doc_offset_ptr.cpp +++ b/example/doc_offset_ptr.cpp @@ -45,7 +45,7 @@ int main() //nodes and the container itself must be created in shared memory const int MaxElem = 100; const int ShmSize = 50000; - const char *ShmName = "MySharedMemory"; + const char *ShmName = "SharedMemoryName"; using namespace boost::interprocess; diff --git a/example/doc_value_traits.cpp b/example/doc_value_traits.cpp index c29e4f0..7b33662 100644 --- a/example/doc_value_traits.cpp +++ b/example/doc_value_traits.cpp @@ -60,6 +60,7 @@ struct legacy_value_traits static pointer to_value_ptr(node_ptr n) { return pointer(n); } static const_pointer to_value_ptr(const_node_ptr n) { return const_pointer(n); } }; + //] //[doc_value_traits_test diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index 881e363..a42e5af 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -111,6 +111,9 @@ + + @@ -126,6 +129,9 @@ + + @@ -150,6 +156,9 @@ + + @@ -169,7 +178,7 @@ RelativePath="..\..\..\..\..\boost\intrusive\detail\config_end.hpp"> + RelativePath="..\..\..\..\..\boost\intrusive\detail\ebo_functor_holder.hpp"> @@ -186,9 +195,6 @@ - - @@ -225,6 +231,9 @@ + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ProjectType="Visual C++" + Version="7.10" + Name="multiset" + ProjectGUID="{961F0E06-C092-4AF7-ABC5-2A49999F3B79}" + Keyword="Win32Proj"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/set/set.vcproj b/proj/vc7ide/set/set.vcproj index 2894b6a..e57c685 100644 --- a/proj/vc7ide/set/set.vcproj +++ b/proj/vc7ide/set/set.vcproj @@ -1,134 +1,136 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ProjectType="Visual C++" + Version="7.10" + Name="set" + ProjectGUID="{960E01F6-92C1-F74A-BCA5-2A9F3B994979}" + Keyword="Win32Proj"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/slist/slist.vcproj b/proj/vc7ide/slist/slist.vcproj index 9f8b663..25411b5 100644 --- a/proj/vc7ide/slist/slist.vcproj +++ b/proj/vc7ide/slist/slist.vcproj @@ -1,134 +1,136 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ProjectType="Visual C++" + Version="7.10" + Name="slist" + ProjectGUID="{5A02061D-3728-4C49-AFC8-0130C1F161C0}" + Keyword="Win32Proj"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/unordered_multiset/unordered_multiset.vcproj b/proj/vc7ide/unordered_multiset/unordered_multiset.vcproj index 6017680..7a5cd30 100644 --- a/proj/vc7ide/unordered_multiset/unordered_multiset.vcproj +++ b/proj/vc7ide/unordered_multiset/unordered_multiset.vcproj @@ -25,6 +25,8 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" + DisableLanguageExtensions="TRUE" + ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="TRUE" diff --git a/proj/vc7ide/unordered_set/unordered_set.vcproj b/proj/vc7ide/unordered_set/unordered_set.vcproj index 6fa7744..724225c 100644 --- a/proj/vc7ide/unordered_set/unordered_set.vcproj +++ b/proj/vc7ide/unordered_set/unordered_set.vcproj @@ -1,134 +1,136 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ProjectType="Visual C++" + Version="7.10" + Name="unordered_set" + ProjectGUID="{90E701E6-2C91-F4A7-BA6C-A9F3B0949279}" + Keyword="Win32Proj"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/list_test.cpp b/test/list_test.cpp index 1042159..bdb752c 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -20,6 +20,7 @@ #include #include #include "test_macros.hpp" +#include "test_container.hpp" using namespace boost::intrusive; @@ -39,6 +40,20 @@ struct test_list template void test_list::test_all(std::vector& values) { + typedef boost::intrusive::list + < ValueTraits + , ValueTraits::value_type::constant_time_size + , std::size_t + > list_type; + + { + list_type list(values.begin(), values.end()); + test::test_container(list); + list.clear(); + list.insert(list.end(), values.begin(), values.end()); + test::test_sequence_container(list, values); + } + test_front_back(values); test_sort(values); test_insert(values); @@ -46,11 +61,6 @@ void test_list::test_all(std::vector list_type; list_type testlist(values.begin(), values.end()); list_type testlist2; } diff --git a/test/multiset_test.cpp b/test/multiset_test.cpp index c919008..99d803b 100644 --- a/test/multiset_test.cpp +++ b/test/multiset_test.cpp @@ -19,6 +19,7 @@ #include #include #include "test_macros.hpp" +#include "test_container.hpp" using namespace boost::intrusive; @@ -38,6 +39,24 @@ struct test_multiset template void test_multiset::test_all (std::vector& values) { + typedef multiset + + ,ValueTraits::value_type::constant_time_size, std::size_t + > multiset_type; + { + multiset_type testset(values.begin(), values.end()); + test::test_container(testset); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_common_unordered_and_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_non_unique_container(testset, values); + } test_sort(values); test_insert(values); test_swap(values); diff --git a/test/set_test.cpp b/test/set_test.cpp index 39d35eb..6b95383 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -19,6 +19,7 @@ #include #include #include "test_macros.hpp" +#include "test_container.hpp" using namespace boost::intrusive; @@ -38,6 +39,24 @@ struct test_set template void test_set::test_all(std::vector& values) { + typedef boost::intrusive::set + + ,ValueTraits::value_type::constant_time_size, std::size_t + > set_type; + { + set_type testset(values.begin(), values.end()); + test::test_container(testset); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_common_unordered_and_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_unique_container(testset, values); + } test_sort(values); test_insert(values); test_swap(values); diff --git a/test/slist_test.cpp b/test/slist_test.cpp index dfc9d78..bb67700 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -19,6 +19,7 @@ #include #include #include "test_macros.hpp" +#include "test_container.hpp" using namespace boost::intrusive; @@ -41,6 +42,17 @@ template void test_slist ::test_all (std::vector& values) { + typedef boost::intrusive::slist + list_type; + { + list_type list(values.begin(), values.end()); + test::test_container(list); + list.clear(); + list.insert(list.end(), values.begin(), values.end()); + test::test_sequence_container(list, values); + } test_front_back (values); test_sort(values); test_merge (values); diff --git a/test/test_container.hpp b/test/test_container.hpp index 834baaa..3cf4574 100644 --- a/test/test_container.hpp +++ b/test/test_container.hpp @@ -1,119 +1,24 @@ -////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2006 Matias Capeletto -// Copyright (c) 2007 Ion Gaztanaga +// (C) Copyright Ion Gaztanaga 2007 // // 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 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_TEST_TEST_CONTAINER_HPP -#define BOOST_INTRUSIVE_TEST_TEST_CONTAINER_HPP +#ifndef BOOST_INTRUSIVE_TEST_CONTAINER_HPP +#define BOOST_INTRUSIVE_TEST_CONTAINER_HPP -// std -#include -#include -#include -// Boost.Test -//#include "boost/test/included/test_exec_monitor.hpp" +#include -namespace boost{ -namespace intrusive{ +namespace boost { +namespace intrusive { namespace test { -const int NumElem = 5; - -/* -Beginning of range a.begin() iterator if a is mutable, const_iterator otherwise [4] [7] -End of range a.end() iterator if a is mutable, const_iterator otherwise [4] -Size a.size() size_type -Maximum size a.max_size() size_type -Empty container a.empty() Convertible to bool -Swap a.swap(b) void - -Expression semantics -Semantics of an expression is defined only where it differs from, or is not defined in, Assignable, Equality Comparable, or LessThan Comparable Name Expression Precondition Semantics Postcondition -Move constructor X(a) X().size() == a.size(). X() contains a copy of each of a's elements. -Move constructor X b(a); b.size() == a.size(). b contains a copy of each of a's elements. -Move Assignment operator b = a b.size() == a.size(). b contains a copy of each of a's elements. -Destructor a.~X() Each of a's elements is disposed, and memory allocated for them (if any) is deallocated. -Beginning of range a.begin() Returns an iterator pointing to the first element in the container. [7] a.begin() is either dereferenceable or past-the-end. It is past-the-end if and only if a.size() == 0. -End of range a.end() Returns an iterator pointing one past the last element in the container. a.end() is past-the-end. -Size a.size() Returns the size of the container, that is, its number of elements. [8] a.size() >= 0 && a.size() <= max_size() -Maximum size a.max_size() Returns the largest size that this container can ever have. [8] a.max_size() >= 0 && a.max_size() >= a.size() -Empty container a.empty() Equivalent to a.size() == 0. (But possibly faster.) -Swap a.swap(b) Equivalent to swap(a,b) [9] -*/ - -/* -expression return type operational assertion/note complexity - semantics pre/post-condition - - -X::value_type T T is - CopyConstructible -compile time -X::reference lvalue of T compile time -X::const_- -reference -const lvalue of T compile time -X::iterator iterator type -whose value -type is T -any iterator category -except output iterator. -convertible to -X::const_iterator. -compile time -X::const_- -iterator -constant iterator -type whose -value type is T -any iterator category -except output iterator -compile time -X::difference_ -type -signed integral -type -is identical to the -difference type of -X::iterator and -X::const_iterator -compile time -X::size_type unsigned -integral type -size_type can -represent any -non-negative value of -compile time - - - - - - -X u; post: u.size() == 0 constant -X(); X().size() == 0 constant -X(a); a == X(a). linear -X u(a); post: u == a linear -X u = a; Equivalent to: X u; u -= a; -(&a)->X(); void note: the destructor is -applied to every -element of a; all the -memory is deallocated. -linear -a.begin(); iterator; -const_- -iterator for -constant a -constant -*/ - template< class Container > void test_container( Container & c ) { @@ -126,102 +31,231 @@ void test_container( Container & c ) typedef typename Container::const_pointer const_pointer; typedef typename Container::difference_type difference_type; typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::size_type size_type; + typedef typename Container::value_traits value_traits; const size_type num_elem = c.size(); - BOOST_CHECK( c.empty() == (num_elem == 0) ); + BOOST_TEST( c.empty() == (num_elem == 0) ); { iterator it(c.begin()), itend(c.end()); size_type i; for(i = 0; i < num_elem; ++i){ ++it; } - BOOST_CHECK( it == c.end() ); - BOOST_CHECK( c.size() == i ); + BOOST_TEST( it == c.end() ); + BOOST_TEST( c.size() == i ); } + //Check iterator conversion - BOOST_CHECK( const_iterator(c.begin()) == c.cbegin() ); + BOOST_TEST( const_iterator(c.begin()) == c.cbegin() ); { const_iterator it(c.cbegin()), itend(c.cend()); size_type i; for(i = 0; i < num_elem; ++i){ ++it; } - BOOST_CHECK( it == c.cend() ); - BOOST_CHECK( c.size() == i ); + BOOST_TEST( it == c.cend() ); + BOOST_TEST( c.size() == i ); } } -/* -template< class Container > -void test_container - ( Container & c, typename Container::size_type num_elem - , Container & c2, typename Container::size_type num_elem2) + + +template< class Container, class Data > +void test_sequence_container(Container & c, Data & d) { - typedef typename Container::value_type value_type; - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; - typedef typename Container::pointer pointer; - typedef typename Container::const_pointer const_pointer; - typedef typename Container::difference_type difference_type; - typedef typename Container::size_type size_type; + assert( d.size() > 2 ); - //For the future: - // - //move-copy constructor - //move-assignment + c.clear(); - test_container_helper(c, num_elem); - test_container_helper(c2, num_elem2); + BOOST_TEST( c.size() == 0 ); + BOOST_TEST( c.empty() ); - //Test swap and test again - c.swap(c2); - test_container_helper(c, num_elem2); - test_container_helper(c2, num_elem); -}*/ + c.insert( c.begin(), *d.begin() ); + c.insert( c.end(), *(++d.begin()) ); -template< class Sequence > -void test_sequence( Sequence & seq ) -{ - //First the container requirements - test_container(seq); - typedef Sequence::value_type value_type; - typedef Sequence::iterator iterator; + BOOST_TEST( c.size() == 2 ); + BOOST_TEST( !c.empty() ); - Sequence::size_type old_size(seq.size()); + c.erase( c.begin() ); - //Now test sequence requirements - //insert(p, t) - Sequence::value_type one(1); - iterator one_pos = seq.insert(seq.begin(), one); - BOOST_CHECK( &*seq.begin() == &one ); - BOOST_CHECK( seq.size() == (old_size + 1) ); + BOOST_TEST( c.size() == 1 ); - //insert(p, i, j) - value_type range[2] = { value_type(2), value_type(3) }; - iterator range_it = one_pos; ++range_it; - seq.insert(range_it, &range[0], &range[2]); - BOOST_CHECK( seq.size() == (old_size + 3) ); - range_it = ++seq.begin(); - BOOST_CHECK( &*range_it == &range[0] ); - ++range_it; - BOOST_CHECK( &*range_it == &range[1] ); + c.insert( c.begin(), *(++++d.begin()) ); - //erase(q) - iterator it_from_erase = seq.erase(seq.begin()); - BOOST_CHECK( seq.size() == (old_size + 2) ); - BOOST_CHECK( &*it_from_erase == &range[0] ); + c.erase( c.begin(), c.end() ); - //erase(q1, q2) - iterator q1(it_from_erase), q2(it_from_erase); - ++++q2; - it_from_erase = seq.erase(q1, q2); - BOOST_CHECK( seq.size() == old_size ); - //clear(), assign()??? + BOOST_TEST( c.empty() ); + + c.insert( c.begin(), *d.begin() ); + + BOOST_TEST( c.size() == 1 ); + + BOOST_TEST( c.begin() != c.end() ); + + c.erase( 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() ); } -} // namespace test{ -} // namespace intrusive{ -} // namespace boost{ +template< class Container, class Data > +void test_common_unordered_and_associative_container(Container & c, Data & d) +{ + typedef typename Container::size_type size_type; -#endif // BOOST_INTRUSIVE_TEST_TEST_CONTAINER_HPP + 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 da = d.begin(); + typename Data::const_iterator db = ++d.begin(); + + size_type old_size = c.size(); + + c.erase(*da); + + BOOST_TEST( c.size() == old_size-1 ); + + 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() ); +} + +template< class Container, class Data > +void test_associative_container_invariants(Container & c, Data & d) +{ + typedef typename Container::const_iterator const_iterator; + for( typename Data::const_iterator di = d.begin(), de = d.end(); + di != de; ++di) + { + const_iterator ci = c.find(*di); + BOOST_TEST( ci != c.end() ); + BOOST_TEST( ! c.value_comp()(*ci, *di) ); + const_iterator cil = c.lower_bound(*di); + const_iterator ciu = c.upper_bound(*di); + std::pair er = c.equal_range(*di); + BOOST_TEST( cil == er.first ); + BOOST_TEST( ciu == er.second ); + if(ciu != c.end()){ + BOOST_TEST( c.value_comp()(*cil, *ciu) ); + } + if(c.count(*di) > 1){ + const_iterator ci_next = cil; ++ci_next; + for( ; ci_next != ciu; ++cil, ++ci_next){ + BOOST_TEST( !c.value_comp()(*ci_next, *cil) ); + } + } + } +} + +template< class Container, class Data > +void test_associative_container(Container & c, Data & d) +{ + typedef typename Container::const_iterator const_iterator; + assert( d.size() > 2 ); + + c.clear(); + c.insert(d.begin(),d.end()); + + test_associative_container_invariants(c, d); + + const Container & cr = c; + + test_associative_container_invariants(cr, d); +} + +template< class Container, class Data > +void test_unordered_associative_container_invariants(Container & c, Data & d) +{ + typedef typename Container::size_type size_type; + typedef typename Container::const_iterator const_iterator; + + for( typename Data::const_iterator di = d.begin(), de = d.end() ; + di != de ; ++di ){ + const_iterator i = c.find(*di); + size_type nb = c.bucket(*i); + 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 ); + std::pair er = c.equal_range(*di); + size_type cnt = std::distance(er.first, er.second); + BOOST_TEST( cnt == c.count(*di)); + if(cnt > 1) + for(const_iterator n = er.first, i = n++, e = er.second; n != e; ++i, ++n){ + BOOST_TEST( c.key_eq()(*i, *n) ); + BOOST_TEST( c.hash_function()(*i) == c.hash_function()(*n) ); + } + } + + size_type blen = c.bucket_count(); + size_type total_objects = 0; + for(size_type i = 0; i < blen; ++i){ + total_objects += c.bucket_size(i); + } + BOOST_TEST( total_objects == c.size() ); +} + +template< class Container, class Data > +void test_unordered_associative_container(Container & c, Data & d) +{ + c.clear(); + c.insert( d.begin(), d.end() ); + + test_unordered_associative_container_invariants(c, d); + + const Container & cr = c; + + test_unordered_associative_container_invariants(cr, d); +} + +template< class Container, class Data > +void test_unique_container(Container & c, Data & d) +{ + typedef typename Container::value_type value_type; + c.clear(); + c.insert(d.begin(),d.end()); + typename Container::size_type old_size = c.size(); + value_type v(*d.begin()); + c.insert(v); + BOOST_TEST( c.size() == old_size ); + c.clear(); +} + +template< class Container, class Data > +void test_non_unique_container(Container & c, Data & d) +{ + typedef typename Container::value_type value_type; + c.clear(); + c.insert(d.begin(),d.end()); + typename Container::size_type old_size = c.size(); + value_type v(*d.begin()); + c.insert(v); + BOOST_TEST( c.size() == (old_size+1) ); + c.clear(); +} + +}}} + +#endif //#ifndef BOOST_INTRUSIVE_TEST_CONTAINER_HPP diff --git a/test/test_intrusive_associative_container.hpp b/test/test_intrusive_associative_container.hpp new file mode 100644 index 0000000..e69de29 diff --git a/test/test_intrusive_sequence_container.hpp b/test/test_intrusive_sequence_container.hpp new file mode 100644 index 0000000..e69de29 diff --git a/test/test_intrusive_unordered_container.hpp b/test/test_intrusive_unordered_container.hpp new file mode 100644 index 0000000..e69de29 diff --git a/test/unordered_multiset_test.cpp b/test/unordered_multiset_test.cpp index d35981a..b78aeee 100644 --- a/test/unordered_multiset_test.cpp +++ b/test/unordered_multiset_test.cpp @@ -21,6 +21,7 @@ #include #include #include "test_macros.hpp" +#include "test_container.hpp" using namespace boost::intrusive; @@ -43,6 +44,27 @@ struct test_unordered_multiset template void test_unordered_multiset::test_all (std::vector& values) { + typedef boost::intrusive::unordered_multiset + + ,std::equal_to + ,ValueTraits::value_type::constant_time_size, std::size_t + > unordered_multiset_type; + { + typename unordered_multiset_type::bucket_type buckets [BucketSize]; + unordered_multiset_type testset(buckets, BucketSize); + testset.insert(values.begin(), values.end()); + test::test_container(testset); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_common_unordered_and_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_unordered_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_non_unique_container(testset, values); + } test_sort(values); test_insert(values); test_swap(values); diff --git a/test/unordered_set_test.cpp b/test/unordered_set_test.cpp index a3c6ca5..e0c1c5e 100644 --- a/test/unordered_set_test.cpp +++ b/test/unordered_set_test.cpp @@ -20,6 +20,7 @@ #include #include #include "test_macros.hpp" +#include "test_container.hpp" using namespace boost::intrusive; @@ -42,6 +43,27 @@ struct test_unordered_set template void test_unordered_set::test_all(std::vector& values) { + typedef boost::intrusive::unordered_set + + ,std::equal_to + ,ValueTraits::value_type::constant_time_size, std::size_t + > unordered_set_type; + { + typename unordered_set_type::bucket_type buckets [BucketSize]; + unordered_set_type testset(buckets, BucketSize); + testset.insert(values.begin(), values.end()); + test::test_container(testset); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_common_unordered_and_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_unordered_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_unique_container(testset, values); + } test_sort(values); test_insert(values); test_swap(values);