Skip to content

Commit

Permalink
etl::span: Add advance(), copy(), reinterpret_as()
Browse files Browse the repository at this point in the history
  • Loading branch information
rolandreichweinbmw committed Mar 2, 2025
1 parent 37539a2 commit bbb58b9
Show file tree
Hide file tree
Showing 4 changed files with 268 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/etl/file_error_numbers.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,6 @@ SOFTWARE.
#define ETL_BASE64_FILE_ID "72"
#define ETL_SINGLETON_BASE_FILE_ID "73"
#define ETL_UNALIGNED_TYPE_FILE_ID "74"
#define ETL_SPAN_FILE_ID "75"

#endif
93 changes: 93 additions & 0 deletions include/etl/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ SOFTWARE.
#define ETL_SPAN_INCLUDED

#include "platform.h"

#include "error_handler.h"
#include "exception.h"
#include "alignment.h"
#include "iterator.h"
#include "algorithm.h"
#include "circular_iterator.h"
Expand All @@ -55,6 +59,34 @@ SOFTWARE.

namespace etl
{
//***************************************************************************
///\ingroup span
/// Exception base for span
//***************************************************************************
class span_exception : public exception
{
public:

span_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
: exception(reason_, file_name_, line_number_)
{
}
};

//***************************************************************************
///\ingroup span
/// Bad alignment exception.
//***************************************************************************
class span_alignment_exception : public span_exception
{
public:

span_alignment_exception(string_type file_name_, numeric_type line_number_)
: span_exception(ETL_ERROR_TEXT("span:alignment", ETL_SPAN_FILE_ID"A"), file_name_, line_number_)
{
}
};

//***************************************************************************
/// Span - Fixed Extent
//***************************************************************************
Expand Down Expand Up @@ -426,6 +458,18 @@ namespace etl
: etl::span<element_type, etl::dynamic_extent>(pbegin + offset, pbegin + offset + count);
}

//*************************************************************************
/// Reinterpret the span as a span with different element type.
//*************************************************************************
template<typename TNew>
ETL_NODISCARD ETL_CONSTEXPR14 etl::span<TNew, etl::dynamic_extent> reinterpret_as() const
{
ETL_ASSERT(etl::is_aligned<etl::alignment_of<TNew>::value>(pbegin), ETL_ERROR(span_alignment_exception));

return etl::span<TNew, etl::dynamic_extent>(reinterpret_cast<TNew*>(pbegin),
Extent * sizeof(element_type) / sizeof(TNew));
}

private:

pointer pbegin;
Expand Down Expand Up @@ -812,6 +856,28 @@ namespace etl
: etl::span<element_type, etl::dynamic_extent>(pbegin + offset, pbegin + offset + count);
}

//*************************************************************************
/// Moves the pointer to the first element of the span further by a specified number of elements.
///\tparam elements Number of elements to move forward
//*************************************************************************
void advance(size_t elements) ETL_NOEXCEPT
{
elements = etl::min(elements, size());
pbegin += elements;
}

//*************************************************************************
/// Reinterpret the span as a span with different element type.
//*************************************************************************
template<typename TNew>
ETL_NODISCARD ETL_CONSTEXPR14 etl::span<TNew, etl::dynamic_extent> reinterpret_as() const
{
ETL_ASSERT(etl::is_aligned<etl::alignment_of<TNew>::value>(pbegin), ETL_ERROR(span_alignment_exception));

return etl::span<TNew, etl::dynamic_extent>(reinterpret_cast<TNew*>(pbegin),
(pend - pbegin) * sizeof(element_type) / sizeof(TNew));
}

private:

pointer pbegin;
Expand Down Expand Up @@ -884,6 +950,33 @@ namespace etl
etl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

//*************************************************************************
/// Copy complete element data from one span to another. If the destination
/// span is bigger than the source span, only the initial part of
/// destination span is overwritten.
///\param src Source
///\param dst Destination
///\return true, if copy was successful (including empty source span, or
/// spans pointing to the same address)
///\return false, if the destination span is shorter than the source span.
//*************************************************************************
template <typename T1, size_t N1, typename T2, size_t N2>
typename etl::enable_if<etl::is_same<typename etl::remove_cv<T1>::type, typename etl::remove_cv<T2>::type>::value &&
!etl::is_const<T2>::value, bool>::type
copy(const etl::span<T1, N1>& src, const etl::span<T2, N2>& dst)
{
if (src.empty() || (src.begin() == dst.begin()))
{
return true;
}
if (src.size() > dst.size())
{
return false;
}
(void) etl::copy(src.begin(), src.end(), dst.begin());
return true;
}

//*************************************************************************
/// Template deduction guides.
//*************************************************************************
Expand Down
103 changes: 103 additions & 0 deletions test/test_span_dynamic_extent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ SOFTWARE.

#include "etl/span.h"
#include "etl/array.h"
#include "etl/unaligned_type.h"

#include <array>
#include <vector>
Expand Down Expand Up @@ -1244,6 +1245,108 @@ namespace
}
}

//*************************************************************************
TEST(test_advance)
{
{
uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
etl::span<uint8_t> data0 = data;

CHECK_EQUAL(data0.size(), 5);
data0.advance(1);
CHECK_EQUAL(data0.size(), 4);
CHECK_EQUAL(data0[0], 0x02);
data0.advance(2);
CHECK_EQUAL(data0.size(), 2);
CHECK_EQUAL(data0[0], 0x04);
data0.advance(1);
CHECK_EQUAL(data0.size(), 1);
CHECK_EQUAL(data0[0], 0x05);
data0.advance(1);
CHECK_EQUAL(data0.size(), 0);
}
{
const uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
etl::span<const uint8_t> data0 = data;

CHECK_EQUAL(data0.size(), 5);
data0.advance(1);
CHECK_EQUAL(data0.size(), 4);
CHECK_EQUAL(data0[0], 0x02);
data0.advance(2);
CHECK_EQUAL(data0.size(), 2);
CHECK_EQUAL(data0[0], 0x04);
data0.advance(1);
CHECK_EQUAL(data0.size(), 1);
CHECK_EQUAL(data0[0], 0x05);
data0.advance(1);
CHECK_EQUAL(data0.size(), 0);
data0.advance(1);
CHECK_EQUAL(data0.size(), 0);
data0.advance(100);
CHECK_EQUAL(data0.size(), 0);
}
}

//*************************************************************************
TEST(test_reinterpret_as)
{
uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
etl::span<uint8_t> data0 = data;

etl::span<etl::be_uint16_t> data1 = data0.reinterpret_as<etl::be_uint16_t>();

CHECK_EQUAL(data1.size(), 2);
CHECK(data1[0] == 0x102);
CHECK(data1[1] == 0x304);
}

//*************************************************************************
TEST(test_reinterpret_as_aligned)
{
uint32_t data[] = { 0x01020304, 0x020406080, 0x03400560};
etl::span<uint32_t> data0 = data;
CHECK_EQUAL(data0.size(), 3);

etl::span<uint8_t> data1 = data0.reinterpret_as<uint8_t>();
CHECK_EQUAL(data1.size(), 12);

etl::span<uint16_t> data2 = data1.subspan(2).reinterpret_as<uint16_t>();
CHECK_EQUAL(data2.size(), 5);

CHECK_THROW(data2 = data1.subspan(1).reinterpret_as<uint16_t>(), etl::span_alignment_exception);
}

//*************************************************************************
TEST(test_copy)
{
uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
uint8_t dst[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
etl::span<uint8_t> data0 = src;
etl::span<uint8_t> data1 = dst;

CHECK_EQUAL(etl::copy(data0, data1), true);
CHECK(std::equal(data0.begin(), data0.end(), data1.begin()));

data1 = data1.subspan(1);

CHECK_EQUAL(etl::copy(data0, data1), true);
CHECK(std::equal(data0.begin(), data0.end(), data1.begin()));

data1 = data1.subspan(1);

CHECK_EQUAL(etl::copy(data0, data1), false);

data0 = data0.subspan(0, 0);

CHECK_EQUAL(etl::copy(data0, data1), true);

data0 = src;
data1 = src;

CHECK_EQUAL(etl::copy(data0, data1), true);
}

#include "etl/private/diagnostic_pop.h"
};
}
70 changes: 70 additions & 0 deletions test/test_span_fixed_extent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ SOFTWARE.

#include "etl/span.h"
#include "etl/array.h"
#include "etl/unaligned_type.h"

#include <array>
#include <vector>
Expand Down Expand Up @@ -1166,6 +1167,75 @@ namespace
}
}

//*************************************************************************
TEST(test_reinterpret_as)
{
uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
etl::span<uint8_t, 5> data0 = data;

etl::span<etl::be_uint16_t> data1 = data0.reinterpret_as<etl::be_uint16_t>();

CHECK_EQUAL(data1.size(), 2);
CHECK(data1[0] == 0x102);
CHECK(data1[1] == 0x304);
}

//*************************************************************************
TEST(test_reinterpret_as_aligned)
{
uint32_t data[] = { 0x01020304, 0x020406080, 0x03400560};
etl::span<uint32_t, 3> data0 = data;
CHECK_EQUAL(data0.size(), 3);

etl::span<uint8_t> data1 = data0.reinterpret_as<uint8_t>();
CHECK_EQUAL(data1.size(), 12);

etl::span<uint16_t> data2 = data1.subspan(2).reinterpret_as<uint16_t>();
CHECK_EQUAL(data2.size(), 5);

CHECK_THROW(data2 = data1.subspan(1).reinterpret_as<uint16_t>(), etl::span_alignment_exception);
}

//*************************************************************************
TEST(test_copy)
{
uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
uint8_t dst[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
{
etl::span<uint8_t, 5> data0 = src;
etl::span<uint8_t, 6> data1 = dst;

CHECK_EQUAL(etl::copy(data0, data1), true);
CHECK(std::equal(data0.begin(), data0.end(), data1.begin()));
}
{
etl::span<uint8_t, 5> data0 = src;
etl::span<uint8_t, 5> data1(&dst[1], 5);

CHECK_EQUAL(etl::copy(data0, data1), true);
CHECK(std::equal(data0.begin(), data0.end(), data1.begin()));
}

{
etl::span<uint8_t, 5> data0 = src;
etl::span<uint8_t, 4> data1(&dst[2], 4);

CHECK_EQUAL(etl::copy(data0, data1), false);
}
{
etl::span<uint8_t, 0> data0(&src[0], 0);
etl::span<uint8_t, 6> data1 = dst;

CHECK_EQUAL(etl::copy(data0, data1), true);
}
{
etl::span<uint8_t, 5> data0 = src;
etl::span<uint8_t, 5> data1 = src;

CHECK_EQUAL(etl::copy(data0, data1), true);
}
}

#include "etl/private/diagnostic_pop.h"
};
}

0 comments on commit bbb58b9

Please sign in to comment.