From 51b6b7e57563f15813a12e5e5f74598baf4017c3 Mon Sep 17 00:00:00 2001 From: Edward Catmur Date: Thu, 4 Feb 2021 10:27:22 +0000 Subject: [PATCH 1/6] Specialize range_const_iterator_helper for std::span std::span does not have const_iterator member type, so this fails: #include #include using X = boost::range_iterator const>::type; --- include/boost/range/const_iterator.hpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/boost/range/const_iterator.hpp b/include/boost/range/const_iterator.hpp index 727fdad05..e67f8a748 100644 --- a/include/boost/range/const_iterator.hpp +++ b/include/boost/range/const_iterator.hpp @@ -23,6 +23,9 @@ #include #include #include +#if __cpp_lib_span >= 201902L +# include +#endif namespace boost { @@ -60,6 +63,20 @@ struct range_const_iterator_helper< T[sz] > typedef const T* type; }; +////////////////////////////////////////////////////////////////////////// +// span +////////////////////////////////////////////////////////////////////////// + +#if __cpp_lib_span >= 201902L + +template< typename T, std::size_t sz > +struct range_const_iterator_helper< std::span > +{ + typedef typename std::span::iterator type; +}; + +#endif + } // namespace range_detail template From 855f51f7f5c23fcf3f19d7403d08ae1ac75097a5 Mon Sep 17 00:00:00 2001 From: Edward Catmur Date: Tue, 9 Feb 2021 13:35:21 +0000 Subject: [PATCH 2/6] also begin/end --- include/boost/range/begin.hpp | 18 ++++++++++++++++++ include/boost/range/end.hpp | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/include/boost/range/begin.hpp b/include/boost/range/begin.hpp index 17d9f8423..f2a219dcc 100644 --- a/include/boost/range/begin.hpp +++ b/include/boost/range/begin.hpp @@ -21,6 +21,10 @@ #include #include +#if __cpp_lib_span >= 201902L +# include +#endif + namespace boost { @@ -80,6 +84,20 @@ namespace range_detail return a; } + ////////////////////////////////////////////////////////////////////////// + // span + ////////////////////////////////////////////////////////////////////////// + +#if __cpp_lib_span >= 201902L + + template< typename T, std::size_t sz > + BOOST_CONSTEXPR inline BOOST_DEDUCED_TYPENAME std::span::iterator + range_begin( std::span const& s ) + { + return std::span(s).begin(); + } + +#endif #if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) } // namespace 'range_detail' diff --git a/include/boost/range/end.hpp b/include/boost/range/end.hpp index 332590973..bb9a24dc3 100644 --- a/include/boost/range/end.hpp +++ b/include/boost/range/end.hpp @@ -23,6 +23,10 @@ #include #include +#if __cpp_lib_span >= 201902L +# include +#endif + namespace boost { @@ -78,6 +82,21 @@ namespace range_detail return range_detail::array_end( a ); } + ////////////////////////////////////////////////////////////////////////// + // span + ////////////////////////////////////////////////////////////////////////// + +#if __cpp_lib_span >= 201902L + + template< typename T, std::size_t sz > + BOOST_CONSTEXPR inline BOOST_DEDUCED_TYPENAME std::span::iterator + range_end( std::span const& s ) + { + return std::span(s).end(); + } + +#endif + #if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) } // namespace 'range_detail' #endif From f17e3cfaf1a54e170510197f38d3853dbb8e96b9 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Thu, 30 Dec 2021 08:59:32 +0000 Subject: [PATCH 3/6] Add unit test --- test/Jamfile.v2 | 1 + test/std_span.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 test/std_span.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index cd2774e9f..b83091afa 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -209,6 +209,7 @@ test-suite range : [ range-test reversible_range ] [ range-test size_type ] [ range-test std_container ] + [ range-test std_span ] [ range-test string ] [ range-test sub_range ] [ range-test ticket_5486 ] diff --git a/test/std_span.cpp b/test/std_span.cpp new file mode 100644 index 000000000..5cadd9ce4 --- /dev/null +++ b/test/std_span.cpp @@ -0,0 +1,85 @@ + // Boost.Range library +// +// Copyright Thorsten Ottosen 2003-2004. Use, modification and +// distribution is subject to 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) +// +// For more information, see http://www.boost.org/libs/range/ +// + + +#include + +#if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) +# pragma warn -8091 // suppress warning in Boost.Test +# pragma warn -8057 // unused argument argc/argv in Boost.Test +#endif + +#include +#include +#include +#include +#include +#include +#if __cpp_lib_span >= 201902L +# include +#endif + +#if __cpp_lib_span >= 201902L +void check_std_span() +{ + std::array arr = {1, 2, 3}; + using span_t = std::span; + span_t sp = arr; + using cspan_t = std::span; + cspan_t = sp; + + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, span_t::value_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::iterator >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::const_iterator >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, span_t::difference_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, span_t::size_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::iterator >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::const_iterator >::value )); + + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, span_t::value_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, span_t::difference_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, span_t::size_type >::value )); + + BOOST_CHECK( boost::begin( sp ) == sp.begin() ); + BOOST_CHECK( boost::end( sp ) == sp.end() ); + BOOST_CHECK( boost::empty( sp ) == sp.empty() ); + BOOST_CHECK( static_cast(boost::size( sp )) == sp.size() ); + + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, cspan_t::value_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::iterator >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::const_iterator >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, cspan_t::difference_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, cspan_t::size_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::iterator >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::const_iterator >::value )); + + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, cspan_t::value_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, cspan_t::difference_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, cspan_t::size_type >::value )); + + BOOST_CHECK( boost::begin( csp ) == csp.begin() ); + BOOST_CHECK( boost::end( csp ) == csp.end() ); + BOOST_CHECK( boost::empty( csp ) == csp.empty() ); + BOOST_CHECK( static_cast(boost::size( csp )) == csp.size() ); +} +#endif + +#include + +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + boost::unit_test::test_suite* test = BOOST_TEST_SUITE( "Range Test Suite" ); + +#if __cpp_lib_span >= 201902L + test->add( BOOST_TEST_CASE( &check_std_span ) ); +#endif + + return test; +} From 639e8ec51b6f840eadec3130ca34a782d9cef803 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Thu, 30 Dec 2021 16:21:06 +0000 Subject: [PATCH 4/6] Fix implementation for const iterator == iterator --- include/boost/range/begin.hpp | 18 ------------------ include/boost/range/const_iterator.hpp | 4 ++-- include/boost/range/end.hpp | 19 ------------------- test/std_span.cpp | 10 +++------- 4 files changed, 5 insertions(+), 46 deletions(-) diff --git a/include/boost/range/begin.hpp b/include/boost/range/begin.hpp index f2a219dcc..17d9f8423 100644 --- a/include/boost/range/begin.hpp +++ b/include/boost/range/begin.hpp @@ -21,10 +21,6 @@ #include #include -#if __cpp_lib_span >= 201902L -# include -#endif - namespace boost { @@ -84,20 +80,6 @@ namespace range_detail return a; } - ////////////////////////////////////////////////////////////////////////// - // span - ////////////////////////////////////////////////////////////////////////// - -#if __cpp_lib_span >= 201902L - - template< typename T, std::size_t sz > - BOOST_CONSTEXPR inline BOOST_DEDUCED_TYPENAME std::span::iterator - range_begin( std::span const& s ) - { - return std::span(s).begin(); - } - -#endif #if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) } // namespace 'range_detail' diff --git a/include/boost/range/const_iterator.hpp b/include/boost/range/const_iterator.hpp index e67f8a748..6aa90062d 100644 --- a/include/boost/range/const_iterator.hpp +++ b/include/boost/range/const_iterator.hpp @@ -24,7 +24,7 @@ #include #include #if __cpp_lib_span >= 201902L -# include +# include #endif namespace boost @@ -72,7 +72,7 @@ struct range_const_iterator_helper< T[sz] > template< typename T, std::size_t sz > struct range_const_iterator_helper< std::span > { - typedef typename std::span::iterator type; + typedef typename std::span::iterator type; }; #endif diff --git a/include/boost/range/end.hpp b/include/boost/range/end.hpp index bb9a24dc3..332590973 100644 --- a/include/boost/range/end.hpp +++ b/include/boost/range/end.hpp @@ -23,10 +23,6 @@ #include #include -#if __cpp_lib_span >= 201902L -# include -#endif - namespace boost { @@ -82,21 +78,6 @@ namespace range_detail return range_detail::array_end( a ); } - ////////////////////////////////////////////////////////////////////////// - // span - ////////////////////////////////////////////////////////////////////////// - -#if __cpp_lib_span >= 201902L - - template< typename T, std::size_t sz > - BOOST_CONSTEXPR inline BOOST_DEDUCED_TYPENAME std::span::iterator - range_end( std::span const& s ) - { - return std::span(s).end(); - } - -#endif - #if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) } // namespace 'range_detail' #endif diff --git a/test/std_span.cpp b/test/std_span.cpp index 5cadd9ce4..dcb625309 100644 --- a/test/std_span.cpp +++ b/test/std_span.cpp @@ -33,17 +33,15 @@ void check_std_span() using span_t = std::span; span_t sp = arr; using cspan_t = std::span; - cspan_t = sp; + cspan_t csp = sp; BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, span_t::value_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::iterator >::value )); - BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::const_iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, span_t::difference_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, span_t::size_type >::value )); - BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::iterator >::value )); - BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::const_iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, span_t::value_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, span_t::difference_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, span_t::size_type >::value )); @@ -54,13 +52,11 @@ void check_std_span() BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, cspan_t::value_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::iterator >::value )); - BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::const_iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, cspan_t::difference_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, cspan_t::size_type >::value )); - BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::iterator >::value )); - BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::const_iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, cspan_t::value_type >::value )); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, cspan_t::difference_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, cspan_t::size_type >::value )); From 7a5636a64563e0476c6f7c27a9da839a40be796f Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Thu, 30 Dec 2021 16:44:03 +0000 Subject: [PATCH 5/6] add tests and rationale --- test/std_span.cpp | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/test/std_span.cpp b/test/std_span.cpp index dcb625309..ea69bb8f0 100644 --- a/test/std_span.cpp +++ b/test/std_span.cpp @@ -29,41 +29,58 @@ #if __cpp_lib_span >= 201902L void check_std_span() { + // const_iterator was removed from std::span for C++20: https://cplusplus.github.io/LWG/issue3320 + // but see https://github.com/cplusplus/papers/issues/971 - it may be reintroduced as a std::const_iterator + // Check that boost::begin etc. behave consistently with their respective member methods; this may require + // additional work in future. + std::array arr = {1, 2, 3}; using span_t = std::span; span_t sp = arr; - using cspan_t = std::span; + const span_t spc = sp; + using cspan_t = std::span; cspan_t csp = sp; + const cspan_t cspc = csp; BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, span_t::value_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, span_t::difference_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, span_t::size_type >::value )); + BOOST_CHECK( boost::begin( sp ) == sp.begin() ); + BOOST_CHECK( boost::end( sp ) == sp.end() ); + BOOST_CHECK( boost::empty( sp ) == sp.empty() ); + BOOST_CHECK( static_cast(boost::size( sp )) == sp.size() ); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, span_t::value_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, span_t::iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, span_t::difference_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, span_t::size_type >::value )); - BOOST_CHECK( boost::begin( sp ) == sp.begin() ); - BOOST_CHECK( boost::end( sp ) == sp.end() ); - BOOST_CHECK( boost::empty( sp ) == sp.empty() ); - BOOST_CHECK( static_cast(boost::size( sp )) == sp.size() ); + BOOST_CHECK( boost::begin( spc ) == spc.begin() ); + BOOST_CHECK( boost::end( spc ) == spc.end() ); + BOOST_CHECK( boost::empty( spc ) == spc.empty() ); + BOOST_CHECK( static_cast(boost::size( spc )) == spc.size() ); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, cspan_t::value_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, cspan_t::difference_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, cspan_t::size_type >::value )); + BOOST_CHECK( boost::begin( csp ) == csp.begin() ); + BOOST_CHECK( boost::end( csp ) == csp.end() ); + BOOST_CHECK( boost::empty( csp ) == csp.empty() ); + BOOST_CHECK( static_cast(boost::size( csp )) == csp.size() ); + BOOST_STATIC_ASSERT(( boost::is_same< boost::range_value::type, cspan_t::value_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_iterator::type, cspan_t::iterator >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_difference::type, cspan_t::difference_type >::value )); BOOST_STATIC_ASSERT(( boost::is_same< boost::range_size::type, cspan_t::size_type >::value )); - BOOST_CHECK( boost::begin( csp ) == csp.begin() ); - BOOST_CHECK( boost::end( csp ) == csp.end() ); - BOOST_CHECK( boost::empty( csp ) == csp.empty() ); - BOOST_CHECK( static_cast(boost::size( csp )) == csp.size() ); + BOOST_CHECK( boost::begin( cspc ) == cspc.begin() ); + BOOST_CHECK( boost::end( cspc ) == cspc.end() ); + BOOST_CHECK( boost::empty( cspc ) == cspc.empty() ); + BOOST_CHECK( static_cast(boost::size( cspc )) == cspc.size() ); } #endif From 726c2c02fc1618a4c6fa6a55c88c234f7f3ebe6e Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Thu, 30 Dec 2021 19:46:25 +0000 Subject: [PATCH 6/6] specify c++20 at build system level --- test/Jamfile.v2 | 2 +- test/std_span.cpp | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b83091afa..73b5db59e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -209,7 +209,7 @@ test-suite range : [ range-test reversible_range ] [ range-test size_type ] [ range-test std_container ] - [ range-test std_span ] + [ run std_span.cpp /boost/test//boost_unit_test_framework : : : 20 ] [ range-test string ] [ range-test sub_range ] [ range-test ticket_5486 ] diff --git a/test/std_span.cpp b/test/std_span.cpp index ea69bb8f0..07b19a4f7 100644 --- a/test/std_span.cpp +++ b/test/std_span.cpp @@ -22,11 +22,8 @@ #include #include #include -#if __cpp_lib_span >= 201902L -# include -#endif +#include -#if __cpp_lib_span >= 201902L void check_std_span() { // const_iterator was removed from std::span for C++20: https://cplusplus.github.io/LWG/issue3320 @@ -82,7 +79,6 @@ void check_std_span() BOOST_CHECK( boost::empty( cspc ) == cspc.empty() ); BOOST_CHECK( static_cast(boost::size( cspc )) == cspc.size() ); } -#endif #include @@ -90,9 +86,7 @@ boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) { boost::unit_test::test_suite* test = BOOST_TEST_SUITE( "Range Test Suite" ); -#if __cpp_lib_span >= 201902L test->add( BOOST_TEST_CASE( &check_std_span ) ); -#endif return test; }