// bslstl_span.h                                                      -*-C++-*-
#ifndef INCLUDED_BSLSTL_SPAN
#define INCLUDED_BSLSTL_SPAN

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a (mostly) standard-compliant 'span' class template.
//
//@CLASSES:
//  bsl::span: C++03-compliant implementation of 'std::span'.
//
//@CANONICAL_HEADER: bslstl_span.h
//
//@SEE_ALSO: ISO C++ Standard
//
//@DESCRIPTION: This component provides the C+20 standard view type 'span',
// that is a view over a contiguous sequence of objects.  Note that if compiler
// supports the C++20 standard, then the 'std' implementation of 'span' is
// used.
//
// There are two implementations of 'span'; one for 'statically sized' (i. e.,
//  size fixed at compile time) spans, and 'dynamically sized' (size can be
//  altered at run-time).
//
// 'bsl::span' differs from 'std::span' in the following ways:
//: o The 'constexpr' inline symbol 'std::dynamic_extent' has been replaced by
//:   an enumeration for C++03 compatibility.
//: o A 'bsl::span' can be implicitly constructed from a 'bsl::array'.
//: o The implicit construction from an arbitrary container that supports
//:   'data()' and 'size()' is enabled only for C++11 and later.
//
///Usage
///-----
// This section illustrates intended usage of this component.
//
///Example 1: Using Span To Pass A Portion Of An Array As A Container
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we already have an array of values of type 'TYPE', and we want to
// pass a subset of the array to a function, which is expecting some kind of a
// container.   We can create a 'span' from the array, and then pass that.
// Since the span is a 'view' into the array, i.e, the span owns no storage,
// the elements in the span are the same as the ones in the array.
//
// First, we create a template function that takes a generic container.  This
// function inspects each of the (numeric) values in the container, and if the
// low bit is set, flips it.  This has the effect of turning odd values into
// even values.
//..
//  template <class CONTAINER>
//  void MakeEven(CONTAINER &c)
//      // Make every value in the specified container 'c' even.
//  {
//      for (typename CONTAINER::iterator it = c.begin();
//                                        it != c.end();
//                                        ++it) {
//          if (*it & 1) {
//              *it ^= 1;
//          }
//      }
//  }
//..
//  We then create a span, and verify that it contains the values that we
//  expect, and pass it to 'MakeEven' to modify it.  Afterwards, we check that
//  none of the elements in the array that were not included in the span are
//  unchanged, and the ones in the span were.
//..
//  int            arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
//  bsl::span<int> sp(arr + 3, 4);   // 4 elements, starting at 3.
//  for (int i = 0; i < 10; ++i)
//  {
//      assert(arr[i] == i);
//  }
//
//  assert(sp[0] == 3);
//  assert(sp[1] == 4);
//  assert(sp[2] == 5);
//  assert(sp[3] == 6);
//
//  MakeEven(sp);
//
//  assert(sp[0] == 2); // Has been changed
//  assert(sp[1] == 4);
//  assert(sp[2] == 4); // Has been changed
//  assert(sp[3] == 6);
//
//  assert(arr[0] == 0); // Not part of the span
//  assert(arr[1] == 1); // Not part of the span
//  assert(arr[2] == 2); // Not part of the span
//  assert(arr[3] == 2); // Has been changed
//  assert(arr[4] == 4);
//  assert(arr[5] == 4); // Has been changed
//  assert(arr[6] == 6);
//  assert(arr[7] == 7); // Not part of the span
//  assert(arr[8] == 8); // Not part of the span
//  assert(arr[9] == 9); // Not part of the span
//..
//
///Example 2: Returning A Subset Of A Container From A Function
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we already have a vector of values of type 'TYPE', and we want to
// return a (contiguous) subset of the vector from a function, which can then
// be processed processed using a range-based for loop.  To achieve that, we
// can use 'span' as the return type.  The calling code can then interate over
// the span as if it was a container.  Note that since the span doesn't own the
// elements of the vector, the span might become invalid when the vector is
// changed (or resized, or destroyed).
//
// First, we create the vector and define our function that returns a slice as
// a 'span'.
//..
//  bsl::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
//
//  bsl::span<const int> slice(const bsl::vector<int>& vec,
//                             size_t                  first,
//                             size_t                  last)
//      // Return a span into the specified 'vec', starting at the specified
//      // 'first' index, and continuing up to (but not including) the
//      // specified 'last' index.
//  {
//      return bsl::span<const int>(vec.data() + first, last-first);
//  }
//..
//  We can now iterate over the elements in the slice using the span:
//..
//  bsl::span<const int> sp = slice(v, 4, 7);
//  int            val = 4;
//  for (int x: sp) {
//       assert(x == val++);
//   }
//..
//  Note that we can use the return value directly and avoid declaring the
//  variable 'sp':
//..
//   val = 2;
//   for (int x: slice(v, 2, 8)) {
//       assert(x == val++);
//   }
//..

#include <bslscm_version.h>

#include <bsls_compilerfeatures.h>
#include <bsls_libraryfeatures.h>

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP20_BASELINE_LIBRARY
#include <span>
namespace bsl {
    using std::dynamic_extent;
    using std::span;
    using std::as_bytes;
    using std::as_writable_bytes;
}
#else

#include <bslmf_assert.h>
#include <bslmf_enableif.h>
#include <bslmf_integralconstant.h>
#include <bslmf_isconvertible.h>
#include <bslmf_removepointer.h>
#include <bslmf_removecv.h>

#include <bsls_assert.h>
#include <bsls_keyword.h>
#include <bsls_nullptr.h>

#include <bslstl_array.h>
#include <bslstl_iterator.h>
#include <bslstl_vector.h>

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
#include <array>     // 'std::array'
#endif
#include <iterator>  // 'reverse_iterator', '!='
#include <stddef.h>  // 'size_t', 'NULL', 'std::byte'

namespace bsl {

enum { dynamic_extent = size_t(-1) };

template <class TYPE, size_t EXTENT = dynamic_extent> class span;


                        // ===================
                        // struct Span_Utility
                        // ===================
struct Span_Utility
    // This component-private struct provides a namespace for meta-programming
    // utilities used by the 'span' implementation.
{
    // PUBLIC TYPES
    template <class FROM, class TO>
    struct IsArrayConvertible : public bsl::integral_constant<bool,
                              bsl::is_convertible<FROM(*)[], TO(*)[]>::value>
    {};

    template <class TYPE, size_t EXTENT, size_t COUNT, size_t OFFSET>
    struct SubspanReturnType
    {
        // PUBLIC TYPES
        typedef bsl::span<TYPE, COUNT != dynamic_extent
          ? COUNT
          : EXTENT - OFFSET> type;

    };

    template <class TYPE>
    struct TypeIdentity
    {
        // PUBLIC TYPES
        typedef TYPE type;
    };

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
    template <class TP>
    struct IsSpanImpl : public bsl::false_type {};

    template <class TP, size_t SZ>
    struct IsSpanImpl<span<TP, SZ> > : public bsl::true_type {};

    template <class TP>
    struct IsSpan : public IsSpanImpl<typename bsl::remove_cv<TP>::type> {};

    template <class TP>
    struct IsBSLArrayImpl : public bsl::false_type {};

    template <class TP, size_t SZ>
    struct IsBSLArrayImpl<bsl::array<TP, SZ> > : public bsl::true_type {};

    template <class TP>
    struct IsBSLArray
                : public IsBSLArrayImpl<typename bsl::remove_cv<TP>::type> {};

    template <class TP>
    struct IsSTDArrayImpl : public bsl::false_type {};

    template <class TP, size_t SZ>
    struct IsSTDArrayImpl<std::array<TP, SZ> > : public bsl::true_type {};

    template <class TP>
    struct IsSTDArray
                : public IsSTDArrayImpl<typename bsl::remove_cv<TP>::type> {};

    template <class TP, class ELEMENT_TYPE, class = void>
    struct IsSpanCompatibleContainer : public bsl::false_type {};

    template <class TP, class ELEMENT_TYPE>
    struct IsSpanCompatibleContainer<TP, ELEMENT_TYPE,
        bsl::void_t<
        // is not a specialization of span
            typename bsl::enable_if<!IsSpan<TP>::value, bsl::nullptr_t>::type,
        // is not a specialization of bsl::array
            typename bsl::enable_if<
                                 !IsBSLArray<TP>::value, bsl::nullptr_t>::type,
        // is not a specialization of std::array
            typename bsl::enable_if<
                                 !IsSTDArray<TP>::value, bsl::nullptr_t>::type,
        // is not a C-style array
            typename bsl::enable_if<
                              !bsl::is_array<TP>::value, bsl::nullptr_t>::type,
        // data(cont) and size(cont) are well formed
            decltype(data(std::declval<TP>())),
            decltype(size(std::declval<TP>())),
        // The underlying types are compatible
            typename bsl::enable_if<
                Span_Utility::IsArrayConvertible<
                   typename bsl::remove_pointer<
                                   decltype(data(std::declval<TP &>()))>::type,
                   ELEMENT_TYPE>::value,
                bsl::nullptr_t>::type
            > >
        : public bsl::true_type {};
#endif

};

template <class TYPE, size_t EXTENT>
class span {

  public:
    // PUBLIC TYPES
    typedef TYPE                                   element_type;
    typedef typename bsl::remove_cv<TYPE>::type    value_type;
    typedef size_t                                 size_type;
    typedef ptrdiff_t                              difference_type;
    typedef TYPE                                  *pointer;
    typedef const TYPE                            *const_pointer;
    typedef TYPE&                                  reference;
    typedef const TYPE&                            const_reference;
    typedef pointer                                iterator;
    typedef bsl::reverse_iterator<iterator>        reverse_iterator;

// BDE_VERIFY pragma: push
// BDE_VERIFY pragma: -MN03  // Constant ... names must begin with 's_' or 'k_'
    // PUBLIC CLASS DATA
    static BSLS_KEYWORD_CONSTEXPR_MEMBER size_type extent = EXTENT;
// BDE_VERIFY pragma: pop

    // CREATORS
    BSLS_KEYWORD_CONSTEXPR_CPP14 span() BSLS_KEYWORD_NOEXCEPT;
        // Construct an empty 'span' object.  The behavior is undefined unless
        // '0 == EXTENT'

    BSLS_KEYWORD_CONSTEXPR_CPP14 span(const span& original)
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Create a span that refers to the same data as the specified
        // 'original' object.

    BSLS_KEYWORD_CONSTEXPR_CPP14 explicit span(pointer ptr, size_type count);
        // Construct a span that refers to the specified 'count' consecutive
        // objects starting from the specified 'ptr'.  The behavior is
        // undefined unless 'EXTENT == count'.

    BSLS_KEYWORD_CONSTEXPR_CPP14 explicit span(pointer first, pointer last);
        // Construct a span from the specified 'first' and specified 'last'.
        // The behavior is undefined unless
        // 'EXTENT == bsl::distance(first, last)'.

    template <size_t SIZE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
          typename Span_Utility::TypeIdentity<element_type>::type (&arr)[SIZE])
          BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified C-style array 'arr'.  The
        // behavior is undefined unless 'SIZE == EXTENT'.

#ifndef BSLSTL_ARRAY_IS_ALIASED
    template <class t_OTHER_TYPE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
       bsl::array<t_OTHER_TYPE, EXTENT>& arr,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified bsl::array 'arr'.  This
        // constructor participates in overload resolution only if
        // 't_OTHER_TYPE(*)[]' is convertible to 'element_type(*)[]'.

    template <class t_OTHER_TYPE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
     const bsl::array<t_OTHER_TYPE, EXTENT>& arr,
     typename bsl::enable_if<
         Span_Utility::IsArrayConvertible<
                                      const t_OTHER_TYPE, element_type>::value,
         void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified bsl::array 'arr'.  This
        // constructor participates in overload resolution only if
        // 't_OTHER_TYPE(*)[]' is convertible to 'element_type(*)[]'.
#endif

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
    template <class t_OTHER_TYPE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
           std::array<t_OTHER_TYPE, EXTENT>& arr,
           typename bsl::enable_if<
               Span_Utility::IsArrayConvertible<
                                            t_OTHER_TYPE, element_type>::value,
               void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified std::array 'arr'.  This
        // constructor participates in overload resolution only if
        // 't_OTHER_TYPE(*)[]' is convertible to 'element_type(*)[]'.

    template <class t_OTHER_TYPE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
     const std::array<t_OTHER_TYPE, EXTENT>& arr,
     typename bsl::enable_if<
         Span_Utility::IsArrayConvertible<
                                      const t_OTHER_TYPE, element_type>::value,
         void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified std::array 'arr'.  This
        // constructor participates in overload resolution only if
        // 't_OTHER_TYPE(*)[]' is convertible to 'element_type(*)[]'.
#endif

    template <class t_OTHER_TYPE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
           const span<t_OTHER_TYPE, EXTENT>& other,
           typename bsl::enable_if<
               Span_Utility::IsArrayConvertible<
                                            t_OTHER_TYPE, element_type>::value,
               void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified span 'other'.  This constructor
        // participates in overload resolution only if 't_OTHER_TYPE(*)[]' is
        // convertible to 'element_type(*)[]'.

    template <class t_OTHER_TYPE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
            const span<t_OTHER_TYPE, dynamic_extent>& other,
            typename bsl::enable_if<
               Span_Utility::IsArrayConvertible<
                                            t_OTHER_TYPE, element_type>::value,
               void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified span 'other'.  This constructor
        // participates in overload resolution only if 't_OTHER_TYPE(*)[]' is
        // convertible to 'element_type(*)[]'.  The behavior is undefined
        // unless 'other.size() == EXTENT'.

    //  ~span() noexcept = default;
        // Destroy this object.

    // ACCESSORS
    BSLS_KEYWORD_CONSTEXPR_CPP14 reference back() const BSLS_KEYWORD_NOEXCEPT
        // Return a reference to the last element of this span.  The behavior
        // is undefined if this span is empty.
    {
        // Implemented inline because of Sun/AIX compiler limitations.
        BSLMF_ASSERT(EXTENT > 0);
        return d_data_p[size() - 1];
    }

    BSLS_KEYWORD_CONSTEXPR pointer data() const BSLS_KEYWORD_NOEXCEPT;
        // Return a pointer to the data referenced by this span.

    BSLS_KEYWORD_CONSTEXPR bool empty() const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this span contains no elements and 'false'
        // otherwise.

    template <size_t COUNT>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, COUNT> first() const BSLS_KEYWORD_NOEXCEPT;
        // Return a statically-sized span consisting of the first 'COUNT'
        // elements of this span.  The behavior is undefined unless
        // 'COUNT <= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, dynamic_extent>
    first(size_type count) const BSLS_KEYWORD_NOEXCEPT;
        // Return a dynamically-sized span consisting of the first (specified)
        // 'count' elements of this span.  The behavior is undefined unless
        // 'count <= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14 reference front() const BSLS_KEYWORD_NOEXCEPT
        // Return a reference to the first element of this span.  The behavior
        // is undefined if this span is empty.
    {
        // Implemented inline because of Sun/AIX compiler limitations.
        BSLMF_ASSERT(EXTENT > 0);
        return d_data_p[0];
    }

    template <size_t COUNT>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, COUNT> last() const BSLS_KEYWORD_NOEXCEPT;
        // Return a statically-sized span consisting of the last 'COUNT'
        // elements of this span.  The behavior is undefined unless
        // 'COUNT <= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, dynamic_extent>
    last(size_type count) const BSLS_KEYWORD_NOEXCEPT;
        // Return a dynamically-sized span consisting of the last (specified)
        // 'count' elements of this span.  The behavior is undefined unless
        // 'count <= size()'.

    BSLS_KEYWORD_CONSTEXPR size_type size() const BSLS_KEYWORD_NOEXCEPT
        // Return the size of this span.
    {
        // Implemented inline because of Sun/AIX compiler limitations.
        return EXTENT;
    }

    BSLS_KEYWORD_CONSTEXPR size_type size_bytes() const BSLS_KEYWORD_NOEXCEPT;
        // Return the size of this span in bytes.

    template <size_t OFFSET,
#ifdef BSLS_COMPILERFEATURES_SUPPORT_DEFAULT_TEMPLATE_ARGS
              size_t COUNT = dynamic_extent>
#else
              size_t COUNT>
#endif
    BSLS_KEYWORD_CONSTEXPR_CPP14
    typename Span_Utility::SubspanReturnType<TYPE, EXTENT, COUNT, OFFSET>::type
    subspan() const BSLS_KEYWORD_NOEXCEPT
        // If the template parameter 'COUNT' is 'dynamic_extent', return a
        // dynamically-sized span consisting consisting of the elements of this
        // span in the half-open range '[OFFSET, EXTENT)'.  Otherwise, return a
        // statically-sized span consisting of the elements of this span in the
        // half-open range '[OFFSET, OFFSET+COUNT)'.  The behavior is undefined
        // unless 'OFFSET <= EXTENT'.  If 'COUNT != dynamic_extent', the
        // behavior is undefined unless 'OFFSET + COUNT <= EXTENT'.
    {
        // Implemented inline because of Sun/AIX compiler limitations.
        typedef typename
            Span_Utility::SubspanReturnType<TYPE, EXTENT, COUNT, OFFSET>::type
                                                                    ReturnType;
        BSLMF_ASSERT(OFFSET <= EXTENT);
        BSLMF_ASSERT(COUNT == dynamic_extent || OFFSET + COUNT <= EXTENT);
        return ReturnType(data() + OFFSET,
                            COUNT == dynamic_extent ? size() - OFFSET : COUNT);
    }

    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, dynamic_extent>
    subspan(size_type offset, size_type count = dynamic_extent)
                                                   const BSLS_KEYWORD_NOEXCEPT;
        // Return a dynamically-sized span starting at the specified 'offset'.
        // If the optionally specified 'count' is 'dynamic_extent', the span
        // will consist of the half-open range '[offset, size () - offset)' and
        // the behavior is undefined if 'offset > size()'.  Otherwise, the span
        // will consist of the half-open range '[offset, count)' and the
        // behavior is undefined if 'offset + count > size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reference operator[](size_type index) const BSLS_KEYWORD_NOEXCEPT
        // Return a reference to the element at the specified 'index'.  The
        // behavior is undefined unless 'index < size()'.
    {
        // Implemented inline because of Sun/AIX compiler limitations.
        BSLS_ASSERT(index < size());
        return d_data_p[index];
    }

    //                      ITERATOR OPERATIONS
    BSLS_KEYWORD_CONSTEXPR_CPP14 iterator begin() const BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing modifiable access to the first element
        // of this span, and the past-the-end iterator if this span is empty.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    iterator end() const BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end iterator providing modifiable access to this
        //  span.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reverse_iterator rbegin() const BSLS_KEYWORD_NOEXCEPT;
        // Return a reverse iterator providing modifiable access to the last
        // element of this span, and the past-the-end reverse iterator if this
        // span is empty.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reverse_iterator rend() const BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end reverse iterator providing modifiable access
        // to this span.

    // MANIPULATORS
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span& operator=(const span&) BSLS_KEYWORD_NOEXCEPT;
        // Assign to this span the value of the specified 'rhs' object, and
        // return a reference providing modifiable access to this span.

    BSLS_KEYWORD_CONSTEXPR_CPP14 void swap(span &other) BSLS_KEYWORD_NOEXCEPT;
        // Exchange the value of this span with the value of the specified
        // 'other' object.

  private:
    // DATA
    pointer    d_data_p;
};


template <class TYPE>
class span<TYPE, dynamic_extent> {
  public:
    // PUBLIC TYPES
    typedef TYPE                                   element_type;
    typedef typename bsl::remove_cv<TYPE>::type    value_type;
    typedef size_t                                 size_type;
    typedef ptrdiff_t                              difference_type;
    typedef TYPE                                  *pointer;
    typedef const TYPE                            *const_pointer;
    typedef TYPE&                                  reference;
    typedef const TYPE&                            const_reference;
    typedef pointer                                iterator;
    typedef bsl::reverse_iterator<iterator>        reverse_iterator;

// BDE_VERIFY pragma: push
// BDE_VERIFY pragma: -MN03  // Constant ... names must begin with 's_' or 'k_'
    // PUBLIC CLASS DATA
    static BSLS_KEYWORD_CONSTEXPR_MEMBER size_type extent = dynamic_extent;
// BDE_VERIFY pragma: pop

    // CREATORS
    BSLS_KEYWORD_CONSTEXPR_CPP14 span() BSLS_KEYWORD_NOEXCEPT;
        // Construct an empty 'span' object.

    BSLS_KEYWORD_CONSTEXPR_CPP14 span(const span& original)
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Create a span that refers to the same data as the specified
        // 'original' object.

    BSLS_KEYWORD_CONSTEXPR_CPP14 span(pointer ptr, size_type count);
        // Construct a span that refers to the specified 'count' consecutive
        // objects starting from the specified 'ptr'.

    BSLS_KEYWORD_CONSTEXPR_CPP14 span(pointer first, pointer last);
        // Construct a span from the specified 'first' and specified 'last'.

    template <size_t SIZE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
          typename Span_Utility::TypeIdentity<element_type>::type (&arr)[SIZE])
          BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified C-style array 'arr'.

#ifndef BSLSTL_ARRAY_IS_ALIASED
    template <class t_OTHER_TYPE, size_t SIZE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(bsl::array<t_OTHER_TYPE, SIZE>& arr,
           typename bsl::enable_if<
               Span_Utility::IsArrayConvertible<
                                            t_OTHER_TYPE, element_type>::value,
               void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified bsl::array 'arr'.  This
        // constructor participates in overload resolution only if
        // 't_OTHER_TYPE(*)[]' is convertible to 'element_type(*)[]'.

    template <class t_OTHER_TYPE, size_t SIZE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
                                     const bsl::array<t_OTHER_TYPE, SIZE>& arr,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<
                                      const t_OTHER_TYPE, element_type>::value,
           void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified bsl::array 'arr'.  This
        // constructor participates in overload resolution only if
        // 't_OTHER_TYPE(*)[]' is convertible to 'element_type(*)[]'.
#endif

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
    template <class t_OTHER_TYPE, size_t SIZE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(std::array<t_OTHER_TYPE, SIZE>& arr,
           typename bsl::enable_if<
               Span_Utility::IsArrayConvertible<
                                            t_OTHER_TYPE, element_type>::value,
               void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified std::array 'arr'.  This
        // constructor participates in overload resolution only if
        // 't_OTHER_TYPE(*)[]' is convertible to 'element_type(*)[]'.

    template <class t_OTHER_TYPE, size_t SIZE>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
     const std::array<t_OTHER_TYPE, SIZE>& arr,
     typename bsl::enable_if<
         Span_Utility::IsArrayConvertible<
                                      const t_OTHER_TYPE, element_type>::value,
         void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified std::array 'arr'.  This
        // constructor participates in overload resolution only if
        // 't_OTHER_TYPE(*)[]' is convertible to 'element_type(*)[]'.
#endif

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
    template <class CONTAINER>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
         CONTAINER& c,
         typename bsl::enable_if<
             Span_Utility::IsSpanCompatibleContainer<CONTAINER, TYPE>::value,
             void *>::type = NULL)
    : d_data_p(bsl::data(c))
    , d_size(bsl::size(c))
    {
    }

    template <class CONTAINER>
    BSLS_KEYWORD_CONSTEXPR_CPP14 span(
       const CONTAINER& c,
       typename bsl::enable_if<
         Span_Utility::IsSpanCompatibleContainer<const CONTAINER, TYPE>::value,
         void *>::type = NULL)
    : d_data_p(bsl::data(c))
    , d_size(bsl::size(c))
    {
    }
#endif

    template <class t_OTHER_TYPE, size_t OTHER_EXTENT>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span(const span<t_OTHER_TYPE, OTHER_EXTENT>& other,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
        // Construct a span from the specified span 'other'.  This constructor
        // participates in overload resolution only if 't_OTHER_TYPE(*)[]' is
        // convertible to 'element_type(*)[]'.

    //  ~span() noexcept = default;
        // Destroy this object.

    // ACCESSORS
    BSLS_KEYWORD_CONSTEXPR_CPP14 reference back() const BSLS_KEYWORD_NOEXCEPT;
        // Return a reference to the last element of this span.  The behavior
        // is undefined if this span is empty.

    BSLS_KEYWORD_CONSTEXPR pointer data() const BSLS_KEYWORD_NOEXCEPT;
        // Return a pointer to the data referenced by this span.

    BSLS_KEYWORD_CONSTEXPR bool empty() const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if 'size() == 0' and 'false' otherwise.

    template <size_t COUNT>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, COUNT> first() const BSLS_KEYWORD_NOEXCEPT;
        // Return a statically-sized span consisting of the first 'COUNT'
        // elements of this span.  The behavior is undefined unless
        // 'COUNT <= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, dynamic_extent>
    first(size_type count) const BSLS_KEYWORD_NOEXCEPT;
        // Return a dynamically-sized span consisting of the first (specified)
        // 'count' elements of this span.  The behavior is undefined unless
        // 'count <= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14 reference front() const BSLS_KEYWORD_NOEXCEPT;
        // Return a reference to the first element of this span.  The behavior
        // is undefined if this span is empty.

    template <size_t COUNT>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, COUNT> last() const BSLS_KEYWORD_NOEXCEPT;
        // Return a statically-sized span consisting of the last 'COUNT'
        // elements of this span.  The behavior is undefined unless
        // 'COUNT <= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, dynamic_extent>
    last(size_type count) const BSLS_KEYWORD_NOEXCEPT;
        // Return a dynamically-sized span consisting of the last (specified)
        // 'count' elements of this span.  The behavior is undefined unless
        // 'count <= size()'.

    BSLS_KEYWORD_CONSTEXPR size_type size() const BSLS_KEYWORD_NOEXCEPT;
        // Return the size of this span.

    BSLS_KEYWORD_CONSTEXPR size_type size_bytes() const BSLS_KEYWORD_NOEXCEPT;
        // Return the size of this span in bytes.

    template <size_t OFFSET,
#ifdef BSLS_COMPILERFEATURES_SUPPORT_DEFAULT_TEMPLATE_ARGS
              size_t COUNT = dynamic_extent>
#else
              size_t COUNT>
#endif
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, COUNT> subspan() const BSLS_KEYWORD_NOEXCEPT;
        // Return a dynamically-sized span consisting of the 'COUNT' elements
        // of this span starting at 'OFFSET'.  The behavior is undefined unless
        // 'COUNT + OFFSET <= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14 span<element_type, dynamic_extent>
    subspan(size_type offset, size_type count = dynamic_extent)
                                                   const BSLS_KEYWORD_NOEXCEPT;
        // Return a dynamically-sized span starting at the specified 'offset'.
        // If the optionally specified 'count' is 'dynamic_extent', the span
        // will consist of the half-open range '[offset, size () - offset)' and
        // the behavior is undefined unless 'offset <= size()'.  Otherwise, the
        // span will consist of the half-open range '[offset, count)' and the
        // behavior is undefined unless 'offset + count <= size()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reference operator[](size_type index) const BSLS_KEYWORD_NOEXCEPT;
        // Return a reference to the element at the specified 'index'.  The
        // behavior is undefined unless 'index < size()'.

    //                      ITERATOR OPERATIONS
    BSLS_KEYWORD_CONSTEXPR_CPP14 iterator begin() const BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing modifiable access to the first element
        // of this span, and the past-the-end iterator if this span is empty.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    iterator end() const BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end iterator providing modifiable access to this
        //  span.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reverse_iterator rbegin() const BSLS_KEYWORD_NOEXCEPT;
        // Return a reverse iterator providing modifiable access to the last
        // element of this span, and the past-the-end reverse iterator if this
        // span is empty.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    reverse_iterator rend() const BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end reverse iterator providing modifiable access
        // to this span.

    // MANIPULATORS
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span& operator=(const span& rhs) BSLS_KEYWORD_NOEXCEPT
        // Assign to this span the value of the specified 'rhs' object, and
        // return a reference providing modifiable access to this span.
    {
        d_data_p = rhs.d_data_p;
        d_size = rhs.d_size;
        return *this;
    }

    BSLS_KEYWORD_CONSTEXPR_CPP14 void swap(span &other) BSLS_KEYWORD_NOEXCEPT;
        // Exchange the value of this span with the value of the specified
        // 'other' object.

  private:
    // DATA
    pointer   d_data_p;
    size_type d_size;
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
// CLASS TEMPLATE DEDUCTION GUIDES

template <class TYPE, size_t SIZE>
span(TYPE (&)[SIZE]) -> span<TYPE, SIZE>;
    // Deduce the template parameters 'TYPE' and 'SIZE' from the type and size
    // of the array supplied to the constructor of 'span'.

#ifndef BSLSTL_ARRAY_IS_ALIASED
template <class TYPE, size_t SIZE>
span(bsl::array<TYPE, SIZE> &) -> span<TYPE, SIZE>;
    // Deduce the template parameters 'TYPE' and 'SIZE' from the corresponding
    // template parameters of the 'bsl::array' supplied to the constructor of
    // 'span'.

template <class TYPE, size_t SIZE>
span(const bsl::array<TYPE, SIZE> &) -> span<const TYPE, SIZE>;
    // Deduce the template parameters 'TYPE' and 'SIZE' from the corresponding
    // template parameters of the 'bsl::array' supplied to the constructor of
    // 'span'.
#endif

template <class TYPE, size_t SIZE>
span(std::array<TYPE, SIZE> &) -> span<TYPE, SIZE>;
    // Deduce the template parameters 'TYPE' and 'SIZE' from the corresponding
    // template parameters of the 'std::array' supplied to the constructor of
    // 'span'.

template <class TYPE, size_t SIZE>
span(const std::array<TYPE, SIZE> &) -> span<const TYPE, SIZE>;
    // Deduce the template parameters 'TYPE' and 'SIZE' from the corresponding
    // template parameters of the 'std::array' supplied to the constructor of
    // 'span'.

template <class TYPE, class ALLOCATOR>
span(bsl::vector<TYPE, ALLOCATOR> &) -> span<TYPE>;
    // Deduce the template parameters 'TYPE' from the corresponding template
    // parameter of the 'bsl::vector' supplied to the constructor of 'span'.

template <class TYPE, class ALLOCATOR>
span(const bsl::vector<TYPE, ALLOCATOR> &) -> span<const TYPE>;
    // Deduce the template parameters 'TYPE' from the corresponding template
    // parameter of the 'bsl::vector' supplied to the constructor of 'span'.
#endif

// FREE FUNCTIONS
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 span<const std::byte, EXTENT * sizeof(TYPE)>
as_bytes(span<TYPE, EXTENT> s) BSLS_KEYWORD_NOEXCEPT;
    // Return a span referring to to same data as the specified 's', but
    // referring to the data as a span of non-modifiable bytes.

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 span<const std::byte, dynamic_extent>
as_bytes(span<TYPE, dynamic_extent> s) BSLS_KEYWORD_NOEXCEPT;
    // Return a span referring to to same data as the specified 's', but
    // referring to the data as a span of non-modifiable bytes.

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 span<std::byte, EXTENT * sizeof(TYPE)>
as_writable_bytes(span<TYPE, EXTENT> s) BSLS_KEYWORD_NOEXCEPT;
    // Return a span referring to to same data as the specified 's', but
    // referring to the data as a span of modifiable bytes.

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 span<std::byte, dynamic_extent>
as_writable_bytes(span<TYPE, dynamic_extent> s) BSLS_KEYWORD_NOEXCEPT;
    // Return a span referring to to same data as the specified 's', but
    // referring to the data as a span of modifiable bytes.

#endif

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 void swap(span<TYPE, EXTENT>& a,
                                       span<TYPE, EXTENT>& b)
                                                         BSLS_KEYWORD_NOEXCEPT;
    // Exchange the value of the specified 'a' object with the value of the
    // specified 'b' object.

}  // close namespace bsl

// ============================================================================
//                           INLINE DEFINITIONS
// ============================================================================

                            // ----------------
                            // class span<T, N>
                            // ----------------

// CREATORS
template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span() BSLS_KEYWORD_NOEXCEPT
: d_data_p(NULL)
{
    BSLMF_ASSERT(EXTENT == 0);
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(const span &original) BSLS_KEYWORD_NOEXCEPT
: d_data_p(original.d_data_p)
{
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(pointer ptr, size_type count)
: d_data_p(ptr)
{
    (void)count;
    BSLS_ASSERT(EXTENT == count);
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(pointer first, pointer last)
: d_data_p(first)
{
    (void)last;
    BSLS_ASSERT(EXTENT == bsl::distance(first, last));
}


template <class TYPE, size_t EXTENT>
template <size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(
     typename bsl::Span_Utility::TypeIdentity<element_type>::type (&arr)[SIZE])
                                                          BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr)
{
    BSLMF_ASSERT(SIZE == EXTENT);
}

#ifndef BSLSTL_ARRAY_IS_ALIASED
template <class TYPE, size_t EXTENT>
template <class t_OTHER_TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(bsl::array<t_OTHER_TYPE, EXTENT>& arr,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr.data())
{
}

template <class TYPE, size_t EXTENT>
template <class t_OTHER_TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(const bsl::array<t_OTHER_TYPE, EXTENT>& arr,
    typename bsl::enable_if<
        Span_Utility::IsArrayConvertible<
                                      const t_OTHER_TYPE, element_type>::value,
        void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr.data())
{
}
#endif

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
template <class TYPE, size_t EXTENT>
template <class t_OTHER_TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(std::array<t_OTHER_TYPE, EXTENT>& arr,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr.data())
{
}

template <class TYPE, size_t EXTENT>
template <class t_OTHER_TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(const std::array<t_OTHER_TYPE, EXTENT>& arr,
   typename bsl::enable_if<
     Span_Utility::IsArrayConvertible<const t_OTHER_TYPE, element_type>::value,
     void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr.data())
{
}
#endif

template <class TYPE, size_t EXTENT>
template <class t_OTHER_TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(const bsl::span<t_OTHER_TYPE, EXTENT>& other,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(other.data())
{
}


template <class TYPE, size_t EXTENT>
template <class t_OTHER_TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>::span(
       const bsl::span<t_OTHER_TYPE, bsl::dynamic_extent>& other,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(other.data())
{
    BSLS_ASSERT(EXTENT == other.size());
}

// ACCESSORS
template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR inline
typename bsl::span<TYPE, EXTENT>::pointer
bsl::span<TYPE, EXTENT>::data() const BSLS_KEYWORD_NOEXCEPT
{
    return d_data_p;
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR inline
bool bsl::span<TYPE, EXTENT>::empty() const BSLS_KEYWORD_NOEXCEPT
{
    return 0 == EXTENT;
}

template <class TYPE, size_t EXTENT>
template <size_t COUNT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, COUNT>
bsl::span<TYPE, EXTENT>::first() const BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, COUNT> ReturnType;
    BSLMF_ASSERT(COUNT <= EXTENT);
    return ReturnType(data(), COUNT);
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>
bsl::span<TYPE, EXTENT>::first(size_type count) const BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, bsl::dynamic_extent> ReturnType;
    BSLS_ASSERT(count <= size());
    return ReturnType(data(), count);
}

template <class TYPE, size_t EXTENT>
template <size_t COUNT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, COUNT>
bsl::span<TYPE, EXTENT>::last() const BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, COUNT> ReturnType;
    BSLMF_ASSERT(COUNT <= EXTENT);
    return ReturnType(data() + size() - COUNT, COUNT);
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>
bsl::span<TYPE, EXTENT>::last(size_type count) const BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, bsl::dynamic_extent> ReturnType;
    BSLS_ASSERT(count <= size());
    return ReturnType(data() + size() - count, count);
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR inline
typename bsl::span<TYPE, EXTENT>::size_type
bsl::span<TYPE, EXTENT>::size_bytes() const BSLS_KEYWORD_NOEXCEPT
{
    return EXTENT * sizeof(element_type);
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>
bsl::span<TYPE, EXTENT>::subspan(size_type offset, size_type count) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, bsl::dynamic_extent> ReturnType;
    BSLS_ASSERT(offset <= size());
    BSLS_ASSERT(count  <= size() || count == bsl::dynamic_extent);
    if (count == bsl::dynamic_extent)
        return ReturnType(data() + offset, size() - offset);          // RETURN

    BSLS_ASSERT(offset <= size() - count);
    return ReturnType(data() + offset, count);
}

//                          ITERATOR OPERATIONS
template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, EXTENT>::iterator
bsl::span<TYPE, EXTENT>::begin() const BSLS_KEYWORD_NOEXCEPT
{
    return iterator(data());
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, EXTENT>::iterator
bsl::span<TYPE, EXTENT>::end() const BSLS_KEYWORD_NOEXCEPT
{
    return iterator(data() + size());
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, EXTENT>::reverse_iterator
bsl::span<TYPE, EXTENT>::rbegin() const BSLS_KEYWORD_NOEXCEPT
{
    return reverse_iterator(end());
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, EXTENT>::reverse_iterator
bsl::span<TYPE, EXTENT>::rend() const BSLS_KEYWORD_NOEXCEPT
{
    return reverse_iterator(begin());
}

// MANIPULATORS
template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, EXTENT>&
bsl::span<TYPE, EXTENT>::operator=(const span &rhs) BSLS_KEYWORD_NOEXCEPT
{
    d_data_p = rhs.d_data_p;
    return *this;
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
void bsl::span<TYPE, EXTENT>::swap(span &other) BSLS_KEYWORD_NOEXCEPT
{
    pointer p = d_data_p;
    d_data_p = other.d_data_p;
    other.d_data_p = p;
}

              // -----------------------------------------
              // class span<T, bsl::dynamic_extent>
              // -----------------------------------------

// CREATORS
template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span() BSLS_KEYWORD_NOEXCEPT
: d_data_p(NULL)
, d_size(0)
{
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(const span& original)
                                                          BSLS_KEYWORD_NOEXCEPT
: d_data_p(original.d_data_p)
, d_size(original.d_size)
{
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(pointer ptr, size_type count)
: d_data_p(ptr)
, d_size(count)
{
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(pointer first, pointer last)
: d_data_p(first)
, d_size(bsl::distance(first, last))
{
}


template <class TYPE>
template <size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(
     typename bsl::Span_Utility::TypeIdentity<element_type>::type (&arr)[SIZE])
                                                          BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr)
, d_size(SIZE)
{
}

#ifndef BSLSTL_ARRAY_IS_ALIASED
template <class TYPE>
template <class t_OTHER_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(
       bsl::array<t_OTHER_TYPE, SIZE>& arr,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr.data())
, d_size(SIZE)
{
}

template <class TYPE>
template <class t_OTHER_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(
  const bsl::array<t_OTHER_TYPE, SIZE>& arr,
  typename bsl::enable_if<
     Span_Utility::IsArrayConvertible<const t_OTHER_TYPE, element_type>::value,
     void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr.data())
, d_size(SIZE)
{
}
#endif

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
template <class TYPE>
template <class t_OTHER_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(
       std::array<t_OTHER_TYPE, SIZE>& arr,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr.data())
, d_size(SIZE)
{
}

template <class TYPE>
template <class t_OTHER_TYPE, size_t SIZE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(
    const std::array<t_OTHER_TYPE, SIZE>& arr,
        typename bsl::enable_if<
            Span_Utility::IsArrayConvertible<
                                      const t_OTHER_TYPE, element_type>::value,
            void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(arr.data())
, d_size(SIZE)
{
}
#endif

template <class TYPE>
template <class t_OTHER_TYPE, size_t OTHER_EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>::span(
       const bsl::span<t_OTHER_TYPE, OTHER_EXTENT>& other,
       typename bsl::enable_if<
           Span_Utility::IsArrayConvertible<t_OTHER_TYPE, element_type>::value,
           void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(other.data())
, d_size(other.size())
{
}

// ACCESSORS
template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, bsl::dynamic_extent>::reference
bsl::span<TYPE, bsl::dynamic_extent>::back() const BSLS_KEYWORD_NOEXCEPT
{
    BSLS_ASSERT(size() > 0);
    return d_data_p[size() - 1];
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR inline
typename bsl::span<TYPE, bsl::dynamic_extent>::pointer
bsl::span<TYPE, bsl::dynamic_extent>::data() const BSLS_KEYWORD_NOEXCEPT
{
    return d_data_p;
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR inline
bool
bsl::span<TYPE, bsl::dynamic_extent>::empty() const BSLS_KEYWORD_NOEXCEPT
{
    return 0 == size();
}

template <class TYPE>
template <size_t COUNT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, COUNT>
bsl::span<TYPE, bsl::dynamic_extent>::first() const BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, COUNT> ReturnType;
    BSLS_ASSERT(COUNT <= size());
    return ReturnType(data(), COUNT);
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>
bsl::span<TYPE, bsl::dynamic_extent>::first(size_type count) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, bsl::dynamic_extent> ReturnType;
    BSLS_ASSERT(count <= size());
    return ReturnType(data(), count);
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, bsl::dynamic_extent>::reference
bsl::span<TYPE, bsl::dynamic_extent>::front() const BSLS_KEYWORD_NOEXCEPT
{
    BSLS_ASSERT(size() > 0);
    return d_data_p[0];
}

template <class TYPE>
template <size_t COUNT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, COUNT>
bsl::span<TYPE, bsl::dynamic_extent>::last() const BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, COUNT> ReturnType;
    BSLS_ASSERT(COUNT <= size());
    return ReturnType(data() + size() - COUNT, COUNT);
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>
bsl::span<TYPE, bsl::dynamic_extent>::last(size_type count) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, bsl::dynamic_extent> ReturnType;
    BSLS_ASSERT(count <= size());
    return ReturnType(data() + size() - count, count);
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR inline
typename bsl::span<TYPE, bsl::dynamic_extent>::size_type
bsl::span<TYPE, bsl::dynamic_extent>::size() const BSLS_KEYWORD_NOEXCEPT
{
    return d_size;
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR inline
typename bsl::span<TYPE, bsl::dynamic_extent>::size_type
bsl::span<TYPE, bsl::dynamic_extent>::size_bytes() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return size() * sizeof(element_type);
}

template <class TYPE>
template <size_t OFFSET, size_t COUNT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, COUNT>
bsl::span<TYPE, bsl::dynamic_extent>::subspan() const BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, COUNT> ReturnType;
    BSLS_ASSERT(OFFSET <= size());
    BSLS_ASSERT(COUNT == bsl::dynamic_extent || OFFSET + COUNT <= size());
    return ReturnType(data() + OFFSET,
                COUNT == bsl::dynamic_extent ? size() - OFFSET : COUNT);
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<TYPE, bsl::dynamic_extent>
bsl::span<TYPE, bsl::dynamic_extent>::subspan(
                                   size_type offset,
                                   size_type count) const BSLS_KEYWORD_NOEXCEPT
{
    typedef bsl::span<TYPE, bsl::dynamic_extent> ReturnType;
    BSLS_ASSERT(offset <= size());
    BSLS_ASSERT(count  <= size() || count == bsl::dynamic_extent);
    if (count == bsl::dynamic_extent)
        return ReturnType(data() + offset, size() - offset);          // RETURN

    BSLS_ASSERT(offset <= size() - count);
    return ReturnType(data() + offset, count);
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, bsl::dynamic_extent>::reference
bsl::span<TYPE, bsl::dynamic_extent>::operator[](size_type index) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    BSLS_ASSERT(index < size());
    return d_data_p[index];
}

// MANIPULATORS
template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
void bsl::span<TYPE, bsl::dynamic_extent>::swap(span &other)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    pointer p = d_data_p;
    d_data_p = other.d_data_p;
    other.d_data_p = p;

    size_t sz = d_size;
    d_size = other.d_size;
    other.d_size = sz;
}

//                          ITERATOR OPERATIONS
template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, bsl::dynamic_extent>::iterator
bsl::span<TYPE, bsl::dynamic_extent>::begin() const BSLS_KEYWORD_NOEXCEPT
{
    return iterator(data());
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, bsl::dynamic_extent>::iterator
bsl::span<TYPE, bsl::dynamic_extent>::end() const BSLS_KEYWORD_NOEXCEPT
{
    return iterator(data() + size());
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, bsl::dynamic_extent>::reverse_iterator
bsl::span<TYPE, bsl::dynamic_extent>::rbegin() const BSLS_KEYWORD_NOEXCEPT
{
    return reverse_iterator(end());
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, bsl::dynamic_extent>::reverse_iterator
bsl::span<TYPE, bsl::dynamic_extent>::rend() const BSLS_KEYWORD_NOEXCEPT
{
    return reverse_iterator(begin());
}

// FREE FUNCTIONS
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY
// BDE_VERIFY pragma: push
// BDE_VERIFY pragma: -SAL01:  //  Possible strict-aliasing violation

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<const std::byte, EXTENT * sizeof(TYPE)>
bsl::as_bytes(bsl::span<TYPE, EXTENT> s) BSLS_KEYWORD_NOEXCEPT
{
    return bsl::span<const std::byte, EXTENT * sizeof(TYPE)> (
                                 reinterpret_cast<const std::byte *>(s.data()),
                                 s.size_bytes());
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<const std::byte, bsl::dynamic_extent>
bsl::as_bytes(bsl::span<TYPE, bsl::dynamic_extent> s) BSLS_KEYWORD_NOEXCEPT
{
    return bsl::span<const std::byte, bsl::dynamic_extent>(
                                 reinterpret_cast<const std::byte *>(s.data()),
                                 s.size_bytes());
}

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<std::byte, EXTENT * sizeof(TYPE)>
bsl::as_writable_bytes(bsl::span<TYPE, EXTENT> s) BSLS_KEYWORD_NOEXCEPT
{
    return bsl::span<std::byte, EXTENT * sizeof(TYPE)>(
                                       reinterpret_cast<std::byte *>(s.data()),
                                       s.size_bytes());
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
bsl::span<std::byte, bsl::dynamic_extent>
bsl::as_writable_bytes(bsl::span<TYPE, bsl::dynamic_extent> s)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return bsl::span<std::byte, bsl::dynamic_extent>(
                                       reinterpret_cast<std::byte *>(s.data()),
                                       s.size_bytes());
}

// BDE_VERIFY pragma: pop
#endif

template <class TYPE, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
void
bsl::swap(bsl::span<TYPE, EXTENT>& a, bsl::span<TYPE, EXTENT>& b)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    a.swap(b);
}

#endif  // BSLS_LIBRARYFEATURES_HAS_CPP20_BASELINE_LIBRARY
#endif  // INCLUDED_BSLSTL_SPAN

// ----------------------------------------------------------------------------
// Copyright 2022 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------