diff --git a/bench/bench_set.cpp b/bench/bench_set.cpp index ac8c98a..8d87880 100644 --- a/bench/bench_set.cpp +++ b/bench/bench_set.cpp @@ -290,6 +290,15 @@ template void launch_tests(const char *BoostContName, const char *StdContName) { try { + std::cout << "**********************************************" << '\n'; + std::cout << "**********************************************" << '\n'; + std::cout << "**********************************************" << '\n'; + std::cout << '\n'; + std::cout << BoostContName << " .VS " << StdContName << '\n'; + std::cout << '\n'; + std::cout << "**********************************************" << '\n'; + std::cout << "**********************************************" << '\n'; + std::cout << "**********************************************" << '\n' << std::endl; fill_ranges(); { std::cout << "Construct benchmark:" << BoostContName << std::endl; @@ -333,20 +342,36 @@ void launch_tests(const char *BoostContName, const char *StdContName) int main() { + using namespace boost::container; //set vs std::set - launch_tests< boost::container::set , std::set > - ("boost::container::set", "std::set"); + launch_tests< set , std::set > + ("set", "std::set"); + //set(RB) vs set(AVL) + launch_tests< set, set, std::allocator, tree_assoc_options< tree_type >::type > > + ("set(RB)", "set(AVL)"); + //set(RB) vs set(SG) + launch_tests< set, set, std::allocator, tree_assoc_options< tree_type >::type > > + ("set(RB)", "set(SG)"); + launch_tests< set, set, std::allocator, tree_assoc_options< tree_type >::type > > + ("set(RB)", "set(SP)"); + //set(sizeopt) vs set(!sizeopt) + launch_tests< set, set, std::allocator, tree_assoc_options< optimize_size >::type > > + ("set(sizeopt=true)", "set(sizeopt=false)"); + //set(AVL,sizeopt) vs set(AVL,!sizeopt) + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type > + , set, std::allocator, tree_assoc_options< tree_type, optimize_size >::type > > + ("set(AVL,sizeopt=true)", "set(AVL,sizeopt=false)"); //set vs set<..., allocator_v2> - launch_tests< boost::container::set , boost::container::set, boost::container::allocator > > - ("boost::container::set", "boost::container::set" ); + launch_tests< set , set, allocator > > + ("set", "set" ); //multiset vs std::set - launch_tests< boost::container::multiset , std::multiset > - ("boost::container::multiset", "std::multiset"); + launch_tests< multiset , std::multiset > + ("multiset", "std::multiset"); //flat_set vs set - launch_tests< boost::container::flat_set , boost::container::set > - ("boost::container::flat_set", "boost::container::set"); + launch_tests< flat_set , set > + ("flat_set", "set"); //flat_multiset vs multiset - launch_tests< boost::container::flat_multiset , boost::container::multiset > - ("boost::container::flat_multiset", "boost::container::multiset"); + launch_tests< flat_multiset , multiset > + ("flat_multiset", "multiset"); return 0; } diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 3e3b32a..90d6feb 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -35,7 +35,9 @@ doxygen autodoc \"BOOST_RV_REF_BEG=\" \\ \"BOOST_RV_REF_END=&&\" \\ \"BOOST_COPY_ASSIGN_REF(T)=const T &\" \\ - \"BOOST_FWD_REF(a)=a &&\"" + \"BOOST_FWD_REF(a)=a &&\" \\ + \"BOOST_INTRUSIVE_OPTION_CONSTANT(OPTION_NAME, TYPE, VALUE, CONSTANT_NAME) = template struct OPTION_NAME{};\" \\ + \"BOOST_INTRUSIVE_OPTION_TYPE(OPTION_NAME, TYPE, TYPEDEF_EXPR, TYPEDEF_NAME) = template struct OPTION_NAME{};\" " "boost.doxygen.reftitle=Boost.Container Header Reference" ; diff --git a/doc/container.qbk b/doc/container.qbk index 1bf5290..08ebbb6 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -549,6 +549,46 @@ times. [endsect] +[section:configurable_tree_based_associative_containers Configurable tree-based associative ordered containers] + +[classref boost::container::set set], [classref boost::container::multiset multiset], +[classref boost::container::map map] and [classref boost::container::multimap multimap] associative containers +are implemented as binary search trees which offer the needed complexity and stability guarantees required by the +C++ standard for associative containers. + +[*Boost.Container] offers the possibility to configure at compile time some parameters of the binary search tree +implementation. This configuration is passed as the last template parameter and defined using the utility class +[classref boost::container::tree_assoc_options tree_assoc_options]. + +The following parameters can be configured: + +* The underlying [*tree implementation] type ([classref boost::container::tree_type tree_type]). + By default these containers use a red-black tree but the user can use other tree types: + * [@http://en.wikipedia.org/wiki/Red%E2%80%93black_tree Red-Black Tree] + * [@http://en.wikipedia.org/wiki/Avl_trees AVL tree] + * [@http://en.wikipedia.org/wiki/Scapegoat_tree Scapegoat tree]. In this case Insertion and Deletion + are amortized O(log n) instead of O(log n). + * [@http://en.wikipedia.org/wiki/Splay_tree Splay tree]. In this case Searches, Insertions and Deletions + are amortized O(log n) instead of O(log n). + +* Whether the [*size saving] mechanisms are used to implement the tree nodes + ([classref boost::container::optimize_size optimize_size]). By default this option is activated and is only + meaningful to red-black and avl trees (in other cases, this option will be ignored). + This option will try to put rebalancing metadata inside the "parent" pointer of the node if the pointer + type has enough alignment. Usually, due to alignment issues, the metadata uses the size of a pointer yielding + to four pointer size overhead per node, whereas activating this option usually leads to 3 pointer size overhead. + Although some mask operations must be performed to extract + data from this special "parent" pointer, in several systems this option also improves performance due to the + improved cache usage produced by the node size reduction. + +See the following example to see how [classref boost::container::tree_assoc_options tree_assoc_options] can be +used to customize these containers: + +[import ../example/doc_custom_tree.cpp] +[doc_custom_tree] + +[endsect] + [section:constant_time_range_splice Constant-time range splice for `(s)list`] In the first C++ standard `list::size()` was not required to be constant-time, @@ -637,6 +677,11 @@ The following extended allocators are provided: to the system. The overhead can be very low (< 5% for small nodes) and it's nearly as fast as [classref boost::container::node_allocator node_allocator]. It's also suitable for node containers. +Use them simply specifying the new allocator in the corresponding template argument of your favourite container: + +[import ../example/doc_extended_allocators.cpp] +[doc_extended_allocators] + [endsect] [/ @@ -880,6 +925,11 @@ use [*Boost.Container]? There are several reasons for that: * Added DlMalloc-based [link container.extended_functionality.extended_allocators Extended Allocators]. +* [link container.extended_functionality.configurable_tree_based_associative_containers Improved configurability] + of tree-based ordered associative containers. AVL, Scapegoat and Splay trees are now available + to implement [classref boost::container::set set], [classref boost::container::multiset multiset], + [classref boost::container::map map] and [classref boost::container::multimap multimap]. + * Fixed bugs: * [@https://svn.boost.org/trac/boost/ticket/9338 #9338: ['"VS2005 compiler errors in swap() definition after including container/memory_util.hpp"]]. diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 2371b80..58ebcdd 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -21,7 +21,7 @@ rule test_all for local fileb in [ glob doc_*.cpp ] { - all_rules += [ run $(fileb) + all_rules += [ run $(fileb) /boost/container//boost_container /boost/timer//boost_timer : # additional args : # test-files : # requirements diff --git a/example/doc_custom_tree.cpp b/example/doc_custom_tree.cpp new file mode 100644 index 0000000..651dd22 --- /dev/null +++ b/example/doc_custom_tree.cpp @@ -0,0 +1,64 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_custom_tree +#include +#include + +int main () +{ + using namespace boost::container; + + //First define several options + // + + //This option specifies an AVL tree based associative container + typedef tree_assoc_options< tree_type >::type AVLTree; + + //This option specifies an AVL tree based associative container + //disabling node size optimization. + typedef tree_assoc_options< tree_type + , optimize_size >::type AVLTreeNoSizeOpt; + + //This option specifies an Splay tree based associative container + typedef tree_assoc_options< tree_type >::type SplayTree; + + //Now define new tree-based associative containers + // + + //AVLTree based set container + typedef set, std::allocator, AVLTree> AvlSet; + + //AVLTree based set container without size optimization + typedef set, std::allocator, AVLTreeNoSizeOpt> AvlSetNoSizeOpt; + + //Splay tree based multiset container + typedef multiset, std::allocator, SplayTree> SplayMultiset; + + //Use them + // + AvlSet avl_set; + avl_set.insert(0); + assert(avl_set.find(0) != avl_set.end()); + + AvlSetNoSizeOpt avl_set_no_szopt; + avl_set_no_szopt.insert(1); + avl_set_no_szopt.insert(1); + assert(avl_set_no_szopt.count(1) == 1); + + SplayMultiset splay_mset; + splay_mset.insert(2); + splay_mset.insert(2); + assert(splay_mset.count(2) == 2); + return 0; +} +//] +#include diff --git a/example/doc_extended_allocators.cpp b/example/doc_extended_allocators.cpp new file mode 100644 index 0000000..0eceba4 --- /dev/null +++ b/example/doc_extended_allocators.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_extended_allocators +#include +#include +#include +#include + +//"allocator" is a general purpose allocator that can reallocate +//memory, something useful for vector and flat associative containers +#include + +//"adaptive_pool" is a node allocator, specially suited for +//node-based containers +#include + +int main () +{ + using namespace boost::container; + + //A vector that can reallocate memory to implement faster insertions + vector > extended_alloc_vector; + + //A flat set that can reallocate memory to implement faster insertions + flat_set, allocator > extended_alloc_flat_set; + + //A list that can manages nodes to implement faster + //range insertions and deletions + list > extended_alloc_list; + + //A set that can recycle nodes to implement faster + //range insertions and deletions + set, adaptive_pool > extended_alloc_set; + + //Now user them as always + extended_alloc_vector.push_back(0); + extended_alloc_flat_set.insert(0); + extended_alloc_list.push_back(0); + extended_alloc_set.insert(0); + + //... + return 0; +} +//] +#include diff --git a/include/boost/container/container_fwd.hpp b/include/boost/container/container_fwd.hpp index 075c223..415de0f 100644 --- a/include/boost/container/container_fwd.hpp +++ b/include/boost/container/container_fwd.hpp @@ -16,7 +16,7 @@ #endif //! \file -//! This header file forward declares the following classes: +//! This header file forward declares the following containers: //! - boost::container::vector //! - boost::container::stable_vector //! - boost::container::static_vector @@ -33,11 +33,13 @@ //! - boost::container::basic_string //! - boost::container::string //! - boost::container::wstring +//! +//! It forward declares the following allocators: //! - boost::container::allocator //! - boost::container::node_allocator //! - boost::container::adaptive_pool //! -//! and defines the following types: +//! And finally it defines the following types ////////////////////////////////////////////////////////////////////////////// // Standard predeclarations @@ -74,7 +76,7 @@ namespace container { //! Enumeration used to configure ordered associative containers //! with a concrete tree implementation. -enum tree_type +enum tree_type_enum { red_black_tree, avl_tree, @@ -107,30 +109,35 @@ template > class slist; +template +struct tree_opt; + +typedef tree_opt tree_assoc_defaults; + template ,class Allocator = std::allocator - ,tree_type = red_black_tree > + ,class Options = tree_assoc_defaults > class set; template ,class Allocator = std::allocator - ,tree_type = red_black_tree > + ,class Options = tree_assoc_defaults > class multiset; template ,class Allocator = std::allocator > - ,tree_type = red_black_tree > + ,class Options = tree_assoc_defaults > class map; template ,class Allocator = std::allocator > - ,tree_type = red_black_tree > + ,class Options = tree_assoc_defaults > class multimap; template class node_allocator; +#else + +//! Default options for tree-based associative containers +//! - tree_type +//! - optimize_size +typedef implementation_defined tree_assoc_defaults; + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED //! Type used to tag that the input range is diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index c1c83cc..d15aada 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -23,6 +23,8 @@ #include #include #include +#include + // #include #include @@ -90,13 +92,44 @@ struct tree_value_compare { return key_compare::operator()(this->key_forward(key1), this->key_forward(key2)); } }; -template -struct intrusive_tree_hook +template +struct intrusive_tree_hook; + +template +struct intrusive_tree_hook { typedef typename container_detail::bi::make_set_base_hook < container_detail::bi::void_pointer , container_detail::bi::link_mode - , container_detail::bi::optimize_size + , container_detail::bi::optimize_size + >::type type; +}; + +template +struct intrusive_tree_hook +{ + typedef typename container_detail::bi::make_avl_set_base_hook + < container_detail::bi::void_pointer + , container_detail::bi::link_mode + , container_detail::bi::optimize_size + >::type type; +}; + +template +struct intrusive_tree_hook +{ + typedef typename container_detail::bi::make_bs_set_base_hook + < container_detail::bi::void_pointer + , container_detail::bi::link_mode + >::type type; +}; + +template +struct intrusive_tree_hook +{ + typedef typename container_detail::bi::make_bs_set_base_hook + < container_detail::bi::void_pointer + , container_detail::bi::link_mode >::type type; }; @@ -114,23 +147,23 @@ struct tree_internal_data_type< std::pair > typedef pair type; }; - //The node to be store in the tree -template +template struct tree_node - : public intrusive_tree_hook::type + : public intrusive_tree_hook::type { private: //BOOST_COPYABLE_AND_MOVABLE(tree_node) tree_node(); public: - typedef typename intrusive_tree_hook::type hook_type; - + typedef typename intrusive_tree_hook + ::type hook_type; typedef T value_type; - typedef typename tree_internal_data_type::type internal_type; + typedef typename tree_internal_data_type::type internal_type; - typedef tree_node node_type; + typedef tree_node< T, VoidPointer + , tree_type_value, OptimizeSize> node_type; T &get_data() { @@ -215,12 +248,67 @@ class push_back_functor namespace container_detail { -template -struct intrusive_tree_type; +template< class NodeType, class NodeCompareType + , class SizeType, class HookType + , boost::container::tree_type_enum tree_type_value> +struct intrusive_tree_dispatch; -template -struct intrusive_tree_type +template +struct intrusive_tree_dispatch + { + typedef typename container_detail::bi::make_rbtree + + ,container_detail::bi::base_hook + ,container_detail::bi::constant_time_size + ,container_detail::bi::size_type + >::type type; +}; + +template +struct intrusive_tree_dispatch + +{ + typedef typename container_detail::bi::make_avltree + + ,container_detail::bi::base_hook + ,container_detail::bi::constant_time_size + ,container_detail::bi::size_type + >::type type; +}; + +template +struct intrusive_tree_dispatch + +{ + typedef typename container_detail::bi::make_sgtree + + ,container_detail::bi::base_hook + ,container_detail::bi::constant_time_size + ,container_detail::bi::size_type + >::type type; +}; + +template +struct intrusive_tree_dispatch + +{ + typedef typename container_detail::bi::make_splaytree + + ,container_detail::bi::base_hook + ,container_detail::bi::constant_time_size + ,container_detail::bi::size_type + >::type type; +}; + +template +struct intrusive_tree_type +{ + private: typedef typename boost::container:: allocator_traits::value_type value_type; typedef typename boost::container:: @@ -228,16 +316,49 @@ struct intrusive_tree_type typedef typename boost::container:: allocator_traits::size_type size_type; typedef typename container_detail::tree_node - node_type; + < value_type, void_pointer + , tree_type_value, OptimizeSize> node_type; typedef node_compare node_compare_type; - typedef typename container_detail::bi::make_rbtree - - ,container_detail::bi::base_hook::type> - ,container_detail::bi::constant_time_size - ,container_detail::bi::size_type - >::type container_type; - typedef container_type type ; + //Deducing the hook type from node_type (e.g. node_type::hook_type) would + //provoke an early instantiation of node_type that could ruin recursive + //tree definitions, so retype the complete type to avoid any problem. + typedef typename intrusive_tree_hook + ::type hook_type; + public: + typedef typename intrusive_tree_dispatch + < node_type, node_compare_type + , size_type, hook_type + , tree_type_value>::type type; +}; + +//Trait to detect manually rebalanceable tree types +template +struct is_manually_balanceable +{ static const bool value = true; }; + +template<> struct is_manually_balanceable +{ static const bool value = false; }; + +template<> struct is_manually_balanceable +{ static const bool value = false; }; + +//Proxy traits to implement different operations depending on the +//is_manually_balanceable<>::value +template< boost::container::tree_type_enum tree_type_value + , bool IsManuallyRebalanceable = is_manually_balanceable::value> +struct intrusive_tree_proxy +{ + template + static void rebalance(Icont &) {} +}; + +template +struct intrusive_tree_proxy +{ + template + static void rebalance(Icont &c) + { c.rebalance(); } }; } //namespace container_detail { @@ -326,24 +447,25 @@ struct key_node_compare template + class Options> class tree : protected container_detail::node_alloc_holder < A , typename container_detail::intrusive_tree_type < A, tree_value_compare //ValComp - , tree_type_value>::type + , Options::tree_type, Options::optimize_size>::type > { typedef tree_value_compare ValComp; typedef typename container_detail::intrusive_tree_type - < A, ValComp, tree_type_value>::type Icont; + < A, ValComp, Options::tree_type + , Options::optimize_size>::type Icont; typedef container_detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; typedef tree < Key, Value, KeyOfValue - , KeyCompare, A, tree_type_value> ThisType; + , KeyCompare, A, Options> ThisType; typedef typename AllocHolder::NodeAlloc NodeAlloc; typedef typename AllocHolder::ValAlloc ValAlloc; typedef typename AllocHolder::Node Node; @@ -353,6 +475,7 @@ class tree typedef typename AllocHolder::allocator_v1 allocator_v1; typedef typename AllocHolder::allocator_v2 allocator_v2; typedef typename AllocHolder::alloc_version alloc_version; + typedef intrusive_tree_proxy intrusive_tree_proxy_t; BOOST_COPYABLE_AND_MOVABLE(tree) @@ -985,6 +1108,9 @@ class tree (const_iterator(ret.first), const_iterator(ret.second)); } + void rebalance() + { intrusive_tree_proxy_t::rebalance(this->icont()); } + friend bool operator==(const tree& x, const tree& y) { return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index cb931ef..397369f 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -39,22 +39,26 @@ namespace boost { namespace container { +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! A map is a kind of associative container that supports unique keys (contains at //! most one of each key value) and provides for fast retrieval of values of another //! type T based on the keys. The map class supports bidirectional iterators. //! //! A map satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. For a -//! map the key_type is Key and the value_type is std::pair. +//! container and of an associative container. The value_type stored +//! by this container is the value_type is std::pair. //! -//! Compare is the ordering function for Keys (e.g. std::less). -//! -//! Allocator is the allocator to allocate the value_types -//! (e.g. allocator< std::pair > ). -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = std::allocator< std::pair< const Key, T> > > +//! \tparam Key is the key_type of the map +//! \tparam Value is the mapped_type +//! \tparam Compare is the ordering function for Keys (e.g. std::less). +//! \tparam Allocator is the allocator to allocate the value_types +//! (e.g. allocator< std::pair > ). +//! \tparam MapOptions is an packed option type generated using using boost::container::tree_assoc_options. +template < class Key, class T, class Compare = std::less + , class Allocator = std::allocator< std::pair< const Key, T> >, class MapOptions = tree_assoc_defaults > #else -template +template #endif class map { @@ -64,7 +68,7 @@ class map typedef std::pair value_type_impl; typedef container_detail::tree - , Compare, Allocator, tree_type_value> tree_t; + , Compare, Allocator, MapOptions> tree_t; typedef container_detail::pair movable_value_type_impl; typedef container_detail::tree_value_compare < Key, value_type_impl, Compare, container_detail::select1st @@ -744,26 +748,53 @@ class map std::pair equal_range(const key_type& x) const { return m_tree.equal_range(x); } + //! Effects: Rebalances the tree. It's a no-op for Red-Black and AVL trees. + //! + //! Complexity: Linear + void rebalance() + { return m_tree.rebalance(); } + + //! Effects: Returns true if x and y are equal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator==(const map& x, const map& y) - { return x.m_tree == y.m_tree; } - - friend bool operator<(const map& x, const map& y) - { return x.m_tree < y.m_tree; } + { return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } + //! Effects: Returns true if x and y are unequal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator!=(const map& x, const map& y) - { return !(x == y); } + { return !(x == y); } + //! Effects: Returns true if x is less than y + //! + //! Complexity: Linear to the number of elements in the container. + friend bool operator<(const map& x, const map& y) + { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + //! Effects: Returns true if x is greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>(const map& x, const map& y) - { return y < x; } + { return y < x; } + //! Effects: Returns true if x is equal or less than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator<=(const map& x, const map& y) - { return !(y < x); } + { return !(y < x); } + //! Effects: Returns true if x is equal or greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>=(const map& x, const map& y) - { return !(x < y); } + { return !(x < y); } + //! Effects: x.swap(y) + //! + //! Complexity: Constant. friend void swap(map& x, map& y) - { x.swap(y); } + { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: @@ -814,23 +845,27 @@ namespace container { #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! A multimap is a kind of associative container that supports equivalent keys //! (possibly containing multiple copies of the same key value) and provides for //! fast retrieval of values of another type T based on the keys. The multimap class //! supports bidirectional iterators. //! //! A multimap satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. For a -//! map the key_type is Key and the value_type is std::pair. +//! container and of an associative container. The value_type stored +//! by this container is the value_type is std::pair. //! -//! Compare is the ordering function for Keys (e.g. std::less). -//! -//! Allocator is the allocator to allocate the value_types -//!(e.g. allocator< std::pair<const Key, T> >). -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = std::allocator< std::pair< const Key, T> > > +//! \tparam Key is the key_type of the map +//! \tparam Value is the mapped_type +//! \tparam Compare is the ordering function for Keys (e.g. std::less). +//! \tparam Allocator is the allocator to allocate the value_types +//! (e.g. allocator< std::pair > ). +//! \tparam MultiMapOptions is an packed option type generated using using boost::container::tree_assoc_options. +template < class Key, class T, class Compare = std::less + , class Allocator = std::allocator< std::pair< const Key, T> >, class MultiMapOptions = tree_assoc_defaults> #else -template +template #endif class multimap { @@ -840,7 +875,7 @@ class multimap typedef std::pair value_type_impl; typedef container_detail::tree - , Compare, Allocator, tree_type_value> tree_t; + , Compare, Allocator, MultiMapOptions> tree_t; typedef container_detail::pair movable_value_type_impl; typedef container_detail::tree_value_compare < Key, value_type_impl, Compare, container_detail::select1st @@ -1424,24 +1459,51 @@ class multimap std::pair equal_range(const key_type& x) const { return m_tree.equal_range(x); } + //! Effects: Rebalances the tree. It's a no-op for Red-Black and AVL trees. + //! + //! Complexity: Linear + void rebalance() + { return m_tree.rebalance(); } + + //! Effects: Returns true if x and y are equal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator==(const multimap& x, const multimap& y) - { return x.m_tree == y.m_tree; } - - friend bool operator<(const multimap& x, const multimap& y) - { return x.m_tree < y.m_tree; } + { return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } + //! Effects: Returns true if x and y are unequal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator!=(const multimap& x, const multimap& y) - { return !(x == y); } + { return !(x == y); } + //! Effects: Returns true if x is less than y + //! + //! Complexity: Linear to the number of elements in the container. + friend bool operator<(const multimap& x, const multimap& y) + { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + //! Effects: Returns true if x is greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>(const multimap& x, const multimap& y) { return y < x; } + //! Effects: Returns true if x is equal or less than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator<=(const multimap& x, const multimap& y) { return !(y < x); } + //! Effects: Returns true if x is equal or greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>=(const multimap& x, const multimap& y) { return !(x < y); } + //! Effects: x.swap(y) + //! + //! Complexity: Constant. friend void swap(multimap& x, multimap& y) { x.swap(y); } }; diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp new file mode 100644 index 0000000..11bf9de --- /dev/null +++ b/include/boost/container/options.hpp @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013 +// +// 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/container for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_OPTIONS_HPP +#define BOOST_CONTAINER_OPTIONS_HPP + +#include +#include +#include + +namespace boost { +namespace container { + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +template +struct tree_opt +{ + static const boost::container::tree_type_enum tree_type = TreeType; + static const bool optimize_size = OptimizeSize; +}; + +#endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +//!This option setter specifies the underlying tree type +//!(red-black, AVL, Scapegoat or Splay) for ordered associative containers +BOOST_INTRUSIVE_OPTION_CONSTANT(tree_type, tree_type_enum, TreeType, tree_type) + +//!This option setter specifies if node size is optimized +//!storing rebalancing data masked into pointers for ordered associative containers +BOOST_INTRUSIVE_OPTION_CONSTANT(optimize_size, bool, Enabled, optimize_size) + +//! Helper metafunction to combine options into a single type to be used +//! by \c boost::container::set, \c boost::container::multiset +//! \c boost::container::map and \c boost::container::multimap. +//! Supported options are: \c boost::container::optimize_size and \c boost::container::tree_type +#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct tree_assoc_options +{ + /// @cond + typedef typename ::boost::intrusive::pack_options + < tree_assoc_defaults, + #if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + typedef tree_opt implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_OPTIONS_HPP diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index 1f5ab2b..0edea92 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -35,6 +35,8 @@ namespace boost { namespace container { +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! A set is a kind of associative container that supports unique keys (contains at //! most one of each key value) and provides for fast retrieval of the keys themselves. //! Class set supports bidirectional iterators. @@ -42,10 +44,14 @@ namespace container { //! A set satisfies all of the requirements of a container and of a reversible container //! , and of an associative container. A set also provides most operations described in //! for unique keys. -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = std::allocator > +//! +//! \tparam Key is the type to be inserted in the set, which is also the key_type +//! \tparam Compare is the comparison functor used to order keys +//! \tparam Allocator is the allocator to be used to allocate memory for this container +//! \tparam SetOptions is an packed option type generated using using boost::container::tree_assoc_options. +template , class Allocator = std::allocator, class SetOptions = tree_assoc_defaults > #else -template +template #endif class set { @@ -53,7 +59,7 @@ class set private: BOOST_COPYABLE_AND_MOVABLE(set) typedef container_detail::tree - < Key, Key, container_detail::identity, Compare, Allocator, tree_type_value> tree_t; + < Key, Key, container_detail::identity, Compare, Allocator, SetOptions> tree_t; tree_t m_tree; // red-black tree representing set #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -589,24 +595,51 @@ class set std::pair equal_range(const key_type& x) const { return m_tree.equal_range(x); } + //! Effects: Rebalances the tree. It's a no-op for Red-Black and AVL trees. + //! + //! Complexity: Linear + void rebalance() + { return m_tree.rebalance(); } + + //! Effects: Returns true if x and y are equal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator==(const set& x, const set& y) - { return x.m_tree == y.m_tree; } - - friend bool operator<(const set& x, const set& y) - { return x.m_tree < y.m_tree; } + { return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } + //! Effects: Returns true if x and y are unequal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator!=(const set& x, const set& y) - { return !(x == y); } + { return !(x == y); } + //! Effects: Returns true if x is less than y + //! + //! Complexity: Linear to the number of elements in the container. + friend bool operator<(const set& x, const set& y) + { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + //! Effects: Returns true if x is greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>(const set& x, const set& y) - { return y < x; } + { return y < x; } + //! Effects: Returns true if x is equal or less than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator<=(const set& x, const set& y) - { return !(y < x); } + { return !(y < x); } + //! Effects: Returns true if x is equal or greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>=(const set& x, const set& y) { return !(x < y); } + //! Effects: x.swap(y) + //! + //! Complexity: Constant. friend void swap(set& x, set& y) { x.swap(y); } @@ -628,8 +661,8 @@ class set //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { static const bool value = has_trivial_destructor_after_move::value && has_trivial_destructor_after_move::value; }; @@ -638,6 +671,8 @@ namespace container { #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! A multiset is a kind of associative container that supports equivalent keys //! (possibly contains multiple copies of the same key value) and provides for //! fast retrieval of the keys themselves. Class multiset supports bidirectional iterators. @@ -645,10 +680,14 @@ namespace container { //! A multiset satisfies all of the requirements of a container and of a reversible //! container, and of an associative container). multiset also provides most operations //! described for duplicate keys. -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = std::allocator > +//! +//! \tparam Key is the type to be inserted in the set, which is also the key_type +//! \tparam Compare is the comparison functor used to order keys +//! \tparam Allocator is the allocator to be used to allocate memory for this container +//! \tparam MultiSetOptions is an packed option type generated using using boost::container::tree_assoc_options. +template , class Allocator = std::allocator, class MultiSetOptions = tree_assoc_defaults > #else -template +template #endif class multiset { @@ -656,7 +695,7 @@ class multiset private: BOOST_COPYABLE_AND_MOVABLE(multiset) typedef container_detail::tree - , Compare, Allocator, tree_type_value> tree_t; + , Compare, Allocator, MultiSetOptions> tree_t; tree_t m_tree; // red-black tree representing multiset #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -1182,24 +1221,51 @@ class multiset std::pair equal_range(const key_type& x) const { return m_tree.equal_range(x); } + //! Effects: Rebalances the tree. It's a no-op for Red-Black and AVL trees. + //! + //! Complexity: Linear + void rebalance() + { return m_tree.rebalance(); } + + //! Effects: Returns true if x and y are equal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator==(const multiset& x, const multiset& y) - { return x.m_tree == y.m_tree; } - - friend bool operator<(const multiset& x, const multiset& y) - { return x.m_tree < y.m_tree; } + { return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } + //! Effects: Returns true if x and y are unequal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator!=(const multiset& x, const multiset& y) - { return !(x == y); } + { return !(x == y); } + //! Effects: Returns true if x is less than y + //! + //! Complexity: Linear to the number of elements in the container. + friend bool operator<(const multiset& x, const multiset& y) + { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + //! Effects: Returns true if x is greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>(const multiset& x, const multiset& y) { return y < x; } + //! Effects: Returns true if x is equal or less than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator<=(const multiset& x, const multiset& y) { return !(y < x); } + //! Effects: Returns true if x is equal or greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>=(const multiset& x, const multiset& y) { return !(x < y); } + //! Effects: x.swap(y) + //! + //! Complexity: Constant. friend void swap(multiset& x, multiset& y) { x.swap(y); } @@ -1222,8 +1288,8 @@ class multiset //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { static const bool value = has_trivial_destructor_after_move::value && has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 3620302..290dfc5 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -1423,6 +1423,9 @@ class slist void splice(const_iterator p, BOOST_RV_REF(slist) x, const_iterator first, const_iterator last) BOOST_CONTAINER_NOEXCEPT { this->splice(p, static_cast(x), first, last); } + //! Effects: Returns true if x and y are equal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator==(const slist& x, const slist& y) { if(x.size() != y.size()){ @@ -1440,26 +1443,41 @@ class slist return i1 == end1; } - friend bool operator<(const slist& x, const slist& y) - { - return std::lexicographical_compare - (x.begin(), x.end(), y.begin(), y.end()); - } - + //! Effects: Returns true if x and y are unequal + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator!=(const slist& x, const slist& y) - { return !(x == y); } + { return !(x == y); } + //! Effects: Returns true if x is less than y + //! + //! Complexity: Linear to the number of elements in the container. + friend bool operator<(const slist& x, const slist& y) + { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + //! Effects: Returns true if x is greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>(const slist& x, const slist& y) - { return y < x; } + { return y < x; } + //! Effects: Returns true if x is equal or less than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator<=(const slist& x, const slist& y) - { return !(y < x); } + { return !(y < x); } + //! Effects: Returns true if x is equal or greater than y + //! + //! Complexity: Linear to the number of elements in the container. friend bool operator>=(const slist& x, const slist& y) - { return !(x < y); } - + { return !(x < y); } + + //! Effects: x.swap(y) + //! + //! Complexity: Constant. friend void swap(slist& x, slist& y) - { x.swap(y); } + { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 9f64ed3..feff780 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -131,6 +131,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scoped_allocator_usage_test ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_custom_tree", "doc_custom_tree.vcproj", "{5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_extended_allocators", "doc_extended_allocators.vcproj", "{5CE11C83-FA84-295A-4FA2-D7921A0BAB02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -271,6 +279,14 @@ Global {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Debug.Build.0 = Debug|Win32 {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.ActiveCfg = Release|Win32 {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.Build.0 = Release|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Debug.ActiveCfg = Debug|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Debug.Build.0 = Debug|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Release.ActiveCfg = Release|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Release.Build.0 = Release|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Debug.Build.0 = Debug|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Release.ActiveCfg = Release|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 5327450..5ed1f0e 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -128,6 +128,9 @@ + + diff --git a/proj/vc7ide/doc_custom_tree.vcproj b/proj/vc7ide/doc_custom_tree.vcproj new file mode 100644 index 0000000..2a08e67 --- /dev/null +++ b/proj/vc7ide/doc_custom_tree.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_extended_allocators.vcproj b/proj/vc7ide/doc_extended_allocators.vcproj new file mode 100644 index 0000000..b488dc2 --- /dev/null +++ b/proj/vc7ide/doc_extended_allocators.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_recursive_containers.vcproj b/proj/vc7ide/doc_recursive_containers.vcproj index 758c1e6..1f36a8b 100644 --- a/proj/vc7ide/doc_recursive_containers.vcproj +++ b/proj/vc7ide/doc_recursive_containers.vcproj @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="7.10" Name="doc_recursive_containers" - ProjectGUID="{5D1C8E13-255A-FA84-4FA2-DA92100BAD42}" + ProjectGUID="{1B51C8B2-A832-F55A-4FA2-210AF9D43BD2}" Keyword="Win32Proj"> , typename boost::container::allocator_traits::template portable_rebind_alloc< std::pair >::type - , red_black_tree> + //tree_assoc_defaults + > { BOOST_COPYABLE_AND_MOVABLE(map_propagate_test_wrapper) typedef boost::container::map < T, T, std::less , typename boost::container::allocator_traits::template portable_rebind_alloc< std::pair >::type - , red_black_tree> Base; + > Base; public: map_propagate_test_wrapper() : Base() @@ -203,7 +204,7 @@ class map_propagate_test_wrapper }; -template +template struct GetAllocatorMap { template @@ -214,6 +215,9 @@ struct GetAllocatorMap , std::less , typename allocator_traits ::template portable_rebind_alloc< std::pair >::type + , typename boost::container::tree_assoc_options + < boost::container::tree_type + >::type > map_type; typedef multimap< ValueType @@ -221,22 +225,25 @@ struct GetAllocatorMap , std::less , typename allocator_traits ::template portable_rebind_alloc< std::pair >::type + , typename boost::container::tree_assoc_options + < boost::container::tree_type + >::type > multimap_type; }; }; -template +template int test_map_variants() { - typedef typename GetAllocatorMap::template apply::map_type MyMap; - typedef typename GetAllocatorMap::template apply::map_type MyMoveMap; - typedef typename GetAllocatorMap::template apply::map_type MyCopyMoveMap; - typedef typename GetAllocatorMap::template apply::map_type MyCopyMap; + typedef typename GetAllocatorMap::template apply::map_type MyMap; + typedef typename GetAllocatorMap::template apply::map_type MyMoveMap; + typedef typename GetAllocatorMap::template apply::map_type MyCopyMoveMap; + typedef typename GetAllocatorMap::template apply::map_type MyCopyMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyMultiMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyMoveMultiMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyCopyMoveMultiMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyCopyMultiMap; + typedef typename GetAllocatorMap::template apply::multimap_type MyMultiMap; + typedef typename GetAllocatorMap::template apply::multimap_type MyMoveMultiMap; + typedef typename GetAllocatorMap::template apply::multimap_type MyCopyMoveMultiMap; + typedef typename GetAllocatorMap::template apply::multimap_type MyCopyMultiMap; typedef std::map MyStdMap; typedef std::multimap MyStdMultiMap; @@ -298,34 +305,96 @@ int main () test_move >(); } - if(test_map_variants< std::allocator >()){ + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + // std:allocator + if(test_map_variants< std::allocator, red_black_tree >()){ std::cerr << "test_map_variants< std::allocator > failed" << std::endl; return 1; } - - if(test_map_variants< allocator >()){ + // boost::container::allocator + if(test_map_variants< allocator, red_black_tree >()){ std::cerr << "test_map_variants< allocator > failed" << std::endl; return 1; } - - if(test_map_variants< node_allocator >()){ + // boost::container::node_allocator + if(test_map_variants< node_allocator, red_black_tree >()){ std::cerr << "test_map_variants< node_allocator > failed" << std::endl; return 1; } - - if(test_map_variants< adaptive_pool >()){ + // boost::container::adaptive_pool + if(test_map_variants< adaptive_pool, red_black_tree >()){ std::cerr << "test_map_variants< adaptive_pool > failed" << std::endl; return 1; } + //////////////////////////////////// + // Tree implementations + //////////////////////////////////// + // AVL + if(test_map_variants< std::allocator, avl_tree >()){ + std::cerr << "test_map_variants< std::allocator, avl_tree > failed" << std::endl; + return 1; + } + // SCAPEGOAT TREE + if(test_map_variants< std::allocator, scapegoat_tree >()){ + std::cerr << "test_map_variants< std::allocator, scapegoat_tree > failed" << std::endl; + return 1; + } + // SPLAY TREE + if(test_map_variants< std::allocator, splay_tree >()){ + std::cerr << "test_map_variants< std::allocator, splay_tree > failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// const test::EmplaceOptions MapOptions = (test::EmplaceOptions)(test::EMPLACE_HINT_PAIR | test::EMPLACE_ASSOC_PAIR); if(!boost::container::test::test_emplace, MapOptions>()) return 1; if(!boost::container::test::test_emplace, MapOptions>()) return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// if(!boost::container::test::test_propagate_allocator()) return 1; + //////////////////////////////////// + // Test optimize_size option + //////////////////////////////////// + // + // map + // + typedef map< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > rbmap_size_optimized_no; + typedef map< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > rbmap_size_optimized_yes; + BOOST_STATIC_ASSERT(sizeof(rbmap_size_optimized_yes) < sizeof(rbmap_size_optimized_no)); + + typedef map< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > avlmap_size_optimized_no; + typedef map< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > avlmap_size_optimized_yes; + BOOST_STATIC_ASSERT(sizeof(avlmap_size_optimized_yes) < sizeof(avlmap_size_optimized_no)); + // + // multimap + // + typedef multimap< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > rbmmap_size_optimized_no; + typedef multimap< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > rbmmap_size_optimized_yes; + BOOST_STATIC_ASSERT(sizeof(rbmmap_size_optimized_yes) < sizeof(rbmmap_size_optimized_no)); + + typedef multimap< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > avlmmap_size_optimized_no; + typedef multimap< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > avlmmap_size_optimized_yes; + BOOST_STATIC_ASSERT(sizeof(avlmmap_size_optimized_yes) < sizeof(avlmmap_size_optimized_no)); + return 0; } diff --git a/test/map_test.hpp b/test/map_test.hpp index 2c6a7c9..98e1ba5 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -23,6 +23,13 @@ #include #include +#include +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME rebalance +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace test { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 0, )) +#include BOOST_PP_ITERATE() + template bool operator ==(std::pair &p1, std::pair &p2) { @@ -33,6 +40,16 @@ namespace boost{ namespace container { namespace test{ +template +void map_test_rebalanceable(C &, boost::container::container_detail::false_type) +{} + +template +void map_test_rebalanceable(C &c, boost::container::container_detail::true_type) +{ + c.rebalance(); +} + template::value>()); + if(!CheckEqualContainers(boostmap, stdmap)){ + std::cout << "Error in boostmap->rebalance()" << std::endl; + return 1; + } + map_test_rebalanceable(*boostmultimap + , container_detail::bool_::value>()); + if(!CheckEqualContainers(boostmultimap, stdmultimap)){ + std::cout << "Error in boostmultimap->rebalance()" << std::endl; + return 1; + } } //Compare count with std containers diff --git a/test/set_test.cpp b/test/set_test.cpp index c604343..f5416ca 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -145,10 +145,12 @@ void test_move() template class set_propagate_test_wrapper - : public boost::container::set, A, red_black_tree> + : public boost::container::set, A + //tree_assoc_defaults + > { BOOST_COPYABLE_AND_MOVABLE(set_propagate_test_wrapper) - typedef boost::container::set, A, red_black_tree> Base; + typedef boost::container::set, A > Base; public: set_propagate_test_wrapper() : Base() @@ -172,7 +174,7 @@ class set_propagate_test_wrapper { this->Base::swap(x); } }; -template +template struct GetAllocatorSet { template @@ -182,28 +184,34 @@ struct GetAllocatorSet , std::less , typename allocator_traits ::template portable_rebind_alloc::type + , typename boost::container::tree_assoc_options + < boost::container::tree_type + >::type > set_type; typedef multiset < ValueType , std::less , typename allocator_traits ::template portable_rebind_alloc::type + , typename boost::container::tree_assoc_options + < boost::container::tree_type + >::type > multiset_type; }; }; -template +template int test_set_variants() { - typedef typename GetAllocatorSet::template apply::set_type MySet; - typedef typename GetAllocatorSet::template apply::set_type MyMoveSet; - typedef typename GetAllocatorSet::template apply::set_type MyCopyMoveSet; - typedef typename GetAllocatorSet::template apply::set_type MyCopySet; + typedef typename GetAllocatorSet::template apply::set_type MySet; + typedef typename GetAllocatorSet::template apply::set_type MyMoveSet; + typedef typename GetAllocatorSet::template apply::set_type MyCopyMoveSet; + typedef typename GetAllocatorSet::template apply::set_type MyCopySet; - typedef typename GetAllocatorSet::template apply::multiset_type MyMultiSet; - typedef typename GetAllocatorSet::template apply::multiset_type MyMoveMultiSet; - typedef typename GetAllocatorSet::template apply::multiset_type MyCopyMoveMultiSet; - typedef typename GetAllocatorSet::template apply::multiset_type MyCopyMultiSet; + typedef typename GetAllocatorSet::template apply::multiset_type MyMultiSet; + typedef typename GetAllocatorSet::template apply::multiset_type MyMoveMultiSet; + typedef typename GetAllocatorSet::template apply::multiset_type MyCopyMoveMultiSet; + typedef typename GetAllocatorSet::template apply::multiset_type MyCopyMultiSet; typedef std::set MyStdSet; typedef std::multiset MyStdMultiSet; @@ -266,34 +274,95 @@ int main () test_move >(); } - if(test_set_variants< std::allocator >()){ + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + // std:allocator + if(test_set_variants< std::allocator, red_black_tree >()){ std::cerr << "test_set_variants< std::allocator > failed" << std::endl; return 1; } - - if(test_set_variants< allocator >()){ + // boost::container::allocator + if(test_set_variants< allocator, red_black_tree>()){ std::cerr << "test_set_variants< allocator > failed" << std::endl; return 1; } - - if(test_set_variants< node_allocator >()){ + // boost::container::node_allocator + if(test_set_variants< node_allocator, red_black_tree>()){ std::cerr << "test_set_variants< node_allocator > failed" << std::endl; return 1; } - - if(test_set_variants< adaptive_pool >()){ + // boost::container::adaptive_pool + if(test_set_variants< adaptive_pool, red_black_tree>()){ std::cerr << "test_set_variants< adaptive_pool > failed" << std::endl; return 1; } + //////////////////////////////////// + // Tree implementations + //////////////////////////////////// + // AVL + if(test_set_variants< std::allocator, avl_tree >()){ + std::cerr << "test_set_variants< std::allocator, avl_tree > failed" << std::endl; + return 1; + } + // SCAPEGOAT TREE + if(test_set_variants< std::allocator, scapegoat_tree >()){ + std::cerr << "test_set_variants< std::allocator, scapegoat_tree > failed" << std::endl; + return 1; + } + // SPLAY TREE + if(test_set_variants< std::allocator, splay_tree >()){ + std::cerr << "test_set_variants< std::allocator, splay_tree > failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC); if(!boost::container::test::test_emplace, SetOptions>()) return 1; if(!boost::container::test::test_emplace, SetOptions>()) return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// if(!boost::container::test::test_propagate_allocator()) return 1; + //////////////////////////////////// + // Test optimize_size option + //////////////////////////////////// + // + // set + // + typedef set< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > rbset_size_optimized_no; + typedef set< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > rbset_size_optimized_yes; + BOOST_STATIC_ASSERT(sizeof(rbset_size_optimized_yes) < sizeof(rbset_size_optimized_no)); + + typedef set< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > avlset_size_optimized_no; + typedef set< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > avlset_size_optimized_yes; + BOOST_STATIC_ASSERT(sizeof(avlset_size_optimized_yes) < sizeof(avlset_size_optimized_no)); + // + // multiset + // + typedef multiset< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > rbmset_size_optimized_no; + typedef multiset< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > rbmset_size_optimized_yes; + BOOST_STATIC_ASSERT(sizeof(rbmset_size_optimized_yes) < sizeof(rbmset_size_optimized_no)); + + typedef multiset< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > avlmset_size_optimized_no; + typedef multiset< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > avlmset_size_optimized_yes; + BOOST_STATIC_ASSERT(sizeof(avlmset_size_optimized_yes) < sizeof(avlmset_size_optimized_no)); return 0; } diff --git a/test/set_test.hpp b/test/set_test.hpp index dea835f..871adce 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -21,10 +21,28 @@ #include #include +#include +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME rebalance +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace test { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 0, )) +#include BOOST_PP_ITERATE() + + namespace boost{ namespace container { namespace test{ +template +void set_test_rebalanceable(C &, boost::container::container_detail::false_type) +{} + +template +void set_test_rebalanceable(C &c, boost::container::container_detail::true_type) +{ + c.rebalance(); +} + templateinsert(boostmultiset->lower_bound(move_me2), boost::move(move_me2))" << std::endl; return 1; } + set_test_rebalanceable(*boostset + , container_detail::bool_::value>()); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset->rebalance()" << std::endl; + return 1; + } + set_test_rebalanceable(*boostmultiset + , container_detail::bool_::value>()); + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset->rebalance()" << std::endl; + return 1; + } } }