Skip to content

Commit

Permalink
Update stdutils::span
Browse files Browse the repository at this point in the history
  • Loading branch information
pierre-dejoue committed Aug 18, 2023
1 parent 00fb711 commit 123c325
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 3 deletions.
45 changes: 44 additions & 1 deletion src/stdutils/include/stdutils/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@

#include <cassert>
#include <cstddef>
#include <limits>
#include <type_traits>


namespace stdutils
{

inline constexpr std::size_t dyn_extent = std::numeric_limits<std::size_t>::max(); // -1

// Imitation of std::span in C++20

template <typename T, std::size_t Sz = dyn_extent, class Enable = void>
class span {};

template <typename T>
class span
class span<T, dyn_extent, void>
{
public:
span(T* ptr, std::size_t size) noexcept : m_ptr(ptr), m_size(size) { assert(m_ptr); }
Expand All @@ -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; }

Expand All @@ -36,4 +47,36 @@ class span
std::size_t m_size;
};

template <typename T, std::size_t Sz>
class span<T, Sz, std::enable_if_t<Sz != dyn_extent>>
{
using this_type = span<T, Sz, std::enable_if_t<Sz != dyn_extent>>;
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 <typename R>
span(const span<R, Sz, void>& 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
20 changes: 18 additions & 2 deletions src/tests/stdutils/src/test_span.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
#include <catch_amalgamated.hpp>

#include <stdutils/span.h>

#include <vector>

TEST_CASE("span<T> to span<const T>", "[span]")
TEST_CASE("Dynamic extent span<T> to span<const T>", "[span]")
{
std::vector<int> test_vect { 0, 2, 3, 4 };

auto span = stdutils::span(test_vect.data(), test_vect.size());
auto span = stdutils::span<int>(test_vect.data(), test_vect.size());
span[0] = 1;
CHECK(test_vect[0] == 1);

auto const_span = stdutils::span<const int>(span);
CHECK(const_span[0] == 1);
CHECK(const_span.size() == test_vect.size());
}

TEST_CASE("Static extent span<T> to span<const T>", "[span]")
{
std::vector<int> test_vect { 1, 2, 3, 4 };

auto span = stdutils::span<int, 2>(test_vect.data() + 2);
REQUIRE(span.size() == 2);
span[0] = 0;
CHECK(test_vect[2] == 0);

auto const_span = stdutils::span<const int, 2>(span);
REQUIRE(const_span.size() == 2);
CHECK(const_span[0] == 0);
CHECK(const_span[1] == 4);
}

0 comments on commit 123c325

Please sign in to comment.