#pragma once #include #include #include #include inline constexpr std::size_t dynamic_extent = std::numeric_limits::max(); template class span; namespace detail { template struct span_storage { constexpr span_storage() noexcept = default; constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept : ptr(p_ptr) {} E* ptr = nullptr; static constexpr std::size_t size = S; }; template struct span_storage { constexpr span_storage() noexcept = default; constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept : ptr(p_ptr), size(p_size) {} E* ptr = nullptr; std::size_t size = 0; }; using std::void_t; template using uncvref_t = typename std::remove_cv_t>; template struct is_span : std::false_type { }; template struct is_span> : std::true_type { }; template static constexpr auto is_span_v = is_span::value; template struct is_std_array : std::false_type { }; template struct is_std_array> : std::true_type { }; template static constexpr auto is_std_array_v = is_std_array::value; template struct has_size_and_data : std::false_type { }; template struct has_size_and_data())), decltype(std::data(std::declval()))>> : std::true_type { }; template static constexpr auto has_size_and_data_v = has_size_and_data::value; template > struct is_container { static constexpr bool value = !is_span_v && !is_std_array_v && !std::is_array_v && has_size_and_data_v; }; template static constexpr auto is_container_v = is_container::value; template using remove_pointer_t = std::remove_pointer_t; template struct is_container_element_type_compatible : std::false_type { }; template struct is_container_element_type_compatible< T, E, typename std::enable_if< !std::is_same_v()))>, void> && std::is_convertible_v()))> (*)[], E (*)[]>>::type> : std::true_type { }; template static constexpr auto is_container_element_type_compatible_v = is_container_element_type_compatible::value; template struct is_complete : std::false_type { }; template struct is_complete : std::true_type { }; template static constexpr auto is_complete_v = is_complete::value; } // namespace detail template class span { static_assert(std::is_object_v, "A span's ElementType must be an object type (not a " "reference type or void)"); static_assert(detail::is_complete_v, "A span's ElementType must be a complete type (not a forward " "declaration)"); static_assert(!std::is_abstract_v, "A span's ElementType cannot be an abstract class type"); using storage_type = detail::span_storage; public: // constants and types using element_type = ElementType; using value_type = std::remove_cv_t; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using pointer = element_type*; using const_pointer = const element_type*; using reference = element_type&; using const_reference = const element_type&; using iterator = pointer; using reverse_iterator = std::reverse_iterator; static constexpr size_type extent = Extent; // [span.cons], span constructors, copy, assignment, and destructor template = 0> constexpr span() noexcept { } constexpr span(pointer ptr, size_type count) : storage_(ptr, count) { assert(extent == dynamic_extent || count == extent); } constexpr span(pointer first_elem, pointer last_elem) : storage_(first_elem, last_elem - first_elem) { assert(extent == dynamic_extent || last_elem - first_elem == static_cast(extent)); } template >> constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N) { } template &, ElementType>>> constexpr span(std::array& arr) noexcept : storage_(arr.data(), N) { } template < typename T, std::size_t N, std::size_t E = Extent, typename = std::enable_if_t<(E == dynamic_extent || N == E) && detail::is_container_element_type_compatible_v&, ElementType>>> constexpr span(const std::array& arr) noexcept : storage_(arr.data(), N) { } template && detail::is_container_element_type_compatible_v>> constexpr span(Container& cont) : storage_(std::data(cont), std::size(cont)) { } template && detail::is_container_element_type_compatible_v>> constexpr span(const Container& cont) : storage_(std::data(cont), std::size(cont)) { } constexpr span(const span& other) noexcept = default; template >> constexpr span(const span& other) noexcept : storage_(other.data(), other.size()) { } ~span() noexcept = default; constexpr span& operator=(const span& other) noexcept = default; // [span.sub], span subviews template constexpr span first() const { assert(Count <= size()); return {data(), Count}; } template constexpr span last() const { assert(Count <= size()); return {data() + (size() - Count), Count}; } template using subspan_return_t = span; template constexpr subspan_return_t subspan() const { assert(Offset <= size() && (Count == dynamic_extent || Offset + Count <= size())); return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset}; } constexpr span first(size_type count) const { assert(count <= size()); return {data(), count}; } constexpr span last(size_type count) const { assert(count <= size()); return {data() + (size() - count), count}; } constexpr span subspan(size_type offset, size_type count = dynamic_extent) const { assert(offset <= size() && (count == dynamic_extent || offset + count <= size())); return {data() + offset, count == dynamic_extent ? size() - offset : count}; } // [span.obs], span observers constexpr size_type size() const noexcept { return storage_.size; } constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); } [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access constexpr reference operator[](size_type idx) const { assert(idx < size()); return *(data() + idx); } constexpr reference front() const { assert(!empty()); return *data(); } constexpr reference back() const { assert(!empty()); return *(data() + (size() - 1)); } constexpr pointer data() const noexcept { return storage_.ptr; } // [span.iterators], span iterator support constexpr iterator begin() const noexcept { return data(); } constexpr iterator end() const noexcept { return data() + size(); } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } private: storage_type storage_{}; }; /* Deduction Guides */ template span(T (&)[N]) -> span; template span(std::array&) -> span; template span(const std::array&) -> span; template span(Container&) -> span()))>>; template span(const Container&) -> span; template constexpr span make_span(span s) noexcept { return s; } template constexpr span make_span(T (&arr)[N]) noexcept { return {arr}; } template constexpr span make_span(std::array& arr) noexcept { return {arr}; } template constexpr span make_span(const std::array& arr) noexcept { return {arr}; } template constexpr span()))>> make_span(Container& cont) { return {cont}; } template constexpr span make_span(const Container& cont) { return {cont}; } template span as_bytes( span s) noexcept { return {reinterpret_cast(s.data()), s.size_bytes()}; } template >> span as_writable_bytes( span s) noexcept { return {reinterpret_cast(s.data()), s.size_bytes()}; } template constexpr auto get(span s) -> decltype(s[N]) { return s[N]; } namespace std { template class tuple_size<::span> : public integral_constant { }; template class tuple_size<::span>; // not defined template class tuple_element> { public: static_assert(Extent != ::dynamic_extent && I < Extent, ""); using type = ElementType; }; } // end namespace std