From ad7167c5640efb42a444eda80905c956817a3086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 21 Apr 2021 00:43:31 +0200 Subject: [PATCH] Fixes #150 ("Use std::contiguous_iterator_tag if available"), tested in MSVC and GCC. --- doc/container.qbk | 1 + include/boost/container/detail/std_fwd.hpp | 3 +++ include/boost/container/vector.hpp | 24 +++++++++++++++++++ test/vector_test.cpp | 27 ++++++++++++++++++++-- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 1e9c9e7..b0d04ff 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1341,6 +1341,7 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_77_00 Boost 1.77 Release] * Fixed bugs/issues: + * [@https://github.com/boostorg/container/issues/150 GitHub #150: ['"Use std::contiguous_iterator_tag if available"]]. * [@https://github.com/boostorg/container/issues/184 GitHub #184: ['"Issues with custom exceptions implementation"]]. [endsect] diff --git a/include/boost/container/detail/std_fwd.hpp b/include/boost/container/detail/std_fwd.hpp index a25c411..d67f669 100644 --- a/include/boost/container/detail/std_fwd.hpp +++ b/include/boost/container/detail/std_fwd.hpp @@ -53,6 +53,9 @@ struct allocator_arg_t; struct piecewise_construct_t; +template +struct pointer_traits; + BOOST_MOVE_STD_NS_END #include diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index e641ab5..c13d011 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -82,7 +82,17 @@ class vec_iterator { public: typedef std::random_access_iterator_tag iterator_category; + typedef std::contiguous_iterator_tag iterator_concept; typedef typename boost::intrusive::pointer_traits::element_type value_type; + + //Defining element_type to make libstdc++'s std::pointer_traits well-formed leads to ambiguity + //due to LWG3446. So we need to specialize std::pointer_traits. See + //https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96416 for details. /Many thanks to Jonathan Wakely + //for explaning the issue. + #ifndef BOOST_GNU_STDLIB + //Define element_ + typedef typename boost::intrusive::pointer_traits::element_type element_type; + #endif typedef typename boost::intrusive::pointer_traits::difference_type difference_type; typedef typename dtl::if_c < IsConst @@ -3378,6 +3388,20 @@ struct has_trivial_destructor_after_move +struct pointer_traits< boost::container::vec_iterator > + : public boost::intrusive::pointer_traits< boost::container::vec_iterator > +{}; + +BOOST_MOVE_STD_NS_END + +#endif //BOOST_GNU_STDLIB + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #include diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 136b471..180980d 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -194,7 +194,25 @@ bool test_merge_empty_free() vector< int, check_dealloc_allocator > empty; empty.merge(source.begin(), source.end()); - return empty.get_stored_allocator().deallocate_called_without_allocate_; + return !empty.get_stored_allocator().deallocate_called_without_allocate_; +} + +#ifdef __cpp_lib_span +#include +#endif + +bool test_span_conversion() +{ + #ifdef __cpp_lib_span + { + boost::container::vector myVec{1, 2, 3, 4, 5}; + std::span mySpan1{myVec}; // (1) + std::span mySpan2{myVec.data(), myVec.size()}; // (2) + return mySpan1.size() == myVec.size() && mySpan1.size() == mySpan2.size(); + } + #else + return true; + #endif } int main() @@ -331,11 +349,16 @@ int main() } #endif - if (test_merge_empty_free()) { + if (!test_merge_empty_free()) { std::cerr << "Merge into empty vector test failed" << std::endl; return 1; } + if (!test_span_conversion()) { + std::cerr << "Span conversion failed" << std::endl; + return 1; + } + //////////////////////////////////// // has_trivial_destructor_after_move testing ////////////////////////////////////