text: //
  // span for C++98 and later.
  // Based on http://wg21.link/p0122r7
  // For more information see https://github.com/martinmoene/span-lite
  //
  // Copyright 2015, 2018-2020 Martin Moene
  // Copyright 2015 Microsoft Corporation. All rights reserved.
  //
  // Distributed under the Boost Software License, Version 1.0.
  // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  
  #include <ciso646>
  #include "span-main.t.hpp"
  
  #define DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) )
  
  #define span_STD_OR(     expr )  ( span_USES_STD_SPAN) || ( expr )
  #define span_NONSTD_AND( expr )  (!span_USES_STD_SPAN) && ( expr )
  
  using namespace nonstd;
  
  typedef span<int>::size_type size_type;
  typedef std::ptrdiff_t       ssize_type;
  
  CASE( "span<>: Terminates construction from a nullptr and a non-zero size (C++11)" )
  {
  #if span_NONSTD_AND( span_HAVE( NULLPTR ) )
      struct F { static void blow() { span<int> v( nullptr, 42 ); } };
  
      EXPECT_THROWS( F::blow() );
  #else
      EXPECT( !!"nullptr is not available (no C++11), or no exception, using std::span)" );
  #endif
  }
  
  CASE( "span<>: Terminates construction from two pointers in the wrong order" )
  {
  #if !span_USES_STD_SPAN
      struct F { static void blow() { int a[2]; span<int> v( &a[1], &a[0] ); } };
  
      EXPECT_THROWS( F::blow() );
  #else
      EXPECT( !!"No exception, using std::span" );
  #endif
  }
  
  CASE( "span<>: Terminates construction from a null pointer and a non-zero size" )
  {
  #if !span_USES_STD_SPAN
      struct F { static void blow() { int * p = span_nullptr; span<int> v( p, 42 ); } };
  
      EXPECT_THROWS( F::blow() );
  #else
      EXPECT( !!"No exception, using std::span" );
  #endif
  }
  
  CASE( "span<>: Terminates creation of a sub span of the first n elements for n exceeding the span" )
  {
  #if !span_USES_STD_SPAN
      struct F {
      static void blow()
      {
          int arr[] = { 1, 2, 3, };
          span<int> v( arr );
  
          (void) v.first( 4 );
      }};
  
      EXPECT_THROWS( F::blow() );
  #else
      EXPECT( !!"No exception, using std::span" );
  #endif
  }
  
  CASE( "span<>: Terminates creation of a sub span of the last n elements for n exceeding the span" )
  {
  #if !span_USES_STD_SPAN
      struct F {
      static void blow()
      {
          int arr[] = { 1, 2, 3, };
          span<int> v( arr );
  
          (void) v.last( 4 );
      }};
  
      EXPECT_THROWS( F::blow() );
  #else
      EXPECT( !!"No exception, using std::span" );
  #endif
  }
  
  CASE( "span<>: Terminates creation of a sub span outside the span" )
  {
  #if !span_USES_STD_SPAN
      struct F {
          static void blow_offset() { int arr[] = { 1, 2, 3, }; span<int> v( arr ); (void) v.subspan( 4 ); }
          static void blow_count()  { int arr[] = { 1, 2, 3, }; span<int> v( arr ); (void) v.subspan( 1, 3 ); }
      };
  
      EXPECT_THROWS( F::blow_offset() );
      EXPECT_THROWS( F::blow_count()  );
  #else
      EXPECT( !!"No exception, using std::span" );
  #endif
  }
  
  CASE( "span<>: Terminates access outside the span" )
  {
  #if !span_USES_STD_SPAN
      struct F {
          static void blow_ix(size_type i) { int arr[] = { 1, 2, 3, }; span<int> v( arr ); (void) v[i]; }
  #if span_NONSTD_AND( span_FEATURE( MEMBER_CALL_OPERATOR ) )
          static void blow_iv(size_type i) { int arr[] = { 1, 2, 3, }; span<int> v( arr ); (void) v(i); }
  #endif
  #if span_NONSTD_AND( span_FEATURE( MEMBER_AT ) )
          static void blow_at(size_type i) { int arr[] = { 1, 2, 3, }; span<int> v( arr ); (void) v.at(i); }
  #endif
      };
  
      EXPECT_NO_THROW( F::blow_ix(2) );
      EXPECT_THROWS(   F::blow_ix(3) );
  
  #if span_NONSTD_AND( span_FEATURE( MEMBER_CALL_OPERATOR ) )
      EXPECT_NO_THROW( F::blow_iv(2) );
      EXPECT_THROWS(   F::blow_iv(3) );
  #endif
  #if span_NONSTD_AND( span_FEATURE( MEMBER_AT ) )
      EXPECT_NO_THROW( F::blow_at(2) );
      EXPECT_THROWS(   F::blow_at(3) );
  #endif
  #else
      EXPECT( !!"No exception, using std::span" );
  #endif
  }
  
  CASE( "span<>: Throws  on access outside the span via at(): std::out_of_range [span_FEATURE_MEMBER_AT>0][span_CONFIG_NO_EXCEPTIONS=0]" )
  {
  #if span_NONSTD_AND( span_FEATURE( MEMBER_AT ) )
      int arr[] = { 1, 2, 3, };
      span<int>       v( arr );
      span<int> const w( arr );
  
      EXPECT_THROWS_AS( v.at(42), std::out_of_range );
      EXPECT_THROWS_AS( w.at(42), std::out_of_range );
  
      struct F {
          static void fail(lest::env & lest_env) {
              int arr[] = { 1, 2, 3, }; span<int> v( arr ); EXPECT( (v.at(42), true) );
      }};
  
      lest::test fail[] = { lest::test( "F", F::fail ) };
  
      std::ostringstream os;
  
      EXPECT( 1 == run( fail, os ) );
  #if span_FEATURE( MEMBER_AT ) > 1
      EXPECT( std::string::npos != os.str().find("42") );
      EXPECT( std::string::npos != os.str().find("3)") );
  #else
      EXPECT( std::string::npos != os.str().find("index outside span") );
  #endif
  #else
      EXPECT( !!"member at() is not available (span_FEATURE_MEMBER_AT=0, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Termination throws std::logic_error-derived exception [span_CONFIG_CONTRACT_VIOLATION_THROWS=1]" )
  {
  #if span_NONSTD_AND( span_CONFIG( CONTRACT_VIOLATION_THROWS ) )
      struct F {
          static void blow() { int arr[] = { 1, }; span<int> v( arr ); (void) v[1]; }
      };
  
      EXPECT_THROWS_AS( F::blow(), nonstd::span_lite::detail::contract_violation );
  #else
      EXPECT( !!"exception contract_violation is not available (non-throwing contract violation, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to default-construct" )
  {
      span<int> v;
      span<int, 0> w;
  
      EXPECT( v.size() == size_type( 0 ) );
      EXPECT( w.size() == size_type( 0 ) );
  }
  
  CASE( "span<>: Allows to construct from a nullptr and a zero size (C++11)" )
  {
  #if span_NONSTD_AND( span_HAVE(  NULLPTR ) )
      span<      int> v( nullptr, size_type(0) );
      span<const int> w( nullptr, size_type(0) );
  
      EXPECT( v.size() == size_type( 0 ) );
      EXPECT( w.size() == size_type( 0 ) );
  #else
      EXPECT( !!"nullptr is not available (no C++11)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from two pointers" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<      int> v( arr, arr + DIMENSION_OF( arr ) );
      span<const int> w( arr, arr + DIMENSION_OF( arr ) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
      EXPECT( std::equal( w.begin(), w.end(), arr ) );
  }
  
  CASE( "span<>: Allows to construct from two iterators" )
  {
  #if span_HAVE_ITERATOR_CTOR
      std::vector<int> v( 5, 123 );
  
      span<int> s( v.begin(), v.end() );
  
      EXPECT( std::equal( s.begin(), s.end(), v.begin() ) );
  #else
      EXPECT( !!"construction from iterator is not available (no C++11)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from two iterators - empty range" )
  {
  #if span_HAVE_ITERATOR_CTOR
  #if ! (span_COMPILER_MSVC_VER && defined(_DEBUG) )
      std::vector<int> v;
  
     span<int> s( v.begin(), v.end() );
  
     EXPECT( std::equal( s.begin(), s.end(), v.begin() ) );
  #else
      EXPECT( !!"construction from empty range not available (MSVC Debug)" );
  #endif
  #else
      EXPECT( !!"construction from iterator is not available (no C++11)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from an iterator and a size" )
  {
  #if span_HAVE_ITERATOR_CTOR
      std::vector<int> v( 5, 123 );
  
      span<int> s( v.begin(), v.size() );
  
      EXPECT( std::equal( s.begin(), s.end(), v.begin() ) );
  #else
      EXPECT( !!"construction from iterator is not available (no C++11)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from an iterator and a size - empty range" )
  {
  #if span_HAVE_ITERATOR_CTOR
  #if ! (span_COMPILER_MSVC_VER && defined(_DEBUG) )
      std::vector<int> v;
  
      span<int> s( v.begin(), v.size() );
  
      EXPECT( std::equal( s.begin(), s.end(), v.begin() ) );
  #else
      EXPECT( !!"construction from empty range not available (MSVC Debug)" );
  #endif
  #else
      EXPECT( !!"construction from iterator is not available (no C++11)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from two pointers to const" )
  {
      const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<const int> v( arr, arr + DIMENSION_OF( arr ) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "span<>: Allows to construct from a non-null pointer and a size" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<      int> v( arr, DIMENSION_OF( arr ) );
      span<const int> w( arr, DIMENSION_OF( arr ) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
      EXPECT( std::equal( w.begin(), w.end(), arr ) );
  }
  
  CASE( "span<>: Allows to construct from a non-null pointer to const and a size" )
  {
      const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<const int> v( arr, DIMENSION_OF( arr ) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "span<>: Allows to construct from a temporary pointer and a size" )
  {
      int x = 42;
  
      span<      int> v( &x, 1 );
      span<const int> w( &x, 1 );
  
      EXPECT( std::equal( v.begin(), v.end(), &x ) );
      EXPECT( std::equal( w.begin(), w.end(), &x ) );
  }
  
  CASE( "span<>: Allows to construct from a temporary pointer to const and a size" )
  {
      const int x = 42;
  
      span<const int> v( &x, 1 );
  
      EXPECT( std::equal( v.begin(), v.end(), &x ) );
  }
  
  CASE( "span<>: Allows to construct from any pointer and a zero size (C++98)" )
  {
  #if !span_HAVE_ITERATOR_CTOR
      struct F {
          static void null() {
              int * p = span_nullptr; span<int> v( p, size_type( 0 ) );
          }
          static void nonnull() {
              int i = 7; int * p = &i; span<int> v( p, size_type( 0 ) );
          }
      };
  
      EXPECT_NO_THROW( F::null() );
      EXPECT_NO_THROW( F::nonnull() );
  #else
      EXPECT( !!"Only with C++98" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from a pointer and a size via a deduction guide (C++17)" )
  {
  #if span_STD_OR( span_HAVE( DEDUCTION_GUIDES ) )
      char const * argv[] = { "prog", "arg1", "arg2" };
      int  const   argc   = DIMENSION_OF( argv );
  
      span args( argv, argc );
  
      EXPECT( args.size() == DIMENSION_OF( argv ) );
  #else
      EXPECT( !!"deduction guide is not available (no C++17)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from an iterator and a size via a deduction guide (C++17)" )
  {
  #if span_STD_OR( span_HAVE( DEDUCTION_GUIDES ) )
      std::vector<int> v( 5, 123 );
  
      span spn( v.begin(), v.size() );
  
      EXPECT( spn.size() == v.size() );
  #else
      EXPECT( !!"deduction guide is not available (no C++17)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from two iterators via a deduction guide (C++17)" )
  {
  #if span_STD_OR( span_HAVE( DEDUCTION_GUIDES ) )
      std::vector<int> v( 5, 123 );
  
     span spn( v.begin(), v.end() );
  
     EXPECT( spn.size() == v.size() );
  #else
      EXPECT( !!"deduction guide is not available (no C++17)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from a C-array" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<      int> v( arr );
      span<const int> w( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
      EXPECT( std::equal( w.begin(), w.end(), arr ) );
  }
  
  CASE( "span<>: Allows to construct from a C-array via a deduction guide (C++17)" )
  {
  #if span_STD_OR( span_HAVE( DEDUCTION_GUIDES ) ) && !span_BETWEEN( _MSC_VER, 1, 1920 )
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span v( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  #else
      EXPECT( !!"deduction guide is not available (no C++17)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from a const C-array" )
  {
      const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<const int> v( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "span<>: Allows to construct from a C-array with size via decay to pointer (potentially dangerous)" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      {
      span<      int> v( arr, DIMENSION_OF(arr) );
      span<const int> w( arr, DIMENSION_OF(arr) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
      EXPECT( std::equal( w.begin(), w.end(), arr ) );
      }
  
  #if span_CPP14_OR_GREATER
      {
      span<      int> v( arr, 3 );
      span<const int> w( arr, 3 );
  
      EXPECT( std::equal( v.begin(), v.end(), arr, arr + 3 ) );
      EXPECT( std::equal( w.begin(), w.end(), arr, arr + 3 ) );
      }
  #endif
  }
  
  CASE( "span<>: Allows to construct from a const C-array with size via decay to pointer (potentially dangerous)" )
  {
      const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      {
      span<const int> v( arr, DIMENSION_OF(arr) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
      }
  
  #if span_CPP14_OR_GREATER
      {
      span<const int> w( arr, 3 );
  
      EXPECT( std::equal( w.begin(), w.end(), arr, arr + 3 ) );
      }
  #endif
  }
  
  CASE( "span<>: Allows to construct from a std::initializer_list<> (C++11)" )
  {
  #if span_STD_OR( span_HAVE( INITIALIZER_LIST ) )
  #if span_STD_OR( span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) )
      auto il = { 1, 2, 3, 4, 5, };
  
      span<int const> v( il );
  
      EXPECT( std::equal( v.begin(), v.end(), il.begin() ) );
  #else
      EXPECT( !!"constrained construction from container is not available" );
  #endif
  #else
      EXPECT( !!"std::initializer_list<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from a std::array<> (C++11)" )
  {
  #if span_STD_OR( span_HAVE( ARRAY ) )
      std::array<int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }};
  
      span<      int> v( arr );
      span<const int> w( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) );
      EXPECT( std::equal( w.begin(), w.end(), arr.begin() ) );
  #else
      EXPECT( !!"std::array<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from a std::array via a deduction guide (C++17)" )
  {
  #if span_STD_OR( span_HAVE( DEDUCTION_GUIDES ) ) && !span_BETWEEN( _MSC_VER, 1, 1920 )
      std::array<int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }};
  
      span v( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) );
  #else
      EXPECT( !!"deduction guide is not available (no C++17)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from a std::array<> with const data (C++11, span_FEATURE_CONSTR..._ELEMENT_TYPE=1)" )
  {
  #if span_FEATURE( CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE )
  # if span_HAVE( ARRAY )
      std::array<const int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }};
  
      span<const int> v( arr );
      span<const int> const w( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) );
      EXPECT( std::equal( w.begin(), w.end(), arr.begin() ) );
  # else
      EXPECT( !!"std::array<> is not available (no C++11)" );
  # endif
  #else
      EXPECT( !!"construction is not available (span_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from an empty std::array<> (C++11)" )
  {
  #if span_STD_OR( span_HAVE( ARRAY ) )
      std::array<int,0> arr;
  
      span<      int> v( arr );
      span<const int> w( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) );
      EXPECT( std::equal( w.begin(), w.end(), arr.begin() ) );
  #else
      EXPECT( !!"std::array<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from a container (std::vector<>)" )
  {
  #if span_STD_OR( span_HAVE( INITIALIZER_LIST ) )
      std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  #else
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
      std::vector<int> vec( arr, arr + DIMENSION_OF(arr) );
  #endif
  
  #if span_STD_OR( span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) )
      span<      int> v( vec );
      span<const int> w( vec );
  
      EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) );
      EXPECT( std::equal( w.begin(), w.end(), vec.begin() ) );
  #else
      EXPECT( !!"constrained construction from container is not available" );
  #endif
  }
  
  CASE( "span<>: Allows to construct from a container via a deduction guide (std::vector<>, C++17)" )
  {
  #if span_STD_OR( span_HAVE( DEDUCTION_GUIDES ) ) && !span_BETWEEN( _MSC_VER, 1, 1920 )
      std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span v( vec );
  
      EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) );
  #else
      EXPECT( !!"deduction guide is not available (no C++17)" );
  #endif
  }
  
  CASE( "span<>: Allows to tag-construct from a container (std::vector<>)" )
  {
  #if span_NONSTD_AND( span_FEATURE_TO_STD( WITH_CONTAINER ) )
  # if span_HAVE( INITIALIZER_LIST )
      std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  # else
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
      std::vector<int> vec( arr, arr + DIMENSION_OF(arr) );
  # endif
      span<      int> v( with_container, vec );
      span<const int> w( with_container, vec );
  
      EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) );
      EXPECT( std::equal( w.begin(), w.end(), vec.begin() ) );
  #else
      EXPECT( !!"with_container is not available (span_FEATURE_WITH_CONTAINER_TO_STD, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to tag-construct from a const container (std::vector<>)" )
  {
  #if span_NONSTD_AND( span_FEATURE_TO_STD( WITH_CONTAINER ) )
  # if span_HAVE( INITIALIZER_LIST )
      const std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  # else
      const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
      const std::vector<int> vec( arr, arr + DIMENSION_OF(arr) );
  # endif
      span<      int> v( with_container, vec );
      span<const int> w( with_container, vec );
  
      EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) );
      EXPECT( std::equal( w.begin(), w.end(), vec.begin() ) );
  #else
      EXPECT( !!"with_container is not available (span_FEATURE_WITH_CONTAINER_TO_STD, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to copy-construct from another span of the same type" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
      span<      int> v( arr );
      span<const int> w( arr );
  
      span<      int> x( v );
      span<const int> y( w );
  
      EXPECT( std::equal( x.begin(), x.end(), arr ) );
      EXPECT( std::equal( y.begin(), y.end(), arr ) );
  }
  
  CASE( "span<>: Allows to copy-construct from another span of a compatible type" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
      span<      int> v( arr );
      span<const int> w( arr );
  
      span<const volatile int> x( v );
      span<const volatile int> y( v );
  #ifndef _LIBCPP_VERSION
      EXPECT( std::equal( x.begin(), x.end(), arr ) );
      EXPECT( std::equal( y.begin(), y.end(), arr ) );
  #else
      for(size_t i = 0; i < x.size(); ++i)
          EXPECT(x[i] == arr[i]);
      for(size_t i = 0; i < y.size(); ++i)
          EXPECT(y[i] == arr[i]);
  #endif
  }
  
  CASE( "span<>: Allows to copy-construct from a temporary span of the same type (C++11)" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<      int> v(( span<      int>( arr ) ));
  //  span<      int> w(( span<const int>( arr ) ));
      span<const int> x(( span<      int>( arr ) ));
      span<const int> y(( span<const int>( arr ) ));
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
      EXPECT( std::equal( x.begin(), x.end(), arr ) );
      EXPECT( std::equal( y.begin(), y.end(), arr ) );
  }
  
  CASE( "span<>: Allows to copy-assign from another span of the same type" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
      span<      int> v( arr );
      span<      int> s;
      span<const int> t;
  
      s = v;
      t = v;
  
      EXPECT( std::equal( s.begin(), s.end(), arr ) );
      EXPECT( std::equal( t.begin(), t.end(), arr ) );
  }
  
  CASE( "span<>: Allows to copy-assign from a temporary span of the same type (C++11)" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
      span<      int> v;
      span<const int> w;
  
      v = span<int>( arr );
      w = span<int>( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
      EXPECT( std::equal( w.begin(), w.end(), arr ) );
  }
  
  CASE( "span<>: Allows to create a sub span of the first n elements" )
  {
      int arr[] = { 1, 2, 3, 4, 5, };
      span<int> v( arr );
      size_type count = 3;
  
      span<      int> s = v.first( count );
      span<const int> t = v.first( count );
  
      EXPECT( s.size() == count );
      EXPECT( t.size() == count );
      EXPECT( std::equal( s.begin(), s.end(), arr ) );
      EXPECT( std::equal( t.begin(), t.end(), arr ) );
  }
  
  CASE( "span<>: Allows to create a sub span of the last n elements" )
  {
      int arr[] = { 1, 2, 3, 4, 5, };
      span<int> v( arr );
      size_type count = 3;
  
      span<      int> s = v.last( count );
      span<const int> t = v.last( count );
  
      EXPECT( s.size() == count );
      EXPECT( t.size() == count );
      EXPECT( std::equal( s.begin(), s.end(), arr + v.size() - count ) );
      EXPECT( std::equal( t.begin(), t.end(), arr + v.size() - count ) );
  }
  
  CASE( "span<>: Allows to create a sub span starting at a given offset" )
  {
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
      size_type offset = 1;
  
      span<      int> s = v.subspan( offset );
      span<const int> t = v.subspan( offset );
  
      EXPECT( s.size() == v.size() - offset );
      EXPECT( t.size() == v.size() - offset );
      EXPECT( std::equal( s.begin(), s.end(), arr + offset ) );
      EXPECT( std::equal( t.begin(), t.end(), arr + offset ) );
  }
  
  CASE( "span<>: Allows to create a sub span starting at a given offset with a given length" )
  {
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
      size_type offset = 1;
      size_type length = 1;
  
      span<      int> s = v.subspan( offset, length );
      span<const int> t = v.subspan( offset, length );
  
      EXPECT( s.size() == length );
      EXPECT( t.size() == length );
      EXPECT( std::equal( s.begin(), s.end(), arr + offset ) );
      EXPECT( std::equal( t.begin(), t.end(), arr + offset ) );
  }
  
  //CASE( "span<>: Allows to create an empty sub span at full offset" )
  //{
  //    int arr[] = { 1, 2, 3, };
  //    span<int> v( arr );
  //    size_type offset = v.size() - 1;
  //
  //    span<      int> s = v.subspan( offset );
  //    span<const int> t = v.subspan( offset );
  //
  //    EXPECT( s.empty() );
  //    EXPECT( t.empty() );
  //}
  
  //CASE( "span<>: Allows to create an empty sub span at full offset with zero length" )
  //{
  //    int arr[] = { 1, 2, 3, };
  //    span<int> v( arr );
  //    size_type offset = v.size();
  //    size_type length = 0;
  //
  //    span<      int> s = v.subspan( offset, length );
  //    span<const int> t = v.subspan( offset, length );
  //
  //    EXPECT( s.empty() );
  //    EXPECT( t.empty() );
  //}
  
  CASE( "span<>: Allows to observe an element via array indexing" )
  {
      int arr[] = { 1, 2, 3, };
      span<int>       v( arr );
      span<int> const w( arr );
  
      for ( size_type i = 0; i < v.size(); ++i )
      {
          EXPECT( v[i] == arr[i] );
          EXPECT( w[i] == arr[i] );
      }
  }
  
  CASE( "span<>: Allows to observe an element via call indexing" )
  {
  #if span_NONSTD_AND( span_FEATURE( MEMBER_CALL_OPERATOR ) )
      int arr[] = { 1, 2, 3, };
      span<int>       v( arr );
      span<int> const w( arr );
  
      for ( size_type i = 0; i < v.size(); ++i )
      {
          EXPECT( v(i) == arr[i] );
          EXPECT( w(i) == arr[i] );
      }
  #else
      EXPECT( !!"member () is not available (span_FEATURE_MEMBER_CALL_OPERATOR=0, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to observe an element via at() [span_FEATURE_MEMBER_AT>0]" )
  {
  #if span_NONSTD_AND( span_FEATURE( MEMBER_AT ) )
      int arr[] = { 1, 2, 3, };
      span<int>       v( arr );
      span<int> const w( arr );
  
      for ( size_type i = 0; i < v.size(); ++i )
      {
          EXPECT( v.at(i) == arr[i] );
          EXPECT( w.at(i) == arr[i] );
      }
  #else
      EXPECT( !!"member at() is not available (span_FEATURE_MEMBER_AT=0, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to observe an element via data()" )
  {
      int arr[] = { 1, 2, 3, };
      span<int>       v( arr );
      span<int> const w( arr );
  
      EXPECT( *v.data() == *v.begin() );
      EXPECT( *w.data() == *v.begin() );
  
      for ( size_type i = 0; i < v.size(); ++i )
      {
          EXPECT( v.data()[i] == arr[i] );
          EXPECT( w.data()[i] == arr[i] );
      }
  }
  
  CASE( "span<>: Allows to observe the first element via front() [span_FEATURE_MEMBER_BACK_FRONT=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( MEMBER_BACK_FRONT ) )
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
  
      EXPECT( v.front() == 1 );
  #else
      EXPECT( !!"front() is not available (span_FEATURE_MEMBER_BACK_FRONT undefined or 0)" );
  #endif
  }
  
  CASE( "span<>: Allows to observe the last element via back() [span_FEATURE_MEMBER_BACK_FRONT=1]" )
  {
  #if span_FEATURE( MEMBER_BACK_FRONT )
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
  
      EXPECT( v.back() == 3 );
  #else
      EXPECT( !!"back()is not available (span_FEATURE_MEMBER_BACK_FRONT undefined or 0)" );
  #endif
  }
  
  CASE( "span<>: Allows to change an element via array indexing" )
  {
      int arr[] = { 1, 2, 3, };
      span<int>       v( arr );
      span<int> const w( arr );
  
      v[1] = 22;
      w[2] = 33;
  
      EXPECT( 22 == arr[1] );
      EXPECT( 33 == arr[2] );
  }
  
  CASE( "span<>: Allows to change an element via call indexing" )
  {
  #if span_NONSTD_AND( span_FEATURE( MEMBER_CALL_OPERATOR ) )
      int arr[] = { 1, 2, 3, };
      span<int>       v( arr );
      span<int> const w( arr );
  
      v(1) = 22;
      w(2) = 33;
  
      EXPECT( 22 == arr[1] );
      EXPECT( 33 == arr[2] );
  #else
      EXPECT( !!"member () is not available (span_FEATURE_MEMBER_CALL_OPERATOR=0, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to change an element via at() [span_FEATURE_MEMBER_AT>0]" )
  {
  #if span_NONSTD_AND( span_FEATURE( MEMBER_AT ) )
      int arr[] = { 1, 2, 3, };
      span<int>       v( arr );
      span<int> const w( arr );
  
      v.at(1) = 22;
      w.at(2) = 33;
  
      EXPECT( 22 == arr[1] );
      EXPECT( 33 == arr[2] );
  #else
      EXPECT( !!"member at() is not available (span_FEATURE_MEMBER_AT=0, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to change an element via data()" )
  {
      int arr[] = { 1, 2, 3, };
  
      span<int> v( arr );
      span<int> const w( arr );
  
      *v.data() = 22;
      EXPECT( 22 == *v.data() );
  
      *w.data() = 33;
      EXPECT( 33 == *w.data() );
  }
  
  CASE( "span<>: Allows to change the first element via front() [span_FEATURE_MEMBER_BACK_FRONT=1]" )
  {
  #if span_FEATURE( MEMBER_BACK_FRONT )
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
  
      v.front() = 42;
  
      EXPECT( v.front() == 42 );
  #else
      EXPECT( !!"front() is not available (span_FEATURE_MEMBER_BACK_FRONT undefined or 0)" );
  #endif
  }
  
  CASE( "span<>: Allows to change the last element via back() [span_FEATURE_MEMBER_BACK_FRONT=1]" )
  {
  #if span_FEATURE( MEMBER_BACK_FRONT )
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
  
      v.back() = 42;
  
      EXPECT( v.back() == 42 );
  #else
      EXPECT( !!"back()is not available (span_FEATURE_MEMBER_BACK_FRONT undefined or 0)" );
  #endif
  }
  
  CASE( "span<>: Allows to swap with another span [span_FEATURE_MEMBER_SWAP=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( MEMBER_SWAP ) )
      int arr[] = { 1, 2, 3, };
      span<int> a( arr );
      span<int> b = a.subspan( 1 );
  
      a.swap( b );
  
      EXPECT( a.size() == size_type(2) );
      EXPECT( b.size() == size_type(3) );
      EXPECT( a[0]     == 2 );
      EXPECT( b[0]     == 1 );
  #else
      EXPECT( !!"swap()is not available (span_FEATURE_MEMBER_SWAP undefined or 0, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows forward iteration" )
  {
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
  
      for ( span<int>::iterator pos = v.begin(); pos != v.end(); ++pos )
      {
          EXPECT( *pos == arr[ std::distance( v.begin(), pos )] );
      }
  }
  
  CASE( "span<>: Allows const forward iteration" )
  {
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
  
  #if span_USES_STD_SPAN
      for ( auto pos = std::cbegin(v); pos != std::cend(v); ++pos )
      {
          EXPECT( *pos == arr[ std::distance( std::cbegin(v), pos )] );
      }
  #else
      for ( span<int>::const_iterator pos = v.cbegin(); pos != v.cend(); ++pos )
      {
          EXPECT( *pos == arr[ std::distance( v.cbegin(), pos )] );
      }
  #endif
  }
  
  CASE( "span<>: Allows reverse iteration" )
  {
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
  
      for ( span<int>::reverse_iterator pos = v.rbegin(); pos != v.rend(); ++pos )
      {
  //        size_t dist = narrow<size_t>( std::distance(v.rbegin(), pos) );
          size_type dist = static_cast<size_type>( std::distance(v.rbegin(), pos) );
          EXPECT( *pos == arr[ v.size() - 1 - dist ] );
      }
  }
  
  CASE( "span<>: Allows const reverse iteration" )
  {
      int arr[] = { 1, 2, 3, };
      const span<int> v( arr );
  
  #if span_USES_STD_SPAN
      for ( auto pos = std::crbegin(v); pos != std::crend(v); ++pos )
      {
  //        size_t dist = narrow<size_t>( std::distance(v.crbegin(), pos) );
          size_type dist = static_cast<size_type>( std::distance(std::crbegin(v), pos) );
          EXPECT( *pos == arr[ v.size() - 1 - dist ] );
      }
  #else
      for ( span<int>::const_reverse_iterator pos = v.crbegin(); pos != v.crend(); ++pos )
      {
  //        size_t dist = narrow<size_t>( std::distance(v.crbegin(), pos) );
          size_type dist = static_cast<size_type>( std::distance(v.crbegin(), pos) );
          EXPECT( *pos == arr[ v.size() - 1 - dist ] );
      }
  #endif
  }
  
  CASE( "span<>: Allows to identify if a span is the same as another span [span_FEATURE_SAME=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ) )
  #if span_FEATURE( SAME )
      int  a[] = { 1 }, b[] = { 1 }, c[] = { 1, 2 };
      char x[] = { '\x1' };
  
      span<int > va( a );
      span<int > vb( b );
      span<int > vc( c );
      span<char> vx( x );
      span<unsigned char> vu( reinterpret_cast<unsigned char*>( &x[0] ), 1 );
  
      EXPECT(     same( va, va ) );
      EXPECT_NOT( same( vb, va ) );
      EXPECT_NOT( same( vc, va ) );
      EXPECT_NOT( same( vx, va ) );
      EXPECT_NOT( same( vx, vu ) );
  
      EXPECT(         va == va );
      EXPECT(         vb == va );
      EXPECT_NOT(     vc == va );
      EXPECT(         vx == va );
      EXPECT(         vx == vu );
  #else
      EXPECT( !!"same() is not available (span_FEATURE_SAME=0)" );
  #endif
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0, or using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to compare equal to another span of the same type [span_FEATURE_COMPARISON=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ) )
      int a[] = { 1 }, b[] = { 1 }, c[] = { 2 }, d[] = { 1, 2 };
      span<int> va( a );
      span<int> vb( b );
      span<int> vc( c );
      span<int> vd( d );
  
      EXPECT(     va == va );
      EXPECT(     vb == va );
      EXPECT_NOT( vc == va );
      EXPECT_NOT( vd == va );
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to compare unequal to another span of the same type [span_FEATURE_COMPARISON=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ))
      int a[] = { 1 }, b[] = { 1 }, c[] = { 2 }, d[] = { 1, 2 };
      span<int> va( a );
      span<int> vb( b );
      span<int> vc( c );
      span<int> vd( d );
  
      EXPECT_NOT( va != va );
      EXPECT_NOT( vb != va );
      EXPECT(     vc != va );
      EXPECT(     vd != va );
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to compare less than another span of the same type [span_FEATURE_COMPARISON=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ))
      int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 };
      span<int> va( a );
      span<int> vb( b );
      span<int> vc( c );
  
      EXPECT_NOT( va < va );
      EXPECT(     va < vb );
      EXPECT(     va < vc );
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to compare less than or equal to another span of the same type [span_FEATURE_COMPARISON=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ))
      int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 };
      span<int> va( a );
      span<int> vb( b );
      span<int> vc( c );
  
      EXPECT_NOT( vb <= va );
      EXPECT(     va <= vb );
      EXPECT(     va <= vc );
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to compare greater than another span of the same type [span_FEATURE_COMPARISON=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ))
      int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 };
      span<int> va( a );
      span<int> vb( b );
      span<int> vc( c );
  
      EXPECT_NOT( va > va );
      EXPECT(     vb > va );
      EXPECT(     vc > va );
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to compare greater than or equal to another span of the same type [span_FEATURE_COMPARISON=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ))
      int a[] = { 1 }, b[] = { 2 }, c[] = { 1, 2 };
      span<int> va( a );
      span<int> vb( b );
      span<int> vc( c );
  
      EXPECT_NOT( va >= vb );
      EXPECT(     vb >= va );
      EXPECT(     vc >= va );
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to compare to another span of the same type and different cv-ness [span_FEATURE_SAME=0]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ))
  #if span_FEATURE( SAME )
      EXPECT( !!"skipped as same() is provided via span_FEATURE_SAME=1" );
  #else
      int aa[] = { 1 }, bb[] = { 2 };
      span<         int>  a( aa );
      span<   const int> ca( aa );
      span<volatile int> va( aa );
      span<         int>  b( bb );
      span<   const int> cb( bb );
  
      EXPECT( va == ca );
      EXPECT(  a == va );
  
      EXPECT(  a == ca );
      EXPECT(  a != cb );
      EXPECT(  a <= cb );
      EXPECT(  a <  cb );
      EXPECT(  b >= ca );
      EXPECT(  b >  ca );
  #endif
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to compare empty spans as equal [span_FEATURE_COMPARISON=1]" )
  {
  #if span_NONSTD_AND( span_FEATURE( COMPARISON ))
      int a;
  
      span<int> p;
      span<int> q;
      span<int> r( &a, size_type( 0 ) );
  
      EXPECT( p == q );
      EXPECT( p == r );
  
  #if span_STD_OR( span_HAVE( NULLPTR ) )
      span<int> s( nullptr, size_type( 0 ) );
      span<int> t( nullptr, size_type( 0 ) );
  
      EXPECT( s == p );
      EXPECT( s == r );
      EXPECT( s == t );
  #endif
  #else
      EXPECT( !!"comparison is not available (span_FEATURE_COMPARISON=0)" );
  #endif
  }
  
  CASE( "span<>: Allows to test for empty span via empty(), empty case" )
  {
      span<int> v;
  
      EXPECT( v.empty() );
  }
  
  CASE( "span<>: Allows to test for empty span via empty(), non-empty case" )
  {
      int a[] = { 1 };
      span<int> v( a );
  
      EXPECT_NOT( v.empty() );
  }
  
  CASE( "span<>: Allows to obtain the number of elements via size()" )
  {
      int a[] = { 1, 2, 3, };
      int b[] = { 1, 2, 3, 4, 5, };
  
      span<int> z;
      span<int> va( a );
      span<int> vb( b );
  
      EXPECT( va.size() == size_type( DIMENSION_OF( a ) ) );
      EXPECT( vb.size() == size_type( DIMENSION_OF( b ) ) );
      EXPECT(  z.size() == size_type( 0 ) );
  }
  
  CASE( "span<>: Allows to obtain the number of elements via ssize()" )
  {
  #if !span_USES_STD_SPAN
      int a[] = { 1, 2, 3, };
      int b[] = { 1, 2, 3, 4, 5, };
  
      span<int> z;
      span<int> va( a );
      span<int> vb( b );
  
      EXPECT( va.ssize() == ssize_type( DIMENSION_OF( a ) ) );
      EXPECT( vb.ssize() == ssize_type( DIMENSION_OF( b ) ) );
      EXPECT(  z.ssize() == 0 );
  #else
      EXPECT( !!"member ssize() is not available (using std::span)" );
  #endif
  }
  
  CASE( "span<>: Allows to obtain the number of bytes via size_bytes()" )
  {
      int a[] = { 1, 2, 3, };
      int b[] = { 1, 2, 3, 4, 5, };
  
      span<int> z;
      span<int> va( a );
      span<int> vb( b );
  
      EXPECT( va.size_bytes() == size_type( DIMENSION_OF( a ) * sizeof(int) ) );
      EXPECT( vb.size_bytes() == size_type( DIMENSION_OF( b ) * sizeof(int) ) );
      EXPECT(  z.size_bytes() == size_type( 0 * sizeof(int) ) );
  }
  
  //CASE( "span<>: Allows to swap with another span of the same type" )
  //{
  //    int a[] = { 1, 2, 3, };
  //    int b[] = { 1, 2, 3, 4, 5, };
  //
  //    span<int> va0( a );
  //    span<int> vb0( b );
  //    span<int> va( a );
  //    span<int> vb( b );
  //
  //    va.swap( vb );
  //
  //    EXPECT( va == vb0 );
  //    EXPECT( vb == va0 );
  //}
  
  #if span_STD_OR( span_HAVE( BYTE ) ) || span_HAVE( NONSTD_BYTE )
  
  static bool is_little_endian()
  {
      union U
      {
          U() : i(1) {}
          int i;
          char c[ sizeof(int) ];
      };
      return 1 != U().c[ sizeof(int) - 1 ];
  }
  #endif
  
  CASE( "span<>: Allows to view the elements as read-only bytes" )
  {
  #if span_CPP11_OR_GREATER && ( span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE ) )
      using byte = xstd::byte;
      using type = std::int32_t;
  
      EXPECT( sizeof( type ) == size_t( 4 ) );
  
      type  a[] = { 0x12345678, };
      byte be[] = { byte{0x12}, byte{0x34}, byte{0x56}, byte{0x78}, };
      byte le[] = { byte{0x78}, byte{0x56}, byte{0x34}, byte{0x12}, };
  
      xstd::byte * b = is_little_endian() ? le : be;
  
      span<type> va( a );
      span<const xstd::byte> vb( as_bytes( va ) );
  
      EXPECT( vb[0] == b[0] );
      EXPECT( vb[1] == b[1] );
      EXPECT( vb[2] == b[2] );
      EXPECT( vb[3] == b[3] );
  #else
      EXPECT( !!"(non)std::byte is not available (no C++17, no byte-lite); test requires C++11" );
  #endif
  }
  
  CASE( "span<>: Allows to view and change the elements as writable bytes" )
  {
  #if span_CPP11_OR_GREATER && ( span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE ) )
      using byte = xstd::byte;
      using type = std::int32_t;
  
      EXPECT( sizeof(type) == size_t( 4 ) );
  
      type  a[] = { 0x0, };
      span<type> va( a );
      span<byte> vb( as_writable_bytes(va) );
  
      for ( size_type i = 0; i < size_type( sizeof(type) ); ++i )
      {
          EXPECT( vb[i] == byte{0} );
      }
  
      vb[0] = byte{0x42};
  
      EXPECT( vb[0] == byte{0x42} );
      for ( size_type i = 1; i < size_type( sizeof(type) ); ++i )
      {
          EXPECT( vb[i] == byte{0} );
      }
  #else
      EXPECT( !!"(non)std::byte is not available (no C++17, no byte-lite); test requires C++11" );
  #endif
  }
  
  //CASE( "span<>: Allows to view the elements as a span of another type" )
  //{
  //#if span_STD_OR( span_HAVE( SIZED_TYPES ) )
  //    typedef int32_t type1;
  //    typedef int16_t type2;
  //#else
  //    typedef int   type1;
  //    typedef short type2;
  //#endif
  //    EXPECT( sizeof( type1 ) == size_t( 4 ) );
  //    EXPECT( sizeof( type2 ) == size_t( 2 ) );
  //
  //    type1  a[] = { 0x12345678, };
  //    type2 be[] = { type2(0x1234), type2(0x5678), };
  //    type2 le[] = { type2(0x5678), type2(0x1234), };
  //
  //    type2 * b = is_little_endian() ? le : be;
  //
  //    span<type1> va( a );
  //    span<type2> vb( va );
  //
  //    EXPECT( vb[0] == b[0] );
  //    EXPECT( vb[1] == b[1] );
  //}
  
  //CASE( "span<>: Allows to change the elements from a span of another type" )
  //{
  //#if span_STD_OR( span_HAVE( SIZED_TYPES ) )
  //    typedef int32_t type1;
  //    typedef int16_t type2;
  //#else
  //    typedef int   type1;
  //    typedef short type2;
  //#endif
  //    EXPECT( sizeof( type1 ) == size_t( 4 ) );
  //    EXPECT( sizeof( type2 ) == size_t( 2 ) );
  //
  //    type1  a[] = { 0x0, };
  //
  //    span<type1> va( a );
  //#if span_COMPILER_MSVC_VERSION == 60
  //    span<type2> vb( va.as_span( type2() ) );
  //#else
  //    span<type2> vb( va.as_span<type2>() );
  //#endif
  //
  //    {for ( size_t i = 0; i < sizeof(type2); ++i ) EXPECT( vb[i] == type2(0) ); }
  //
  //    vb[0] = 0x42;
  //
  //    EXPECT( vb[0] == type2(0x42) );
  //    {for ( size_t i = 1; i < sizeof(type2); ++i ) EXPECT( vb[i] == type2(0) ); }
  //}
  
  #if span_FEATURE_TO_STD( MAKE_SPAN )
  
  CASE( "make_span() [span_FEATURE_MAKE_SPAN_TO_STD=99]" )
  {
      EXPECT( !!"(avoid warning)" );  // suppress: unused parameter 'lest_env' [-Wunused-parameter]
  }
  
  CASE( "make_span(): Allows building from two pointers" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<int> v = make_span( arr, arr + DIMENSION_OF( arr ) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "make_span(): Allows building from two const pointers" )
  {
      const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<const int> v = make_span( arr, arr + DIMENSION_OF( arr ) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "make_span(): Allows building from a non-null pointer and a size" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<int> v = make_span( arr, DIMENSION_OF( arr ) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "make_span(): Allows building from a non-null const pointer and a size" )
  {
      const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<const int> v = make_span( arr, DIMENSION_OF( arr ) );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "make_span(): Allows building from a C-array" )
  {
      int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<int> v = make_span( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "make_span(): Allows building from a const C-array" )
  {
      const int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<const int> v = make_span( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr ) );
  }
  
  CASE( "make_span(): Allows building from a std::initializer_list<> (C++11)" )
  {
  #if span_STD_OR( span_HAVE( INITIALIZER_LIST ) )
  #if span_STD_OR( span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) )
      auto il = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span<int const> v = make_span( il );
  
      EXPECT( std::equal( v.begin(), v.end(), il.begin() ) );
  #else
      EXPECT( !!"constrained construction from container is not available" );
  #endif
  #else
      EXPECT( !!"std::initializer_list<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "make_span(): Allows building from a std::array<> (C++11)" )
  {
  #if span_STD_OR( span_HAVE( ARRAY ) )
      std::array<int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }};
  
      span<int> v = make_span( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) );
  #else
      EXPECT( !!"std::array<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "make_span(): Allows building from a const std::array<> (C++11)" )
  {
  #if span_STD_OR( span_HAVE( ARRAY ) )
      const std::array<int,9> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }};
  
      span<const int> v = make_span( arr );
  
      EXPECT( std::equal( v.begin(), v.end(), arr.begin() ) );
  #else
      EXPECT( !!"std::array<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "make_span(): Allows building from a container (std::vector<>)" )
  {
  #if span_STD_OR( span_HAVE( INITIALIZER_LIST ) )
      std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  #else
      std::vector<int> vec; {for ( int i = 1; i < 10; ++i ) vec.push_back(i); }
  #endif
      span<int> v = make_span( vec );
  
      EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) );
  }
  
  CASE( "make_span(): Allows building from a const container (std::vector<>)" )
  {
  #if span_STD_OR( span_HAVE( INITIALIZER_LIST ) )
      const std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  #else
      const std::vector<int> vec( 10, 42 );
  #endif
      span<const int> v = make_span( vec );
  
      EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) );
  }
  
  CASE( "make_span(): Allows building from a container (with_container_t, std::vector<>)" )
  {
  #if span_NONSTD_AND( span_FEATURE_TO_STD( WITH_CONTAINER ) )
  #if span_STD_OR( span_HAVE( INITIALIZER_LIST ) )
      std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  #else
      std::vector<int> vec; {for ( int i = 1; i < 10; ++i ) vec.push_back(i); }
  #endif
      span<int> v = make_span( with_container, vec );
  
      EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) );
  #else
      EXPECT( !!"make_span(with_container,...) is not available (span_PROVIDE_WITH_CONTAINER_TO_STD=0, or using std::span)" );
  #endif
  }
  
  CASE( "make_span(): Allows building from a const container (with_container_t, std::vector<>)" )
  {
  #if span_NONSTD_AND( span_FEATURE_TO_STD( WITH_CONTAINER ) )
  #if span_STD_OR( span_HAVE( INITIALIZER_LIST ) )
      const std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  #else
      const std::vector<int> vec( 10, 42 );
  #endif
      span<const int> v = make_span( with_container, vec );
  
      EXPECT( std::equal( v.begin(), v.end(), vec.begin() ) );
  #else
      EXPECT( !!"make_span(with_container,...) is not available (span_PROVIDE_WITH_CONTAINER_TO_STD=0, or using std::span)" );
  #endif
  }
  
  #endif // span_FEATURE_MAKE_SPAN
  
  #if span_FEATURE( BYTE_SPAN )
  
  CASE( "byte_span() [span_FEATURE_BYTE_SPAN=1]" )
  {
      EXPECT( !!"(avoid warning)" );  // suppress: unused parameter 'lest_env' [-Wunused-parameter]
  }
  
  CASE( "byte_span(): Allows building a span of std::byte from a single object (C++17, byte-lite)" )
  {
  #if span_CPP11_OR_GREATER && ( span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE ) )
      int x = (std::numeric_limits<int>::max)();
  
      span<xstd::byte> spn = byte_span( x );
  
      EXPECT( spn.size() == size_type( sizeof x ) );
  #if span_STD_OR( span_HAVE( NONSTD_BYTE ) )
      EXPECT( spn[0]     == to_byte( 0xff ) );
  #else
      EXPECT( spn[0]     == xstd::byte( 0xff ) );
  #endif
  #else
      EXPECT( !!"(non)std::byte is not available (no C++17, no byte-lite); test requires C++11" );
  #endif
  }
  
  CASE( "byte_span(): Allows building a span of const std::byte from a single const object (C++17, byte-lite)" )
  {
  #if span_CPP11_OR_GREATER && ( span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE ) )
      const int x = (std::numeric_limits<int>::max)();
  
      span<const xstd::byte> spn = byte_span( x );
  
      EXPECT( spn.size() == size_type( sizeof x ) );
  #if span_STD_OR( span_HAVE( NONSTD_BYTE ) )
      EXPECT( spn[0]     == to_byte( 0xff ) );
  #else
      EXPECT( spn[0]     == xstd::byte( 0xff ) );
  #endif
  #else
      EXPECT( !!"(non)std::byte is not available (no C++17, no byte-lite); test requires C++11" );
  #endif
  }
  
  #endif // span_FEATURE( BYTE_SPAN )
  
  CASE( "first(), last(), subspan() [span_FEATURE_NON_MEMBER_FIRST_LAST_SUB=1]" )
  {
      EXPECT( !!"(avoid warning)" );  // suppress: unused parameter 'lest_env' [-Wunused-parameter]
  }
  
  CASE( "first(): Allows to create a sub span of the first n elements" )
  {
  #if span_NONSTD_AND( span_FEATURE( NON_MEMBER_FIRST_LAST_SUB ) )
  #if span_CPP11_120
      int arr[] = { 1, 2, 3, 4, 5, };
      span<int> v( arr );
      size_type count = 3;
  
      span<      int> s = first( v, count );
      span<const int> t = first( v, count );
  
      EXPECT( s.size() == count );
      EXPECT( t.size() == count );
      EXPECT( std::equal( s.begin(), s.end(), arr ) );
      EXPECT( std::equal( t.begin(), t.end(), arr ) );
  #else
      EXPECT( !!"first() is not available (no C++11)" );
  #endif
  #else
      EXPECT( !!"first() is not available (NON_MEMBER_FIRST_LAST_SUB=0, or using std::span)" );
  #endif
  }
  
  CASE( "last(): Allows to create a sub span of the last n elements" )
  {
  #if span_NONSTD_AND( span_FEATURE( NON_MEMBER_FIRST_LAST_SUB ) )
  #if span_CPP11_120
      int arr[] = { 1, 2, 3, 4, 5, };
      span<int> v( arr );
      size_type count = 3;
  
      span<      int> s = last( v, count );
      span<const int> t = last( v, count );
  
      EXPECT( s.size() == count );
      EXPECT( t.size() == count );
      EXPECT( std::equal( s.begin(), s.end(), arr + v.size() - count ) );
      EXPECT( std::equal( t.begin(), t.end(), arr + v.size() - count ) );
  #else
      EXPECT( !!"last() is not available (no C++11)" );
  #endif
  #else
      EXPECT( !!"last() is not available (NON_MEMBER_FIRST_LAST_SUB=0, or using std::span)" );
  #endif
  }
  
  CASE( "subspan(): Allows to create a sub span starting at a given offset" )
  {
  #if span_NONSTD_AND( span_FEATURE( NON_MEMBER_FIRST_LAST_SUB ) )
  #if span_CPP11_120
      int arr[] = { 1, 2, 3, };
      span<int> v( arr );
      size_type offset = 1;
  
      span<      int> s = subspan( v, offset );
      span<const int> t = subspan( v, offset );
  
      EXPECT( s.size() == v.size() - offset );
      EXPECT( t.size() == v.size() - offset );
      EXPECT( std::equal( s.begin(), s.end(), arr + offset ) );
      EXPECT( std::equal( t.begin(), t.end(), arr + offset ) );
  #else
      EXPECT( !!"subspan() is not available (no C++11)" );
  #endif
  #else
      EXPECT( !!"subspan() is not available (NON_MEMBER_FIRST_LAST_SUB=0, or using std::span)" );
  #endif
  }
  
  CASE( "size(): Allows to obtain the number of elements via size()" )
  {
      int a[] = { 1, 2, 3, };
      int b[] = { 1, 2, 3, 4, 5, };
  
      span<int> z;
      span<int> va( a );
      span<int> vb( b );
  
      EXPECT( size( va ) == DIMENSION_OF( a ) );
      EXPECT( size( vb ) == DIMENSION_OF( b ) );
      EXPECT( size( z  ) == size_t( 0 ) );
  }
  
  CASE( "ssize(): Allows to obtain the number of elements via ssize()" )
  {
      int a[] = { 1, 2, 3, };
      int b[] = { 1, 2, 3, 4, 5, };
  
      span<int> z;
      span<int> va( a );
      span<int> vb( b );
  
      EXPECT( ssize( va ) == ssize_type( DIMENSION_OF( a ) ) );
      EXPECT( ssize( vb ) == ssize_type( DIMENSION_OF( b ) ) );
      EXPECT( ssize( z  ) == 0 );
  }
  
  CASE( "tuple_size<>: Allows to obtain the number of elements via std::tuple_size<> (C++11)" )
  {
  #if span_NONSTD_AND( span_HAVE( STRUCT_BINDING ) )
      const auto N = 3u;
      using T = span<int, N>;
  
      int a[N] = { 1, 2, 3, };
  
      T v( a );
  
      EXPECT(           ssize( v )        == N );
      EXPECT( std::tuple_size< T >::value == N );
  
      static_assert( std::tuple_size< T >::value == N, "std::tuple_size< span<> > fails" );
  #else
      EXPECT( !!"std::tuple_size<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "tuple_element<>: Allows to obtain an element via std::tuple_element<> (C++11)" )
  {
  #if span_NONSTD_AND( span_HAVE( STRUCT_BINDING ) )
      using S = span<int,3>;
      using T = std::tuple_element<0, S>::type;
  
      EXPECT( (std::is_same<T, int>::value) );
  
     static_assert( std::is_same<T, int>::value, "std::tuple_element<0, S>::type fails" );
  #else
      EXPECT( !!"std::tuple_element<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "tuple_element<>: Allows to obtain an element via std::tuple_element_t<> (C++11)" )
  {
  #if span_NONSTD_AND( span_HAVE( STRUCT_BINDING ) ) && span_CPP11_140
      using S = span<int,3>;
      using T = std::tuple_element_t<0, S>;
  
      EXPECT( (std::is_same<T, int>::value) );
  
     static_assert( std::is_same<T, int>::value, "std::tuple_element_t<0, S> fails" );
  #else
      EXPECT( !!"std::tuple_element<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "get<I>(spn): Allows to access an element via std::get<>()" )
  {
  #if span_NONSTD_AND( span_HAVE( STRUCT_BINDING ) )
      SETUP("") {
          const auto N = 3u;
  
          using T = span<int, N>;
          using U = span<const int, N>;
  
                int a[N] = { 1, 2, 3, };
          const int b[N] = { 1, 2, 3, };
  
                T vna( a );
                U vnb( b );
          const T vca( a );
          const U vcb( b );
  
      SECTION("lvalue")
      {
  
          EXPECT( std::get< 1 >( vna ) == a[1] );
          EXPECT( std::get< 1 >( vnb ) == a[1] );
          EXPECT( std::get< 1 >( vca ) == a[1] );
          EXPECT( std::get< 1 >( vcb ) == a[1] );
  
          std::get< 1 >( vna ) = 7;
  //      std::get< 1 >( vca ) = 7; // read-only
  
          EXPECT( std::get< 1 >( vna ) == 7 );
  
          // static_assert( std::get< 1 >( vc ) == 2, "std::tuple_element<I>(spn) fails" );
      }
  
      SECTION("rvalue")
      {
          EXPECT( std::get< 1 >( std::move(vna) ) == 2 );
          EXPECT( std::get< 1 >( std::move(vnb) ) == 2 );
          EXPECT( std::get< 1 >( std::move(vca) ) == 2 );
          EXPECT( std::get< 1 >( std::move(vcb) ) == 2 );
      }}
  #else
      EXPECT( !!"std::get<>(spn) is not available (no C++11)" );
  #endif
  }
  
  // Issues
  
  #include <cassert>
  
  CASE( "[hide][issue-3: heterogeneous comparison]" )
  {
  #if span_NONSTD_AND( span_FEATURE_TO_STD( MAKE_SPAN ) )
  #if span_FEATURE( COMPARISON )
      static const int data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
  
      span< const int > spn( data );
  
      EXPECT( !!"(avoid warning)" );  // suppress: unused parameter 'lest_env' [-Wunused-parameter]
  
      assert( make_span( data ) == make_span(data) ); // Ok, non-heterogeneous comparison
      assert( make_span( data ) == spn             ); // Compile error: comparing fixed with dynamic extension
  #else
      EXPECT( !!"test is unavailable as comparison of span is not provided via span_FEATURE_COMPARISON=1" );
  #endif // span_FEATURE( COMPARISON )
  #else
      EXPECT( !!"test is unavailable as make_span() is not provided via span_FEATURE_MAKE_SPAN_TO_STD=99" );
  #endif // span_FEATURE_TO_STD( MAKE_SPAN )
  }
  
  CASE( "[hide][issue-3: same()]" )
  {
  #if span_NONSTD_AND( span_FEATURE_TO_STD( MAKE_SPAN ) )
  #if span_FEATURE( SAME )
      EXPECT( !!"(avoid warning)" );  // suppress: unused parameter 'lest_env' [-Wunused-parameter]
  
      typedef unsigned char uint8_type;
  
      static uint8_type const data[]    = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
      static float      const farray[4] = { 0, 1, 2, 3 };
  
      span<float const> fspan1 = make_span( farray );
  
      assert( fspan1.data() == farray );
      assert( fspan1.size() == static_cast<size_type>( DIMENSION_OF( farray ) ) );
  
  #if span_STD_OR( span_HAVE( BYTE ) )
      span<std::byte const> fspan2 = byte_span( farray[0] );
  
      assert( static_cast<void const *>( fspan1.data() ) == fspan2.data() );
      assert(                            fspan1.size()   == fspan2.size() );
      assert(                    ! same( fspan1          ,  fspan2 )      );
  # endif
  
      span<uint8_type const> bspan4 = make_span( data, 4 );
  
      assert(        bspan4 == fspan1   );
      assert(        fspan1 == bspan4   );
      assert( !same( fspan1 ,  bspan4 ) );
  
  #if span_STD_OR( span_HAVE( BYTE ) )
      assert(        as_bytes( fspan1 ) != as_bytes( bspan4 )   );
      assert( !same( as_bytes( fspan1 ) ,  as_bytes( bspan4 ) ) );
  #endif
  
      union
      {
          int i;
          float f;
          char c;
      } u = { 0x12345678 };
  
      span<int  > uspan1 = make_span( &u.i, 1 );
      span<float> uspan2 = make_span( &u.f, 1 );
      span<char > uspan3 = make_span( &u.c, 1 );
  
      assert( static_cast<void const *>( uspan1.data() ) == uspan2.data() );
      assert(                            uspan1.size()   == uspan2.size() );
      assert( static_cast<void const *>( uspan1.data() ) == uspan3.data() );
      assert(                            uspan1.size()   == uspan3.size() );
  
      assert( !same( uspan1, uspan2 ) );
      assert( !same( uspan1, uspan3 ) );
      assert( !same( uspan2, uspan3 ) );
  
      assert( uspan1 != uspan2 );
      assert( uspan1 != uspan3 );
      assert( uspan2 != uspan3 );
  
  #if span_STD_OR( span_HAVE( BYTE ) )
      assert(  same( as_bytes( uspan1 ), as_bytes( uspan2 ) ) );
      assert( !same( as_bytes( uspan1 ), as_bytes( uspan3 ) ) );
      assert( !same( as_bytes( uspan2 ), as_bytes( uspan3 ) ) );
  #endif
  #else
      EXPECT( !!"same() is not provided via span_FEATURE_SAME=1" );
  #endif // span_FEATURE( SAME )
  #else
      EXPECT( !!"test is unavailable as make_span is not provided via span_FEATURE_MAKE_SPAN_TO_STD=99" );
  #endif // span_FEATURE_TO_STD( MAKE_SPAN )
  }
  
  // issue #64
  
  #if span_HAVE_ITERATOR_CTOR
  
  namespace issue64 {
  
      void fun(nonstd::span<unsigned>) {}
      void fun(nonstd::span<nonstd::span<unsigned> >) {}
  }
  #endif
  
  CASE( "[hide][issue-64: overly permissive constructor]" )
  {
  #if span_HAVE_ITERATOR_CTOR
      using issue64::fun;
      unsigned u;
  
      fun( {&u, 1u} );
  #else
      EXPECT( !!"std::initializer_list<> is not available (no C++11)" );
  #endif
  }
  
  CASE( "tweak header: reads tweak header if supported " "[tweak]" )
  {
  #if span_HAVE( TWEAK_HEADER )
      EXPECT( SPAN_TWEAK_VALUE == 42 );
  #else
      EXPECT( !!"Tweak header is not available (span_HAVE_TWEAK_HEADER: 0)." );
  #endif
  }
  
  // end of file
  