From 43a784a1f9d071b0a6455339290928a509ef9ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 26 Dec 2011 17:12:31 +0000 Subject: [PATCH] Changes for 1.49 [SVN r76180] --- doc/container.qbk | 57 ++- proj/to-do.txt | 44 +++ proj/vc7ide/allocator_traits_test.vcproj | 139 +++++++ proj/vc7ide/container.sln | 52 ++- proj/vc7ide/container.vcproj | 282 +++++++------- .../{list_ex.vcproj => list_test.vcproj} | 0 proj/vc7ide/pair_test.vcproj | 133 +++++++ test/allocator_traits_test.cpp | 355 ++++++++++++++++++ test/check_equal_containers.hpp | 6 +- test/deque_test.cpp | 44 ++- test/dummy_test_allocator.hpp | 232 +++++++++++- test/emplace_test.hpp | 92 ++--- test/expand_bwd_test_allocator.hpp | 12 +- test/flat_tree_test.cpp | 148 +++++++- test/heap_allocator_v1.hpp | 2 +- test/list_test.cpp | 17 + test/list_test.hpp | 6 +- test/map_test.hpp | 25 +- test/movable_int.hpp | 39 ++ test/pair_test.cpp | 54 +++ test/propagate_allocator_test.hpp | 181 +++++++++ test/set_test.hpp | 1 + test/slist_test.cpp | 15 + test/stable_vector_test.cpp | 27 +- test/string_test.cpp | 221 +++++++++-- test/tree_test.cpp | 157 +++++++- test/vector_test.cpp | 19 +- test/vector_test.hpp | 7 +- 28 files changed, 2034 insertions(+), 333 deletions(-) create mode 100644 proj/vc7ide/allocator_traits_test.vcproj rename proj/vc7ide/{list_ex.vcproj => list_test.vcproj} (100%) create mode 100644 proj/vc7ide/pair_test.vcproj create mode 100644 test/allocator_traits_test.cpp create mode 100644 test/pair_test.cpp create mode 100644 test/propagate_allocator_test.hpp diff --git a/doc/container.qbk b/doc/container.qbk index a9c4337..54f37c3 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -60,7 +60,7 @@ compiler include path. [*Boost.Container] requires a decent C++98 compatibility. Some compilers known to work are: * Visual C++ >= 7.1. -* GCC >= 3.4. +* GCC >= 4.1. * Intel C++ >= 9.0 [endsect] @@ -412,7 +412,7 @@ a finite (10) number of parameters. [endsect] -[section:alloc_traits_move_traits Stateful allocators and Scoped allocators] +[section:alloc_traits_move_traits Stateful allocators] C++03 was not stateful-allocator friendly. For compactness of container objects and for simplicity, it did not require containers to support allocators with state: Allocator objects @@ -422,24 +422,18 @@ to suppose two allocators of the same type always compare equal (that means that by one allocator object could be deallocated by another instance of the same type) and allocators were not swapped when the container was swapped. -Many C++ container implementors felt C++03 guarantees were too weak and started to offer extensions. -[*Boost.Container], following [@http://www.boost.org/libs/interprocess/ Boost.Interprocess] -containers experience supporting stateful allocators, offers the following guarantees: - -* Allocators are copy-constructed in copy/move constructors -* If possible, a single allocator is hold to construct `value_type` and this allocator is copy constructed - from the user-supplied allocator object during container's constructor. If the container needs an auxiliary - allocator (e.g. a array allocator used by `deque` or `stable_vector`), that allocator is also - copy-constructed from the user-supplied allocator when the container is constructed (i.e. it's - not constructed on the fly when auxiliary memory is needed). -* Allocators are compared for equality when swapping containers. If allocators don't compare - equal allocators are swapped using an unqualified `swap` call. - C++11 further improves stateful allocator support through the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2554.pdf -Scoped Allocators model], using classes like `std::scoped_allocator_adaptor` and `std::allocator_traits`. -[*Boost.Container does not support it yet, but there are plans to do so and backport scoped allocator -support to C++03 compilers. +Scoped Allocators model]. [@http://en.cppreference.com/w/cpp/memory/allocator_traits +`std::allocator_traits`] is the protocol between a container and an allocator, and +an allocator writer can customize its behaviour (should the container propagate it in +move constructor, swap, etc.?) following `allocator_traits` requirements. [*Boost.Container] +not only supports this model with C++11 but also [*backports it to C++03]. + +If possible, a single allocator is hold to construct `value_type`. If the container needs an auxiliary +allocator (e.g. a array allocator used by `deque` or `stable_vector`), that allocator is also +constructed from the user-supplied allocator when the container is constructed (i.e. it's +not constructed on the fly when auxiliary memory is needed). [endsect] @@ -451,7 +445,14 @@ to C++03 compilers. [endsect] -[section:Vector_bool vector] +[section:forward_list `forward_list`] + +[*Boost.Container] does not offer C++11 `forward_list` container yet, but it will be available in future +versions. + +[endsect] + +[section:Vector_bool `vector`] `vector` specialization has been quite problematic, and there have been several unsuccessful tries to deprecate or remove it from the standard. [*Boost.Container] does not implement it @@ -584,7 +585,23 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] -* First release with Boost 1.48. Container code from [*Boost.Interprocess] was deleted +[section:release_notes_boost_1_49_00 Boost 1.49 Release] + +* Fixed bugs + [@https://svn.boost.org/trac/boost/ticket/6205 #6205], + [@https://svn.boost.org/trac/boost/ticket/6287 #6287], + [@https://svn.boost.org/trac/boost/ticket/4383 #4383]. + +* Added `allocator_traits` support for both C++11 and C++03 + compilers through an internal `allocator_traits` clone. + +[endsect] + +[section:release_notes_boost_1_48_00 Boost 1.48 Release] + +* First release. Container code from [*Boost.Interprocess] was deleted and redirected to [*Boost.Container ] via using directives. [endsect] + +[endsect] diff --git a/proj/to-do.txt b/proj/to-do.txt index c7f77cf..d82bd8a 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -1,2 +1,46 @@ ->Change "insert" and "push_back"/"push_front" to catch non-const rvalues ->Add an example with stateful allocators +->Add test to check convertible types in push_back/insert + + +Review allocator traits +-> Explicit instantiation of simple allocator & std::allocator to detect missing allocator_traits calls +-> Avoid any rebind<>::other +-> Review select_on_container_copy_xxx +-> Review propagate_on_xxx +-> Put default constructed containers with their own constructor (different nothrow guarantees). Optimization, not needed +-> Default + swap move constructors correct? +-> Review container documentation in swap/copy/move regarding allocators + +Check all move constructors: swap might not be a valid idiom, allocators must be move constructed, intrusive containers are now movable + +Add and test: + +Test different propagation values and with inequal allocators + + +propagate_on_container_move_assignment +select_on_container_copy_construction +propagate_on_container_swap +propagate_on_container_copy_assignment + +Test move constructors with data values and unequal allocators + +An allocator should use a smart allocator not constructible from raw pointers to catch missing pointer_traits calls + +Review all internal container swap's to check allocator propagation is correct + +Add initializer lists + +Write forward_list + +Review all move constructors to test if allocator is move constructed + +check move if noexcept conditions in vector, deque and stable_vector + +Add new allocator propagation copy constructors + +Review all destructors (search for "~") to detect placement destruction and replace it with allocator_traits::destroy + +All functions from base classes like vector_base, node_alloc_holder, etc., should be named with underscore or +similar to avoid namespace pollution. \ No newline at end of file diff --git a/proj/vc7ide/allocator_traits_test.vcproj b/proj/vc7ide/allocator_traits_test.vcproj new file mode 100644 index 0000000..ad50eba --- /dev/null +++ b/proj/vc7ide/allocator_traits_test.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index ea29003..38cb19d 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -1,4 +1,12 @@ Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_containerlib", "container.vcproj", "{FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "allocator_traits_test", "allocator_traits_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deque_test", "deque_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792655}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -7,7 +15,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_tree_test", "flat_tree ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_ex.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist_test", "slist_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792608}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject @@ -23,15 +31,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tree_test", "tree_test.vcpr ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist_test", "slist_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792608}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_test", "vector_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_containerlib", "container.vcproj", "{FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pair_test", "pair_test.vcproj", "{58CA17C5-A74F-9602-48FE-B06310DA7FA6}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject @@ -43,6 +51,14 @@ Global GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution + {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Debug.ActiveCfg = Debug|Win32 + {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Debug.Build.0 = Debug|Win32 + {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Release.ActiveCfg = Release|Win32 + {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Release.Build.0 = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.ActiveCfg = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.ActiveCfg = Release|Win32 @@ -51,10 +67,10 @@ Global {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.Build.0 = Release|Win32 {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Debug.ActiveCfg = Debug|Win32 {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Debug.Build.0 = Debug|Win32 {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Release.ActiveCfg = Release|Win32 @@ -67,18 +83,18 @@ Global {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.Build.0 = Release|Win32 {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 - {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Debug.ActiveCfg = Debug|Win32 - {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Debug.Build.0 = Debug|Win32 - {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Release.ActiveCfg = Release|Win32 - {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Release.Build.0 = Release|Win32 + {58CA17C5-A74F-9602-48FE-B06310DA7FA6}.Debug.ActiveCfg = Debug|Win32 + {58CA17C5-A74F-9602-48FE-B06310DA7FA6}.Debug.Build.0 = Debug|Win32 + {58CA17C5-A74F-9602-48FE-B06310DA7FA6}.Release.ActiveCfg = Release|Win32 + {58CA17C5-A74F-9602-48FE-B06310DA7FA6}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 500b5ca..7588d88 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -96,86 +96,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -209,15 +130,9 @@ - - - - @@ -230,18 +145,12 @@ - - - - @@ -254,67 +163,154 @@ + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/list_ex.vcproj b/proj/vc7ide/list_test.vcproj similarity index 100% rename from proj/vc7ide/list_ex.vcproj rename to proj/vc7ide/list_test.vcproj diff --git a/proj/vc7ide/pair_test.vcproj b/proj/vc7ide/pair_test.vcproj new file mode 100644 index 0000000..6f32b3e --- /dev/null +++ b/proj/vc7ide/pair_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/allocator_traits_test.cpp b/test/allocator_traits_test.cpp new file mode 100644 index 0000000..ed109d4 --- /dev/null +++ b/test/allocator_traits_test.cpp @@ -0,0 +1,355 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2011. 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 +#include +#include +#include +#include +#include +#include + +template +class SimpleAllocator +{ + bool allocate_called_; + bool deallocate_called_; + public: + typedef T value_type; + + SimpleAllocator() + : allocate_called_(false) + , deallocate_called_(false) + {} + + T* allocate(std::size_t) + { allocate_called_ = true; return 0; } + + void deallocate(T*, std::size_t) + { deallocate_called_ = true; } + + bool allocate_called() const + { return allocate_called_; } + + bool deallocate_called() const + { return deallocate_called_; } +}; + +template +class SimpleSmartPtr +{ + public: + + SimpleSmartPtr() + : ptr_(0) + {} + + SimpleSmartPtr(const SimpleSmartPtr &c) + { this->ptr_ = c.ptr_; } + + SimpleSmartPtr & operator=(const SimpleSmartPtr &c) + { this->ptr_ = c.ptr_; } + + typedef T* pointer; + + private: + T *ptr_; +}; + +template +class ComplexAllocator +{ + bool allocate_called_; + bool deallocate_called_; + bool allocate_hint_called_; + bool destroy_called_; + mutable bool max_size_called_; + mutable bool select_on_container_copy_construction_called_; + bool construct_called_; + + public: + typedef T value_type; + typedef SimpleSmartPtr pointer; + typedef SimpleSmartPtr const_pointer; + typedef T & reference; + typedef const T & const_reference; + typedef SimpleSmartPtr void_pointer; + typedef SimpleSmartPtr const_void_pointer; + typedef signed short difference_type; + typedef unsigned short size_type; + typedef boost::true_type propagate_on_container_copy_assignment; + typedef boost::true_type propagate_on_container_move_assignment; + typedef boost::true_type propagate_on_container_swap; + + ComplexAllocator() + : allocate_called_(false) + , deallocate_called_(false) + , allocate_hint_called_(false) + , destroy_called_(false) + , max_size_called_(false) + , select_on_container_copy_construction_called_(false) + , construct_called_(false) + {} + + pointer allocate(size_type) + { allocate_called_ = true; return pointer(); } + + void deallocate(pointer, size_type) + { deallocate_called_ = true; } + + //optional + ComplexAllocator select_on_container_copy_construction() const + { select_on_container_copy_construction_called_ = true; return *this; } + + pointer allocate(size_type n, const const_void_pointer &) + { allocate_hint_called_ = true; return allocate(n); } + + template + void destroy(U*) + { destroy_called_ = true; } + + size_type max_size() const + { max_size_called_ = true; return size_type(size_type(0)-1); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void construct(U *p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + construct_called_ = true; \ + ::new (p) U (BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ + } \ + // + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + //getters + bool allocate_called() const + { return allocate_called_; } + + bool deallocate_called() const + { return deallocate_called_; } + + bool allocate_hint_called() const + { return allocate_hint_called_; } + + bool destroy_called() const + { return destroy_called_; } + + bool max_size_called() const + { return max_size_called_; } + + bool select_on_container_copy_construction_called() const + { return select_on_container_copy_construction_called_; } + + bool construct_called() const + { return construct_called_; } +}; + +class copymovable +{ + bool copymoveconstructed_; + bool moved_; + + BOOST_COPYABLE_AND_MOVABLE(copymovable) + + public: + + copymovable(int, int, int) + : copymoveconstructed_(false), moved_(false) + {} + + copymovable() + : copymoveconstructed_(false), moved_(false) + {} + + copymovable(const copymovable &) + : copymoveconstructed_(true), moved_(false) + {} + + copymovable(BOOST_RV_REF(copymovable)) + : copymoveconstructed_(true), moved_(true) + {} + + copymovable & operator=(BOOST_COPY_ASSIGN_REF(copymovable) ){ return *this; } + copymovable & operator=(BOOST_RV_REF(copymovable) ){ return *this; } + + bool copymoveconstructed() const + { return copymoveconstructed_; } + + bool moved() const + { return moved_; } +}; + +int main() +{ + //SimpleAllocator + BOOST_STATIC_ASSERT(( boost::is_same >::value_type, int>::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::pointer, int*>::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::const_pointer, const int*>::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::void_pointer, void*>::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::const_void_pointer, const void*>::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::difference_type, std::ptrdiff_t>::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::size_type, std::size_t>::value )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::propagate_on_container_copy_assignment::value == false )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::propagate_on_container_move_assignment::value == false )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::propagate_on_container_swap::value == false )); + BOOST_STATIC_ASSERT(( boost::is_same >::rebind_traits::allocator_type + , SimpleAllocator >::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::rebind_alloc::value_type + , double >::value )); + + //ComplexAllocator + BOOST_STATIC_ASSERT(( boost::is_same >::value_type, int>::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::pointer, SimpleSmartPtr >::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::const_pointer, SimpleSmartPtr >::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::void_pointer, SimpleSmartPtr >::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::const_void_pointer, SimpleSmartPtr >::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::difference_type, signed short>::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::size_type, unsigned short>::value )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::propagate_on_container_copy_assignment::value == true )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::propagate_on_container_move_assignment::value == true )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::propagate_on_container_swap::value == true )); + BOOST_STATIC_ASSERT(( boost::is_same >::rebind_traits::allocator_type + , ComplexAllocator >::value )); + BOOST_STATIC_ASSERT(( boost::is_same >::rebind_alloc::value_type + , double >::value )); + + typedef ComplexAllocator CAlloc; + typedef SimpleAllocator SAlloc; + typedef boost::container::allocator_traits CAllocTraits; + typedef boost::container::allocator_traits SAllocTraits; + CAlloc c_alloc; + SAlloc s_alloc; + + //allocate + CAllocTraits::allocate(c_alloc, 1); + if(!c_alloc.allocate_called()){ + return 1; + } + SAllocTraits::allocate(s_alloc, 1); + if(!s_alloc.allocate_called()){ + return 1; + } + + //deallocate + CAllocTraits::deallocate(c_alloc, CAllocTraits::pointer(), 1); + if(!c_alloc.deallocate_called()){ + return 1; + } + SAllocTraits::deallocate(s_alloc, SAllocTraits::pointer(), 1); + if(!s_alloc.deallocate_called()){ + return 1; + } + + //allocate with hint + CAllocTraits::allocate(c_alloc, 1, CAllocTraits::const_void_pointer()); + if(!c_alloc.allocate_hint_called()){ + return 1; + } + SAllocTraits::allocate(s_alloc, 1, SAllocTraits::const_void_pointer()); + + //destroy + float dummy; + CAllocTraits::destroy(c_alloc, &dummy); + if(!c_alloc.destroy_called()){ + return 1; + } + SAllocTraits::destroy(s_alloc, &dummy); + + //max_size + CAllocTraits::max_size(c_alloc); + if(!c_alloc.max_size_called()){ + return 1; + } + SAllocTraits::max_size(s_alloc); + + //select_on_container_copy_construction + CAllocTraits::select_on_container_copy_construction(c_alloc); + if(!c_alloc.select_on_container_copy_construction_called()){ + return 1; + } + SAllocTraits::select_on_container_copy_construction(s_alloc); + + //construct + { + copymovable c; + copymovable c2; + CAllocTraits::construct(c_alloc, &c, c2); + if(!c_alloc.construct_called() || !c.copymoveconstructed() || c.moved()){ + return 1; + } + } + { + copymovable c; + copymovable c2; + CAllocTraits::construct(c_alloc, &c, ::boost::move(c2)); + if(!c_alloc.construct_called() || !c.copymoveconstructed() || !c.moved()){ + return 1; + } + } + { + copymovable c; + copymovable c2; + SAllocTraits::construct(s_alloc, &c, c2); + if(!c.copymoveconstructed() || c.moved()){ + return 1; + } + } + { + copymovable c; + copymovable c2; + SAllocTraits::construct(s_alloc, &c, ::boost::move(c2)); + if(!c.copymoveconstructed() || !c.moved()){ + return 1; + } + } + { + copymovable c; + CAllocTraits::construct(c_alloc, &c, 0, 1, 2); + if(!c_alloc.construct_called() || c.copymoveconstructed() || c.moved()){ + return 1; + } + } + { + copymovable c; + copymovable c2; + SAllocTraits::construct(s_alloc, &c, 0, 1, 2); + if(c.copymoveconstructed() || c.moved()){ + return 1; + } + } + + return 0; +} +#include diff --git a/test/check_equal_containers.hpp b/test/check_equal_containers.hpp index ccdfa45..ad89e6b 100644 --- a/test/check_equal_containers.hpp +++ b/test/check_equal_containers.hpp @@ -8,8 +8,8 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINERS_HPP -#define BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINERS_HPP +#ifndef BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINER_HPP +#define BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINER_HPP #include #include @@ -73,4 +73,4 @@ bool CheckEqualPairContainers(MyBoostCont *boostcont, MyStdCont *stdcont) #include -#endif //#ifndef BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINERS_HPP +#endif //#ifndef BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINER_HPP diff --git a/test/deque_test.cpp b/test/deque_test.cpp index ad4b7ac..bc8bf9e 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -26,26 +26,39 @@ #include #include #include "emplace_test.hpp" +#include "propagate_allocator_test.hpp" #include "vector_test.hpp" - using namespace boost::container; +namespace boost { +namespace container { + //Explicit instantiation to detect compilation errors +template class boost::container::deque + < test::movable_and_copyable_int + , test::simple_allocator >; + template class boost::container::deque < test::movable_and_copyable_int , test::dummy_test_allocator >; +template class boost::container::deque + < test::movable_and_copyable_int + , std::allocator >; + +}} + //Function to check if both sets are equal template -bool deque_copyable_only(V1 *, V2 *, containers_detail::false_type) +bool deque_copyable_only(V1 *, V2 *, container_detail::false_type) { return true; } //Function to check if both sets are equal template -bool deque_copyable_only(V1 *cntdeque, V2 *stddeque, containers_detail::true_type) +bool deque_copyable_only(V1 *cntdeque, V2 *stddeque, container_detail::true_type) { typedef typename V1::value_type IntType; std::size_t size = cntdeque->size(); @@ -100,6 +113,10 @@ bool deque_copyable_only(V1 *cntdeque, V2 *stddeque, containers_detail::true_typ class recursive_deque { public: + + recursive_deque & operator=(const recursive_deque &x) + { this->deque_ = x.deque_; return *this; } + int id_; deque deque_; }; @@ -161,6 +178,7 @@ bool do_test() typename MyCntDeque::iterator it; typename MyCntDeque::const_iterator cit = it; + (void)cit; cntdeque->erase(cntdeque->begin()++); stddeque->erase(stddeque->begin()++); @@ -212,7 +230,7 @@ bool do_test() } if(!deque_copyable_only(cntdeque, stddeque - ,containers_detail::bool_::value>())){ + ,container_detail::bool_::value>())){ return false; } @@ -268,6 +286,21 @@ int main () if(!do_test()) return 1; + if(!do_test()) + return 1; + + if(!do_test()) + return 1; + + //Test non-copy-move operations + { + deque d; + d.emplace_back(); + d.emplace_front(1); + d.resize(10); + d.resize(1); + } + { typedef deque MyDeque; typedef deque MyMoveDeque; @@ -289,6 +322,9 @@ int main () < deque, Options>()) return 1; + if(!boost::container::test::test_propagate_allocator()) + return 1; + return 0; } diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index e03255e..719d0ca 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -23,7 +23,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -37,34 +40,59 @@ namespace boost { namespace container { namespace test { -//This allocator just allows two allocations. The first one will return -//mp_buffer + m_offset configured in the constructor. The second one -//will return mp_buffer. +//Very simple version 1 allocator +template +class simple_allocator +{ + public: + typedef T value_type; + + simple_allocator() + {} + + template + simple_allocator(const simple_allocator &) + {} + + T* allocate(std::size_t n) + { return (T*)::new char[sizeof(T)*n]; } + + void deallocate(T*p, std::size_t) + { delete[] ((char*)p);} + + friend bool operator==(const simple_allocator &, const simple_allocator &) + { return true; } + + friend bool operator!=(const simple_allocator &, const simple_allocator &) + { return false; } +}; + +//Version 2 allocator with rebind template class dummy_test_allocator { private: - typedef dummy_test_allocator self_t; + typedef dummy_test_allocator self_t; typedef void * aux_pointer_t; typedef const void * cvoid_ptr; - template - dummy_test_allocator& operator=(const dummy_test_allocator&); - - dummy_test_allocator& operator=(const dummy_test_allocator&); - public: typedef T value_type; typedef T * pointer; typedef const T * const_pointer; - typedef typename containers_detail::add_reference + typedef typename container_detail::add_reference ::type reference; - typedef typename containers_detail::add_reference + typedef typename container_detail::add_reference ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; -// typedef boost::container::version_type version; + typedef container_detail::basic_multiallocation_chain + multialloc_cached_counted; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + typedef boost::container::container_detail::version_type version; template struct rebind @@ -115,7 +143,7 @@ class dummy_test_allocator size_type, size_type, size_type &, const pointer & = 0) - { return std::pair(pointer(0), true); } + { return std::pair(pointer(), true); } //!Returns maximum the number of objects the previously allocated memory //!pointed by p can hold. @@ -126,26 +154,198 @@ class dummy_test_allocator //!must be deallocated only with deallocate_one(). //!Throws boost::container::bad_alloc if there is no enough memory pointer allocate_one() - { return pointer(0); } + { return pointer(); } //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &) {} + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + multiallocation_chain allocate_individual(size_type) + { return multiallocation_chain(); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain) + {} + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain) + {} }; //!Equality test for same type of dummy_test_allocator template inline bool operator==(const dummy_test_allocator &, const dummy_test_allocator &) -{ return false; } +{ return true; } //!Inequality test for same type of dummy_test_allocator template inline bool operator!=(const dummy_test_allocator &, const dummy_test_allocator &) -{ return true; } +{ return false; } + + +template< class T + , bool PropagateOnContCopyAssign + , bool PropagateOnContMoveAssign + , bool PropagateOnContSwap + , bool CopyOnPropagateOnContSwap + > +class propagation_test_allocator +{ + BOOST_COPYABLE_AND_MOVABLE(propagation_test_allocator) + + public: + typedef T value_type; + typedef boost::container::container_detail::bool_ + propagate_on_container_copy_assignment; + typedef boost::container::container_detail::bool_ + propagate_on_container_move_assignment; + typedef boost::container::container_detail::bool_ + propagate_on_container_swap; + + template + struct rebind + { typedef propagation_test_allocator + < T2 + , PropagateOnContCopyAssign + , PropagateOnContMoveAssign + , PropagateOnContSwap + , CopyOnPropagateOnContSwap> other; + }; + + propagation_test_allocator select_on_container_copy_construction() const + { return CopyOnPropagateOnContSwap ? propagation_test_allocator(*this) : propagation_test_allocator(); } + + explicit propagation_test_allocator() + : id_(unique_id_++) + , ctr_copies_(0) + , ctr_moves_(0) + , assign_copies_(0) + , assign_moves_(0) + , swaps_(0) + {} + + propagation_test_allocator(const propagation_test_allocator &x) + : id_(x.id_) + , ctr_copies_(x.ctr_copies_+1) + , ctr_moves_(x.ctr_moves_) + , assign_copies_(x.assign_copies_) + , assign_moves_(x.assign_moves_) + , swaps_(x.swaps_) + {} + + template + propagation_test_allocator(const propagation_test_allocator + < U + , PropagateOnContCopyAssign + , PropagateOnContMoveAssign + , PropagateOnContSwap + , CopyOnPropagateOnContSwap> &x) + : id_(x.id_) + , ctr_copies_(0) + , ctr_moves_(0) + , assign_copies_(0) + , assign_moves_(0) + , swaps_(0) + {} + + propagation_test_allocator(BOOST_RV_REF(propagation_test_allocator) x) + : id_(x.id_) + , ctr_copies_(x.ctr_copies_) + , ctr_moves_(x.ctr_moves_ + 1) + , assign_copies_(x.assign_copies_) + , assign_moves_(x.assign_moves_) + , swaps_(x.swaps_) + {} + + propagation_test_allocator &operator=(BOOST_COPY_ASSIGN_REF(propagation_test_allocator) x) + { + id_ = x.id_; + ctr_copies_ = x.ctr_copies_; + ctr_moves_ = x.ctr_moves_; + assign_copies_ = x.assign_copies_+1; + assign_moves_ = x.assign_moves_; + swaps_ = x.swaps_; + return *this; + } + + propagation_test_allocator &operator=(BOOST_RV_REF(propagation_test_allocator) x) + { + id_ = x.id_; + ctr_copies_ = x.ctr_copies_; + ctr_moves_ = x.ctr_moves_; + assign_copies_ = x.assign_copies_; + assign_moves_ = x.assign_moves_+1; + swaps_ = x.swaps_; + return *this; + } + + static void reset_unique_id() + { unique_id_ = 0; } + + T* allocate(std::size_t n) + { return (T*)::new char[sizeof(T)*n]; } + + void deallocate(T*p, std::size_t) + { delete[] ((char*)p);} + + friend bool operator==(const propagation_test_allocator &, const propagation_test_allocator &) + { return true; } + + friend bool operator!=(const propagation_test_allocator &, const propagation_test_allocator &) + { return false; } + + friend void swap(propagation_test_allocator &l, propagation_test_allocator &r) + { + ++l.swaps_; ++r.swaps_; + container_detail::do_swap(l.id_, r.id_); + container_detail::do_swap(l.ctr_copies_, r.ctr_copies_); + container_detail::do_swap(l.ctr_moves_, r.ctr_moves_); + container_detail::do_swap(l.assign_copies_, r.assign_copies_); + container_detail::do_swap(l.assign_moves_, r.assign_moves_); + container_detail::do_swap(l.swaps_, r.swaps_); + } + + unsigned int id_; + unsigned int ctr_copies_; + unsigned int ctr_moves_; + unsigned int assign_copies_; + unsigned int assign_moves_; + unsigned int swaps_; + static unsigned unique_id_; +}; + +template< class T + , bool PropagateOnContCopyAssign + , bool PropagateOnContMoveAssign + , bool PropagateOnContSwap + , bool CopyOnPropagateOnContSwap + > +unsigned int propagation_test_allocator< T + , PropagateOnContCopyAssign + , PropagateOnContMoveAssign + , PropagateOnContSwap + , CopyOnPropagateOnContSwap>::unique_id_ = 0; + } //namespace test { } //namespace container { diff --git a/test/emplace_test.hpp b/test/emplace_test.hpp index 3cae3f8..ff93659 100644 --- a/test/emplace_test.hpp +++ b/test/emplace_test.hpp @@ -157,7 +157,7 @@ static EmplaceIntPair * expected_pair = initialize_emplace_int_pair(); template -bool test_emplace_back(containers_detail::true_) +bool test_emplace_back(container_detail::true_) { std::cout << "Starting test_emplace_back." << std::endl << " Class: " << typeid(Container).name() << std::endl; @@ -194,11 +194,11 @@ bool test_emplace_back(containers_detail::true_) } template -bool test_emplace_back(containers_detail::false_) +bool test_emplace_back(container_detail::false_) { return true; } template -bool test_emplace_front(containers_detail::true_) +bool test_emplace_front(container_detail::true_) { std::cout << "Starting test_emplace_front." << std::endl << " Class: " << typeid(Container).name() << std::endl; @@ -234,11 +234,11 @@ bool test_emplace_front(containers_detail::true_) } template -bool test_emplace_front(containers_detail::false_) +bool test_emplace_front(container_detail::false_) { return true; } template -bool test_emplace_before(containers_detail::true_) +bool test_emplace_before(container_detail::true_) { std::cout << "Starting test_emplace_before." << std::endl << " Class: " << typeid(Container).name() << std::endl; @@ -309,11 +309,11 @@ bool test_emplace_before(containers_detail::true_) } template -bool test_emplace_before(containers_detail::false_) +bool test_emplace_before(container_detail::false_) { return true; } template -bool test_emplace_after(containers_detail::true_) +bool test_emplace_after(container_detail::true_) { std::cout << "Starting test_emplace_after." << std::endl << " Class: " << typeid(Container).name() << std::endl; @@ -383,11 +383,11 @@ bool test_emplace_after(containers_detail::true_) } template -bool test_emplace_after(containers_detail::false_) +bool test_emplace_after(container_detail::false_) { return true; } template -bool test_emplace_assoc(containers_detail::true_) +bool test_emplace_assoc(container_detail::true_) { std::cout << "Starting test_emplace_assoc." << std::endl << " Class: " << typeid(Container).name() << std::endl; @@ -423,11 +423,11 @@ bool test_emplace_assoc(containers_detail::true_) } template -bool test_emplace_assoc(containers_detail::false_) +bool test_emplace_assoc(container_detail::false_) { return true; } template -bool test_emplace_hint(containers_detail::true_) +bool test_emplace_hint(container_detail::true_) { std::cout << "Starting test_emplace_hint." << std::endl << " Class: " << typeid(Container).name() << std::endl; @@ -466,11 +466,11 @@ bool test_emplace_hint(containers_detail::true_) } template -bool test_emplace_hint(containers_detail::false_) +bool test_emplace_hint(container_detail::false_) { return true; } template -bool test_emplace_assoc_pair(containers_detail::true_) +bool test_emplace_assoc_pair(container_detail::true_) { std::cout << "Starting test_emplace_assoc_pair." << std::endl << " Class: " << typeid(Container).name() << std::endl; @@ -478,15 +478,9 @@ bool test_emplace_assoc_pair(containers_detail::true_) new(&expected_pair[0].first) EmplaceInt(); new(&expected_pair[0].second) EmplaceInt(); new(&expected_pair[1].first) EmplaceInt(1); - new(&expected_pair[1].second) EmplaceInt(); + new(&expected_pair[1].second) EmplaceInt(1); new(&expected_pair[2].first) EmplaceInt(2); new(&expected_pair[2].second) EmplaceInt(2); - new(&expected_pair[3].first) EmplaceInt(3); - new(&expected_pair[3].second) EmplaceInt(2, 3); - new(&expected_pair[4].first) EmplaceInt(4); - new(&expected_pair[4].second) EmplaceInt(2, 3, 4); - new(&expected_pair[5].first) EmplaceInt(5); - new(&expected_pair[5].second) EmplaceInt(2, 3, 4, 5); { Container c; c.emplace(); @@ -494,7 +488,7 @@ bool test_emplace_assoc_pair(containers_detail::true_) std::cout << "Error after c.emplace();\n"; return false; } - c.emplace(1); + c.emplace(1, 1); if(!test_expected_container(c, &expected_pair[0], 2)){ std::cout << "Error after c.emplace(1);\n"; return false; @@ -504,31 +498,16 @@ bool test_emplace_assoc_pair(containers_detail::true_) std::cout << "Error after c.emplace(2, 2);\n"; return false; } - c.emplace(3, 2, 3); - if(!test_expected_container(c, &expected_pair[0], 4)){ - std::cout << "Error after c.emplace(3, 2, 3);\n"; - return false; - } - c.emplace(4, 2, 3, 4); - if(!test_expected_container(c, &expected_pair[0], 5)){ - std::cout << "Error after c.emplace(4, 2, 3, 4);\n"; - return false; - } - c.emplace(5, 2, 3, 4, 5); - if(!test_expected_container(c, &expected_pair[0], 6)){ - std::cout << "Error after c.emplace(5, 2, 3, 4, 5);\n"; - return false; - } } return true; } template -bool test_emplace_assoc_pair(containers_detail::false_) +bool test_emplace_assoc_pair(container_detail::false_) { return true; } template -bool test_emplace_hint_pair(containers_detail::true_) +bool test_emplace_hint_pair(container_detail::true_) { std::cout << "Starting test_emplace_hint_pair." << std::endl << " Class: " << typeid(Container).name() << std::endl; @@ -536,15 +515,9 @@ bool test_emplace_hint_pair(containers_detail::true_) new(&expected_pair[0].first) EmplaceInt(); new(&expected_pair[0].second) EmplaceInt(); new(&expected_pair[1].first) EmplaceInt(1); - new(&expected_pair[1].second) EmplaceInt(); + new(&expected_pair[1].second) EmplaceInt(1); new(&expected_pair[2].first) EmplaceInt(2); new(&expected_pair[2].second) EmplaceInt(2); - new(&expected_pair[3].first) EmplaceInt(3); - new(&expected_pair[3].second) EmplaceInt(2, 3); - new(&expected_pair[4].first) EmplaceInt(4); - new(&expected_pair[4].second) EmplaceInt(2, 3, 4); - new(&expected_pair[5].first) EmplaceInt(5); - new(&expected_pair[5].second) EmplaceInt(2, 3, 4, 5); { Container c; typename Container::const_iterator it; @@ -553,7 +526,7 @@ bool test_emplace_hint_pair(containers_detail::true_) std::cout << "Error after c.emplace(1);\n"; return false; } - it = c.emplace_hint(it, 1); + it = c.emplace_hint(it, 1, 1); if(!test_expected_container(c, &expected_pair[0], 2)){ std::cout << "Error after c.emplace(it, 1);\n"; return false; @@ -563,44 +536,29 @@ bool test_emplace_hint_pair(containers_detail::true_) std::cout << "Error after c.emplace(it, 2, 2);\n"; return false; } - it = c.emplace_hint(it, 3, 2, 3); - if(!test_expected_container(c, &expected_pair[0], 4)){ - std::cout << "Error after c.emplace(it, 3, 2, 3);\n"; - return false; - } - it = c.emplace_hint(it, 4, 2, 3, 4); - if(!test_expected_container(c, &expected_pair[0], 5)){ - std::cout << "Error after c.emplace(it, 4, 2, 3, 4);\n"; - return false; - } - it = c.emplace_hint(it, 5, 2, 3, 4, 5); - if(!test_expected_container(c, &expected_pair[0], 6)){ - std::cout << "Error after c.emplace(it, 5, 2, 3, 4, 5);\n"; - return false; - } } return true; } template -bool test_emplace_hint_pair(containers_detail::false_) +bool test_emplace_hint_pair(container_detail::false_) { return true; } template struct emplace_active { static const bool value = (0 != (O & Mask)); - typedef containers_detail::bool_ type; + typedef container_detail::bool_ type; operator type() const{ return type(); } }; template bool test_emplace() { -// if(!test_emplace_back(emplace_active())) -// return false; + if(!test_emplace_back(emplace_active())) + return false; if(!test_emplace_front(emplace_active())) - return false;/* + return false; if(!test_emplace_before(emplace_active())) return false; if(!test_emplace_after(emplace_active())) @@ -612,7 +570,7 @@ bool test_emplace() if(!test_emplace_assoc_pair(emplace_active())) return false; if(!test_emplace_hint_pair(emplace_active())) - return false;*/ + return false; return true; } diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 1b690e3..67aea9d 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -56,14 +56,14 @@ class expand_bwd_test_allocator typedef T value_type; typedef T * pointer; typedef const T * const_pointer; - typedef typename containers_detail::add_reference + typedef typename container_detail::add_reference ::type reference; - typedef typename containers_detail::add_reference + typedef typename container_detail::add_reference ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef boost::container::containers_detail::version_type version; + typedef boost::container::container_detail::version_type version; template struct rebind @@ -109,9 +109,9 @@ class expand_bwd_test_allocator friend void swap(self_t &alloc1, self_t &alloc2) { - containers_detail::do_swap(alloc1.mp_buffer, alloc2.mp_buffer); - containers_detail::do_swap(alloc1.m_size, alloc2.m_size); - containers_detail::do_swap(alloc1.m_offset, alloc2.m_offset); + container_detail::do_swap(alloc1.mp_buffer, alloc2.mp_buffer); + container_detail::do_swap(alloc1.m_size, alloc2.m_size); + container_detail::do_swap(alloc1.m_offset, alloc2.m_offset); } //Experimental version 2 expand_bwd_test_allocator functions diff --git a/test/flat_tree_test.cpp b/test/flat_tree_test.cpp index e8f9173..4203704 100644 --- a/test/flat_tree_test.cpp +++ b/test/flat_tree_test.cpp @@ -17,10 +17,106 @@ #include "movable_int.hpp" #include "set_test.hpp" #include "map_test.hpp" +#include "propagate_allocator_test.hpp" #include "emplace_test.hpp" using namespace boost::container; +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +//flat_map +template class flat_map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::dummy_test_allocator + < std::pair > + >; + +template class flat_map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::simple_allocator + < std::pair > + >; + +template class flat_map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , std::allocator + < std::pair > + >; + +//flat_multimap +template class flat_multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::dummy_test_allocator + < std::pair > + >; + +template class flat_multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::simple_allocator + < std::pair > + >; + +template class flat_multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , std::allocator + < std::pair > + >; +//flat_set +template class flat_set + < test::movable_and_copyable_int + , std::less + , test::dummy_test_allocator + >; + +template class flat_set + < test::movable_and_copyable_int + , std::less + , test::simple_allocator + >; + +template class flat_set + < test::movable_and_copyable_int + , std::less + , std::allocator + >; + +//flat_multiset +template class flat_multiset + < test::movable_and_copyable_int + , std::less + , test::dummy_test_allocator + >; + +template class flat_multiset + < test::movable_and_copyable_int + , std::less + , test::simple_allocator + >; + +template class flat_multiset + < test::movable_and_copyable_int + , std::less + , std::allocator + >; + +}} //boost::container + + //Alias allocator type typedef std::allocator allocator_t; typedef std::allocator @@ -84,7 +180,6 @@ typedef flat_multimap MyCopyBoostMultiMap; - //Test recursive structures class recursive_flat_set { @@ -178,6 +273,36 @@ void test_move() move_assign.swap(original); } +template +class flat_tree_propagate_test_wrapper + : public container_detail::flat_tree, std::less, A> +{ + BOOST_COPYABLE_AND_MOVABLE(flat_tree_propagate_test_wrapper) + typedef container_detail::flat_tree, std::less, A> Base; + public: + flat_tree_propagate_test_wrapper() + : Base() + {} + + flat_tree_propagate_test_wrapper(const flat_tree_propagate_test_wrapper &x) + : Base(x) + {} + + flat_tree_propagate_test_wrapper(BOOST_RV_REF(flat_tree_propagate_test_wrapper) x) + : Base(boost::move(static_cast(x))) + {} + + flat_tree_propagate_test_wrapper &operator=(BOOST_COPY_ASSIGN_REF(flat_tree_propagate_test_wrapper) x) + { this->Base::operator=(x); return *this; } + + flat_tree_propagate_test_wrapper &operator=(BOOST_RV_REF(flat_tree_propagate_test_wrapper) x) + { this->Base::operator=(boost::move(static_cast(x))); return *this; } + + void swap(flat_tree_propagate_test_wrapper &x) + { this->Base::swap(x); } +}; + + int main() { using namespace boost::container::test; @@ -272,13 +397,13 @@ int main() return 1; } -// if (0 != map_test< -// MyMovableBoostMap -// ,MyStdMap -// ,MyMovableBoostMultiMap -// ,MyStdMultiMap>()){ -// return 1; -// } + if (0 != map_test< + MyMovableBoostMap + ,MyStdMap + ,MyMovableBoostMultiMap + ,MyStdMultiMap>()){ + return 1; + } if (0 != map_test< MyMoveCopyBoostMap @@ -319,14 +444,17 @@ int main() const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC); 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; if(!boost::container::test::test_emplace, MapOptions>()) return 1; if(!boost::container::test::test_emplace, SetOptions>()) return 1; if(!boost::container::test::test_emplace, SetOptions>()) return 1; + if(!boost::container::test::test_propagate_allocator()) + return 1; + return 0; } diff --git a/test/heap_allocator_v1.hpp b/test/heap_allocator_v1.hpp index 1e572c3..32b46b5 100644 --- a/test/heap_allocator_v1.hpp +++ b/test/heap_allocator_v1.hpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/test/list_test.cpp b/test/list_test.cpp index 9127ee1..602f547 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -11,15 +11,29 @@ #include #include #include "dummy_test_allocator.hpp" +#include #include "movable_int.hpp" #include "list_test.hpp" +#include "propagate_allocator_test.hpp" #include "emplace_test.hpp" using namespace boost::container; +namespace boost { +namespace container { + //Explicit instantiation to detect compilation errors +template class boost::container::list >; + template class boost::container::list >; + +template class boost::container::list >; + +}} + typedef list MyList; typedef list MyMoveList; @@ -72,6 +86,9 @@ int main () if(!boost::container::test::test_emplace, Options>()) return 1; + if(!boost::container::test::test_propagate_allocator()) + return 1; + return 0; } diff --git a/test/list_test.hpp b/test/list_test.hpp index 121c287..c248231 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -26,14 +26,14 @@ namespace container { namespace test{ template -bool list_copyable_only(V1 *, V2 *, boost::container::containers_detail::false_type) +bool list_copyable_only(V1 *, V2 *, boost::container::container_detail::false_type) { return true; } //Function to check if both sets are equal template -bool list_copyable_only(V1 *boostlist, V2 *stdlist, boost::container::containers_detail::true_type) +bool list_copyable_only(V1 *boostlist, V2 *stdlist, boost::container::container_detail::true_type) { typedef typename V1::value_type IntType; boostlist->insert(boostlist->end(), 50, IntType(1)); @@ -289,7 +289,7 @@ int list_test (bool copied_allocators_equal = true) } if(!list_copyable_only(boostlist, stdlist - ,containers_detail::bool_::value>())){ + ,container_detail::bool_::value>())){ return 1; } } diff --git a/test/map_test.hpp b/test/map_test.hpp index f41acba..5eee229 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -38,7 +38,7 @@ template IntPairType; + typedef container_detail::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; const int max = 100; @@ -101,6 +101,9 @@ int map_test () IntType i2(i); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); } + if(!CheckEqualContainers(boostmap2, stdmap2)) return 1; + if(!CheckEqualContainers(boostmultimap2, stdmultimap2)) return 1; + /* MyBoostMap *boostmap3 = new MyBoostMap ( ordered_unique_range @@ -122,6 +125,23 @@ int map_test () return 1; } */ + IntType i0(0); + boostmap2->erase(i0); + boostmultimap2->erase(i0); + stdmap2->erase(0); + stdmultimap2->erase(0); + { + IntType i0(0); + IntType i1(1); + (*boostmap2)[::boost::move(i0)] = ::boost::move(i1); + } + { + IntType i1(1); + (*boostmap2)[IntType(0)] = ::boost::move(i1); + } + (*stdmap2)[0] = 1; + if(!CheckEqualContainers(boostmap2, stdmap2)) return 1; + delete boostmap2; delete boostmultimap2; delete stdmap2; @@ -158,6 +178,7 @@ int map_test () typename MyBoostMap::iterator it; typename MyBoostMap::const_iterator cit = it; + (void)cit; boostmap->erase(boostmap->begin()++); stdmap->erase(stdmap->begin()++); @@ -449,7 +470,7 @@ template IntPairType; + typedef container_detail::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; const int max = 100; diff --git a/test/movable_int.hpp b/test/movable_int.hpp index 37bf71d..599dbbb 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -221,6 +221,45 @@ struct is_copyable static const bool value = true; }; +class non_copymovable_int +{ + non_copymovable_int(const non_copymovable_int& mmi); + non_copymovable_int & operator= (const non_copymovable_int &mi); + + public: + non_copymovable_int() + : m_int(0) + {} + + explicit non_copymovable_int(int a) + : m_int(a) + {} + + bool operator ==(const non_copymovable_int &mi) const + { return this->m_int == mi.m_int; } + + bool operator !=(const non_copymovable_int &mi) const + { return this->m_int != mi.m_int; } + + bool operator <(const non_copymovable_int &mi) const + { return this->m_int < mi.m_int; } + + bool operator <=(const non_copymovable_int &mi) const + { return this->m_int <= mi.m_int; } + + bool operator >=(const non_copymovable_int &mi) const + { return this->m_int >= mi.m_int; } + + bool operator >(const non_copymovable_int &mi) const + { return this->m_int > mi.m_int; } + + int get_int() const + { return m_int; } + + private: + int m_int; +}; + } //namespace test { } //namespace container { } //namespace boost { diff --git a/test/pair_test.cpp b/test/pair_test.cpp new file mode 100644 index 0000000..c44b9d5 --- /dev/null +++ b/test/pair_test.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2011. 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 +#include "movable_int.hpp" +#include "emplace_test.hpp" +#include + +//non_copymovable_int +//copyable_int +//movable_int +//movable_and_copyable_int + + +using namespace ::boost::container; + +int main () +{ + { + container_detail::pair p1; + container_detail::pair p2; + container_detail::pair p3; + container_detail::pair p4; + } + { //Constructible from two values + container_detail::pair p1(1, 2); + container_detail::pair p2(1, 2); + container_detail::pair p3(1, 2); + container_detail::pair p4(1, 2); + } + + { //Constructible from internal types + container_detail::pair p2(test::copyable_int(1), test::copyable_int(2)); + { + test::movable_int a(1), b(2); + container_detail::pair p3(::boost::move(a), ::boost::move(b)); + } + { + test::movable_and_copyable_int a(1), b(2); + container_detail::pair p4(::boost::move(a), ::boost::move(b)); + } + } + //piecewise_construct missing... + return 0; +} + +#include diff --git a/test/propagate_allocator_test.hpp b/test/propagate_allocator_test.hpp new file mode 100644 index 0000000..8901d77 --- /dev/null +++ b/test/propagate_allocator_test.hpp @@ -0,0 +1,181 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008. 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_PROPAGATE_ALLOCATOR_TEST_HPP +#define BOOST_CONTAINER_PROPAGATE_ALLOCATOR_TEST_HPP + +#include +#include +#include "dummy_test_allocator.hpp" + +#include + +namespace boost{ +namespace container { +namespace test{ + +template class ContainerWrapper> +bool test_propagate_allocator() +{ + { + typedef propagation_test_allocator AlwaysPropagate; + typedef ContainerWrapper PropagateCont; + + ////////////////////////////////////////// + //Test AlwaysPropagate allocator propagation + ////////////////////////////////////////// + AlwaysPropagate::reset_unique_id(); + + //default constructor + PropagateCont c; + BOOST_TEST (c.get_stored_allocator().id_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + + //copy constructor + PropagateCont c2(c); + //propagate_on_copy_constructor produces copies, moves or RVO (depending on the compiler). + //For allocators that copy in select_on_container_copy_construction, at least we must have a copy + unsigned int ctr_copies = c2.get_stored_allocator().ctr_copies_; + unsigned int ctr_moves = c2.get_stored_allocator().ctr_moves_; + BOOST_TEST (c2.get_stored_allocator().id_ == 0); + BOOST_TEST (ctr_copies > 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ >= 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + + //move constructor + PropagateCont c3(boost::move(c2)); + BOOST_TEST (c3.get_stored_allocator().id_ == 0); + BOOST_TEST (c3.get_stored_allocator().ctr_copies_ == ctr_copies); + BOOST_TEST (c3.get_stored_allocator().ctr_moves_ > ctr_moves); + ctr_moves = c3.get_stored_allocator().ctr_moves_; + BOOST_TEST (ctr_moves > 0); + BOOST_TEST (c3.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c3.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c3.get_stored_allocator().swaps_ == 0); + + //copy assign + c2 = c3; + unsigned int assign_copies = c2.get_stored_allocator().assign_copies_; + BOOST_TEST (c2.get_stored_allocator().id_ == 0); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == ctr_copies); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == ctr_moves); + BOOST_TEST (assign_copies == 1); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + + //move assign + c = boost::move(c2); + unsigned int assign_moves = c.get_stored_allocator().assign_moves_; + BOOST_TEST (c.get_stored_allocator().id_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == ctr_copies); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == ctr_moves); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == assign_copies); + BOOST_TEST (assign_moves == 1); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + + //swap + c.get_stored_allocator().id_ = 999; + c.swap(c2); + unsigned int swaps = c2.get_stored_allocator().swaps_; + BOOST_TEST (c2.get_stored_allocator().id_ == 999); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == ctr_copies); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == ctr_moves); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == assign_copies); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == assign_moves); + BOOST_TEST (swaps == 1); + } + + ////////////////////////////////////////// + //Test NeverPropagate allocator propagation + ////////////////////////////////////////// + { + typedef propagation_test_allocator NeverPropagate; + typedef ContainerWrapper NoPropagateCont; + NeverPropagate::reset_unique_id(); + + //default constructor + NoPropagateCont c; + BOOST_TEST (c.get_stored_allocator().id_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + + //copy constructor + //propagate_on_copy_constructor produces copies, moves or RVO (depending on the compiler) + //For allocators that don't copy in select_on_container_copy_construction we must have a default + //construction + NoPropagateCont c2(c); + unsigned int ctr_copies = c2.get_stored_allocator().ctr_copies_; + unsigned int ctr_moves = c2.get_stored_allocator().ctr_moves_; + BOOST_TEST (c2.get_stored_allocator().id_ == 1); + BOOST_TEST (ctr_copies >= 0); + BOOST_TEST (ctr_moves >= 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + + //move constructor + NoPropagateCont c3(boost::move(c2)); + BOOST_TEST (c3.get_stored_allocator().id_ == 1); + BOOST_TEST (c3.get_stored_allocator().ctr_copies_ == ctr_copies); + BOOST_TEST (c3.get_stored_allocator().ctr_moves_ > ctr_moves); + unsigned int ctr_moves2 = ctr_moves; + ctr_moves = c3.get_stored_allocator().ctr_moves_; + BOOST_TEST (c3.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c3.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c3.get_stored_allocator().swaps_ == 0); + + //copy assign + c2 = c3; + BOOST_TEST (c2.get_stored_allocator().id_ == 1); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == ctr_copies); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == ctr_moves2); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + + //move assign + c = boost::move(c2); + BOOST_TEST (c.get_stored_allocator().id_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + + //swap + c.get_stored_allocator().id_ = 999; + c2.swap(c); + BOOST_TEST (c2.get_stored_allocator().id_ == 1); + BOOST_TEST (c.get_stored_allocator().id_ == 999); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == ctr_copies); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == ctr_moves2); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + + return report_errors() == 0; +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_CONTAINER_PROPAGATE_ALLOCATOR_TEST_HPP diff --git a/test/set_test.hpp b/test/set_test.hpp index e4061eb..5dd6a2a 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -145,6 +145,7 @@ int set_test () typename MyBoostSet::iterator it; typename MyBoostSet::const_iterator cit = it; + (void)cit; boostset->erase(boostset->begin()++); stdset->erase(stdset->begin()++); diff --git a/test/slist_test.cpp b/test/slist_test.cpp index e18f0bb..fb9f28f 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -9,17 +9,29 @@ ////////////////////////////////////////////////////////////////////////////// #include #include +#include #include "dummy_test_allocator.hpp" #include "movable_int.hpp" #include "list_test.hpp" +#include "propagate_allocator_test.hpp" #include "emplace_test.hpp" using namespace boost::container; +namespace boost { +namespace container { + //Explicit instantiation to detect compilation errors +template class boost::container::slist >; + template class boost::container::slist >; +template class boost::container::slist >; +}} + typedef slist MyList; typedef slist MyMoveList; typedef slist MyCopyMoveList; @@ -76,6 +88,9 @@ int main () if(!boost::container::test::test_emplace < slist, Options>()) return 1; + + if(!boost::container::test::test_propagate_allocator()) + return 1; } #include diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index bf42978..edcd404 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -21,13 +21,25 @@ #include "expand_bwd_test_allocator.hpp" #include "expand_bwd_test_template.hpp" #include "dummy_test_allocator.hpp" +#include "propagate_allocator_test.hpp" #include "vector_test.hpp" using namespace boost::container; +namespace boost { +namespace container { + //Explicit instantiation to detect compilation errors -//template class stable_vector >; +template class stable_vector >; + +template class stable_vector >; + +template class stable_vector >; + +}} class recursive_vector { @@ -58,6 +70,14 @@ int main() move_assign = boost::move(move_ctor); move_assign.swap(original); } + + //Test non-copy-move operations + { + stable_vector sv; + sv.emplace_back(); + sv.resize(10); + sv.resize(1); + } typedef stable_vector MyVector; typedef stable_vector MyMoveVector; typedef stable_vector MyCopyMoveVector; @@ -80,6 +100,9 @@ int main() < stable_vector, Options>()) return 1; + if(!boost::container::test::test_propagate_allocator()) + return 1; + return 0; } diff --git a/test/string_test.cpp b/test/string_test.cpp index 8c873ce..3799d4a 100644 --- a/test/string_test.cpp +++ b/test/string_test.cpp @@ -22,6 +22,7 @@ #include "check_equal_containers.hpp" #include "expand_bwd_test_allocator.hpp" #include "expand_bwd_test_template.hpp" +#include "propagate_allocator_test.hpp" using namespace boost::container; @@ -32,13 +33,23 @@ typedef test::dummy_test_allocator DummyWCharAllocator; typedef basic_string, DummyWCharAllocator> DummyWString; typedef test::dummy_test_allocator DummyWStringAllocator; +namespace boost { +namespace container { + //Explicit instantiations of container::basic_string -template class basic_string, DummyCharAllocator>; +template class basic_string, DummyCharAllocator>; template class basic_string, DummyWCharAllocator>; +template class basic_string, test::simple_allocator >; +template class basic_string, test::simple_allocator >; +template class basic_string, std::allocator >; +template class basic_string, std::allocator >; + //Explicit instantiation of container::vectors of container::strings template class vector; template class vector; +}} + struct StringEqual { template @@ -60,10 +71,64 @@ bool CheckEqualStringVector(StrVector1 *strvect1, StrVector2 *strvect2) strvect2->begin(), comp); } +template +struct string_literals; + +template<> +struct string_literals +{ + static const char *String() + { return "String"; } + static const char *Prefix() + { return "Prefix"; } + static const char *Suffix() + { return "Suffix"; } + static const char *LongString() + { return "LongLongLongLongLongLongLongLongLongLongLongLongLongString"; } + + static void sprintf_number(char *buf, int number) + { + std::sprintf(buf, "%i", number); + } +}; + +template<> +struct string_literals +{ + static const wchar_t *String() + { return L"String"; } + static const wchar_t *Prefix() + { return L"Prefix"; } + static const wchar_t *Suffix() + { return L"Suffix"; } + static const wchar_t *LongString() + { return L"LongLongLongLongLongLongLongLongLongLongLongLongLongString"; } + + static void sprintf_number(wchar_t *buffer, unsigned int number) + { + //For compilers without wsprintf, print it backwards + const wchar_t *digits = L"0123456789"; + wchar_t *buf = buffer; + + while(1){ + int rem = number % 10; + number = number / 10; + + *buf = digits[rem]; + ++buf; + if(!number){ + *buf = 0; + break; + } + } + + } +}; + template int string_test() { - typedef std::string StdString; + typedef std::basic_string StdString; typedef vector StdStringVector; typedef basic_string BoostString; typedef vector BoostStringVector; @@ -81,9 +146,9 @@ int string_test() //First, push back for(int i = 0; i < MaxSize; ++i){ - auxBoostString = "String"; - auxStdString = "String"; - std::sprintf(buffer, "%i", i); + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + string_literals::sprintf_number(buffer, i); auxBoostString += buffer; auxStdString += buffer; boostStringVect->push_back(auxBoostString); @@ -96,9 +161,9 @@ int string_test() //Now push back moving for(int i = 0; i < MaxSize; ++i){ - auxBoostString = "String"; - auxStdString = "String"; - std::sprintf(buffer, "%i", i); + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + string_literals::sprintf_number(buffer, i); auxBoostString += buffer; auxStdString += buffer; boostStringVect->push_back(boost::move(auxBoostString)); @@ -111,9 +176,9 @@ int string_test() //push front for(int i = 0; i < MaxSize; ++i){ - auxBoostString = "String"; - auxStdString = "String"; - std::sprintf(buffer, "%i", i); + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + string_literals::sprintf_number(buffer, i); auxBoostString += buffer; auxStdString += buffer; boostStringVect->insert(boostStringVect->begin(), auxBoostString); @@ -126,9 +191,9 @@ int string_test() //Now push front moving for(int i = 0; i < MaxSize; ++i){ - auxBoostString = "String"; - auxStdString = "String"; - std::sprintf(buffer, "%i", i); + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + string_literals::sprintf_number(buffer, i); auxBoostString += buffer; auxStdString += buffer; boostStringVect->insert(boostStringVect->begin(), boost::move(auxBoostString)); @@ -142,8 +207,8 @@ int string_test() //Now test long and short representation swapping //Short first - auxBoostString = "String"; - auxStdString = "String"; + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); BoostString boost_swapper; StdString std_swapper; boost_swapper.swap(auxBoostString); @@ -177,8 +242,8 @@ int string_test() return 1; //Long string - auxBoostString = "LongLongLongLongLongLongLongLongLongLongLongLongLongString"; - auxStdString = "LongLongLongLongLongLongLongLongLongLongLongLongLongString"; + auxBoostString = string_literals::LongString(); + auxStdString = string_literals::LongString(); boost_swapper = BoostString(); std_swapper = StdString(); boost_swapper.swap(auxBoostString); @@ -208,9 +273,9 @@ int string_test() std::sort(stdStringVect->begin(), stdStringVect->end()); if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; - const CharType prefix [] = "Prefix"; - const int prefix_size = sizeof(prefix)/sizeof(prefix[0])-1; - const CharType sufix [] = "Suffix"; + const CharType *prefix = string_literals::Prefix(); + const int prefix_size = std::char_traits::length(prefix); + const CharType *sufix = string_literals::Suffix(); for(int i = 0; i < MaxSize; ++i){ (*boostStringVect)[i].append(sufix); @@ -247,10 +312,10 @@ int string_test() for(int i = 0; i < MaxSize; ++i){ (*boostStringVect)[i].replace((*boostStringVect)[i].begin(), (*boostStringVect)[i].end(), - "String"); + string_literals::String()); (*stdStringVect)[i].replace((*stdStringVect)[i].begin(), (*stdStringVect)[i].end(), - "String"); + string_literals::String()); } if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; @@ -261,6 +326,80 @@ int string_test() stdStringVect->end()); if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; + //Check addition + { + typedef std::basic_string StdString; + typedef basic_string BoostString; + + BoostString bs2 = string_literals::String(); + StdString ss2 = string_literals::String(); + BoostString bs3 = string_literals::Suffix(); + StdString ss3 = string_literals::Suffix(); + BoostString bs4 = bs2 + bs3; + StdString ss4 = ss2 + ss3; + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs4 = bs2 + BoostString(); + ss4 = ss2 + StdString(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs4 = BoostString() + bs2; + ss4 = StdString() + ss2; + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs4 = BoostString() + boost::move(bs2); + ss4 = StdString() + boost::move(ss2); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = boost::move(bs2) + BoostString(); + ss4 = boost::move(ss2) + StdString(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = string_literals::Prefix() + boost::move(bs2); + ss4 = string_literals::Prefix() + boost::move(ss2); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = boost::move(bs2) + string_literals::Suffix(); + ss4 = boost::move(ss2) + string_literals::Suffix(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = string_literals::Prefix() + bs2; + ss4 = string_literals::Prefix() + ss2; + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = bs2 + string_literals::Suffix(); + ss4 = ss2 + string_literals::Suffix(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + } + //When done, delete vector delete boostStringVect; delete stdStringVect; @@ -278,15 +417,51 @@ bool test_expand_bwd() return test::test_all_expand_bwd(); } +template +class string_propagate_test_wrapper + : public basic_string, A> +{ + BOOST_COPYABLE_AND_MOVABLE(string_propagate_test_wrapper) + typedef basic_string, A> Base; + public: + string_propagate_test_wrapper() + : Base() + {} + + string_propagate_test_wrapper(const string_propagate_test_wrapper &x) + : Base(x) + {} + + string_propagate_test_wrapper(BOOST_RV_REF(string_propagate_test_wrapper) x) + : Base(boost::move(static_cast(x))) + {} + + string_propagate_test_wrapper &operator=(BOOST_COPY_ASSIGN_REF(string_propagate_test_wrapper) x) + { this->Base::operator=(x); return *this; } + + string_propagate_test_wrapper &operator=(BOOST_RV_REF(string_propagate_test_wrapper) x) + { this->Base::operator=(boost::move(static_cast(x))); return *this; } + + void swap(string_propagate_test_wrapper &x) + { this->Base::swap(x); } +}; + int main() { if(string_test()){ return 1; } + if(string_test()){ + return 1; + } + if(!test_expand_bwd()) return 1; + if(!boost::container::test::test_propagate_allocator()) + return 1; + return 0; } diff --git a/test/tree_test.cpp b/test/tree_test.cpp index 0df3ac4..0717cce 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -16,6 +16,7 @@ #include "dummy_test_allocator.hpp" #include "set_test.hpp" #include "map_test.hpp" +#include "propagate_allocator_test.hpp" #include "emplace_test.hpp" using namespace boost::container; @@ -49,10 +50,109 @@ typedef map MyCopyBoostMap; typedef multimap MyCopyBoostMultiMap; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +//map +template class map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::dummy_test_allocator + < std::pair > + >; + +template class map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::simple_allocator + < std::pair > + >; + +template class map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , std::allocator + < std::pair > + >; + +//multimap +template class multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::dummy_test_allocator + < std::pair > + >; + +template class multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::simple_allocator + < std::pair > + >; + +template class multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , std::allocator + < std::pair > + >; + +//set +template class set + < test::movable_and_copyable_int + , std::less + , test::dummy_test_allocator + >; + +template class set + < test::movable_and_copyable_int + , std::less + , test::simple_allocator + >; + +template class set + < test::movable_and_copyable_int + , std::less + , std::allocator + >; + +//multiset +template class multiset + < test::movable_and_copyable_int + , std::less + , test::dummy_test_allocator + >; + +template class multiset + < test::movable_and_copyable_int + , std::less + , test::simple_allocator + >; + +template class multiset + < test::movable_and_copyable_int + , std::less + , std::allocator + >; + +}} //boost::container + //Test recursive structures class recursive_set { public: + recursive_set & operator=(const recursive_set &x) + { id_ = x.id_; set_ = x.set_; return *this; } + int id_; set set_; friend bool operator< (const recursive_set &a, const recursive_set &b) @@ -62,6 +162,9 @@ public: class recursive_map { public: + recursive_map & operator=(const recursive_map &x) + { id_ = x.id_; map_ = x.map_; return *this; } + int id_; map map_; friend bool operator< (const recursive_map &a, const recursive_map &b) @@ -71,7 +174,10 @@ class recursive_map //Test recursive structures class recursive_multiset { -public: + public: + recursive_multiset & operator=(const recursive_multiset &x) + { id_ = x.id_; multiset_ = x.multiset_; return *this; } + int id_; multiset multiset_; friend bool operator< (const recursive_multiset &a, const recursive_multiset &b) @@ -80,7 +186,10 @@ public: class recursive_multimap { -public: + public: + recursive_multimap & operator=(const recursive_multimap &x) + { id_ = x.id_; multimap_ = x.multimap_; return *this; } + int id_; multimap multimap_; friend bool operator< (const recursive_multimap &a, const recursive_multimap &b) @@ -98,6 +207,35 @@ void test_move() move_assign.swap(original); } +template +class tree_propagate_test_wrapper + : public container_detail::rbtree, std::less, A> +{ + BOOST_COPYABLE_AND_MOVABLE(tree_propagate_test_wrapper) + typedef container_detail::rbtree, std::less, A> Base; + public: + tree_propagate_test_wrapper() + : Base() + {} + + tree_propagate_test_wrapper(const tree_propagate_test_wrapper &x) + : Base(x) + {} + + tree_propagate_test_wrapper(BOOST_RV_REF(tree_propagate_test_wrapper) x) + : Base(boost::move(static_cast(x))) + {} + + tree_propagate_test_wrapper &operator=(BOOST_COPY_ASSIGN_REF(tree_propagate_test_wrapper) x) + { this->Base::operator=(x); return *this; } + + tree_propagate_test_wrapper &operator=(BOOST_RV_REF(tree_propagate_test_wrapper) x) + { this->Base::operator=(boost::move(static_cast(x))); return *this; } + + void swap(tree_propagate_test_wrapper &x) + { this->Base::swap(x); } +}; + int main () { //Recursive container instantiation @@ -180,13 +318,12 @@ int main () return 1; } -// if (0 != test::map_test()){ -// return 1; -// } + if (0 != test::map_test()){ + return 1; + } if (0 != test::map_test, MapOptions>()) return 1; + if(!boost::container::test::test_propagate_allocator()) + return 1; return 0; } diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 9bdc584..3be90ae 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// - #include #include #include @@ -16,19 +15,32 @@ #include #include +#include #include "check_equal_containers.hpp" #include "movable_int.hpp" #include "expand_bwd_test_allocator.hpp" #include "expand_bwd_test_template.hpp" #include "dummy_test_allocator.hpp" +#include "propagate_allocator_test.hpp" #include "vector_test.hpp" using namespace boost::container; +namespace boost { +namespace container { + //Explicit instantiation to detect compilation errors +template class boost::container::vector >; + template class boost::container::vector >; +template class boost::container::vector >; + +}} + int test_expand_bwd() { //Now test all back insertion possibilities @@ -81,7 +93,6 @@ enum Test zero, one, two, three, four, five, six }; - int main() { recursive_vector_test(); @@ -99,7 +110,6 @@ int main() typedef vector MyCopyVector; typedef vector MyEnumVector; - if(test::vector_test()) return 1; if(test::vector_test()) @@ -122,6 +132,9 @@ int main() < vector, Options>()) return 1; + if(!boost::container::test::test_propagate_allocator()) + return 1; + return 0; } #include diff --git a/test/vector_test.hpp b/test/vector_test.hpp index c57700e..4b6d7b7 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -30,14 +30,14 @@ namespace container { namespace test{ template -bool vector_copyable_only(V1 *, V2 *, boost::container::containers_detail::false_type) +bool vector_copyable_only(V1 *, V2 *, boost::container::container_detail::false_type) { return true; } //Function to check if both sets are equal template -bool vector_copyable_only(V1 *boostvector, V2 *stdvector, boost::container::containers_detail::true_type) +bool vector_copyable_only(V1 *boostvector, V2 *stdvector, boost::container::container_detail::true_type) { typedef typename V1::value_type IntType; std::size_t size = boostvector->size(); @@ -111,6 +111,7 @@ int vector_test() typename MyBoostVector::iterator boostit(boostvector->begin()); typename MyStdVector::iterator stdit(stdvector->begin()); typename MyBoostVector::const_iterator cboostit = boostit; + (void)cboostit; ++boostit; ++stdit; boostvector->erase(boostit); stdvector->erase(stdit); @@ -183,7 +184,7 @@ int vector_test() if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; if(!vector_copyable_only(boostvector, stdvector - ,containers_detail::bool_::value>())){ + ,container_detail::bool_::value>())){ return 1; }