// 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: bsl_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:
// * The `constexpr` inline symbol `std::dynamic_extent` has been replaced by
//   an enumeration for C++03 compatibility.
// * A `bsl::span` can be implicitly constructed from a `bsl::array`.
// * The implicit construction from an arbitrary container that supports
//   `data()` and `size()` is enabled only for C++11 and later.
// * bsl::span is implicitly constructible from a bsl::vector in C++03.
//
///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};
//
// /// Return a span into the specified `vec`, starting at the specified
// /// `first` index, and continuing up to (but not including) the
// /// specified `last` index.
// bsl::span<const int> slice(const bsl::vector<int>& vec,
//                            size_t                  first,
//                            size_t                  last)
// {
//     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>

#if defined (BSLS_LIBRARYFEATURES_HAS_CPP20_BASELINE_LIBRARY) && \
   !(defined(BSLS_LIBRARYFEATURES_FORCE_ABI_ENABLED) &&          \
    (BSLS_LIBRARYFEATURES_FORCE_ABI_ENABLED < 20))
#include <span>
namespace bsl {
    using std::dynamic_extent;
    using std::span;
    using std::as_bytes;
    using std::as_writable_bytes;
}
#define BSLSTL_SPAN_IS_ALIASED
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP20_BASELINE_LIBRARY & not disabled

#ifndef BSLSTL_SPAN_IS_ALIASED
#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_string.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
                        // ===================

/// This component-private struct provides a namespace for meta-programming
/// utilities used by the `span` implementation.
struct Span_Utility
{
    // PUBLIC TYPES

    /// A metaclass that derives from `true_type` if an array of type `FROM`
    /// objects (or functions) can be implicitly converted to an array of
    /// type `TO` objects (or functions).  Typically, this is a test that
    /// `TO` is the same type as `FROM`, but potentially having a stricter
    /// cv-qualification.  Note that the preferred implementation would use
    /// arrays of unknown bound to be clear that there is nothing specific
    /// about the length of the arrays; however, to avoid warnings on the
    /// Solaris compiler that complains about the use of pointers to arrays
    /// of unknown bound, we arbitrarily pick the array length of 5, as the
    /// behavior is the same regardless of the length of the arrays.
    template <class FROM, class TO>
    struct IsArrayConvertible : bsl::is_convertible<FROM(*)[5], TO(*)[5]>::type
    {
    };

    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(bsl::data(std::declval<TP>())),
            decltype(bsl::size(std::declval<TP>())),
        // The underlying types are compatible
            typename bsl::enable_if<
                Span_Utility::IsArrayConvertible<
                   typename bsl::remove_pointer<
                              decltype(bsl::data(std::declval<TP &>()))>::type,
                   ELEMENT_TYPE>::value,
                bsl::nullptr_t>::type
            > >
        : public bsl::true_type {};
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY

};

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 const size_type extent = EXTENT;
// BDE_VERIFY pragma: pop

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(span, bsl::is_trivially_copyable);

    // CREATORS

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

    /// Create a span that refers to the same data as the specified
    /// `original` object.
    //! BSLS_KEYWORD_CONSTEXPR_CPP14 span(const span&) noexcept = default;

    /// 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 ptr, size_type count);

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

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

#ifndef BSLSTL_ARRAY_IS_ALIASED
    /// 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(
       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;
#endif  // BSLSTL_ARRAY_IS_ALIASED

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
    /// 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(
           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;
#endif // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY

    /// 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, 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`.
    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;

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

    // ACCESSORS

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

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

    /// Return `true` if this span contains no elements and `false`
    /// otherwise.
    BSLS_KEYWORD_CONSTEXPR bool empty() 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()`.
    template <size_t COUNT>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, COUNT> first() const;

    /// 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
    span<element_type, dynamic_extent>
    first(size_type count) const;

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

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

    /// 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_CPP14
    span<element_type, dynamic_extent>
    last(size_type count) const;

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

    /// Return the size of this span in bytes.
    BSLS_KEYWORD_CONSTEXPR size_type size_bytes() 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`.
    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
    {
        // 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);
    }

    /// 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
    span<element_type, dynamic_extent>
    subspan(size_type offset, size_type count = dynamic_extent) const;

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

    /// Return a reference to the element at the specified `index`.  Throws
    /// an `out_of_range` exception if `index >= size()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    reference at(size_type index) const;

    //                      ITERATOR OPERATIONS


    /// 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 begin() const BSLS_KEYWORD_NOEXCEPT;

    /// Return the past-the-end iterator providing modifiable access to this
    /// span.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    iterator end() 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 rbegin() const BSLS_KEYWORD_NOEXCEPT;

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

    // MANIPULATORS

    /// Assign to this span the value of the specified `rhs` object, and
    /// return a reference providing modifiable access to this span.
    //! constexpr span& operator=(const span&) noexcept = default;

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

  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 const size_type extent = dynamic_extent;
// BDE_VERIFY pragma: pop

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(span, bsl::is_trivially_copyable);

    // CREATORS

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

    /// Create a span that refers to the same data as the specified
    /// `original` object.
    //! BSLS_KEYWORD_CONSTEXPR_CPP14 span(const span&) noexcept = default;

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

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

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

#ifndef BSLSTL_ARRAY_IS_ALIASED
    /// 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(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;
#endif  // BSLSTL_ARRAY_IS_ALIASED

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
    /// 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(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;
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY

#ifndef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
    /// Construct a span from the specified bsl::vector `v`.  This
    /// constructor participates in overload resolution only if
    /// `t_OTHER_TYPE(*)[]` is convertible to `element_type(*)[]`.
    template <class t_OTHER_TYPE, class ALLOCATOR>
    span(bsl::vector<t_OTHER_TYPE, ALLOCATOR>& v,
         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::vector `v`.  This
    /// constructor participates in overload resolution only if
    /// `const t_OTHER_TYPE(*)[]` is convertible to `element_type(*)[]`.
    template <class t_OTHER_TYPE, class ALLOCATOR>
    span(const bsl::vector<t_OTHER_TYPE, ALLOCATOR>& v,
         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::string `s`.  This
    /// constructor participates in overload resolution only if
    /// `CHAR_TYPE(*)[]` is convertible to `element_type(*)[]`.
    template<class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
    span(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& s,
         typename bsl::enable_if<
               Span_Utility::IsArrayConvertible<
                                            CHAR_TYPE, element_type>::value,
               void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;

    /// Construct a span from the specified bsl::string `s`.  This
    /// constructor participates in overload resolution only if
    /// `const CHAR_TYPE(*)[]` is convertible to `element_type(*)[]`.
    template<class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
    span(const bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& s,
         typename bsl::enable_if<
             Span_Utility::IsArrayConvertible<
                                      const CHAR_TYPE, element_type>::value,
               void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;

    /// Construct a span from the specified bsl::string_view `sv`.  This
    /// constructor participates in overload resolution only if
    /// `const CHAR_TYPE(*)[]` is convertible to `element_type(*)[]`.
    template<class CHAR_TYPE, class CHAR_TRAITS>
    span(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>& sv,
         typename bsl::enable_if<
             Span_Utility::IsArrayConvertible<
                                      const CHAR_TYPE, element_type>::value,
               void *>::type = NULL) BSLS_KEYWORD_NOEXCEPT;
#endif  // no BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY

#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  // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY

    /// 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, 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;

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

    // ACCESSORS

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

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

    // Return `true` if `size() == 0` and `false` otherwise.
    BSLS_KEYWORD_CONSTEXPR bool empty() 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()`.
    template <size_t COUNT>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    span<element_type, COUNT> first() const;

    /// 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
    span<element_type, dynamic_extent>
    first(size_type count) const;

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

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

    /// 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_CPP14
    span<element_type, dynamic_extent>
    last(size_type count) const;

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

    /// Return the size of this span in bytes.
    BSLS_KEYWORD_CONSTEXPR size_type size_bytes() 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()`.
    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;

    /// 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 span<element_type, dynamic_extent>
    subspan(size_type offset, size_type count = dynamic_extent) const;

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

    /// Return a reference to the element at the specified `index`.  Throws
    /// an `out_of_range` exception if `index >= size()`.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    reference at(size_type index) const;

    //                      ITERATOR OPERATIONS

    /// 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 begin() const BSLS_KEYWORD_NOEXCEPT;

    /// Return the past-the-end iterator providing modifiable access to this
    ///  span.
    BSLS_KEYWORD_CONSTEXPR_CPP14
    iterator end() 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 rbegin() const BSLS_KEYWORD_NOEXCEPT;

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

    // MANIPULATORS

    /// Assign to this span the value of the specified `rhs` object, and
    /// return a reference providing modifiable access to this span.
    //! constexpr span& operator=(const span&) noexcept = default;

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

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

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
// CLASS TEMPLATE DEDUCTION GUIDES

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

#ifndef BSLSTL_ARRAY_IS_ALIASED
/// 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(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>;
#endif  // not BSLSTL_ARRAY_IS_ALIASED

/// 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(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` from the corresponding template
/// parameter of the `bsl::vector` 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>;
#endif  // BSLS_COMPILERFEATURES_SUPPORT_CTAD

// FREE FUNCTIONS
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY

/// Return a span referring 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<const std::byte, EXTENT * sizeof(TYPE)>
as_bytes(span<TYPE, EXTENT> s) BSLS_KEYWORD_NOEXCEPT;

/// Return a span referring 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 same data as the specified `s`, but
/// referring to the data as a span of 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 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;

#endif  // BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY

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

}  // 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(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  // not BSLSTL_ARRAY_IS_ALIASED

#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  // 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(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
{
    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
{
    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
{
    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
{
    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
{
    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, size_t EXTENT>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, EXTENT>::reference
bsl::span<TYPE, EXTENT>::at(size_type index) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(index >= size())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                           "span<T, static_extent>::at(index): invalid index");
    }
    return d_data_p[index];
}

//                          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
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(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  // not BSLSTL_ARRAY_IS_ALIASED

#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  // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY

#ifndef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
template <class TYPE>
template <class t_OTHER_TYPE, class ALLOCATOR>
inline bsl::span<TYPE, bsl::dynamic_extent>::span(
                      bsl::vector<t_OTHER_TYPE, ALLOCATOR>& v,
                      typename bsl::enable_if<Span_Utility::IsArrayConvertible<
                                            t_OTHER_TYPE, element_type>::value,
                      void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(v.data())
, d_size(v.size())
{
}

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

template <class TYPE>
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline bsl::span<TYPE, bsl::dynamic_extent>::span(
                      bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& s,
                      typename bsl::enable_if<Span_Utility::IsArrayConvertible<
                                               CHAR_TYPE, element_type>::value,
                      void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(s.data())
, d_size(s.size())
{
}

template <class TYPE>
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline bsl::span<TYPE, bsl::dynamic_extent>::span(
                 const bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& s,
                 typename bsl::enable_if<Span_Utility::IsArrayConvertible<
                                         const CHAR_TYPE, element_type>::value,
                 void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(s.data())
, d_size(s.size())
{
}

template <class TYPE>
template <class CHAR_TYPE, class CHAR_TRAITS>
inline bsl::span<TYPE, bsl::dynamic_extent>::span(
                 const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>& sv,
                 typename bsl::enable_if<Span_Utility::IsArrayConvertible<
                                         const CHAR_TYPE, element_type>::value,
                 void *>::type) BSLS_KEYWORD_NOEXCEPT
: d_data_p(sv.data())
, d_size(sv.size())
{
}
#endif  // no BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY

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_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
{
    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
{
    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_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
{
    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
{
    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
{
    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
{
    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_ASSERT(index < size());
    return d_data_p[index];
}

template <class TYPE>
BSLS_KEYWORD_CONSTEXPR_CPP14 inline
typename bsl::span<TYPE, bsl::dynamic_extent>::reference
bsl::span<TYPE, bsl::dynamic_extent>::at(size_type index) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(index >= size())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                          "span<T, dynamic_extent>::at(index): invalid index");
    }
    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  // BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY

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  // BSLSTL_SPAN_IS_ALIASED

#endif

// ----------------------------------------------------------------------------
// 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 ----------------------------------
