From 477e3e75b009f876a4b5516f83410cbbfa85c561 Mon Sep 17 00:00:00 2001 From: Martin Moene Date: Wed, 2 May 2018 12:22:35 +0200 Subject: [PATCH] Add back() and front() (issue #3, thanks to @chris0e3) controlled via span_CONFIG_PROVIDE_BACK_FRONT --- README.md | 36 ++++++++++++++++++-------- include/nonstd/span.hpp | 14 +++++++++++ test/CMakeLists.txt | 3 ++- test/span.t.cpp | 56 +++++++++++++++++++++++++++++++++++++++-- test/t.bat | 3 ++- test/tg.bat | 3 ++- 6 files changed, 100 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 9a8141e..221f81b 100644 --- a/README.md +++ b/README.md @@ -88,23 +88,31 @@ Non-standard extensions ### Construct from container To construct a span from a container with compilers that cannot constrain such a single-parameter constructor to containers, *span lite* provides a constructor that takes an additional parameter of type `with_container_t`. Use `with_container` as value for this parameter. - -### `make_span` -*span lite* can provide `make_span` creator functions to compensate for the class template argument deduction that is missing from pre-C++17 compilers. See the table below and section [configuration](#configuration). +### `back()` and `front()` + +*span lite* can provide `back()` and `front()` member functions for element access. See the table below and section [configuration](#configuration). + +### `make_span()` -### `byte_span` +*span lite* can provide `make_span()` creator functions to compensate for the class template argument deduction that is missing from pre-C++17 compilers. See the table below and section [configuration](#configuration). -*span lite* can provide `byte_span` creator functions to represent an object as a span of bytes. This requires the C++17 type `std::byte` to be available. See the table below and section [configuration](#configuration). +### `byte_span()` + +*span lite* can provide `byte_span()` creator functions to represent an object as a span of bytes. This requires the C++17 type `std::byte` to be available. See the table below and section [configuration](#configuration). | Kind | std | Function or method | |--------------------|------|--------------------| | **Types** | | **with_container_t** type to disambiguate below constructors | | **Objects** | | **with_container** value to disambiguate below constructors | -| **Methods** | | template<class Container>
constexpr **span**(with_container_t, Container & cont) | +| **Constructors** | | template<class Container>
constexpr **span**(with_container_t, Container & cont) | |   | | template<class Container>
constexpr **span**(with_container_t, Container const & cont) | |   | |   | +| **Methods** | | macro **`span_CONFIG_PROVIDE_BACK_FRONT`** | +|   | | constexpr reference **back()** const noexcept | +|   | | constexpr reference **front()** const noexcept | +|   | |   | | **Free functions** | | macro **`span_CONFIG_PROVIDE_MAKE_SPAN`** | |   |   | template<class T>
constexpr span<T>
**make_span**(T \* first, T \* last) noexcept | |   |   | template<class T>
constexpr span<T>
**make_span**(T \* ptr, index_t count) noexcept | @@ -135,13 +143,17 @@ Define this to 1 to select `std::span` as `nonstd::span`. Default is undefined. -Dspan_CONFIG_SELECT_NONSTD_SPAN=1 Define this to 1 to select *span lite*'s `nonstd::span`. Default is undefined. -### Provide `make_span` functions +### Provide `back()` and `front()` member functions +-Dspan_CONFIG_PROVIDE_BACK_FRONT=1 +Define this to 1 to provide member functions `back()` and `front()`. Default is undefined. + +### Provide `make_span()` functions -Dspan_CONFIG_PROVIDE_MAKE_SPAN=1 -Define this to 1 to provide creator functions `nonstd::make_span`. Default is undefined. +Define this to 1 to provide creator functions `nonstd::make_span()`. Default is undefined. -### Provide `byte_span` functions +### Provide `byte_span()` functions -Dspan_CONFIG_PROVIDE_BYTE_SPAN=1 -Define this to 1 to provide creator functions `nonstd::byte_span`. Default is undefined. +Define this to 1 to provide creator functions `nonstd::byte_span()`. Default is undefined. ### Contract violation response macros @@ -286,9 +298,13 @@ span<>: Allows const reverse iteration span<>: Allows to observe an element via array indexing span<>: Allows to observe an element via call indexing span<>: Allows to observe an element via data() +span<>: Allows to observe the first element via front() +span<>: Allows to observe the last element via back() span<>: Allows to change an element via array indexing span<>: Allows to change an element via call indexing span<>: Allows to change an element via data() +span<>: Allows to change the first element via front() +span<>: Allows to change the last element via back() span<>: Allows to compare equal to another span of the same type span<>: Allows to compare unequal to another span of the same type span<>: Allows to compare less than another span of the same type diff --git a/include/nonstd/span.hpp b/include/nonstd/span.hpp index 1ab196c..ac7b94c 100644 --- a/include/nonstd/span.hpp +++ b/include/nonstd/span.hpp @@ -775,6 +775,20 @@ class span return data_; } +#if span_CONFIG_PROVIDE_BACK_FRONT + + span_constexpr reference front() const span_noexcept + { + return *data(); + } + + span_constexpr reference back() const span_noexcept + { + return *( data() + size() - 1 ); + } + +#endif // span_CONFIG_PROVIDE_BACK_FRONT + // 26.7.3.6 Iterator support [span.iterators] span_constexpr iterator begin() const span_noexcept diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9b646f5..7c3d72e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,7 +21,8 @@ set( OPTIONS "" ) set( SPAN_CONFIG -Dspan_CONFIG_CONTRACT_VIOLATION_THROWS -Dspan_CONFIG_PROVIDE_MAKE_SPAN=1 - -Dspan_CONFIG_PROVIDE_BYTE_SPAN=1 ) + -Dspan_CONFIG_PROVIDE_BYTE_SPAN=1 + -Dspan_CONFIG_PROVIDE_BACK_FRONT=1 ) set( HAS_STD_FLAGS FALSE ) set( HAS_CPP98_FLAG FALSE ) diff --git a/test/span.t.cpp b/test/span.t.cpp index e55dadf..c4842e4 100644 --- a/test/span.t.cpp +++ b/test/span.t.cpp @@ -583,6 +583,30 @@ CASE( "span<>: Allows to observe an element via data()" ) } } +CASE( "span<>: Allows to observe the first element via front()" ) +{ +# if span_CONFIG_PROVIDE_BACK_FRONT + int arr[] = { 1, 2, 3, }; + span v( arr ); + + EXPECT( v.front() == 1 ); +#else + EXPECT( !!"front() is not available (span_CONFIG_PROVIDE_BACK_FRONT)" ); +#endif +} + +CASE( "span<>: Allows to observe the last element via back()" ) +{ +# if span_CONFIG_PROVIDE_BACK_FRONT + int arr[] = { 1, 2, 3, }; + span v( arr ); + + EXPECT( v.back() == 3 ); +#else + EXPECT( !!"back()is not available (span_CONFIG_PROVIDE_BACK_FRONT)" ); +#endif +} + CASE( "span<>: Allows to change an element via array indexing" ) { int arr[] = { 1, 2, 3, }; @@ -623,6 +647,34 @@ CASE( "span<>: Allows to change an element via data()" ) EXPECT( 33 == *w.data() ); } +CASE( "span<>: Allows to change the first element via front()" ) +{ +# if span_CONFIG_PROVIDE_BACK_FRONT + int arr[] = { 1, 2, 3, }; + span v( arr ); + + v.front() = 42; + + EXPECT( v.front() == 42 ); +#else + EXPECT( !!"front() is not available (span_CONFIG_PROVIDE_BACK_FRONT)" ); +#endif +} + +CASE( "span<>: Allows to change the last element via back()" ) +{ +# if span_CONFIG_PROVIDE_BACK_FRONT + int arr[] = { 1, 2, 3, }; + span v( arr ); + + v.back() = 42; + + EXPECT( v.back() == 42 ); +#else + EXPECT( !!"back()is not available (span_CONFIG_PROVIDE_BACK_FRONT)" ); +#endif +} + CASE( "span<>: Allows to compare equal to another span of the same type" ) { int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 }; @@ -1056,7 +1108,7 @@ CASE( "byte_span(): Allows building a span of std::byte from a single object (C+ { # if span_HAVE( BYTE ) int x = std::numeric_limits::max(); - + span spn = byte_span( x ); EXPECT( spn.size() == std::ptrdiff_t( sizeof x ) ); @@ -1070,7 +1122,7 @@ CASE( "byte_span(): Allows building a span of const std::byte from a single cons { # if span_HAVE( BYTE ) const int x = std::numeric_limits::max(); - + span spn = byte_span( x ); EXPECT( spn.size() == std::ptrdiff_t( sizeof x ) ); diff --git a/test/t.bat b/test/t.bat index de544db..94bbe67 100644 --- a/test/t.bat +++ b/test/t.bat @@ -6,7 +6,8 @@ if not "%std%"=="" set std=-std:%std% set contract=-Dspan_CONFIG_CONTRACT_VIOLATION_TERMINATES=0 -Dspan_CONFIG_CONTRACT_VIOLATION_THROWS=1 set make_span=-Dspan_CONFIG_PROVIDE_MAKE_SPAN=1 set byte_span=-Dspan_CONFIG_PROVIDE_BYTE_SPAN=1 +set back_front=-Dspan_CONFIG_PROVIDE_BACK_FRONT=1 -cl -W3 -EHsc %std% %stdspn% %contract% %make_span% %byte_span% -DNOMINMAX -I../include/nonstd span-main.t.cpp span.t.cpp && span-main.t.exe +cl -W3 -EHsc %std% %stdspn% %contract% %make_span% %byte_span% %back_front% -DNOMINMAX -I../include/nonstd span-main.t.cpp span.t.cpp && span-main.t.exe endlocal diff --git a/test/tg.bat b/test/tg.bat index daf45d8..5ef4075 100644 --- a/test/tg.bat +++ b/test/tg.bat @@ -6,9 +6,10 @@ if "%std%"=="" set std=c++14 set contract=-Dspan_CONFIG_CONTRACT_VIOLATION_TERMINATES=0 -Dspan_CONFIG_CONTRACT_VIOLATION_THROWS=1 set make_span=-Dspan_CONFIG_PROVIDE_MAKE_SPAN=1 set byte_span=-Dspan_CONFIG_PROVIDE_BYTE_SPAN=1 +set back_front=-Dspan_CONFIG_PROVIDE_BACK_FRONT=1 set flags=-Wpedantic -Wno-padded -Wno-missing-noreturn set gpp=g++ -%gpp% -std=%std% -O2 -Wall -Wextra %flags% %stdspn% %contract% %make_span% %byte_span% -o span-main.t.exe -I../include/nonstd span-main.t.cpp span.t.cpp && span-main.t.exe +%gpp% -std=%std% -O2 -Wall -Wextra %flags% %stdspn% %contract% %make_span% %byte_span% %back_front% -o span-main.t.exe -I../include/nonstd span-main.t.cpp span.t.cpp && span-main.t.exe endlocal