/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SPAN_HPP #define MPT_BASE_SPAN_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include #if MPT_CXX_AT_LEAST(20) #include #else // !C++20 #include #include #include #endif // C++20 #if MPT_CXX_BEFORE(20) #include #endif // !C++20 namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_CXX_AT_LEAST(20) using std::dynamic_extent; using std::span; #else // !C++20 // Simplified version of gsl::span. // Non-owning read-only or read-write view into a contiguous block of T // objects, i.e. equivalent to a (beg,end) or (data,size) tuple. // Can eventually be replaced without further modifications with a full C++20 // std::span. inline constexpr std::size_t dynamic_extent = std::numeric_limits::max(); template class span { public: using element_type = T; using value_type = typename std::remove_cv::type; using index_type = std::size_t; using pointer = T *; using const_pointer = const T *; using reference = T &; using const_reference = const T &; using iterator = pointer; using difference_type = typename std::iterator_traits::difference_type; private: T * m_data; std::size_t m_size; public: span() noexcept : m_data(nullptr) , m_size(0) { } span(pointer beg, pointer end) : m_data(beg) , m_size(end - beg) { } span(pointer data, index_type size) : m_data(data) , m_size(size) { } template span(element_type (&arr)[N]) : m_data(arr) , m_size(N) { } template span(std::array & arr) : m_data(arr.data()) , m_size(arr.size()) { } template span(const std::array & arr) : m_data(arr.data()) , m_size(arr.size()) { } span(const span & other) noexcept = default; template span(const span & other) : m_data(other.data()) , m_size(other.size()) { } span & operator=(const span & other) noexcept = default; iterator begin() const { return iterator(m_data); } iterator end() const { return iterator(m_data + m_size); } reference operator[](index_type index) { return m_data[index]; } const_reference operator[](index_type index) const { return m_data[index]; } bool operator==(const span & other) const noexcept { return size() == other.size() && (m_data == other.m_data || std::equal(begin(), end(), other.begin())); } bool operator!=(const span & other) const noexcept { return !(*this == other); } pointer data() const noexcept { return m_data; } bool empty() const noexcept { return size() == 0; } index_type size() const noexcept { return m_size; } index_type length() const noexcept { return size(); } span subspan(std::size_t offset, std::size_t count = mpt::dynamic_extent) const { return span(data() + offset, (count == mpt::dynamic_extent) ? (size() - offset) : count); } span first(std::size_t count) const { return span(data(), count); } span last(std::size_t count) const { return span(data() + (size() - count), count); } }; // class span #endif // C++20 template inline span as_span(T * beg, T * end) { return span(beg, end); } template inline span as_span(T * data, std::size_t size) { return span(data, size); } template inline span as_span(T (&arr)[N]) { return span(std::begin(arr), std::end(arr)); } template inline span as_span(std::array & cont) { return span(cont); } template inline span as_span(const std::array & cont) { return span(cont); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SPAN_HPP