From fb1be6fa75c965c24a03a658c4990137e547d492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 15 Aug 2016 23:22:57 +0200 Subject: [PATCH] Fix Trac #12117 ("flat_set constructor with ordered_unique_range") adding checks to constructors in debug mode Fix typos on value_type checks in flat_[multi]map. --- doc/container.qbk | 1 + include/boost/container/detail/flat_tree.hpp | 22 +++++++- include/boost/container/detail/is_sorted.hpp | 57 ++++++++++++++++++++ include/boost/container/flat_map.hpp | 56 +++++++++---------- include/boost/container/flat_set.hpp | 16 ++++-- proj/vc7ide/container.vcproj | 3 ++ 6 files changed, 122 insertions(+), 33 deletions(-) create mode 100644 include/boost/container/detail/is_sorted.hpp diff --git a/doc/container.qbk b/doc/container.qbk index 9b5ddd9..2368933 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1219,6 +1219,7 @@ use [*Boost.Container]? There are several reasons for that: * [@https://svn.boost.org/trac/boost/ticket/9481 Trac #9481: ['"Minor comment typo in Boost.Container"]]. * [@https://svn.boost.org/trac/boost/ticket/11170 Trac #11170: ['"Doc slip for index_of"]]. * [@https://svn.boost.org/trac/boost/ticket/11802 Trac #11802: ['"Incorrect ordering after using insert() with ordered_range_t on a flat_multiset with a non-default sort order"]]. + * [@https://svn.boost.org/trac/boost/ticket/12117 Trac #12117: ['"flat_set constructor with ordered_unique_range"]]. * [@https://svn.boost.org/trac/boost/ticket/12177 Trac #12177: ['"vector::priv_merge uses unqualified uintptr_t"]]. * [@https://svn.boost.org/trac/boost/ticket/12183 Trac #12183: ['"GCC 6.1 thinks boost::container::string violates strict aliasing"]]. * [@https://svn.boost.org/trac/boost/ticket/12256 Trac #12256: ['"set>::insert cause compilation error in debug configuration in Visual Studio 2012"]]. diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 7ba35cc..23b0af2 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -32,6 +32,7 @@ #include #include //algo_equal(), algo_lexicographical_compare #include +#include #include #ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER #include @@ -238,7 +239,20 @@ class flat_tree , const Compare& comp = Compare() , const allocator_type& a = allocator_type()) : m_data(comp, a) - { this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); } + { + this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); + BOOST_ASSERT((is_sorted)(this->m_data.m_vect.cbegin(), this->m_data.m_vect.cend(), this->priv_value_comp())); + } + + template + flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last + , const Compare& comp = Compare() + , const allocator_type& a = allocator_type()) + : m_data(comp, a) + { + this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); + BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_vect.cbegin(), this->m_data.m_vect.cend(), this->priv_value_comp())); + } template flat_tree( bool unique_insertion @@ -275,6 +289,12 @@ class flat_tree boost::container::container_detail::is_nothrow_move_assignable::value) { m_data = boost::move(x.m_data); return *this; } + BOOST_CONTAINER_FORCEINLINE const value_compare &priv_value_comp() const + { return static_cast(this->m_data); } + + BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp() + { return static_cast(this->m_data); } + public: // accessors: Compare key_comp() const diff --git a/include/boost/container/detail/is_sorted.hpp b/include/boost/container/detail/is_sorted.hpp new file mode 100644 index 0000000..b8c223b --- /dev/null +++ b/include/boost/container/detail/is_sorted.hpp @@ -0,0 +1,57 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2016-2016. 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_DETAIL_IS_SORTED_HPP +#define BOOST_CONTAINER_DETAIL_IS_SORTED_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +namespace boost { +namespace container { +namespace container_detail { + +template +bool is_sorted (ForwardIterator first, ForwardIterator last, Pred pred) +{ + if(first != last){ + ForwardIterator next = first; + while (++next != last){ + if(pred(*next, *first)) + return false; + ++first; + } + } + return true; +} + +template +bool is_sorted_and_unique (ForwardIterator first, ForwardIterator last, Pred pred) +{ + if(first != last){ + ForwardIterator next = first; + while (++next != last){ + if(!pred(*first, *next)) + return false; + ++first; + } + } + return true; +} + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_IS_SORTED_HPP diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index b02db7e..d18fffe 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -187,7 +187,7 @@ class flat_map container_detail::is_nothrow_default_constructible::value) : m_flat_tree() { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -198,7 +198,7 @@ class flat_map explicit flat_map(const Compare& comp, const allocator_type& a = allocator_type()) : m_flat_tree(comp, container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -208,7 +208,7 @@ class flat_map explicit flat_map(const allocator_type& a) : m_flat_tree(container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -222,7 +222,7 @@ class flat_map const allocator_type& a = allocator_type()) : m_flat_tree(true, first, last, comp, container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -235,7 +235,7 @@ class flat_map flat_map(InputIterator first, InputIterator last, const allocator_type& a) : m_flat_tree(true, first, last, Compare(), container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -252,9 +252,9 @@ class flat_map template flat_map( ordered_unique_range_t, InputIterator first, InputIterator last , const Compare& comp = Compare(), const allocator_type& a = allocator_type()) - : m_flat_tree(ordered_range, first, last, comp, a) + : m_flat_tree(ordered_unique_range, first, last, comp, a) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -268,7 +268,7 @@ class flat_map const allocator_type& a = allocator_type()) : m_flat_tree(true, il.begin(), il.end(), comp, container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -280,7 +280,7 @@ class flat_map flat_map(std::initializer_list il, const allocator_type& a) : m_flat_tree(true, il.begin(), il.end(), Compare(), container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -296,9 +296,9 @@ class flat_map //! Note: Non-standard extension. flat_map(ordered_unique_range_t, std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) - : m_flat_tree(ordered_range, il.begin(), il.end(), comp, a) + : m_flat_tree(ordered_unique_range, il.begin(), il.end(), comp, a) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } #endif @@ -309,7 +309,7 @@ class flat_map flat_map(const flat_map& x) : m_flat_tree(x.m_flat_tree) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -323,7 +323,7 @@ class flat_map BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : m_flat_tree(boost::move(x.m_flat_tree)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -333,7 +333,7 @@ class flat_map flat_map(const flat_map& x, const allocator_type &a) : m_flat_tree(x.m_flat_tree, a) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -344,7 +344,7 @@ class flat_map flat_map(BOOST_RV_REF(flat_map) x, const allocator_type &a) : m_flat_tree(boost::move(x.m_flat_tree), a) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1215,7 +1215,7 @@ class flat_multimap container_detail::is_nothrow_default_constructible::value) : m_flat_tree() { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1227,7 +1227,7 @@ class flat_multimap const allocator_type& a = allocator_type()) : m_flat_tree(comp, container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1237,7 +1237,7 @@ class flat_multimap explicit flat_multimap(const allocator_type& a) : m_flat_tree(container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1252,7 +1252,7 @@ class flat_multimap const allocator_type& a = allocator_type()) : m_flat_tree(false, first, last, comp, container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1265,7 +1265,7 @@ class flat_multimap flat_multimap(InputIterator first, InputIterator last, const allocator_type& a) : m_flat_tree(false, first, last, Compare(), container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1284,7 +1284,7 @@ class flat_multimap const allocator_type& a = allocator_type()) : m_flat_tree(ordered_range, first, last, comp, a) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1297,7 +1297,7 @@ class flat_multimap flat_multimap(std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : m_flat_tree(false, il.begin(), il.end(), comp, container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1309,7 +1309,7 @@ class flat_multimap flat_multimap(std::initializer_list il, const allocator_type& a) : m_flat_tree(false, il.begin(), il.end(), Compare(), container_detail::force(a)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1326,7 +1326,7 @@ class flat_multimap const allocator_type& a = allocator_type()) : m_flat_tree(ordered_range, il.begin(), il.end(), comp, a) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } #endif @@ -1337,7 +1337,7 @@ class flat_multimap flat_multimap(const flat_multimap& x) : m_flat_tree(x.m_flat_tree) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1350,7 +1350,7 @@ class flat_multimap BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : m_flat_tree(boost::move(x.m_flat_tree)) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1360,7 +1360,7 @@ class flat_multimap flat_multimap(const flat_multimap& x, const allocator_type &a) : m_flat_tree(x.m_flat_tree, a) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } @@ -1371,7 +1371,7 @@ class flat_multimap flat_multimap(BOOST_RV_REF(flat_multimap) x, const allocator_type &a) : m_flat_tree(boost::move(x.m_flat_tree), a) { - //A type must be std::pair + //value_type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); } diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 693b295..b0c473a 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -169,7 +169,7 @@ class flat_set flat_set(ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) - : base_t(ordered_range, first, last, comp, a) + : base_t(ordered_unique_range, first, last, comp, a) {} #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -204,7 +204,7 @@ class flat_set //! Note: Non-standard extension. flat_set(ordered_unique_range_t, std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) - : base_t(ordered_range, il.begin(), il.end(), comp, a) + : base_t(ordered_unique_range, il.begin(), il.end(), comp, a) {} #endif @@ -959,8 +959,16 @@ class flat_multiset : base_t(false, il.begin(), il.end(), Compare(), a) {} - //! @copydoc ::boost::container::flat_set::flat_set(ordered_unique_range_t, std::initializer_list, const Compare& comp, const allocator_type&) - flat_multiset(ordered_unique_range_t, std::initializer_list il, + //! Effects: Constructs an empty container using the specified comparison object and + //! allocator, and inserts elements from the ordered unique range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! Requires: [il.begin(), il.end()) must be ordered according to the predicate. + //! + //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. + flat_multiset(ordered_range_t, std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : base_t(ordered_range, il.begin(), il.end(), comp, a) {} diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 9c45018..4344eb0 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -245,6 +245,9 @@ + +