///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // This file implements the eastl::span which is part of the C++ standard // STL library specification. // // eastl::span is a non-owning container that refers to a contiguous block of // memory. It bundles up the classic pattern of a pointer and a size into a // single type. A span can either have a static extent, in which case the // number of elements in the sequence is known and encoded in the type, or a // dynamic extent. // // http://en.cppreference.com/w/cpp/container/span // http://eel.is/c++draft/views#span.syn /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_SPAN_H #define EASTL_SPAN_H #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif #include #include #include #include namespace eastl { static EA_CONSTEXPR size_t dynamic_extent = size_t(-1); namespace Internal { // HasSizeAndData // // custom type trait to determine if eastl::data(Container) and eastl::size(Container) are well-formed. // template struct HasSizeAndData : eastl::false_type {}; template struct HasSizeAndData())), decltype(eastl::data(eastl::declval()))>> : eastl::true_type {}; // SubspanExtent // // Integral constant that calculates the resulting extent of a templated subspan operation. // // If Count is not dynamic_extent then SubspanExtent::value is Count, // otherwise, if Extent is not dynamic_extent, SubspanExtent::value is (Extent - Offset), // otherwise, SubspanExtent::value is dynamic_extent. // template struct SubspanExtent : eastl::integral_constant {}; } template class span { public: typedef T element_type; typedef remove_cv_t value_type; typedef eastl_size_t index_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T* iterator; typedef const T* const_iterator; typedef eastl::reverse_iterator reverse_iterator; typedef eastl::reverse_iterator const_reverse_iterator; static EA_CONSTEXPR size_t extent = Extent; // constructors / destructor EA_CONSTEXPR span() EA_NOEXCEPT = default; EA_CONSTEXPR span(const span& other) EA_NOEXCEPT = default; EA_CONSTEXPR span(pointer ptr, index_type count); EA_CONSTEXPR span(pointer pBegin, pointer pEnd); ~span() EA_NOEXCEPT = default; // copy-assignment operator EA_CPP14_CONSTEXPR span& operator=(const span& other) EA_NOEXCEPT = default; // conversion constructors for c-array and eastl::array template EA_CONSTEXPR span(element_type (&arr)[N]) EA_NOEXCEPT; template EA_CONSTEXPR span(eastl::array& arr) EA_NOEXCEPT; template EA_CONSTEXPR span(const eastl::array& arr) EA_NOEXCEPT; // SfinaeForGenericContainers // template using SfinaeForGenericContainers = enable_if_t && !is_same_v> && !is_array_v && Internal::HasSizeAndData::value && is_convertible_v()))> (*)[], element_type (*)[]>>; // generic container conversion constructors template > EA_CONSTEXPR span(Container& cont); template > EA_CONSTEXPR span(const Container& cont); template )>> EA_CONSTEXPR span(const span& s) EA_NOEXCEPT; // subviews template EA_CPP14_CONSTEXPR span first() const; EA_CPP14_CONSTEXPR span first(size_t Count) const; template EA_CPP14_CONSTEXPR span last() const; EA_CPP14_CONSTEXPR span last(size_t Count) const; template EA_CONSTEXPR span::value> subspan() const; EA_CONSTEXPR span subspan(size_t Offset, size_t Count = dynamic_extent) const; // observers EA_CONSTEXPR pointer data() const EA_NOEXCEPT; EA_CONSTEXPR index_type size() const EA_NOEXCEPT; EA_CONSTEXPR index_type size_bytes() const EA_NOEXCEPT; EA_CONSTEXPR bool empty() const EA_NOEXCEPT; // subscript operators, element access EA_CONSTEXPR reference front() const; EA_CONSTEXPR reference back() const; EA_CONSTEXPR reference operator[](index_type idx) const; EA_CONSTEXPR reference operator()(index_type idx) const; // iterator support EA_CONSTEXPR iterator begin() const EA_NOEXCEPT; EA_CONSTEXPR iterator end() const EA_NOEXCEPT; EA_CONSTEXPR const_iterator cbegin() const EA_NOEXCEPT; EA_CONSTEXPR const_iterator cend() const EA_NOEXCEPT; EA_CONSTEXPR reverse_iterator rbegin() const EA_NOEXCEPT; EA_CONSTEXPR reverse_iterator rend() const EA_NOEXCEPT; EA_CONSTEXPR const_reverse_iterator crbegin() const EA_NOEXCEPT; EA_CONSTEXPR const_reverse_iterator crend() const EA_NOEXCEPT; private: pointer mpData = nullptr; index_type mnSize = 0; private: EA_CONSTEXPR bool bounds_check(size_t) const; // utility used in asserts }; /////////////////////////////////////////////////////////////////////////// // template deduction guides /////////////////////////////////////////////////////////////////////////// #ifdef __cpp_deduction_guides template span(T (&)[N]) -> span ; template span(array&) -> span ; template span(const array&) -> span ; template span(Container&) -> span ; template span(const Container&) -> span ; #endif /////////////////////////////////////////////////////////////////////////// // comparison operators /////////////////////////////////////////////////////////////////////////// template EA_CONSTEXPR bool operator==(span l, span r) { return (l.size() == r.size()) && eastl::equal(l.begin(), l.end(), r.begin()); } template EA_CONSTEXPR bool operator<(span l, span r) { return eastl::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); } template EA_CONSTEXPR bool operator!=(span l, span r) { return !(l == r); } template EA_CONSTEXPR bool operator<=(span l, span r) { return !(r < l); } template EA_CONSTEXPR bool operator>(span l, span r) { return r < l; } template EA_CONSTEXPR bool operator>=(span l, span r) { return !(l < r); } /////////////////////////////////////////////////////////////////////////// // ctor implementations /////////////////////////////////////////////////////////////////////////// template EA_CONSTEXPR span::span(pointer ptr, index_type size) : mpData(ptr), mnSize(size) { } template EA_CONSTEXPR span::span(pointer pBegin, pointer pEnd) : mpData(pBegin), mnSize(static_cast(pEnd - pBegin)) { } template template EA_CONSTEXPR span::span(element_type(&arr)[N]) EA_NOEXCEPT : span(arr, static_cast(N)) { } template template EA_CONSTEXPR span::span(eastl::array &arr) EA_NOEXCEPT : span(arr.data(), arr.size()) { } template template EA_CONSTEXPR span::span(const eastl::array& arr) EA_NOEXCEPT : span(arr.data(), arr.size()) { } template template EA_CONSTEXPR span::span(Container& cont) : span(static_cast(eastl::data(cont)), static_cast(eastl::size(cont))) { } template template EA_CONSTEXPR span::span(const Container& cont) : span(static_cast(eastl::data(cont)), static_cast(eastl::size(cont))) { } template template EA_CONSTEXPR span::span(const span& s) EA_NOEXCEPT : span(s.data(), s.size()) { } /////////////////////////////////////////////////////////////////////////// // member function implementations /////////////////////////////////////////////////////////////////////////// template EA_CONSTEXPR typename span::pointer span::data() const EA_NOEXCEPT { return mpData; } template EA_CONSTEXPR typename span::index_type span::size() const EA_NOEXCEPT { return mnSize; } template EA_CONSTEXPR typename span::index_type span::size_bytes() const EA_NOEXCEPT { return size() * sizeof(element_type); } template EA_CONSTEXPR bool span::empty() const EA_NOEXCEPT { return size() == 0; } template EA_CONSTEXPR typename span::reference span::front() const { EASTL_ASSERT_MSG(!empty(), "undefined behavior accessing an empty span"); return mpData[0]; } template EA_CONSTEXPR typename span::reference span::back() const { EASTL_ASSERT_MSG(!empty(), "undefined behavior accessing an empty span"); return mpData[mnSize - 1]; } template EA_CONSTEXPR typename span::reference span::operator[](index_type idx) const { EASTL_ASSERT_MSG(!empty(), "undefined behavior accessing an empty span"); EASTL_ASSERT_MSG(bounds_check(idx), "undefined behavior accessing out of bounds"); return mpData[idx]; } template EA_CONSTEXPR typename span::reference span::operator()(index_type idx) const { EASTL_ASSERT_MSG(!empty(), "undefined behavior accessing an empty span"); EASTL_ASSERT_MSG(bounds_check(idx), "undefined behavior accessing out of bounds"); return mpData[idx]; } template EA_CONSTEXPR typename span::iterator span::begin() const EA_NOEXCEPT { return mpData; } template EA_CONSTEXPR typename span::iterator span::end() const EA_NOEXCEPT { return mpData + mnSize; } template EA_CONSTEXPR typename span::const_iterator span::cbegin() const EA_NOEXCEPT { return mpData; } template EA_CONSTEXPR typename span::const_iterator span::cend() const EA_NOEXCEPT { return mpData + mnSize; } template EA_CONSTEXPR typename span::reverse_iterator span::rbegin() const EA_NOEXCEPT { return reverse_iterator(mpData + mnSize); } template EA_CONSTEXPR typename span::reverse_iterator span::rend() const EA_NOEXCEPT { return reverse_iterator(mpData); } template EA_CONSTEXPR typename span::const_reverse_iterator span::crbegin() const EA_NOEXCEPT { return const_reverse_iterator(mpData + mnSize); } template EA_CONSTEXPR typename span::const_reverse_iterator span::crend() const EA_NOEXCEPT { return const_reverse_iterator(mpData); } template template EA_CPP14_CONSTEXPR span::element_type, Count> span::first() const { EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds"); return {data(), static_cast(Count)}; } template EA_CPP14_CONSTEXPR span::element_type, dynamic_extent> span::first(size_t sz) const { EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds"); return {data(), static_cast(sz)}; } template template EA_CPP14_CONSTEXPR span::element_type, Count> span::last() const { EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds"); return {data() + size() - Count, static_cast(Count)}; } template EA_CPP14_CONSTEXPR span::element_type, dynamic_extent> span::last(size_t sz) const { EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds"); return {data() + size() - sz, static_cast(sz)}; } template template EA_CONSTEXPR span::element_type, Internal::SubspanExtent::value> span::subspan() const { EASTL_ASSERT_MSG(bounds_check(Offset), "undefined behaviour accessing out of bounds"); EASTL_ASSERT_MSG(Count == dynamic_extent || Count <= (size() - Offset), "undefined behaviour exceeding size of span"); return {data() + Offset, eastl_size_t(Count == dynamic_extent ? size() - Offset : Count)}; } template EA_CONSTEXPR span::element_type, dynamic_extent> span::subspan(size_t offset, size_t count) const { EASTL_ASSERT_MSG(bounds_check(offset), "undefined behaviour accessing out of bounds"); EASTL_ASSERT_MSG(count == dynamic_extent || count <= (size() - offset), "undefined behaviour exceeding size of span"); return {data() + offset, eastl_size_t(count == dynamic_extent ? size() - offset : count)}; } template EA_CONSTEXPR bool span::bounds_check(size_t sz) const { return (sz >= 0 && sz < size()); } } #endif // EASTL_SPAN_H