From 3b4605e59d3ea398a0767a9fa8b05164bcb320f9 Mon Sep 17 00:00:00 2001 From: Martin Moene Date: Tue, 1 May 2018 21:46:38 +0200 Subject: [PATCH] Add non-standard byte_span() creator functions (issue #3, thanks to @chris0e3) --- README.md | 17 +++++++++++++++-- include/nonstd/span.hpp | 34 ++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 3 ++- test/span.t.cpp | 32 ++++++++++++++++++++++++++++++++ test/t.bat | 3 ++- test/tc.bat | 3 ++- test/tg.bat | 3 ++- 7 files changed, 89 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5bdca1d..9a9f46d 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,11 @@ To construct a span from a container with compilers that cannot constrain such a *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). +### `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 | @@ -108,10 +113,14 @@ To construct a span from a container with compilers that cannot constrain such a |   | >= C++11 | template<class T, size_t N>
constexpr span<const T,N>
**make_span**(std::array<T,N > const & arr) noexcept | |   | >= C++11 | template<class Container>
constexpr auto
**make_span**(Container & cont) ->
 span<typename Container::value_type> noexcept | |   | >= C++11 | template<class Container>
constexpr auto
**make_span**(Container const & cont) ->
 span<const typename Container::value_type> noexcept | -|   | < C++11 | template<class Container>
span<typename Container::value_type>
**make_span**( with_container_t, Container & cont ) | -|   | < C++11 | template<class Container>
span<const typename Container::value_type>
**make_span**( with_container_t, Container const & cont ) | +|   |   | template<class Container>
span<typename Container::value_type>
**make_span**( with_container_t, Container & cont ) | +|   |   | template<class Container>
span<const typename Container::value_type>
**make_span**( with_container_t, Container const & cont ) | |   | < C++11 | template<class T, Allocator>
span<T>
**make_span**(std::vector<T, Allocator> & cont) | |   | < C++11 | template<class T, Allocator>
span<const T>
**make_span**(std::vector<T, Allocator> const & cont) | +|   |   |   | +| **Free functions**| | macro **`span_CONFIG_PROVIDE_BYTE_SPAN`** | +|   |   | template<class T>
span<T, sizeof(T)>
**byte_span**(T & t) | +|   |   | template<class T>
span<const T, sizeof(T)>
**byte_span**(T const & t) | Configuration @@ -130,6 +139,10 @@ Define this to 1 to select *span lite*'s `nonstd::span`. Default is undefined. -Dspan_CONFIG_PROVIDE_MAKE_SPAN=1 Define this to 1 to provide creator functions `nonstd::make_span`. Default is undefined. +### Provide `byte_span` functions +-Dspan_CONFIG_PROVIDE_BYTE_SPAN=1 +Define this to 1 to provide creator functions `nonstd::byte_span`. Default is undefined. + ### Contract violation response macros *span-lite* provides contract violation response control as suggested in proposal [N4415](http://wg21.link/n4415). diff --git a/include/nonstd/span.hpp b/include/nonstd/span.hpp index 13daa67..78be608 100644 --- a/include/nonstd/span.hpp +++ b/include/nonstd/span.hpp @@ -935,6 +935,8 @@ as_writeable_bytes( span spn ) span_noexcept } // namespace span_lite } // namespace nonstd +// make available in nonstd: + namespace nonstd { using span_lite::dynamic_extent; @@ -1056,10 +1058,42 @@ make_span( with_container_t, Container const & cont ) span_noexcept } // namespace span_lite } // namespace nonstd +// make available in nonstd: + namespace nonstd { using span_lite::make_span; } // namespace nonstd #endif // span_CONFIG_PROVIDE_MAKE_SPAN +#if span_CONFIG_PROVIDE_BYTE_SPAN && span_HAVE( BYTE ) + +namespace nonstd { +namespace span_lite { + +template< class T > +inline span_constexpr auto +byte_span( T & t ) span_noexcept -> span< std::byte, sizeof(t) > +{ + return span< std::byte, sizeof(t) >( reinterpret_cast< std::byte * >( &t ), sizeof(t) ); +} + +template< class T > +inline span_constexpr auto +byte_span( T const & t ) span_noexcept -> span< const std::byte, sizeof(t) > +{ + return span< const std::byte, sizeof(t) >( reinterpret_cast< std::byte const * >( &t ), sizeof(t) ); +} + +} // namespace span_lite +} // namespace nonstd + +// make available in nonstd: + +namespace nonstd { +using span_lite::byte_span; +} // namespace nonstd + +#endif // span_CONFIG_PROVIDE_BYTE_SPAN + #endif // NONSTD_SPAN_HPP_INCLUDED diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1816488..9b646f5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,7 +20,8 @@ set( HDRPATH ${HDRDIR}/${HDRNAME} ) set( OPTIONS "" ) set( SPAN_CONFIG -Dspan_CONFIG_CONTRACT_VIOLATION_THROWS - -Dspan_CONFIG_PROVIDE_MAKE_SPAN=1 ) + -Dspan_CONFIG_PROVIDE_MAKE_SPAN=1 + -Dspan_CONFIG_PROVIDE_BYTE_SPAN=1 ) set( HAS_STD_FLAGS FALSE ) set( HAS_CPP98_FLAG FALSE ) diff --git a/test/span.t.cpp b/test/span.t.cpp index aa0c446..e55dadf 100644 --- a/test/span.t.cpp +++ b/test/span.t.cpp @@ -1050,6 +1050,38 @@ CASE( "make_span(): Allows building from a const container (with_container_t, st #endif // span_CONFIG_PROVIDE_MAKE_SPAN +#if span_CONFIG_PROVIDE_BYTE_SPAN + +CASE( "byte_span(): Allows building a span of std::byte from a single object (C++17)" ) +{ +# if span_HAVE( BYTE ) + int x = std::numeric_limits::max(); + + span spn = byte_span( x ); + + EXPECT( spn.size() == std::ptrdiff_t( sizeof x ) ); + EXPECT( spn[0] == std::byte( 0xff ) ); +#else + EXPECT( !!"std::byte is not available (no C++17)" ); +#endif +} + +CASE( "byte_span(): Allows building a span of const std::byte from a single const object (C++17)" ) +{ +# if span_HAVE( BYTE ) + const int x = std::numeric_limits::max(); + + span spn = byte_span( x ); + + EXPECT( spn.size() == std::ptrdiff_t( sizeof x ) ); + EXPECT( spn[0] == std::byte( 0xff ) ); +#else + EXPECT( !!"std::byte is not available (no C++17)" ); +#endif +} + +#endif // span_CONFIG_PROVIDE_BYTE_SPAN + // Issues #include diff --git a/test/t.bat b/test/t.bat index e0bed12..de544db 100644 --- a/test/t.bat +++ b/test/t.bat @@ -5,7 +5,8 @@ if not "%std%"=="" set std=-std:%std% ::set stdspn=-Dspan_CONFIG_SELECT_STD_SPAN=1 -Dspan_CONFIG_SELECT_NONSTD_SPAN=1 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 -cl -W3 -EHsc %std% %stdspn% %contract% %make_span% -I../include/nonstd span-main.t.cpp span.t.cpp && span-main.t.exe +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 endlocal diff --git a/test/tc.bat b/test/tc.bat index 5ce7694..847ef6d 100644 --- a/test/tc.bat +++ b/test/tc.bat @@ -5,9 +5,10 @@ if "%std%"=="" set std=c++14 ::set stdspn=-Dspan_CONFIG_SELECT_STD_SPAN=1 -Dspan_CONFIG_SELECT_NONSTD_SPAN=1 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 clang=C:\Program Files\LLVM\bin\clang set flags=-Wpedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-missing-noreturn -Wno-documentation-unknown-command -Wno-documentation-deprecated-sync -Wno-documentation -Wno-weak-vtables -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-global-constructors -"%clang%" -std=%std% -O2 -Wall -Wextra %flags% %stdspn% %contract% %make_span% -fms-compatibility-version=19.00 -isystem "%VCInstallDir%include" -isystem "%WindowsSdkDir_71A%include" -I../include/nonstd -o span-main.t.exe span-main.t.cpp span.t.cpp && span-main.t.exe +"%clang%" -std=%std% -O2 -Wall -Wextra %flags% %stdspn% %contract% %make_span% %byte_span% -fms-compatibility-version=19.00 -isystem "%VCInstallDir%include" -isystem "%WindowsSdkDir_71A%include" -I../include/nonstd -o span-main.t.exe span-main.t.cpp span.t.cpp && span-main.t.exe endlocal diff --git a/test/tg.bat b/test/tg.bat index 31aec10..daf45d8 100644 --- a/test/tg.bat +++ b/test/tg.bat @@ -5,9 +5,10 @@ if "%std%"=="" set std=c++14 ::set stdspn=-Dspan_CONFIG_SELECT_STD_SPAN=1 -Dspan_CONFIG_SELECT_NONSTD_SPAN=1 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 flags=-Wpedantic -Wno-padded -Wno-missing-noreturn set gpp=g++ -%gpp% -std=%std% -O2 -Wall -Wextra %flags% %stdspn% %contract% %make_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% -o span-main.t.exe -I../include/nonstd span-main.t.cpp span.t.cpp && span-main.t.exe endlocal