Skip to content

Commit

Permalink
Add element accessors on Span.
Browse files Browse the repository at this point in the history
This matches std::span and avoids people having to write span.data()[index] and
whatnot.
  • Loading branch information
bzbarsky-apple committed May 4, 2023
1 parent de1c64a commit 61819f0
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 2 deletions.
24 changes: 22 additions & 2 deletions src/lib/support/Span.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ template <class T>
class Span
{
public:
using pointer = T *;
using pointer = T *;
using reference = T &;

constexpr Span() : mDataBuf(nullptr), mDataLen(0) {}
constexpr Span(pointer databuf, size_t datalen) : mDataBuf(databuf), mDataLen(datalen) {}
Expand Down Expand Up @@ -75,6 +76,15 @@ class Span
constexpr pointer begin() const { return data(); }
constexpr pointer end() const { return data() + size(); }

// Element accessors, matching the std::span API.
constexpr reference operator[](size_t index) const
{
VerifyOrDie(index < size());
return data()[index];
}
constexpr reference front() const { return (*this)[0]; }
constexpr reference back() const { return (*this)[size() - 1]; }

template <class U, typename = std::enable_if_t<std::is_same<std::remove_const_t<T>, std::remove_const_t<U>>::value>>
bool data_equal(const Span<U> & other) const
{
Expand Down Expand Up @@ -142,7 +152,8 @@ template <class T, size_t N>
class FixedSpan
{
public:
using pointer = T *;
using pointer = T *;
using reference = T &;

constexpr FixedSpan() : mDataBuf(nullptr) {}

Expand Down Expand Up @@ -188,6 +199,15 @@ class FixedSpan
constexpr pointer begin() const { return mDataBuf; }
constexpr pointer end() const { return mDataBuf + N; }

// Element accessors, matching the std::span API.
constexpr reference operator[](size_t index) const
{
VerifyOrDie(index < size());
return data()[index];
}
constexpr reference front() const { return (*this)[0]; }
constexpr reference back() const { return (*this)[size() - 1]; }

// Allow data_equal for spans that are over the same type up to const-ness.
template <class U, typename = std::enable_if_t<std::is_same<std::remove_const_t<T>, std::remove_const_t<U>>::value>>
bool data_equal(const FixedSpan<U, N> & other) const
Expand Down
48 changes: 48 additions & 0 deletions src/lib/support/tests/TestSpan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ static void TestByteSpan(nlTestSuite * inSuite, void * inContext)
NL_TEST_ASSERT(inSuite, s2.data_equal(s2));
NL_TEST_ASSERT(inSuite, !s2.data_equal(s1));
NL_TEST_ASSERT(inSuite, IsSpanUsable(s2) == true);
NL_TEST_ASSERT(inSuite, s2.front() == 1);
NL_TEST_ASSERT(inSuite, s2.back() == 3);
NL_TEST_ASSERT(inSuite, s2[0] == 1);
NL_TEST_ASSERT(inSuite, s2[1] == 2);
NL_TEST_ASSERT(inSuite, s2[2] == 3);

// Test that for a constexpr span we can use its data as compile-time
// constants.
{
static constexpr uint8_t constArr[] = { 2, 3, 4 };
constexpr ByteSpan constSpan(constArr);

static_assert(constSpan.front() == 2, "Unexpected front()");
uint8_t t1[constSpan.front()];
NL_TEST_ASSERT(inSuite, ArraySize(t1) == 2);

static_assert(constSpan.back() == 4, "Unexpected back()");
uint8_t t2[constSpan.back()];
NL_TEST_ASSERT(inSuite, ArraySize(t2) == 4);

static_assert(constSpan[1] == 3, "Unexpected [1]");
uint8_t t3[constSpan[1]];
NL_TEST_ASSERT(inSuite, ArraySize(t3) == 3);
}

ByteSpan s3 = s2;
NL_TEST_ASSERT(inSuite, s3.data() == arr);
Expand Down Expand Up @@ -175,6 +199,30 @@ static void TestFixedByteSpan(nlTestSuite * inSuite, void * inContext)
NL_TEST_ASSERT(inSuite, s2.data()[2] == 3);
NL_TEST_ASSERT(inSuite, !s2.empty());
NL_TEST_ASSERT(inSuite, s2.data_equal(s2));
NL_TEST_ASSERT(inSuite, s2.front() == 1);
NL_TEST_ASSERT(inSuite, s2.back() == 3);
NL_TEST_ASSERT(inSuite, s2[0] == 1);
NL_TEST_ASSERT(inSuite, s2[1] == 2);
NL_TEST_ASSERT(inSuite, s2[2] == 3);

// Test that for a constexpr span we can use its data as compile-time
// constants.
{
static constexpr uint8_t constArr[] = { 2, 3, 4 };
constexpr FixedByteSpan<ArraySize(constArr)> constSpan(constArr);

static_assert(constSpan.front() == 2, "Unexpected front()");
uint8_t t1[constSpan.front()];
NL_TEST_ASSERT(inSuite, ArraySize(t1) == 2);

static_assert(constSpan.back() == 4, "Unexpected back()");
uint8_t t2[constSpan.back()];
NL_TEST_ASSERT(inSuite, ArraySize(t2) == 4);

static_assert(constSpan[1] == 3, "Unexpected [1]");
uint8_t t3[constSpan[1]];
NL_TEST_ASSERT(inSuite, ArraySize(t3) == 3);
}

FixedByteSpan<3> s3 = s2;
NL_TEST_ASSERT(inSuite, s3.data() == arr);
Expand Down

0 comments on commit 61819f0

Please sign in to comment.