diff --git a/src/stdutils/include/stdutils/span.h b/src/stdutils/include/stdutils/span.h index 86b1da9..5909775 100644 --- a/src/stdutils/include/stdutils/span.h +++ b/src/stdutils/include/stdutils/span.h @@ -2,13 +2,22 @@ #include #include +#include +#include + namespace stdutils { +inline constexpr std::size_t dyn_extent = std::numeric_limits::max(); // -1 + // Imitation of std::span in C++20 + +template +class span {}; + template -class span +class span { public: span(T* ptr, std::size_t size) noexcept : m_ptr(ptr), m_size(size) { assert(m_ptr); } @@ -23,8 +32,10 @@ class span std::size_t size() const { return m_size; } + T* data() { return m_ptr; } T* begin() { return m_ptr; } T* end() { return m_ptr + m_size; } + const T* data() const { return m_ptr; } const T* begin() const { return m_ptr; } const T* end() const { return m_ptr + m_size; } @@ -36,4 +47,36 @@ class span std::size_t m_size; }; +template +class span> +{ + using this_type = span>; +public: + explicit span(T* ptr) noexcept : m_ptr(ptr) { assert(m_ptr); } + span(const this_type&) noexcept = default; + span(this_type&&) noexcept = default; + this_type& operator=(const this_type&) noexcept = default; + this_type& operator=(this_type&&) noexcept = default; + + // For qualification conversions (e.g. non-const T to const T) + template + span(const span& other) noexcept : m_ptr(other.begin()) { assert(m_ptr); } + + constexpr std::size_t size() const { return Sz; } + + T* data() { return m_ptr; } + T* begin() { return m_ptr; } + T* end() { return m_ptr + Sz; } + const T* data() const { return m_ptr; } + const T* begin() const { return m_ptr; } + const T* end() const { return m_ptr + Sz; } + + T& operator[](std::size_t idx) { assert(idx < Sz); return *(m_ptr + idx); } + const T& operator[](std::size_t idx) const { assert(idx < Sz); return *(m_ptr + idx); } + +private: + T* m_ptr; +}; + + } // namespace stdutils \ No newline at end of file diff --git a/src/tests/stdutils/src/test_span.cpp b/src/tests/stdutils/src/test_span.cpp index 205856a..b8e68d9 100644 --- a/src/tests/stdutils/src/test_span.cpp +++ b/src/tests/stdutils/src/test_span.cpp @@ -1,13 +1,14 @@ #include + #include #include -TEST_CASE("span to span", "[span]") +TEST_CASE("Dynamic extent span to span", "[span]") { std::vector test_vect { 0, 2, 3, 4 }; - auto span = stdutils::span(test_vect.data(), test_vect.size()); + auto span = stdutils::span(test_vect.data(), test_vect.size()); span[0] = 1; CHECK(test_vect[0] == 1); @@ -15,3 +16,18 @@ TEST_CASE("span to span", "[span]") CHECK(const_span[0] == 1); CHECK(const_span.size() == test_vect.size()); } + +TEST_CASE("Static extent span to span", "[span]") +{ + std::vector test_vect { 1, 2, 3, 4 }; + + auto span = stdutils::span(test_vect.data() + 2); + REQUIRE(span.size() == 2); + span[0] = 0; + CHECK(test_vect[2] == 0); + + auto const_span = stdutils::span(span); + REQUIRE(const_span.size() == 2); + CHECK(const_span[0] == 0); + CHECK(const_span[1] == 4); +}