#pragma once #include #include #include #include #include #include #include #include #include #include #include // NOLINTBEGIN(modernize-use-constraints) namespace stdx { inline namespace v1 { constexpr static auto dynamic_extent = std::numeric_limits::max(); namespace detail { template struct span_base { constexpr span_base() = default; template constexpr explicit span_base(It, SizeOrEnd) {} constexpr static std::integral_constant size{}; constexpr static std::integral_constant size_bytes{}; constexpr static std::bool_constant empty{}; }; template class span_base { std::size_t sz{}; public: constexpr span_base() = default; template , int> = 0> constexpr span_base(It, SizeOrEnd count) : sz{static_cast(count)} {} template , int> = 0> constexpr span_base(It first, SizeOrEnd last) : sz{static_cast(std::distance(first, last))} {} [[nodiscard]] constexpr auto size() const noexcept -> std::size_t { return sz; } [[nodiscard]] constexpr auto size_bytes() const noexcept -> std::size_t { return sz * sizeof(T); } [[nodiscard]] constexpr auto empty() const noexcept -> bool { return sz == 0u; } }; } // namespace detail template class span : public detail::span_base { template constexpr static inline auto dependent_extent = Extent; using base_t = detail::span_base; T *ptr{}; public: using element_type = T; using value_type = stdx::remove_cvref_t; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using pointer = T *; using const_pointer = T const *; using reference = T &; using const_reference = T const &; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; constexpr static inline auto extent = Extent; constexpr span() = default; template != dynamic_extent, int> = 0> explicit constexpr span(It first, SizeOrEnd) : ptr{stdx::to_address(first)} {} template == dynamic_extent, int> = 0> constexpr span(It first, SizeOrEnd sore) : base_t{first, sore}, ptr{stdx::to_address(first)} {} template // NOLINTNEXTLINE(google-explicit-constructor) constexpr span(std::array &arr LIFETIMEBOUND) noexcept : ptr{std::data(arr)} { static_assert(Extent == dynamic_extent or Extent <= N, "Span extends beyond available storage"); } template // NOLINTNEXTLINE(google-explicit-constructor) constexpr span(std::array const &arr LIFETIMEBOUND) noexcept : ptr{std::data(arr)} { static_assert(Extent == dynamic_extent or Extent <= N, "Span extends beyond available storage"); } template // NOLINTNEXTLINE(google-explicit-constructor) constexpr span( // NOLINTNEXTLINE(*-avoid-c-arrays) stdx::type_identity_t (&arr)[N] LIFETIMEBOUND) noexcept : ptr{std::data(arr)} { static_assert(Extent == dynamic_extent or Extent <= N, "Span extends beyond available storage"); } template != dynamic_extent, int> = 0> explicit constexpr span(R &&r) : ptr{stdx::to_address(std::begin(std::forward(r)))} {} template == dynamic_extent, int> = 0> explicit constexpr span(R &&r) : base_t{std::begin(std::forward(r)), std::end(std::forward(r))}, ptr{stdx::to_address(std::begin(std::forward(r)))} {} template != dynamic_extent and N == dynamic_extent, int> = 0> explicit constexpr span(span const &s) noexcept : ptr{s.data()} {} template == dynamic_extent or N != dynamic_extent, int> = 0> // NOLINTNEXTLINE(google-explicit-constructor) constexpr span(span const &s) noexcept : base_t{s.data(), s.size()}, ptr{s.data()} {} [[nodiscard]] constexpr auto data() const noexcept -> pointer { return ptr; } [[nodiscard]] constexpr auto begin() const noexcept -> iterator { return ptr; } [[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator { return ptr; } [[nodiscard]] constexpr auto rbegin() const noexcept -> reverse_iterator { return std::reverse_iterator{end()}; } [[nodiscard]] constexpr auto crbegin() const noexcept -> const_reverse_iterator { return std::reverse_iterator{cend()}; } [[nodiscard]] constexpr auto end() const noexcept -> iterator { return ptr + this->size(); } [[nodiscard]] constexpr auto cend() const noexcept -> const_iterator { return ptr + this->size(); } [[nodiscard]] constexpr auto rend() const noexcept -> reverse_iterator { return std::reverse_iterator{begin()}; } [[nodiscard]] constexpr auto crend() const noexcept -> const_reverse_iterator { return std::reverse_iterator{cbegin()}; } [[nodiscard]] constexpr auto front() const -> reference { return *begin(); } [[nodiscard]] constexpr auto back() const -> reference { return *std::prev(end()); } [[nodiscard]] constexpr auto operator[](size_type idx) const -> reference { return data()[idx]; } template [[nodiscard]] constexpr auto first() const -> span { static_assert(Count <= Extent, "first cannot form a larger span!"); return span{ptr, Count}; } [[nodiscard]] constexpr auto first(size_type count) const -> span { return {ptr, count}; } template [[nodiscard]] constexpr auto last() const -> span { static_assert(Count <= Extent, "last cannot form a larger span!"); return span{ptr + this->size() - Count, Count}; } [[nodiscard]] constexpr auto last(size_type count) const -> span { return {ptr + this->size() - count, count}; } template [[nodiscard]] constexpr auto subspan() const { if constexpr (Count != dynamic_extent) { static_assert(Offset <= Extent, "subspan cannot start beyond span!"); static_assert(Count <= Extent, "subspan cannot be longer than span!"); static_assert(Offset <= Extent - Count, "subspan cannot end beyond span!"); return span{ptr + Offset, Count}; } else if constexpr (Extent != dynamic_extent) { static_assert(Offset <= Extent, "subspan cannot start beyond span!"); return span{ptr + Offset, Extent - Offset}; } else { return span{ptr + Offset, this->size() - Offset}; } } [[nodiscard]] constexpr auto subspan(size_type Offset, size_type Count = dynamic_extent) const -> span { return {ptr + Offset, std::min(Count, this->size() - Offset)}; } }; // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) template auto as_bytes(span s) noexcept { if constexpr (N == dynamic_extent) { return span{reinterpret_cast(s.data()), s.size_bytes()}; } else { constexpr auto size = s.size_bytes(); return span{ reinterpret_cast(s.data()), size}; } } template , int> = 0> auto as_writable_bytes(span s) noexcept { if constexpr (N == dynamic_extent) { return span{reinterpret_cast(s.data()), s.size_bytes()}; } else { constexpr auto size = s.size_bytes(); return span{reinterpret_cast(s.data()), size}; } } // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) namespace detail { template using iter_reference_t = decltype(*std::declval()); template using iterator_t = decltype(std::begin(std::declval())); template using range_reference_t = iter_reference_t>; } // namespace detail template span(It, EndOrSize) -> span>>; // NOLINTNEXTLINE(*-avoid-c-arrays) template span(T (&)[N]) -> span; template span(std::array &) -> span; template span(std::array const &) -> span; template span(R &&) -> span>>; template constexpr auto ct_capacity_v> = N; } // namespace v1 } // namespace stdx // NOLINTEND(modernize-use-constraints)