//
// span for C++98 and later.
// Based on http://wg21.link/p0122r7
// For more information see https://github.com/martinmoene/span-lite
//
// Copyright 2018-2021 Martin Moene
//
// 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)

// SPDX-License-Identifier: BSL-1.0

// https://github.com/martinmoene/span-lite/blob/dbb484f6c2060b41afa55653dec99b228013a813/include/nonstd/span.hpp

#ifndef NONSTD_SPAN_HPP_INCLUDED
#define NONSTD_SPAN_HPP_INCLUDED

#define span_lite_MAJOR 0
#define span_lite_MINOR 10
#define span_lite_PATCH 3

#define span_lite_VERSION span_STRINGIFY(span_lite_MAJOR) "." span_STRINGIFY(span_lite_MINOR) "." span_STRINGIFY(span_lite_PATCH)

#define span_STRINGIFY(x) span_STRINGIFY_(x)
#define span_STRINGIFY_(x) #x

// span configuration:

#define span_SPAN_DEFAULT 0
#define span_SPAN_NONSTD 1
#define span_SPAN_STD 2

// tweak header support:

#ifdef __has_include
#if __has_include(<nonstd/span.tweak.hpp>)
#include <nonstd/span.tweak.hpp>
#endif
#define span_HAVE_TWEAK_HEADER 1
#else
#define span_HAVE_TWEAK_HEADER 0
//# pragma message("span.hpp: Note: Tweak header not supported.")
#endif

// span selection and configuration:

#define span_HAVE(feature) (span_HAVE_##feature)

#ifndef span_CONFIG_SELECT_SPAN
#define span_CONFIG_SELECT_SPAN (span_HAVE_STD_SPAN ? span_SPAN_STD : span_SPAN_NONSTD)
#endif

#ifndef span_CONFIG_EXTENT_TYPE
#define span_CONFIG_EXTENT_TYPE std::size_t
#endif

#ifndef span_CONFIG_SIZE_TYPE
#define span_CONFIG_SIZE_TYPE std::size_t
#endif

#ifdef span_CONFIG_INDEX_TYPE
#error `span_CONFIG_INDEX_TYPE` is deprecated since v0.7.0; it is replaced by `span_CONFIG_SIZE_TYPE`.
#endif

// span configuration (features):

#ifndef span_FEATURE_WITH_INITIALIZER_LIST_P2447
#define span_FEATURE_WITH_INITIALIZER_LIST_P2447 0
#endif

#ifndef span_FEATURE_WITH_CONTAINER
#ifdef span_FEATURE_WITH_CONTAINER_TO_STD
#define span_FEATURE_WITH_CONTAINER span_IN_STD(span_FEATURE_WITH_CONTAINER_TO_STD)
#else
#define span_FEATURE_WITH_CONTAINER 0
#define span_FEATURE_WITH_CONTAINER_TO_STD 0
#endif
#endif

#ifndef span_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE
#define span_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE 0
#endif

#ifndef span_FEATURE_MEMBER_AT
#define span_FEATURE_MEMBER_AT 0
#endif

#ifndef span_FEATURE_MEMBER_BACK_FRONT
#define span_FEATURE_MEMBER_BACK_FRONT 1
#endif

#ifndef span_FEATURE_MEMBER_CALL_OPERATOR
#define span_FEATURE_MEMBER_CALL_OPERATOR 0
#endif

#ifndef span_FEATURE_MEMBER_SWAP
#define span_FEATURE_MEMBER_SWAP 0
#endif

#ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB
#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB 0
#elif span_FEATURE_NON_MEMBER_FIRST_LAST_SUB
#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN 1
#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER 1
#endif

#ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN
#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN 0
#endif

#ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER
#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER 0
#endif

#ifndef span_FEATURE_COMPARISON
#define span_FEATURE_COMPARISON 0  // Note: C++20 does not provide comparison
#endif

#ifndef span_FEATURE_SAME
#define span_FEATURE_SAME 0
#endif

#if span_FEATURE_SAME && !span_FEATURE_COMPARISON
#error `span_FEATURE_SAME` requires `span_FEATURE_COMPARISON`
#endif

#ifndef span_FEATURE_MAKE_SPAN
#ifdef span_FEATURE_MAKE_SPAN_TO_STD
#define span_FEATURE_MAKE_SPAN span_IN_STD(span_FEATURE_MAKE_SPAN_TO_STD)
#else
#define span_FEATURE_MAKE_SPAN 0
#define span_FEATURE_MAKE_SPAN_TO_STD 0
#endif
#endif

#ifndef span_FEATURE_BYTE_SPAN
#define span_FEATURE_BYTE_SPAN 0
#endif

// Control presence of exception handling (try and auto discover):

#ifndef span_CONFIG_NO_EXCEPTIONS
#if defined(_MSC_VER)
#include <cstddef>  // for _HAS_EXCEPTIONS
#endif
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
#define span_CONFIG_NO_EXCEPTIONS 0
#else
#define span_CONFIG_NO_EXCEPTIONS 1
#undef span_CONFIG_CONTRACT_VIOLATION_THROWS
#undef span_CONFIG_CONTRACT_VIOLATION_TERMINATES
#define span_CONFIG_CONTRACT_VIOLATION_THROWS 0
#define span_CONFIG_CONTRACT_VIOLATION_TERMINATES 1
#endif
#endif

// Control pre- and postcondition violation behaviour:

#if defined(span_CONFIG_CONTRACT_LEVEL_ON)
#define span_CONFIG_CONTRACT_LEVEL_MASK 0x11
#elif defined(span_CONFIG_CONTRACT_LEVEL_OFF)
#define span_CONFIG_CONTRACT_LEVEL_MASK 0x00
#elif defined(span_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY)
#define span_CONFIG_CONTRACT_LEVEL_MASK 0x01
#elif defined(span_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY)
#define span_CONFIG_CONTRACT_LEVEL_MASK 0x10
#else
#define span_CONFIG_CONTRACT_LEVEL_MASK 0x11
#endif

#if defined(span_CONFIG_CONTRACT_VIOLATION_THROWS)
#define span_CONFIG_CONTRACT_VIOLATION_THROWS_V span_CONFIG_CONTRACT_VIOLATION_THROWS
#else
#define span_CONFIG_CONTRACT_VIOLATION_THROWS_V 0
#endif

#if defined(span_CONFIG_CONTRACT_VIOLATION_THROWS) && span_CONFIG_CONTRACT_VIOLATION_THROWS && \
    defined(span_CONFIG_CONTRACT_VIOLATION_TERMINATES) && span_CONFIG_CONTRACT_VIOLATION_TERMINATES
# error Please define none or one of span_CONFIG_CONTRACT_VIOLATION_THROWS and span_CONFIG_CONTRACT_VIOLATION_TERMINATES to 1, but not both.
#endif

// C++ language version detection (C++20 is speculative):
// Note: VC14.0/1900 (VS2015) lacks too much from C++14.

#ifndef span_CPLUSPLUS
#if defined(_MSVC_LANG) && !defined(__clang__)
#define span_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG)
#else
#define span_CPLUSPLUS __cplusplus
#endif
#endif

#define span_CPP98_OR_GREATER (span_CPLUSPLUS >= 199711L)
#define span_CPP11_OR_GREATER (span_CPLUSPLUS >= 201103L)
#define span_CPP14_OR_GREATER (span_CPLUSPLUS >= 201402L)
#define span_CPP17_OR_GREATER (span_CPLUSPLUS >= 201703L)
#define span_CPP20_OR_GREATER (span_CPLUSPLUS >= 202000L)

// C++ language version (represent 98 as 3):

#define span_CPLUSPLUS_V (span_CPLUSPLUS / 100 - (span_CPLUSPLUS > 200000 ? 2000 : 1994))

#define span_IN_STD(v) (((v) == 98 ? 3 : (v)) >= span_CPLUSPLUS_V)

#define span_CONFIG(feature) (span_CONFIG_##feature)
#define span_FEATURE(feature) (span_FEATURE_##feature)
#define span_FEATURE_TO_STD(feature) (span_IN_STD(span_FEATURE(feature##_TO_STD)))

// Use C++20 std::span if available and requested:

#if span_CPP20_OR_GREATER && defined(__has_include)
#if __has_include(<span> )
#define span_HAVE_STD_SPAN 1
#else
#define span_HAVE_STD_SPAN 0
#endif
#else
#define span_HAVE_STD_SPAN 0
#endif

#define span_USES_STD_SPAN \
    ((span_CONFIG_SELECT_SPAN == span_SPAN_STD) || ((span_CONFIG_SELECT_SPAN == span_SPAN_DEFAULT) && span_HAVE_STD_SPAN))

//
// Use C++20 std::span:
//

#if span_USES_STD_SPAN

#include <span>

namespace nonstd {

using std::span;

// Note: C++20 does not provide comparison
// using std::operator==;
// using std::operator!=;
// using std::operator<;
// using std::operator<=;
// using std::operator>;
// using std::operator>=;
}  // namespace nonstd

#else  // span_USES_STD_SPAN

#include <algorithm>

// Compiler versions:
//
// MSVC++  6.0  _MSC_VER == 1200  span_COMPILER_MSVC_VERSION ==  60  (Visual Studio 6.0)
// MSVC++  7.0  _MSC_VER == 1300  span_COMPILER_MSVC_VERSION ==  70  (Visual Studio .NET 2002)
// MSVC++  7.1  _MSC_VER == 1310  span_COMPILER_MSVC_VERSION ==  71  (Visual Studio .NET 2003)
// MSVC++  8.0  _MSC_VER == 1400  span_COMPILER_MSVC_VERSION ==  80  (Visual Studio 2005)
// MSVC++  9.0  _MSC_VER == 1500  span_COMPILER_MSVC_VERSION ==  90  (Visual Studio 2008)
// MSVC++ 10.0  _MSC_VER == 1600  span_COMPILER_MSVC_VERSION == 100  (Visual Studio 2010)
// MSVC++ 11.0  _MSC_VER == 1700  span_COMPILER_MSVC_VERSION == 110  (Visual Studio 2012)
// MSVC++ 12.0  _MSC_VER == 1800  span_COMPILER_MSVC_VERSION == 120  (Visual Studio 2013)
// MSVC++ 14.0  _MSC_VER == 1900  span_COMPILER_MSVC_VERSION == 140  (Visual Studio 2015)
// MSVC++ 14.1  _MSC_VER >= 1910  span_COMPILER_MSVC_VERSION == 141  (Visual Studio 2017)
// MSVC++ 14.2  _MSC_VER >= 1920  span_COMPILER_MSVC_VERSION == 142  (Visual Studio 2019)

#if defined(_MSC_VER) && !defined(__clang__)
#define span_COMPILER_MSVC_VER (_MSC_VER)
#define span_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900)))
#else
#define span_COMPILER_MSVC_VER 0
#define span_COMPILER_MSVC_VERSION 0
#endif

#define span_COMPILER_VERSION(major, minor, patch) (10 * (10 * (major) + (minor)) + (patch))

#if defined(__clang__)
#define span_COMPILER_CLANG_VERSION span_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
#else
#define span_COMPILER_CLANG_VERSION 0
#endif

#if defined(__GNUC__) && !defined(__clang__)
#define span_COMPILER_GNUC_VERSION span_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#else
#define span_COMPILER_GNUC_VERSION 0
#endif

// half-open range [lo..hi):
#define span_BETWEEN(v, lo, hi) ((lo) <= (v) && (v) < (hi))

// Compiler warning suppression:

#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundef"
#pragma clang diagnostic ignored "-Wmismatched-tags"
#define span_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")

#elif defined __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#define span_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")

#elif span_COMPILER_MSVC_VER >= 1900
#define span_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable : codes))
#define span_RESTORE_WARNINGS() __pragma(warning(pop))

// Suppress the following MSVC GSL warnings:
// - C26439, gsl::f.6 : special function 'function' can be declared 'noexcept'
// - C26440, gsl::f.6 : function 'function' can be declared 'noexcept'
// - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions;
//                      use brace initialization, gsl::narrow_cast or gsl::narrow
// - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same
// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead
// - C26490: gsl::t.1 : don't use reinterpret_cast

span_DISABLE_MSVC_WARNINGS(26439 26440 26472 26473 26481 26490)

#else
#define span_RESTORE_WARNINGS() /*empty*/
#endif

// Presence of language and library features:

#ifdef _HAS_CPP0X
#define span_HAS_CPP0X _HAS_CPP0X
#else
#define span_HAS_CPP0X 0
#endif

#define span_CPP11_80 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1400)
#define span_CPP11_90 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1500)
#define span_CPP11_100 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1600)
#define span_CPP11_110 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1700)
#define span_CPP11_120 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1800)
#define span_CPP11_140 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1900)

#define span_CPP14_000 (span_CPP14_OR_GREATER)
#define span_CPP14_120 (span_CPP14_OR_GREATER || span_COMPILER_MSVC_VER >= 1800)
#define span_CPP14_140 (span_CPP14_OR_GREATER || span_COMPILER_MSVC_VER >= 1900)

#define span_CPP17_000 (span_CPP17_OR_GREATER)

// Presence of C++11 language features:

#define span_HAVE_ALIAS_TEMPLATE span_CPP11_140
#define span_HAVE_AUTO span_CPP11_100
#define span_HAVE_CONSTEXPR_11 span_CPP11_140
#define span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG span_CPP11_120
#define span_HAVE_EXPLICIT_CONVERSION span_CPP11_140
#define span_HAVE_INITIALIZER_LIST span_CPP11_120
#define span_HAVE_IS_DEFAULT span_CPP11_140
#define span_HAVE_IS_DELETE span_CPP11_140
#define span_HAVE_NOEXCEPT span_CPP11_140
#define span_HAVE_NULLPTR span_CPP11_100
#define span_HAVE_STATIC_ASSERT span_CPP11_100

// Presence of C++14 language features:

#define span_HAVE_CONSTEXPR_14 span_CPP14_000

// Presence of C++17 language features:

#define span_HAVE_DEPRECATED span_CPP17_000
#define span_HAVE_NODISCARD span_CPP17_000
#define span_HAVE_NORETURN span_CPP17_000

// MSVC: template parameter deduction guides since Visual Studio 2017 v15.7

#if defined(__cpp_deduction_guides)
#define span_HAVE_DEDUCTION_GUIDES 1
#else
#define span_HAVE_DEDUCTION_GUIDES (span_CPP17_OR_GREATER && !span_BETWEEN(span_COMPILER_MSVC_VER, 1, 1913))
#endif

// Presence of C++ library features:

#define span_HAVE_ADDRESSOF span_CPP17_000
#define span_HAVE_ARRAY span_CPP11_110
#define span_HAVE_BYTE span_CPP17_000
#define span_HAVE_CONDITIONAL span_CPP11_120
#define span_HAVE_CONTAINER_DATA_METHOD (span_CPP11_140 || (span_COMPILER_MSVC_VER >= 1500 && span_HAS_CPP0X))
#define span_HAVE_DATA span_CPP17_000
#define span_HAVE_LONGLONG span_CPP11_80
#define span_HAVE_REMOVE_CONST span_CPP11_110
#define span_HAVE_SNPRINTF span_CPP11_140
#define span_HAVE_STRUCT_BINDING span_CPP11_120
#define span_HAVE_TYPE_TRAITS span_CPP11_90

// Presence of byte-lite:

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

// C++ feature usage:

#if span_HAVE_ADDRESSOF
#define span_ADDRESSOF(x) std::addressof(x)
#else
#define span_ADDRESSOF(x) (&x)
#endif

#if span_HAVE_CONSTEXPR_11
#define span_constexpr constexpr
#else
#define span_constexpr /*span_constexpr*/
#endif

#if span_HAVE_CONSTEXPR_14
#define span_constexpr14 constexpr
#else
#define span_constexpr14 /*span_constexpr*/
#endif

#if span_HAVE_EXPLICIT_CONVERSION
#define span_explicit explicit
#else
#define span_explicit /*explicit*/
#endif

#if span_HAVE_IS_DELETE
#define span_is_delete = delete
#else
#define span_is_delete
#endif

#if span_HAVE_IS_DELETE
#define span_is_delete_access public
#else
#define span_is_delete_access private
#endif

#if span_HAVE_NOEXCEPT && !span_CONFIG_CONTRACT_VIOLATION_THROWS_V
#define span_noexcept noexcept
#else
#define span_noexcept /*noexcept*/
#endif

#if span_HAVE_NULLPTR
#define span_nullptr nullptr
#else
#define span_nullptr NULL
#endif

#if span_HAVE_DEPRECATED
#define span_deprecated(msg) [[deprecated(msg)]]
#else
#define span_deprecated(msg) /*[[deprecated]]*/
#endif

#if span_HAVE_NODISCARD
#define span_nodiscard [[nodiscard]]
#else
#define span_nodiscard /*[[nodiscard]]*/
#endif

#if span_HAVE_NORETURN
#define span_noreturn [[noreturn]]
#else
#define span_noreturn /*[[noreturn]]*/
#endif

// Other features:

#define span_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
#define span_HAVE_ITERATOR_CTOR span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG

// Additional includes:

#if span_HAVE(ADDRESSOF)
#include <memory>
#endif

#if span_HAVE(ARRAY)
#include <array>
#endif

#if span_HAVE(BYTE)
#include <cstddef>
#endif

#if span_HAVE(DATA)
#include <iterator>  // for std::data(), std::size()
#endif

#if span_HAVE(TYPE_TRAITS)
#include <type_traits>
#endif

#if !span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR)
#include <vector>
#endif

#if span_FEATURE(MEMBER_AT) > 1
#include <cstdio>
#endif

#if !span_CONFIG(NO_EXCEPTIONS)
#include <stdexcept>
#endif

// Contract violation

#define span_ELIDE_CONTRACT_EXPECTS (0 == (span_CONFIG_CONTRACT_LEVEL_MASK & 0x01))
#define span_ELIDE_CONTRACT_ENSURES (0 == (span_CONFIG_CONTRACT_LEVEL_MASK & 0x10))

#if span_ELIDE_CONTRACT_EXPECTS
#define span_constexpr_exp span_constexpr
#define span_EXPECTS(cond) /* Expect elided */
#else
#define span_constexpr_exp span_constexpr14
#define span_EXPECTS(cond) span_CONTRACT_CHECK("Precondition", cond)
#endif

#if span_ELIDE_CONTRACT_ENSURES
#define span_constexpr_ens span_constexpr
#define span_ENSURES(cond) /* Ensures elided */
#else
#define span_constexpr_ens span_constexpr14
#define span_ENSURES(cond) span_CONTRACT_CHECK("Postcondition", cond)
#endif

#define span_CONTRACT_CHECK(type, cond) \
    cond ? static_cast<void>(0)         \
         : nonstd::span_lite::detail::report_contract_violation(span_LOCATION(__FILE__, __LINE__) ": " type " violation.")

#ifdef __GNUG__
#define span_LOCATION(file, line) file ":" span_STRINGIFY(line)
#else
#define span_LOCATION(file, line) file "(" span_STRINGIFY(line) ")"
#endif

// Method enabling

#if span_HAVE(DEFAULT_FUNCTION_TEMPLATE_ARG)

#define span_REQUIRES_0(VA) template <bool B = (VA), typename std::enable_if<B, int>::type = 0>

#if span_BETWEEN(span_COMPILER_MSVC_VERSION, 1, 140)
// VS 2013 and earlier seem to have trouble with SFINAE for default non-type arguments
#define span_REQUIRES_T(VA) , typename = typename std::enable_if<(VA), nonstd::span_lite::detail::enabler>::type
#else
#define span_REQUIRES_T(VA) , typename std::enable_if<(VA), int>::type = 0
#endif

#define span_REQUIRES_R(R, VA) typename std::enable_if<(VA), R>::type

#define span_REQUIRES_A(VA) , typename std::enable_if<(VA), void*>::type = nullptr

#else

#define span_REQUIRES_0(VA) /*empty*/
#define span_REQUIRES_T(VA) /*empty*/
#define span_REQUIRES_R(R, VA) R
#define span_REQUIRES_A(VA) /*empty*/

#endif

namespace nonstd {
namespace span_lite {

// [views.constants], constants

typedef span_CONFIG_EXTENT_TYPE extent_t;
typedef span_CONFIG_SIZE_TYPE size_t;

span_constexpr const extent_t dynamic_extent = static_cast<extent_t>(-1);

template <class T, extent_t Extent = dynamic_extent>
class span;

// Tag to select span constructor taking a container (prevent ms-gsl warning C26426):

struct with_container_t {
    span_constexpr with_container_t() span_noexcept {}
};
const span_constexpr with_container_t with_container;

// C++11 emulation:

namespace std11 {

#if span_HAVE(REMOVE_CONST)

using std::remove_const;
using std::remove_cv;
using std::remove_volatile;

#else

template <class T>
struct remove_const {
    typedef T type;
};
template <class T>
struct remove_const<T const> {
    typedef T type;
};

template <class T>
struct remove_volatile {
    typedef T type;
};
template <class T>
struct remove_volatile<T volatile> {
    typedef T type;
};

template <class T>
struct remove_cv {
    typedef typename std11::remove_volatile<typename std11::remove_const<T>::type>::type type;
};

#endif  // span_HAVE( REMOVE_CONST )

#if span_HAVE(TYPE_TRAITS)

using std::false_type;
using std::integral_constant;
using std::is_same;
using std::is_signed;
using std::remove_reference;
using std::true_type;

#else

template <class T, T v>
struct integral_constant {
    enum { value = v };
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

template <class T, class U>
struct is_same : false_type {};
template <class T>
struct is_same<T, T> : true_type {};

template <typename T>
struct is_signed : false_type {};
template <>
struct is_signed<signed char> : true_type {};
template <>
struct is_signed<signed int> : true_type {};
template <>
struct is_signed<signed long> : true_type {};

#endif

}  // namespace std11

// C++17 emulation:

namespace std17 {

template <bool v>
struct bool_constant : std11::integral_constant<bool, v> {};

#if span_CPP11_120

template <class...>
using void_t = void;

#endif

#if span_HAVE(DATA)

using std::data;
using std::size;

#elif span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR)

template <typename T, std::size_t N>
inline span_constexpr auto size(const T (&)[N]) span_noexcept->size_t {
    return N;
}

template <typename C>
inline span_constexpr auto size(C const& cont) -> decltype(cont.size()) {
    return cont.size();
}

template <typename T, std::size_t N>
inline span_constexpr auto data(T (&arr)[N]) span_noexcept->T* {
    return &arr[0];
}

template <typename C>
inline span_constexpr auto data(C& cont) -> decltype(cont.data()) {
    return cont.data();
}

template <typename C>
inline span_constexpr auto data(C const& cont) -> decltype(cont.data()) {
    return cont.data();
}

template <typename E>
inline span_constexpr auto data(std::initializer_list<E> il) span_noexcept->E const* {
    return il.begin();
}

#endif  // span_HAVE( DATA )

#if span_HAVE(BYTE)
using std::byte;
#elif span_HAVE(NONSTD_BYTE)
using nonstd::byte;
#endif

}  // namespace std17

// C++20 emulation:

namespace std20 {

#if span_HAVE(DEDUCTION_GUIDES)
template <class T>
using iter_reference_t = decltype(*std::declval<T &>());
#endif

}  // namespace std20

// Implementation details:

namespace detail {

/*enum*/ struct enabler {};

template <typename T>
span_constexpr bool is_positive(T x) {
    return std11::is_signed<T>::value ? x >= 0 : true;
}

#if span_HAVE(TYPE_TRAITS)

template <class Q>
struct is_span_oracle : std::false_type {};

template <class T, span_CONFIG_EXTENT_TYPE Extent>
struct is_span_oracle<span<T, Extent> > : std::true_type {};

template <class Q>
struct is_span : is_span_oracle<typename std::remove_cv<Q>::type> {};

template <class Q>
struct is_std_array_oracle : std::false_type {};

#if span_HAVE(ARRAY)

template <class T, std::size_t Extent>
struct is_std_array_oracle<std::array<T, Extent> > : std::true_type {};

#endif

template <class Q>
struct is_std_array : is_std_array_oracle<typename std::remove_cv<Q>::type> {};

template <class Q>
struct is_array : std::false_type {};

template <class T>
struct is_array<T[]> : std::true_type {};

template <class T, std::size_t N>
struct is_array<T[N]> : std::true_type {};

#if span_CPP11_140 && !span_BETWEEN(span_COMPILER_GNUC_VERSION, 1, 500)

template <class, class = void>
struct has_size_and_data : std::false_type {};

template <class C>
struct has_size_and_data<C, std17::void_t<decltype(std17::size(std::declval<C>())), decltype(std17::data(std::declval<C>()))> >
    : std::true_type {};

template <class, class, class = void>
struct is_compatible_element : std::false_type {};

template <class C, class E>
struct is_compatible_element<C, E, std17::void_t<decltype(std17::data(std::declval<C>()))> >
    : std::is_convertible<typename std::remove_pointer<decltype(std17::data(std::declval<C &>()))>::type (*)[], E (*)[]> {};

template <class C>
struct is_container
    : std17::bool_constant<!is_span<C>::value && !is_array<C>::value && !is_std_array<C>::value && has_size_and_data<C>::value> {};

template <class C, class E>
struct is_compatible_container : std17::bool_constant<is_container<C>::value && is_compatible_element<C, E>::value> {};

#else  // span_CPP11_140

template <
    class C,
    class E span_REQUIRES_T(
        (!is_span<C>::value && !is_array<C>::value && !is_std_array<C>::value &&
         (std::is_convertible<typename std::remove_pointer<decltype(std17::data(std::declval<C &>()))>::type (*)[], E (*)[]>::value)
         //  &&   has_size_and_data< C >::value
         )),
    class = decltype(std17::size(std::declval<C>())), class = decltype(std17::data(std::declval<C>()))>
struct is_compatible_container : std::true_type {};

#endif  // span_CPP11_140

#endif  // span_HAVE( TYPE_TRAITS )

#if !span_CONFIG(NO_EXCEPTIONS)
#if span_FEATURE(MEMBER_AT) > 1

// format index and size:

#if defined(__clang__)
#pragma clang diagnostic ignored "-Wlong-long"
#elif defined __GNUC__
#pragma GCC diagnostic ignored "-Wformat=ll"
#pragma GCC diagnostic ignored "-Wlong-long"
#endif

span_noreturn inline void throw_out_of_range(size_t idx, size_t size) {
    const char fmt[] = "span::at(): index '%lli' is out of range [0..%lli)";
    char buffer[2 * 20 + sizeof fmt];
    sprintf(buffer, fmt, static_cast<long long>(idx), static_cast<long long>(size));

    throw std::out_of_range(buffer);
}

#else   // MEMBER_AT

span_noreturn inline void throw_out_of_range(size_t /*idx*/, size_t /*size*/) {
    throw std::out_of_range("span::at(): index outside span");
}
#endif  // MEMBER_AT
#endif  // NO_EXCEPTIONS

#if span_CONFIG(CONTRACT_VIOLATION_THROWS_V)

struct contract_violation : std::logic_error {
    explicit contract_violation(char const *const message) : std::logic_error(message) {}
};

inline void report_contract_violation(char const *msg) { throw contract_violation(msg); }

#else  // span_CONFIG( CONTRACT_VIOLATION_THROWS_V )

span_noreturn inline void report_contract_violation(char const* /*msg*/) span_noexcept { std::terminate(); }

#endif  // span_CONFIG( CONTRACT_VIOLATION_THROWS_V )

}  // namespace detail

// Prevent signed-unsigned mismatch:

#define span_sizeof(T) static_cast<extent_t>(sizeof(T))

template <class T>
inline span_constexpr size_t to_size(T size) {
    return static_cast<size_t>(size);
}

//
// [views.span] - A view over a contiguous, single-dimension sequence of objects
//
template <class T, extent_t Extent /*= dynamic_extent*/>
class span {
   public:
    // constants and types

    typedef T element_type;
    typedef typename std11::remove_cv<T>::type value_type;

    typedef T &reference;
    typedef T *pointer;
    typedef T const *const_pointer;
    typedef T const &const_reference;

    typedef size_t size_type;
    typedef extent_t extent_type;

    typedef pointer iterator;
    typedef const_pointer const_iterator;

    typedef std::ptrdiff_t difference_type;

    typedef std::reverse_iterator<iterator> reverse_iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

    //    static constexpr extent_type extent = Extent;
    enum { extent = Extent };

    // 26.7.3.2 Constructors, copy, and assignment [span.cons]

    span_REQUIRES_0((Extent == 0) || (Extent == dynamic_extent)) span_constexpr span() span_noexcept : data_(span_nullptr),
                                                                                                       size_(0) {
        // span_EXPECTS( data() == span_nullptr );
        // span_EXPECTS( size() == 0 );
    }

#if span_HAVE(ITERATOR_CTOR)
    // Didn't yet succeed in combining the next two constructors:

    span_constexpr_exp span(std::nullptr_t, size_type count) : data_(span_nullptr), size_(count) {
        span_EXPECTS(data_ == span_nullptr && count == 0);
    }

    template <typename It span_REQUIRES_T((std::is_convertible<decltype(*std::declval<It &>()), element_type &>::value))>
    span_constexpr_exp span(It first, size_type count) : data_(to_address(first)), size_(count) {
        span_EXPECTS((data_ == span_nullptr && count == 0) || (data_ != span_nullptr && detail::is_positive(count)));
    }
#else
    span_constexpr_exp span(pointer ptr, size_type count) : data_(ptr), size_(count) {
        span_EXPECTS((ptr == span_nullptr && count == 0) || (ptr != span_nullptr && detail::is_positive(count)));
    }
#endif

#if span_HAVE(ITERATOR_CTOR)
    template <typename It,
              typename End span_REQUIRES_T((std::is_convertible<decltype(&*std::declval<It &>()), element_type *>::value &&
                                            !std::is_convertible<End, std::size_t>::value))>
    span_constexpr_exp span(It first, End last) : data_(to_address(first)), size_(to_size(last - first)) {
        span_EXPECTS(last - first >= 0);
    }
#else
    span_constexpr_exp span(pointer first, pointer last) : data_(first), size_(to_size(last - first)) {
        span_EXPECTS(last - first >= 0);
    }
#endif

    template <std::size_t N span_REQUIRES_T(((Extent == dynamic_extent || Extent == static_cast<extent_t>(N)) &&
                                             std::is_convertible<value_type (*)[], element_type (*)[]>::value))>
    span_constexpr span(element_type (&arr)[N]) span_noexcept : data_(span_ADDRESSOF(arr[0])), size_(N) {}

#if span_HAVE(ARRAY)

    template <std::size_t N span_REQUIRES_T(((Extent == dynamic_extent || Extent == static_cast<extent_t>(N)) &&
                                             std::is_convertible<value_type (*)[], element_type (*)[]>::value))>
#if span_FEATURE(CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE)
    span_constexpr span(std::array<element_type, N> &arr) span_noexcept
#else
    span_constexpr span(std::array<value_type, N> &arr) span_noexcept
#endif
        : data_(arr.data()),
          size_(to_size(arr.size())) {
    }

    template <std::size_t N
#if span_HAVE(DEFAULT_FUNCTION_TEMPLATE_ARG)
                  span_REQUIRES_T(((Extent == dynamic_extent || Extent == static_cast<extent_t>(N)) &&
                                   std::is_convertible<value_type (*)[], element_type (*)[]>::value))
#endif
              >
    span_constexpr span(std::array<value_type, N> const &arr) span_noexcept : data_(arr.data()), size_(to_size(arr.size())) {
    }

#endif  // span_HAVE( ARRAY )

#if span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR)
    template <class Container span_REQUIRES_T((detail::is_compatible_container<Container, element_type>::value))>
    span_constexpr span(Container &cont) : data_(std17::data(cont)), size_(to_size(std17::size(cont))) {}

    template <class Container span_REQUIRES_T((std::is_const<element_type>::value &&
                                               detail::is_compatible_container<Container, element_type>::value))>
    span_constexpr span(Container const &cont) : data_(std17::data(cont)), size_(to_size(std17::size(cont))) {}

#endif  // span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR )

#if span_FEATURE(WITH_CONTAINER)

    template <class Container>
    span_constexpr span(with_container_t, Container &cont)
        : data_(cont.size() == 0 ? span_nullptr : span_ADDRESSOF(cont[0])), size_(to_size(cont.size())) {}

    template <class Container>
    span_constexpr span(with_container_t, Container const &cont)
        : data_(cont.size() == 0 ? span_nullptr : const_cast<pointer>(span_ADDRESSOF(cont[0]))), size_(to_size(cont.size())) {}
#endif

#if span_FEATURE(WITH_INITIALIZER_LIST_P2447) && span_HAVE(INITIALIZER_LIST)

    // constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il) noexcept;

#if !span_BETWEEN(span_COMPILER_MSVC_VERSION, 120, 130)

    template <extent_t U = Extent span_REQUIRES_T((U != dynamic_extent))>
#if span_COMPILER_GNUC_VERSION >= 900  // prevent GCC's "-Winit-list-lifetime"
    span_constexpr14 explicit span(std::initializer_list<value_type> il) span_noexcept {
        data_ = il.begin();
        size_ = il.size();
    }
#else
    span_constexpr explicit span(std::initializer_list<value_type> il) span_noexcept : data_(il.begin()), size_(il.size()) {
    }
#endif

#endif                                 // MSVC 120 (VS2013)

    template <extent_t U = Extent span_REQUIRES_T((U == dynamic_extent))>
#if span_COMPILER_GNUC_VERSION >= 900  // prevent GCC's "-Winit-list-lifetime"
    span_constexpr14 /*explicit*/ span(std::initializer_list<value_type> il) span_noexcept {
        data_ = il.begin();
        size_ = il.size();
    }
#else
    span_constexpr /*explicit*/ span(std::initializer_list<value_type> il) span_noexcept : data_(il.begin()), size_(il.size()) {
    }
#endif

#endif  // P2447

#if span_HAVE(IS_DEFAULT)
    span_constexpr span(span const &other) span_noexcept = default;

    ~span() span_noexcept = default;

    span_constexpr14 span &operator=(span const &other) span_noexcept = default;
#else
    span_constexpr span(span const& other) span_noexcept : data_(other.data_), size_(other.size_) {}

    ~span() span_noexcept {}

    span_constexpr14 span& operator=(span const& other) span_noexcept {
        data_ = other.data_;
        size_ = other.size_;

        return *this;
    }
#endif

    template <class OtherElementType, extent_type OtherExtent span_REQUIRES_T(
                                          ((Extent == dynamic_extent || OtherExtent == dynamic_extent || Extent == OtherExtent) &&
                                           std::is_convertible<OtherElementType (*)[], element_type (*)[]>::value))>
    span_constexpr_exp span(span<OtherElementType, OtherExtent> const &other) span_noexcept : data_(other.data()),
                                                                                              size_(other.size()) {
        span_EXPECTS(OtherExtent == dynamic_extent || other.size() == to_size(OtherExtent));
    }

    // 26.7.3.3 Subviews [span.sub]

    template <extent_type Count>
    span_constexpr_exp span<element_type, Count> first() const {
        span_EXPECTS(detail::is_positive(Count) && Count <= size());

        return span<element_type, Count>(data(), Count);
    }

    template <extent_type Count>
    span_constexpr_exp span<element_type, Count> last() const {
        span_EXPECTS(detail::is_positive(Count) && Count <= size());

        return span<element_type, Count>(data() + (size() - Count), Count);
    }

#if span_HAVE(DEFAULT_FUNCTION_TEMPLATE_ARG)
    template <size_type Offset, extent_type Count = dynamic_extent>
#else
    template <size_type Offset, extent_type Count /*= dynamic_extent*/>
#endif
    span_constexpr_exp span<element_type, Count> subspan() const {
        span_EXPECTS((detail::is_positive(Offset) && Offset <= size()) &&
                     (Count == dynamic_extent || (detail::is_positive(Count) && Count + Offset <= size())));

        return span<element_type, Count>(
            data() + Offset, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : size() - Offset));
    }

    span_constexpr_exp span<element_type, dynamic_extent> first(size_type count) const {
        span_EXPECTS(detail::is_positive(count) && count <= size());

        return span<element_type, dynamic_extent>(data(), count);
    }

    span_constexpr_exp span<element_type, dynamic_extent> last(size_type count) const {
        span_EXPECTS(detail::is_positive(count) && count <= size());

        return span<element_type, dynamic_extent>(data() + (size() - count), count);
    }

    span_constexpr_exp span<element_type, dynamic_extent> subspan(size_type offset,
                                                                  size_type count = static_cast<size_type>(dynamic_extent)) const {
        span_EXPECTS(((detail::is_positive(offset) && offset <= size())) &&
                     (count == static_cast<size_type>(dynamic_extent) || (detail::is_positive(count) && offset + count <= size())));

        return span<element_type, dynamic_extent>(data() + offset,
                                                  count == static_cast<size_type>(dynamic_extent) ? size() - offset : count);
    }

    // 26.7.3.4 Observers [span.obs]

    span_constexpr size_type size() const span_noexcept { return size_; }

    span_constexpr std::ptrdiff_t ssize() const span_noexcept { return static_cast<std::ptrdiff_t>(size_); }

    span_constexpr size_type size_bytes() const span_noexcept { return size() * to_size(sizeof(element_type)); }

    span_nodiscard span_constexpr bool empty() const span_noexcept { return size() == 0; }

    // 26.7.3.5 Element access [span.elem]

    span_constexpr_exp reference operator[](size_type idx) const {
        span_EXPECTS(detail::is_positive(idx) && idx < size());

        return *(data() + idx);
    }

#if span_FEATURE(MEMBER_CALL_OPERATOR)
    span_deprecated("replace operator() with operator[]")

        span_constexpr_exp reference
        operator()(size_type idx) const {
        span_EXPECTS(detail::is_positive(idx) && idx < size());

        return *(data() + idx);
    }
#endif

#if span_FEATURE(MEMBER_AT)
    span_constexpr14 reference at(size_type idx) const {
#if span_CONFIG(NO_EXCEPTIONS)
        return this->operator[](idx);
#else
        if (!detail::is_positive(idx) || size() <= idx) {
            detail::throw_out_of_range(idx, size());
        }
        return *(data() + idx);
#endif
    }
#endif

    span_constexpr pointer data() const span_noexcept { return data_; }

#if span_FEATURE(MEMBER_BACK_FRONT)

    span_constexpr_exp reference front() const span_noexcept {
        span_EXPECTS(!empty());

        return *data();
    }

    span_constexpr_exp reference back() const span_noexcept {
        span_EXPECTS(!empty());

        return *(data() + size() - 1);
    }

#endif

    // xx.x.x.x Modifiers [span.modifiers]

#if span_FEATURE(MEMBER_SWAP)

    span_constexpr14 void swap(span &other) span_noexcept {
        using std::swap;
        swap(data_, other.data_);
        swap(size_, other.size_);
    }
#endif

    // 26.7.3.6 Iterator support [span.iterators]

    span_constexpr iterator begin() const span_noexcept {
#if span_CPP11_OR_GREATER
        return {data()};
#else
        return iterator(data());
#endif
    }

    span_constexpr iterator end() const span_noexcept {
#if span_CPP11_OR_GREATER
        return {data() + size()};
#else
        return iterator(data() + size());
#endif
    }

    span_constexpr const_iterator cbegin() const span_noexcept {
#if span_CPP11_OR_GREATER
        return {data()};
#else
        return const_iterator(data());
#endif
    }

    span_constexpr const_iterator cend() const span_noexcept {
#if span_CPP11_OR_GREATER
        return {data() + size()};
#else
        return const_iterator(data() + size());
#endif
    }

    span_constexpr reverse_iterator rbegin() const span_noexcept { return reverse_iterator(end()); }

    span_constexpr reverse_iterator rend() const span_noexcept { return reverse_iterator(begin()); }

    span_constexpr const_reverse_iterator crbegin() const span_noexcept { return const_reverse_iterator(cend()); }

    span_constexpr const_reverse_iterator crend() const span_noexcept { return const_reverse_iterator(cbegin()); }

   private:
    // Note: C++20 has std::pointer_traits<Ptr>::to_address( it );

#if span_HAVE(ITERATOR_CTOR)
    static inline span_constexpr pointer to_address(std::nullptr_t) span_noexcept { return nullptr; }

    template <typename U>
    static inline span_constexpr U *to_address(U *p) span_noexcept {
        return p;
    }

    template <typename Ptr span_REQUIRES_T((!std::is_pointer<Ptr>::value))>
    static inline span_constexpr pointer to_address(Ptr const &it) span_noexcept {
        return to_address(it.operator->());
    }
#endif  // span_HAVE( ITERATOR_CTOR )

   private:
    pointer data_;
    size_type size_;
};

// class template argument deduction guides:

#if span_HAVE(DEDUCTION_GUIDES)

template <class T, size_t N>
span(T (&)[N]) -> span<T, static_cast<extent_t>(N)>;

template <class T, size_t N>
span(std::array<T, N> &) -> span<T, static_cast<extent_t>(N)>;

template <class T, size_t N>
span(std::array<T, N> const &) -> span<const T, static_cast<extent_t>(N)>;

#if span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR)

template <class Container>
span(Container &) -> span<typename Container::value_type>;

template <class Container>
span(Container const &) -> span<const typename Container::value_type>;

#endif

// iterator: constraints: It satisfies contiguous_­iterator.

template <class It, class EndOrSize>
span(It, EndOrSize) -> span<typename std11::remove_reference<typename std20::iter_reference_t<It> >::type>;

#endif  // span_HAVE( DEDUCTION_GUIDES )

// 26.7.3.7 Comparison operators [span.comparison]

#if span_FEATURE(COMPARISON)
#if span_FEATURE(SAME)

template <class T1, extent_t E1, class T2, extent_t E2>
inline span_constexpr bool same(span<T1, E1> const &l, span<T2, E2> const &r) span_noexcept {
    return std11::is_same<T1, T2>::value && l.size() == r.size() && static_cast<void const *>(l.data()) == r.data();
}

#endif

template <class T1, extent_t E1, class T2, extent_t E2>
inline span_constexpr bool operator==(span<T1, E1> const &l, span<T2, E2> const &r) {
    return
#if span_FEATURE(SAME)
        same(l, r) ||
#endif
        (l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin()));
}

template <class T1, extent_t E1, class T2, extent_t E2>
inline span_constexpr bool operator<(span<T1, E1> const &l, span<T2, E2> const &r) {
    return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}

template <class T1, extent_t E1, class T2, extent_t E2>
inline span_constexpr bool operator!=(span<T1, E1> const &l, span<T2, E2> const &r) {
    return !(l == r);
}

template <class T1, extent_t E1, class T2, extent_t E2>
inline span_constexpr bool operator<=(span<T1, E1> const &l, span<T2, E2> const &r) {
    return !(r < l);
}

template <class T1, extent_t E1, class T2, extent_t E2>
inline span_constexpr bool operator>(span<T1, E1> const &l, span<T2, E2> const &r) {
    return (r < l);
}

template <class T1, extent_t E1, class T2, extent_t E2>
inline span_constexpr bool operator>=(span<T1, E1> const &l, span<T2, E2> const &r) {
    return !(l < r);
}

#endif  // span_FEATURE( COMPARISON )

// 26.7.2.6 views of object representation [span.objectrep]

#if span_HAVE(BYTE) || span_HAVE(NONSTD_BYTE)

// Avoid MSVC 14.1 (1910), VS 2017: warning C4307: '*': integral constant overflow:

template <typename T, extent_t Extent>
struct BytesExtent {
#if span_CPP11_OR_GREATER
    enum ET : extent_t { value = span_sizeof(T) * Extent };
#else
    enum ET { value = span_sizeof(T) * Extent };
#endif
};

template <typename T>
struct BytesExtent<T, dynamic_extent> {
#if span_CPP11_OR_GREATER
    enum ET : extent_t{value = dynamic_extent};
#else
    enum ET { value = dynamic_extent };
#endif
};

template <class T, extent_t Extent>
inline span_constexpr span<const std17::byte, BytesExtent<T, Extent>::value> as_bytes(span<T, Extent> spn) span_noexcept {
#if 0
    return { reinterpret_cast< std17::byte const * >( spn.data() ), spn.size_bytes() };
#else
    return span<const std17::byte, BytesExtent<T, Extent>::value>(reinterpret_cast<std17::byte const *>(spn.data()),
                                                                  spn.size_bytes());  // NOLINT
#endif
}

template <class T, extent_t Extent>
inline span_constexpr span<std17::byte, BytesExtent<T, Extent>::value> as_writable_bytes(span<T, Extent> spn) span_noexcept {
#if 0
    return { reinterpret_cast< std17::byte * >( spn.data() ), spn.size_bytes() };
#else
    return span<std17::byte, BytesExtent<T, Extent>::value>(reinterpret_cast<std17::byte *>(spn.data()),
                                                            spn.size_bytes());  // NOLINT
#endif
}

#endif  // span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE )

// 27.8 Container and view access [iterator.container]

template <class T, extent_t Extent /*= dynamic_extent*/>
span_constexpr std::size_t size(span<T, Extent> const &spn) {
    return static_cast<std::size_t>(spn.size());
}

template <class T, extent_t Extent /*= dynamic_extent*/>
span_constexpr std::ptrdiff_t ssize(span<T, Extent> const &spn) {
    return static_cast<std::ptrdiff_t>(spn.size());
}

}  // namespace span_lite
}  // namespace nonstd

// make available in nonstd:

namespace nonstd {

using span_lite::dynamic_extent;

using span_lite::span;

using span_lite::with_container;

#if span_FEATURE(COMPARISON)
#if span_FEATURE(SAME)
using span_lite::same;
#endif

using span_lite::operator==;
using span_lite::operator!=;
using span_lite::operator<;
using span_lite::operator<=;
using span_lite::operator>;
using span_lite::operator>=;
#endif

#if span_HAVE(BYTE)
using span_lite::as_bytes;
using span_lite::as_writable_bytes;
#endif

using span_lite::size;
using span_lite::ssize;

}  // namespace nonstd

#endif  // span_USES_STD_SPAN

// make_span() [span-lite extension]:

#if span_FEATURE(MAKE_SPAN) || span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_SPAN) || span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_CONTAINER)

#if span_USES_STD_SPAN
#define span_constexpr constexpr
#define span_noexcept noexcept
#define span_nullptr nullptr
#ifndef span_CONFIG_EXTENT_TYPE
#define span_CONFIG_EXTENT_TYPE std::size_t
#endif
using extent_t = span_CONFIG_EXTENT_TYPE;
#endif  // span_USES_STD_SPAN

namespace nonstd {
namespace span_lite {

template <class T>
inline span_constexpr span<T> make_span(T* ptr, size_t count) span_noexcept {
    return span<T>(ptr, count);
}

template <class T>
inline span_constexpr span<T> make_span(T* first, T* last) span_noexcept {
    return span<T>(first, last);
}

template <class T, std::size_t N>
inline span_constexpr span<T, static_cast<extent_t>(N)> make_span(T (&arr)[N]) span_noexcept {
    return span<T, static_cast<extent_t>(N)>(&arr[0], N);
}

#if span_USES_STD_SPAN || span_HAVE(ARRAY)

template <class T, std::size_t N>
inline span_constexpr span<T, static_cast<extent_t>(N)> make_span(std::array<T, N>& arr) span_noexcept {
    return span<T, static_cast<extent_t>(N)>(arr);
}

template <class T, std::size_t N>
inline span_constexpr span<const T, static_cast<extent_t>(N)> make_span(std::array<T, N> const& arr) span_noexcept {
    return span<const T, static_cast<extent_t>(N)>(arr);
}

#endif  // span_HAVE( ARRAY )

#if span_USES_STD_SPAN || span_HAVE(INITIALIZER_LIST)

template <class T>
inline span_constexpr span<const T> make_span(std::initializer_list<T> il) span_noexcept {
    return span<const T>(il.begin(), il.size());
}

#endif  // span_HAVE( INITIALIZER_LIST )

#if span_USES_STD_SPAN

template <class Container, class EP = decltype(std::data(std::declval<Container&>()))>
inline span_constexpr auto make_span(Container& cont) span_noexcept->span<typename std::remove_pointer<EP>::type> {
    return span<typename std::remove_pointer<EP>::type>(cont);
}

template <class Container, class EP = decltype(std::data(std::declval<Container&>()))>
inline span_constexpr auto make_span(Container const& cont) span_noexcept->span<const typename std::remove_pointer<EP>::type> {
    return span<const typename std::remove_pointer<EP>::type>(cont);
}

#elif span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR) && span_HAVE(AUTO)

template <class Container, class EP = decltype(std17::data(std::declval<Container&>()))>
inline span_constexpr auto make_span(Container& cont) span_noexcept->span<typename std::remove_pointer<EP>::type> {
    return span<typename std::remove_pointer<EP>::type>(cont);
}

template <class Container, class EP = decltype(std17::data(std::declval<Container&>()))>
inline span_constexpr auto make_span(Container const& cont) span_noexcept->span<const typename std::remove_pointer<EP>::type> {
    return span<const typename std::remove_pointer<EP>::type>(cont);
}

#else

template <class T>
inline span_constexpr span<T> make_span(span<T> spn) span_noexcept {
    return spn;
}

template <class T, class Allocator>
inline span_constexpr span<T> make_span(std::vector<T, Allocator>& cont) span_noexcept {
    return span<T>(with_container, cont);
}

template <class T, class Allocator>
inline span_constexpr span<const T> make_span(std::vector<T, Allocator> const& cont) span_noexcept {
    return span<const T>(with_container, cont);
}

#endif  // span_USES_STD_SPAN || ( ... )

#if !span_USES_STD_SPAN && span_FEATURE(WITH_CONTAINER)

template <class Container>
inline span_constexpr span<typename Container::value_type> make_span(with_container_t, Container& cont) span_noexcept {
    return span<typename Container::value_type>(with_container, cont);
}

template <class Container>
inline span_constexpr span<const typename Container::value_type> make_span(with_container_t, Container const& cont) span_noexcept {
    return span<const typename Container::value_type>(with_container, cont);
}

#endif  // ! span_USES_STD_SPAN && span_FEATURE( WITH_CONTAINER )

// extensions: non-member views:
// this feature implies the presence of make_span()

#if span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_SPAN)

template <extent_t Count, class T, extent_t Extent>
span_constexpr span<T, Count> first(span<T, Extent> spn) {
    return spn.template first<Count>();
}

template <class T, extent_t Extent>
span_constexpr span<T> first(span<T, Extent> spn, size_t count) {
    return spn.first(count);
}

template <extent_t Count, class T, extent_t Extent>
span_constexpr span<T, Count> last(span<T, Extent> spn) {
    return spn.template last<Count>();
}

template <class T, extent_t Extent>
span_constexpr span<T> last(span<T, Extent> spn, size_t count) {
    return spn.last(count);
}

template <size_t Offset, extent_t Count, class T, extent_t Extent>
span_constexpr span<T, Count> subspan(span<T, Extent> spn) {
    return spn.template subspan<Offset, Count>();
}

template <class T, extent_t Extent>
span_constexpr span<T> subspan(span<T, Extent> spn, size_t offset, extent_t count = dynamic_extent) {
    return spn.subspan(offset, count);
}

#endif  // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_SPAN )

#if span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_CONTAINER) && span_CPP11_120

template <extent_t Count, class T>
span_constexpr auto first(T& t) -> decltype(make_span(t).template first<Count>()) {
    return make_span(t).template first<Count>();
}

template <class T>
span_constexpr auto first(T& t, size_t count) -> decltype(make_span(t).first(count)) {
    return make_span(t).first(count);
}

template <extent_t Count, class T>
span_constexpr auto last(T& t) -> decltype(make_span(t).template last<Count>()) {
    return make_span(t).template last<Count>();
}

template <class T>
span_constexpr auto last(T& t, extent_t count) -> decltype(make_span(t).last(count)) {
    return make_span(t).last(count);
}

template <size_t Offset, extent_t Count = dynamic_extent, class T>
span_constexpr auto subspan(T& t) -> decltype(make_span(t).template subspan<Offset, Count>()) {
    return make_span(t).template subspan<Offset, Count>();
}

template <class T>
span_constexpr auto subspan(T& t, size_t offset, extent_t count = dynamic_extent) -> decltype(make_span(t).subspan(offset, count)) {
    return make_span(t).subspan(offset, count);
}

#endif  // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_CONTAINER )

}  // namespace span_lite
}  // namespace nonstd

// make available in nonstd:

namespace nonstd {
using span_lite::make_span;

#if span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_SPAN) || (span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_CONTAINER) && span_CPP11_120)

using span_lite::first;
using span_lite::last;
using span_lite::subspan;

#endif  // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_[SPAN|CONTAINER] )

}  // namespace nonstd

#endif  // #if span_FEATURE_TO_STD( MAKE_SPAN )

#if span_CPP11_OR_GREATER && span_FEATURE(BYTE_SPAN) && (span_HAVE(BYTE) || span_HAVE(NONSTD_BYTE))

namespace nonstd {
namespace span_lite {

template <class T>
inline span_constexpr auto byte_span(T& t) span_noexcept->span<std17::byte, span_sizeof(T)> {
    return span<std17::byte, span_sizeof(t)>(reinterpret_cast<std17::byte*>(&t), span_sizeof(T));
}

template <class T>
inline span_constexpr auto byte_span(T const& t) span_noexcept->span<const std17::byte, span_sizeof(T)> {
    return span<const std17::byte, span_sizeof(t)>(reinterpret_cast<std17::byte const*>(&t), span_sizeof(T));
}

}  // namespace span_lite
}  // namespace nonstd

// make available in nonstd:

namespace nonstd {
using span_lite::byte_span;
}  // namespace nonstd

#endif  // span_FEATURE( BYTE_SPAN )

#if span_HAVE(STRUCT_BINDING)

#if span_CPP14_OR_GREATER
#include <tuple>
#elif span_CPP11_OR_GREATER
#include <tuple>
namespace std {
template <std::size_t I, typename T>
using tuple_element_t = typename tuple_element<I, T>::type;
}
#else
namespace std {
template <typename T>
class tuple_size; /*undefined*/

template <std::size_t I, typename T>
class tuple_element; /* undefined */
}  // namespace std
#endif  // span_CPP14_OR_GREATER

namespace std {

// 26.7.X Tuple interface

// std::tuple_size<>:

template <typename ElementType, nonstd::span_lite::extent_t Extent>
class tuple_size<nonstd::span<ElementType, Extent> > : public integral_constant<size_t, static_cast<size_t>(Extent)> {};

// std::tuple_size<>: Leave undefined for dynamic extent:

template <typename ElementType>
class tuple_size<nonstd::span<ElementType, nonstd::dynamic_extent> >;

// std::tuple_element<>:

template <size_t I, typename ElementType, nonstd::span_lite::extent_t Extent>
class tuple_element<I, nonstd::span<ElementType, Extent> > {
   public:
#if span_HAVE(STATIC_ASSERT)
    static_assert(Extent != nonstd::dynamic_extent && I < Extent, "tuple_element<I,span>: dynamic extent or index out of range");
#endif
    using type = ElementType;
};

// std::get<>(), 2 variants:

template <size_t I, typename ElementType, nonstd::span_lite::extent_t Extent>
span_constexpr ElementType& get(nonstd::span<ElementType, Extent>& spn) span_noexcept {
#if span_HAVE(STATIC_ASSERT)
    static_assert(Extent != nonstd::dynamic_extent && I < Extent, "get<>(span): dynamic extent or index out of range");
#endif
    return spn[I];
}

template <size_t I, typename ElementType, nonstd::span_lite::extent_t Extent>
span_constexpr ElementType const& get(nonstd::span<ElementType, Extent> const& spn) span_noexcept {
#if span_HAVE(STATIC_ASSERT)
    static_assert(Extent != nonstd::dynamic_extent && I < Extent, "get<>(span): dynamic extent or index out of range");
#endif
    return spn[I];
}

}  // end namespace std

#endif  // span_HAVE( STRUCT_BINDING )

#if !span_USES_STD_SPAN
span_RESTORE_WARNINGS()
#endif  // span_USES_STD_SPAN

#endif  // NONSTD_SPAN_HPP_INCLUDED
