From 9e2913d4e367e98316875bf52e63a0e389666e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 17 May 2019 08:14:15 +0200 Subject: [PATCH 01/12] Fixes #119 ("Missing files breaks develop documentation build") --- example/doc_custom_small_vector.cpp | 47 ++++++++++++++++++++++++++++ example/doc_custom_static_vector.cpp | 39 +++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 example/doc_custom_small_vector.cpp create mode 100644 example/doc_custom_static_vector.cpp diff --git a/example/doc_custom_small_vector.cpp b/example/doc_custom_small_vector.cpp new file mode 100644 index 0000000..55fe961 --- /dev/null +++ b/example/doc_custom_small_vector.cpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +//[doc_custom_small_vector +#include +#include + +//Make sure assertions are active +#ifdef NDEBUG +#undef NDEBUG +#endif +#include + +int main () +{ + using namespace boost::container; + + //This option specifies the desired alignment for the internal value_type + typedef small_vector_options< inplace_alignment<16u> >::type alignment_16_option_t; + + //Check 16 byte alignment option + small_vector sv; + assert(((std::size_t)sv.data() % 16u) == 0); + + + //This option specifies that a vector will increase its capacity 50% + //each time the previous capacity was exhausted. + typedef small_vector_options< growth_factor >::type growth_50_option_t; + + //Fill the vector until full capacity is reached + small_vector growth_50_vector(10, 0); + const std::size_t old_cap = growth_50_vector.capacity(); + growth_50_vector.resize(old_cap); + + //Now insert an additional item and check the new buffer is 50% bigger + growth_50_vector.push_back(1); + assert(growth_50_vector.capacity() == old_cap*3/2); + + return 0; +} +//] diff --git a/example/doc_custom_static_vector.cpp b/example/doc_custom_static_vector.cpp new file mode 100644 index 0000000..817ec4c --- /dev/null +++ b/example/doc_custom_static_vector.cpp @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +//[doc_custom_static_vector +#include +#include + +//Make sure assertions are active +#ifdef NDEBUG +#undef NDEBUG +#endif +#include + +int main () +{ + using namespace boost::container; + + //This option specifies the desired alignment for value_type + typedef static_vector_options< inplace_alignment<16u> >::type alignment_16_option_t; + + //Check 16 byte alignment option + static_vector sv; + assert(((std::size_t)sv.data() % 16u) == 0); + + //This static_vector won't throw on overflow, for maximum performance + typedef static_vector_options< throw_on_overflow >::type no_throw_options_t; + + //Create static_vector with no throw on overflow + static_vector sv2; + + return 0; +} +//] From f25c767a2bc47eb4c8168ab4d3076fe4708b631f Mon Sep 17 00:00:00 2001 From: Mitsuru Kariya Date: Tue, 28 May 2019 19:26:19 +0900 Subject: [PATCH 02/12] Fix has_trivial_destructor_after_move Most template type parameters 'Allocator' were modified their default type to void since 1.70.0. These modifications cause has_trivial_destructor_after_move to compile error or yield wrong result. So, fix them by changing specializations of has_trivial_destructor_after_move. --- include/boost/container/deque.hpp | 5 +- include/boost/container/detail/flat_tree.hpp | 10 +-- include/boost/container/detail/tree.hpp | 5 +- include/boost/container/flat_map.hpp | 16 ++-- include/boost/container/flat_set.hpp | 12 +-- include/boost/container/list.hpp | 5 +- include/boost/container/map.hpp | 20 ++--- include/boost/container/set.hpp | 14 ++-- include/boost/container/slist.hpp | 5 +- include/boost/container/stable_vector.hpp | 5 +- include/boost/container/string.hpp | 6 +- include/boost/container/vector.hpp | 6 +- test/deque_test.cpp | 28 +++++++ test/flat_map_test.cpp | 77 ++++++++++++++++++++ test/flat_set_test.cpp | 73 +++++++++++++++++++ test/flat_tree_test.cpp | 32 ++++++++ test/list_test.cpp | 28 +++++++ test/map_test.cpp | 54 ++++++++++++++ test/set_test.cpp | 44 +++++++++++ test/slist_test.cpp | 28 +++++++ test/small_vector_test.cpp | 20 +++++ test/stable_vector_test.cpp | 28 +++++++ test/string_test.cpp | 28 +++++++ test/tree_test.cpp | 36 +++++++++ test/vector_test.cpp | 28 +++++++ 25 files changed, 555 insertions(+), 58 deletions(-) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index be88845..ae91106 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -2295,8 +2295,9 @@ namespace boost { template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename boost::container::deque::allocator_type allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 4d86f9e..5d96a21 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -1622,11 +1622,11 @@ template struct has_trivial_destructor_after_move > { - typedef typename boost::container::dtl::select_container_type::type container_type; - typedef typename container_type::allocator_type allocator_t; - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef boost::container::dtl::flat_tree flat_tree; + typedef typename flat_tree::container_type container_type; + typedef typename flat_tree::key_compare key_compare; + static const bool value = ::boost::has_trivial_destructor_after_move::value && + ::boost::has_trivial_destructor_after_move::value; }; } //namespace boost { diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 42e3564..23fbfde 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -1516,8 +1516,9 @@ struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename ::boost::container::dtl::tree::allocator_type allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 2b52e14..366f073 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -1651,10 +1651,10 @@ flat_map(ordered_unique_range_t, InputIterator, InputIterator, Compare const&, A template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef ::boost::container::dtl::pair value_t; + typedef typename ::boost::container::dtl::container_or_allocator_rebind::type alloc_or_cont_t; + typedef ::boost::container::dtl::flat_tree, Compare, alloc_or_cont_t> tree; + static const bool value = ::boost::has_trivial_destructor_after_move::value; }; namespace container { @@ -2961,10 +2961,10 @@ namespace boost { template struct has_trivial_destructor_after_move< boost::container::flat_multimap > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef ::boost::container::dtl::pair value_t; + typedef typename ::boost::container::dtl::container_or_allocator_rebind::type alloc_or_cont_t; + typedef ::boost::container::dtl::flat_tree, Compare, alloc_or_cont_t> tree; + static const bool value = ::boost::has_trivial_destructor_after_move::value; }; } //namespace boost { diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 080beb5..5dae0f9 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -1192,10 +1192,8 @@ flat_set(ordered_unique_range_t, InputIterator, InputIterator, Compare const&, A template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef ::boost::container::dtl::flat_tree, Compare, AllocatorOrContainer> tree; + static const bool value = ::boost::has_trivial_destructor_after_move::value; }; namespace container { @@ -1926,10 +1924,8 @@ flat_multiset(ordered_range_t, InputIterator, InputIterator, Compare const&, All template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef ::boost::container::dtl::flat_tree, Compare, AllocatorOrContainer> tree; + static const bool value = ::boost::has_trivial_destructor_after_move::value; }; namespace container { diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index a17a906..f9ff663 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -1522,8 +1522,9 @@ list(InputIterator, InputIterator, ValueAllocator const&) -> template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename boost::container::list::allocator_type allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index d0c8fc9..447f4ad 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -1366,13 +1366,11 @@ map(ordered_unique_range_t, InputIterator, InputIterator, Compare const&, Alloca //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef ::boost::container::dtl::tree, int, Compare, Allocator, Options> tree; + static const bool value = ::boost::has_trivial_destructor_after_move::value; }; namespace container { @@ -2292,13 +2290,11 @@ multimap(ordered_range_t, InputIterator, InputIterator, Compare const&, Allocato //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef ::boost::container::dtl::tree, int, Compare, Allocator, Options> tree; + static const bool value = ::boost::has_trivial_destructor_after_move::value; }; namespace container { diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index 44bad8c..ca6334f 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -1024,13 +1024,11 @@ set(ordered_unique_range_t, InputIterator, InputIterator, Compare const&, Alloca //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template +template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef ::boost::container::dtl::tree tree; + static const bool value = ::boost::has_trivial_destructor_after_move::value; }; namespace container { @@ -1693,10 +1691,8 @@ multiset(ordered_range_t, InputIterator, InputIterator, Compare const&, Allocato template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; + typedef ::boost::container::dtl::tree tree; + static const bool value = ::boost::has_trivial_destructor_after_move::value; }; namespace container { diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index a9c29f8..d10cf57 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -1696,8 +1696,9 @@ namespace boost { template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename boost::container::slist::allocator_type allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 87525f9..7d0c9b3 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -2183,8 +2183,9 @@ stable_vector(InputIterator, InputIterator, Allocator const&) -> template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename boost::container::stable_vector::allocator_type allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 0943637..46ca567 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -3490,9 +3490,9 @@ namespace boost { template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits - ::allocator_type>::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename boost::container::basic_string::allocator_type allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index d7886d5..099a878 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -3413,9 +3413,9 @@ namespace boost { template struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits - ::type>::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename boost::container::vector::allocator_type allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 01c47e0..22b87f4 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -412,6 +412,34 @@ int main () } } + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::deque cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::deque > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index 9497ee2..9595775 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -8,6 +8,9 @@ // ////////////////////////////////////////////////////////////////////////////// #include + +#include + #include #include #include @@ -715,6 +718,80 @@ int main() } } + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + { + typedef boost::container::dtl::pair value_t; + typedef boost::container::dtl::select1st key_of_value_t; + // flat_map, default + { + typedef boost::container::new_allocator alloc_or_cont_t; + typedef boost::container::flat_map cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_map, default) test failed" << std::endl; + return 1; + } + } + // flat_map, vector + { + typedef boost::container::vector alloc_or_cont_t; + typedef boost::container::flat_map, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_map, vector) test failed" << std::endl; + return 1; + } + } + // flat_map, std::vector + { + typedef std::vector alloc_or_cont_t; + typedef boost::container::flat_map, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_map, std::vector) test failed" << std::endl; + return 1; + } + } + // flat_multimap, default + { + typedef boost::container::new_allocator alloc_or_cont_t; + typedef boost::container::flat_multimap cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multimap, default) test failed" << std::endl; + return 1; + } + } + // flat_multimap, vector + { + typedef boost::container::vector alloc_or_cont_t; + typedef boost::container::flat_multimap, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multimap, vector) test failed" << std::endl; + return 1; + } + } + // flat_multimap, std::vector + { + typedef std::vector alloc_or_cont_t; + typedef boost::container::flat_multimap, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multimap, std::vector) test failed" << std::endl; + return 1; + } + } + } + return 0; } diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index 7e561f7..0ffb839 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -10,7 +10,9 @@ #include +#include #include +#include #include #include @@ -813,6 +815,77 @@ int main() } } + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + { + typedef boost::container::dtl::identity key_of_value_t; + // flat_set, default + { + typedef boost::container::flat_set cont; + typedef boost::container::dtl::flat_tree, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_set, default) test failed" << std::endl; + return 1; + } + } + // flat_set, vector + { + typedef boost::container::vector alloc_or_cont_t; + typedef boost::container::flat_set, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_set, vector) test failed" << std::endl; + return 1; + } + } + // flat_set, std::vector + { + typedef std::vector alloc_or_cont_t; + typedef boost::container::flat_set, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_set, std::vector) test failed" << std::endl; + return 1; + } + } + // flat_multiset, default + { + typedef boost::container::flat_multiset cont; + typedef boost::container::dtl::flat_tree, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multiset, default) test failed" << std::endl; + return 1; + } + } + // flat_multiset, vector + { + typedef boost::container::vector alloc_or_cont_t; + typedef boost::container::flat_multiset, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multiset, vector) test failed" << std::endl; + return 1; + } + } + // flat_multiset, std::vector + { + typedef std::vector alloc_or_cont_t; + typedef boost::container::flat_multiset, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multiset, std::vector) test failed" << std::endl; + return 1; + } + } + } + return 0; } diff --git a/test/flat_tree_test.cpp b/test/flat_tree_test.cpp index b70fb4a..e94c089 100644 --- a/test/flat_tree_test.cpp +++ b/test/flat_tree_test.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "movable_int.hpp" #include "dummy_test_allocator.hpp" @@ -120,5 +122,35 @@ template class flat_tree int main () { + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default + { + typedef boost::container::dtl::flat_tree, + std::less, void> tree; + typedef tree::container_type container_type; + typedef tree::key_compare key_compare; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::dtl::flat_tree, + std::less, std::allocator > tree; + typedef tree::container_type container_type; + typedef tree::key_compare key_compare; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } diff --git a/test/list_test.cpp b/test/list_test.cpp index 5006a7d..c4f9f41 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -252,6 +252,34 @@ int main () } #endif + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::list cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::list > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } diff --git a/test/map_test.cpp b/test/map_test.cpp index b73f569..7448303 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -633,6 +633,60 @@ int main () BOOST_STATIC_ASSERT(sizeof(rbmmap_size_optimized_yes) < sizeof(rbmap_size_optimized_no)); BOOST_STATIC_ASSERT(sizeof(avlmap_size_optimized_yes) < sizeof(avlmmap_size_optimized_no)); + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + { + typedef std::pair value_type; + // + // map + // + // default allocator + { + typedef boost::container::map cont; + typedef boost::container::dtl::tree, void, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(map, default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::map, std::allocator > cont; + typedef boost::container::dtl::tree, std::allocator, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(map, std::allocator) test failed" << std::endl; + return 1; + } + } + // + // multimap + // + // default allocator + { + // default allocator + typedef boost::container::multimap cont; + typedef boost::container::dtl::tree, void, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(multimap, default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::multimap, std::allocator > cont; + typedef boost::container::dtl::tree, std::allocator, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(multimap, std::allocator) test failed" << std::endl; + return 1; + } + } + } + return 0; } diff --git a/test/set_test.cpp b/test/set_test.cpp index 39ab1b7..a7d0b47 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -605,6 +605,50 @@ int main () if(!node_type_test()) return 1; + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // set, default allocator + { + typedef boost::container::set cont; + typedef boost::container::dtl::tree, void, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(set, default allocator) test failed" << std::endl; + return 1; + } + } + // set, std::allocator + { + typedef boost::container::set, std::allocator > cont; + typedef boost::container::dtl::tree, std::allocator, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(set, std::allocator) test failed" << std::endl; + return 1; + } + } + // multiset, default allocator + { + typedef boost::container::multiset cont; + typedef boost::container::dtl::tree, void, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(multiset, default allocator) test failed" << std::endl; + return 1; + } + } + // multiset, std::allocator + { + typedef boost::container::multiset, std::allocator > cont; + typedef boost::container::dtl::tree, std::allocator, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(multiset, std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 4e09837..0894344 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -255,6 +255,34 @@ int main () } #endif + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::slist cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::slist > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } diff --git a/test/small_vector_test.cpp b/test/small_vector_test.cpp index e3b7600..315d64d 100644 --- a/test/small_vector_test.cpp +++ b/test/small_vector_test.cpp @@ -212,5 +212,25 @@ int main() } } + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::small_vector cont; + if (boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::small_vector > cont; + if (boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index fd76330..e0fb586 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -193,6 +193,34 @@ int main() } #endif + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::stable_vector cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::stable_vector > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } diff --git a/test/string_test.cpp b/test/string_test.cpp index 2dfb2a4..b2d17f6 100644 --- a/test/string_test.cpp +++ b/test/string_test.cpp @@ -562,6 +562,34 @@ int main() return 1; } + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::basic_string cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::basic_string, std::allocator > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return boost::report_errors(); } diff --git a/test/tree_test.cpp b/test/tree_test.cpp index c1a1c3d..e075596 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -9,6 +9,10 @@ ////////////////////////////////////////////////////////////////////////////// #include #include +#include +#include + +#include #include "movable_int.hpp" #include "dummy_test_allocator.hpp" @@ -79,5 +83,37 @@ template class tree int main () { + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default + { + typedef boost::container::dtl::tree, void, void> tree; + typedef tree::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + typedef tree::key_compare key_compare; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::dtl::tree, std::allocator, void> tree; + typedef tree::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + typedef tree::key_compare key_compare; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 2420563..c9b82cc 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -332,5 +332,33 @@ int main() return 1; } + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::vector cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::vector > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + return 0; } From 8376286aa6409db33b12d188cefc68f4afea06c1 Mon Sep 17 00:00:00 2001 From: Jan Eisenhauer <44572464+JanEisenhauer@users.noreply.github.com> Date: Fri, 7 Jun 2019 11:52:44 +0200 Subject: [PATCH 03/12] With heterogeneous lookup, `equal_range` can result in a range with length greater than 1. --- include/boost/container/flat_set.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 080beb5..4d4ae47 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -1031,7 +1031,7 @@ class flat_set //! Complexity: Logarithmic template std::pair equal_range(const K& x) - { return this->tree_t::lower_bound_range(x); } + { return this->tree_t::equal_range(x); } //! Requires: This overload is available only if //! key_compare::is_transparent exists. @@ -1041,7 +1041,7 @@ class flat_set //! Complexity: Logarithmic template std::pair equal_range(const K& x) const - { return this->tree_t::lower_bound_range(x); } + { return this->tree_t::equal_range(x); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) From 699b1e966d3f6124a4ad6fd7a528bbcc251d5a73 Mon Sep 17 00:00:00 2001 From: Jan Eisenhauer <44572464+JanEisenhauer@users.noreply.github.com> Date: Fri, 7 Jun 2019 11:55:15 +0200 Subject: [PATCH 04/12] With heterogeneous lookup, `equal_range` can result in a range with length greater than 1. --- include/boost/container/flat_map.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 2b52e14..7ef8c5f 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -1465,7 +1465,7 @@ class flat_map //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const K& x) - { return dtl::force_copy >(m_flat_tree.lower_bound_range(x)); } + { return dtl::force_copy >(m_flat_tree.equal_range(x)); } //! Requires: This overload is available only if //! key_compare::is_transparent exists. @@ -1475,7 +1475,7 @@ class flat_map //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const K& x) const - { return dtl::force_copy >(m_flat_tree.lower_bound_range(x)); } + { return dtl::force_copy >(m_flat_tree.equal_range(x)); } //! Effects: Extracts the internal sequence container. //! From e866c15fae3fe51419f165ac6fa2ebe0cc814895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 8 Jun 2019 12:48:03 +0200 Subject: [PATCH 05/12] Update changelog with #122 ("Fix has_trivial_destructor_after_move") --- doc/container.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/container.qbk b/doc/container.qbk index c9db3ae..a6e19a8 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1332,6 +1332,7 @@ use [*Boost.Container]? There are several reasons for that: * [@https://github.com/boostorg/container/issues/116 GitHub #116: ['"MSVC + boost 1.70 compilation error when windows.h is already included (detail/thread_mutex.hpp)"]]. * [@https://github.com/boostorg/container/issues/117 GitHub #117: ['"flat_map/map::insert_or_assign with hint has wrong return types"]]. * [@https://github.com/boostorg/container/issues/118 GitHub #118: ['"Non-unique inplace_set_difference used in in flat_tree_merge_unique and iterator invalidation in insert_unique"]]. + * [@https://github.com/boostorg/container/issues/122 GitHub #122: ['"Fix has_trivial_destructor_after_move"]]. * [classref boost::container::deque deque] can now have options, using [classref boost::container::deque_options deque_options]. The block size/bytes can be be specified. From 7b62f360b77cf7a95b52fb1cbea6c02a7f6df77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 8 Jun 2019 13:01:24 +0200 Subject: [PATCH 06/12] Add missing tests for small vector and static vector --- test/small_vector_options_test.cpp | 110 ++++++++++++++++++++++++ test/static_vector_options_test.cpp | 124 ++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 test/small_vector_options_test.cpp create mode 100644 test/static_vector_options_test.cpp diff --git a/test/small_vector_options_test.cpp b/test/small_vector_options_test.cpp new file mode 100644 index 0000000..73e4855 --- /dev/null +++ b/test/small_vector_options_test.cpp @@ -0,0 +1,110 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-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 +#include +using namespace boost::container; + +const std::size_t Capacity = 10u; + +void test_alignment() +{ + { //extended alignment + const std::size_t extended_alignment = sizeof(int)*4u; + BOOST_STATIC_ASSERT(extended_alignment > dtl::alignment_of::value); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< inplace_alignment >; + #else + typedef small_vector_options + < inplace_alignment >::type options_t; + #endif + + small_vector v; + v.resize(v.capacity()); + BOOST_ASSERT((reinterpret_cast(&v[0]) % extended_alignment) == 0); + } + { //default alignment + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< inplace_alignment<0> >; + #else + typedef small_vector_options< inplace_alignment<0> >::type options_t; + #endif + + small_vector v; + v.resize(v.capacity()); + BOOST_ASSERT((reinterpret_cast(&v[0]) % dtl::alignment_of::value) == 0); + } +} + +void test_growth_factor_50() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< growth_factor >; + #else + typedef small_vector_options + < growth_factor >::type options_t; + #endif + + small_vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + old_capacity/2); +} + +void test_growth_factor_60() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< growth_factor >; + #else + typedef small_vector_options + < growth_factor >::type options_t; + #endif + + small_vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + 3*old_capacity/5); +} + +void test_growth_factor_100() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< growth_factor >; + #else + typedef small_vector_options + < growth_factor >::type options_t; + #endif + + small_vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == 2*old_capacity); +} + +int main() +{ + test_alignment(); + test_growth_factor_50(); + test_growth_factor_60(); + test_growth_factor_100(); + return ::boost::report_errors(); +} diff --git a/test/static_vector_options_test.cpp b/test/static_vector_options_test.cpp new file mode 100644 index 0000000..e8965d5 --- /dev/null +++ b/test/static_vector_options_test.cpp @@ -0,0 +1,124 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-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. +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_ENABLE_ASSERT_HANDLER +#include +#include +#include //for bad_alloc +#include +using namespace boost::container; + +//User-defined assertion to test throw_on_overflow +struct throw_on_overflow_off +{}; + +namespace boost { + void assertion_failed(char const *, char const *, char const *, long) + { + throw throw_on_overflow_off(); + } + + void assertion_failed_msg(char const *, char const *, char const *, char const *, long ) + { + throw throw_on_overflow_off(); + } +} + +void test_alignment() +{ + const std::size_t Capacity = 10u; + { //extended alignment + const std::size_t extended_alignment = sizeof(int)*4u; + BOOST_STATIC_ASSERT(extended_alignment > dtl::alignment_of::value); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< inplace_alignment >; + #else + typedef static_vector_options + < inplace_alignment >::type options_t; + #endif + + static_vector v; + v.resize(v.capacity()); + BOOST_ASSERT((reinterpret_cast(&v[0]) % extended_alignment) == 0); + } + { //default alignment + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< inplace_alignment<0> >; + #else + typedef static_vector_options< inplace_alignment<0> >::type options_t; + #endif + + static_vector v; + v.resize(v.capacity()); + BOOST_ASSERT((reinterpret_cast(&v[0]) % dtl::alignment_of::value) == 0); + } +} + +void test_throw_on_overflow() +{ + #if !defined(BOOST_NO_EXCEPTIONS) + const std::size_t Capacity = 10u; + { //throw_on_overflow == true, expect bad_alloc + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< throw_on_overflow >; + #else + typedef static_vector_options + < throw_on_overflow >::type options_t; + #endif + + static_vector v; + + v.resize(Capacity); + bool expected_type_thrown = false; + try{ + v.push_back(0); + } + catch(std::bad_alloc&) + { + expected_type_thrown = true; + } + catch(...) + {} + BOOST_TEST(expected_type_thrown == true); + BOOST_TEST(v.capacity() == Capacity); + } + { //throw_on_overflow == false, test it through BOOST_ASSERT + //even in release mode (BOOST_ENABLE_ASSERT_HANDLER), and throwing + //a special type in that assertion. + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< throw_on_overflow >; + #else + typedef static_vector_options< throw_on_overflow >::type options_t; + #endif + + static_vector v; + + v.resize(Capacity); + bool expected_type_thrown = false; + try{ + v.push_back(0); + } + catch(throw_on_overflow_off) + { + expected_type_thrown = true; + } + catch(...) + {} + BOOST_TEST(expected_type_thrown == true); + BOOST_TEST(v.capacity() == Capacity); + } + #endif +} + +int main() +{ + test_alignment(); + test_throw_on_overflow(); + return ::boost::report_errors(); +} From 1aa15ead3513bd72deaac26d79240abe6ab62686 Mon Sep 17 00:00:00 2001 From: Jan Eisenhauer <44572464+JanEisenhauer@users.noreply.github.com> Date: Tue, 11 Jun 2019 10:23:13 +0200 Subject: [PATCH 07/12] Add testcases for heterogeneous lookup with partial keys. --- test/flat_map_test.cpp | 35 +++++++++++++++++++++++++++++++++++ test/flat_set_test.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index 9497ee2..ca4ce1a 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -22,6 +22,7 @@ #include "../../intrusive/test/iterator_test.hpp" #include +#include using namespace boost::container; @@ -557,6 +558,37 @@ bool test_heterogeneous_lookups() return true; } +// An ordered sequence of std:pair is also ordered by std::pair::first. +struct with_lookup_by_first +{ + typedef void is_transparent; + inline bool operator()(std::pair a, std::pair b) const + { + return a < b; + } + inline bool operator()(std::pair a, int first) const + { + return a.first < first; + } + inline bool operator()(int first, std::pair b) const + { + return first < b.first; + } +}; + +bool test_heterogeneous_lookup_by_partial_key() +{ + flat_set, with_lookup_by_first> const set1 + { + {{0, 1}, 3}, + {{0, 2}, 3}, + }; + + auto const first_0_range = uut.equal_range(0); + + return 2 == first_0_range.second - first_0_range.first; +} + }}} //namespace boost::container::test int main() @@ -617,6 +649,9 @@ int main() if (!test_heterogeneous_lookups()) return 1; + if (!test_heterogeneous_lookup_by_partial_key()) + return 1; + //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index 7e561f7..0215a69 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -574,6 +575,37 @@ bool test_heterogeneous_lookups() return true; } +// An ordered sequence of std:pair is also ordered by std::pair::first. +struct with_lookup_by_first +{ + typedef void is_transparent; + inline bool operator()(std::pair a, std::pair b) const + { + return a < b; + } + inline bool operator()(std::pair a, int first) const + { + return a.first < first; + } + inline bool operator()(int first, std::pair b) const + { + return first < b.first; + } +}; + +bool test_heterogeneous_lookup_by_partial_key() +{ + flat_set, with_lookup_by_first> const set1 + { + {0, 1}, + {0, 2}, + }; + + auto const first_0_range = uut.equal_range(0); + + return 2 == first_0_range.second - first_0_range.first; +} + }}} template @@ -715,6 +747,10 @@ int main() return 1; } + if(!test_heterogeneous_lookup_by_partial_key()){ + return 1; + } + //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// From a6b6f97a5000694f460ab0bf9773f1721c306f7d Mon Sep 17 00:00:00 2001 From: Jan Eisenhauer <44572464+JanEisenhauer@users.noreply.github.com> Date: Tue, 11 Jun 2019 11:17:01 +0200 Subject: [PATCH 08/12] Solve copy-paste errors. --- test/flat_map_test.cpp | 4 ++-- test/flat_set_test.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index cbf9c41..e3c3347 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -581,13 +581,13 @@ struct with_lookup_by_first bool test_heterogeneous_lookup_by_partial_key() { - flat_set, with_lookup_by_first> const set1 + flat_map, with_lookup_by_first> const map1 { {{0, 1}, 3}, {{0, 2}, 3}, }; - auto const first_0_range = uut.equal_range(0); + auto const first_0_range = map1.equal_range(0); return 2 == first_0_range.second - first_0_range.first; } diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index 054be9e..c74cb78 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -603,7 +603,7 @@ bool test_heterogeneous_lookup_by_partial_key() {0, 2}, }; - auto const first_0_range = uut.equal_range(0); + auto const first_0_range = set1.equal_range(0); return 2 == first_0_range.second - first_0_range.first; } From 628289cb00b40f7c6750abaf98a7176bf4568d60 Mon Sep 17 00:00:00 2001 From: Jan Eisenhauer <44572464+JanEisenhauer@users.noreply.github.com> Date: Tue, 11 Jun 2019 11:51:28 +0200 Subject: [PATCH 09/12] Solve copy-paste errors. --- test/flat_map_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index e3c3347..ef1e3a4 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -581,7 +581,7 @@ struct with_lookup_by_first bool test_heterogeneous_lookup_by_partial_key() { - flat_map, with_lookup_by_first> const map1 + flat_map,int, with_lookup_by_first> const map1 { {{0, 1}, 3}, {{0, 2}, 3}, From 3f09061d783064f546ba9c014eeeae0a5a369eea Mon Sep 17 00:00:00 2001 From: Jan Eisenhauer <44572464+JanEisenhauer@users.noreply.github.com> Date: Tue, 11 Jun 2019 12:04:43 +0200 Subject: [PATCH 10/12] Remove usage of C++11 features. --- test/flat_map_test.cpp | 12 ++++++------ test/flat_set_test.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index ef1e3a4..d01598b 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -581,13 +581,13 @@ struct with_lookup_by_first bool test_heterogeneous_lookup_by_partial_key() { - flat_map,int, with_lookup_by_first> const map1 - { - {{0, 1}, 3}, - {{0, 2}, 3}, - }; + typedef flat_map,int, with_lookup_by_first> map_t; - auto const first_0_range = map1.equal_range(0); + map_t map1; + map1[std::pair(0, 1)] = 3; + map1[std::pair(0, 2)] = 3; + + std::pair const first_0_range = map1.equal_range(0); return 2 == first_0_range.second - first_0_range.first; } diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index c74cb78..693305f 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -597,13 +597,13 @@ struct with_lookup_by_first bool test_heterogeneous_lookup_by_partial_key() { - flat_set, with_lookup_by_first> const set1 - { - {0, 1}, - {0, 2}, - }; + typedef flat_set, with_lookup_by_first> set_t; - auto const first_0_range = set1.equal_range(0); + set_t set1; + set1.insert(std::pair(0, 1)); + set1.insert(std::pair(0, 2)); + + std::pair const first_0_range = set1.equal_range(0); return 2 == first_0_range.second - first_0_range.first; } From 0c95d4846f8a2c3727a576af5676d0a628fe6d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 22 Jun 2019 10:26:36 +0200 Subject: [PATCH 11/12] Fix "count" with heterogeneous lookups in flat_map and flat_set --- doc/container.qbk | 1 + include/boost/container/detail/flat_tree.hpp | 2 +- include/boost/container/flat_map.hpp | 8 +++++++- include/boost/container/flat_set.hpp | 8 +++++++- test/flat_map_test.cpp | 7 ++++++- test/flat_set_test.cpp | 6 +++++- 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index a6e19a8..644f510 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1333,6 +1333,7 @@ use [*Boost.Container]? There are several reasons for that: * [@https://github.com/boostorg/container/issues/117 GitHub #117: ['"flat_map/map::insert_or_assign with hint has wrong return types"]]. * [@https://github.com/boostorg/container/issues/118 GitHub #118: ['"Non-unique inplace_set_difference used in in flat_tree_merge_unique and iterator invalidation in insert_unique"]]. * [@https://github.com/boostorg/container/issues/122 GitHub #122: ['"Fix has_trivial_destructor_after_move"]]. + * [@https://github.com/boostorg/container/issues/123 GitHub #123: ['"With heterogeneous lookup, `equal_range` can result in a range with length greater than 1"]]. * [classref boost::container::deque deque] can now have options, using [classref boost::container::deque_options deque_options]. The block size/bytes can be be specified. diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 5d96a21..c346360 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -1605,7 +1605,7 @@ class flat_tree const Compare &key_cmp = this->m_data.get_comp(); KeyOfValue key_extract; RanIt lb(this->priv_lower_bound(first, last, k)), ub(lb); - if(lb != last && static_cast(!key_cmp(k, key_extract(*lb)))){ + if(lb != last && !key_cmp(k, key_extract(*lb))){ ++ub; } return std::pair(lb, ub); diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 3a21ea9..a3bcf47 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -1343,7 +1343,9 @@ class flat_map //! //! Complexity: log(size())+count(k) BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const - { return static_cast(m_flat_tree.find(x) != m_flat_tree.end()); } + //Don't use find() != end optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) + { return m_flat_tree.count(x); } //! Requires: This overload is available only if //! key_compare::is_transparent exists. @@ -1465,6 +1467,8 @@ class flat_map //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const K& x) + //Don't use lower_bound_range optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) { return dtl::force_copy >(m_flat_tree.equal_range(x)); } //! Requires: This overload is available only if @@ -1475,6 +1479,8 @@ class flat_map //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const K& x) const + //Don't use lower_bound_range optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) { return dtl::force_copy >(m_flat_tree.equal_range(x)); } //! Effects: Extracts the internal sequence container. diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 2b69e1a..7cb1d5c 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -925,7 +925,9 @@ class flat_set //! Complexity: log(size())+count(k) template BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const - { return static_cast(this->tree_t::find(x) != this->tree_t::cend()); } + //Don't use find() != end optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) + { return this->tree_t::count(x); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1031,6 +1033,8 @@ class flat_set //! Complexity: Logarithmic template std::pair equal_range(const K& x) + //Don't use lower_bound_range optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) { return this->tree_t::equal_range(x); } //! Requires: This overload is available only if @@ -1041,6 +1045,8 @@ class flat_set //! Complexity: Logarithmic template std::pair equal_range(const K& x) const + //Don't use lower_bound_range optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) { return this->tree_t::equal_range(x); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index d01598b..f5caff7 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -589,7 +589,12 @@ bool test_heterogeneous_lookup_by_partial_key() std::pair const first_0_range = map1.equal_range(0); - return 2 == first_0_range.second - first_0_range.first; + if(2 != (first_0_range.second - first_0_range.first)) + return false; + + if(2 != map1.count(0)) + return false; + return true; } }}} //namespace boost::container::test diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index 693305f..7927b99 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -604,8 +604,12 @@ bool test_heterogeneous_lookup_by_partial_key() set1.insert(std::pair(0, 2)); std::pair const first_0_range = set1.equal_range(0); + if(2 != (first_0_range.second - first_0_range.first)) + return false; - return 2 == first_0_range.second - first_0_range.first; + if(2 != set1.count(0)) + return false; + return true; } }}} From d9341ec394ef97bd1b36f05b5e6be6ec538e480c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 22 Jun 2019 11:41:05 +0200 Subject: [PATCH 12/12] Fix "count" with heterogeneous lookups in flat_map and flat_set --- include/boost/container/flat_map.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index a3bcf47..f1d5ed2 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -1343,9 +1343,7 @@ class flat_map //! //! Complexity: log(size())+count(k) BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const - //Don't use find() != end optimization here as transparent comparators with key K might - //return a different range than key_type (which can only return a single element range) - { return m_flat_tree.count(x); } + { return static_cast(m_flat_tree.find(x) != m_flat_tree.end()); } //! Requires: This overload is available only if //! key_compare::is_transparent exists. @@ -1355,7 +1353,9 @@ class flat_map //! Complexity: log(size())+count(k) template BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const - { return static_cast(m_flat_tree.find(x) != m_flat_tree.end()); } + //Don't use find() != end optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) + { return m_flat_tree.count(x); } //! Returns: Returns true if there is an element with key //! equivalent to key in the container, otherwise false.