martinmoene / span-lite

span lite - A C++20-like span for C++98, C++11 and later in a single-file header-only library
Boost Software License 1.0
494 stars 40 forks source link

Support nonstd::as_bytes using byte-lite when span_CPP17_OR_GREATER is false #28

Closed ilyalesokhin closed 5 years ago

ilyalesokhin commented 5 years ago

Currently the nonstd::as_bytes and nonstd::as_writeable_bytes are not available without CPP17. please consider supporting them with byte-lite byte implementation.

chris-durand commented 5 years ago

Using a std::byte implemented with a pre-C++17 compiler in nonstd::as_bytes will result in undefined behaviour. Although it is simply defined as

  enum class byte : unsigned char {}; 

in most standard library implementations, it needs some special treatment by the compiler.

The usefulness of std::byte depends on a special exception to type aliasing rules which is also added in C++17. It allows you to reinterpret_cast every T* to std::byte* and dereference the result without invoking undefined behaviour (just like for char and const char). This exception is actually hardcoded in the compiler implementation (e.g. the commit from gcc)

This line here in the implementation of span would be undefined behaviour with a custom byte and will produce invalid results with optimization turned on (as this unittest from gcc shows).

martinmoene commented 5 years ago

Hi @chris-durand, Thanks for your explanation.

In pre-C++17 byte-lite's byte is defined as:

 struct byte_may_alias byte { typedef unsigned char type; type v; };

which as far as I understand does conform to the type aliasing rules.

martinmoene commented 5 years ago

Note to self:

#ifdef NONSTD_BYTE_LITE_HPP
# define span_HAVE_NONSTD_BYTE  1
#else 
# define span_HAVE_NONSTD_BYTE  0
#endif

#if span_HAVE( BYTE )
...
#elif span_HAVE( NONSTD_BYTE )
... as_bytes(...)
... as_writeable_bytes(...)
#endif

#if span_FEATURE( BYTE_SPAN ) 
# if ( span_USES_STD_SPAN || span_HAVE( BYTE ) )
...
# elif span_HAVE( NONSTD_BYTE )
... byte_span( T & t ) ...
... byte_span( T const & t ) ...
# endif
#endif
martinmoene commented 5 years ago

@ilyalesokhin,Thanks for the suggestion. Implemented.