From ba487bcb0421ec27116a9f795e4db69192b82030 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 6 May 2025 09:52:51 +0200 Subject: [PATCH] Add take() to etl::span (#1083) --- include/etl/span.h | 37 +++++++++ test/test_span_dynamic_extent.cpp | 131 ++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/include/etl/span.h b/include/etl/span.h index 5e364b23..32bf118b 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -932,6 +932,43 @@ namespace etl (pend - pbegin) * sizeof(element_type) / sizeof(TNew)); } + //************************************************************************* + /// Split off and return an initial span of specified type of this span. + /// The original span is advanced by the size of the returned span. + /// \tparam TRet Returned span type + /// \param n Number of elements in returned span + //************************************************************************* + template + ETL_NODISCARD etl::span take(size_t const n) + { + ETL_STATIC_ASSERT(sizeof(TRet) % sizeof(element_type) == 0, "sizeof(TRet) must be divisible by sizeof(T)"); + + ETL_ASSERT(etl::is_aligned::value>(pbegin), ETL_ERROR(span_alignment_exception)); + ETL_ASSERT(sizeof(TRet) * n <= sizeof(element_type) * size(), ETL_ERROR(span_size_mismatch)); + + etl::span result = reinterpret_as().first(n); + advance(sizeof(TRet) / sizeof(element_type) * n); + return result; + } + + //************************************************************************* + /// Split off and return an initial value of specified type of this span. + /// The original span is advanced by the size of TRet + /// \tparam TRet Returned span type + //************************************************************************* + template + ETL_NODISCARD TRet& take() + { + ETL_STATIC_ASSERT(sizeof(TRet) % sizeof(element_type) == 0, "sizeof(TRet) must be divisible by sizeof(T)"); + + ETL_ASSERT(etl::is_aligned::value>(pbegin), ETL_ERROR(span_alignment_exception)); + ETL_ASSERT(sizeof(TRet) <= sizeof(element_type) * size(), ETL_ERROR(span_size_mismatch)); + + TRet& result = *reinterpret_cast(data()); + advance(sizeof(TRet) / sizeof(element_type)); + return result; + } + private: pointer pbegin; diff --git a/test/test_span_dynamic_extent.cpp b/test/test_span_dynamic_extent.cpp index ee85f843..9707dd1d 100644 --- a/test/test_span_dynamic_extent.cpp +++ b/test/test_span_dynamic_extent.cpp @@ -1370,6 +1370,137 @@ namespace CHECK_EQUAL(etl::copy(data0, data1), true); } + //************************************************************************* + TEST(test_take_span_size_error) + { + uint8_t src[] = { 0x01, 0x02, 0x03 }; + etl::span data0 = src; + + CHECK_THROW({etl::span data1 = data0.take(1); (void) data1;}, etl::span_size_mismatch); + } + + //************************************************************************* + TEST(test_take_span) + { + uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05 }; + etl::span data0 = src; + + etl::span data1 = data0.take(1); + + CHECK_EQUAL(data0.size(), 4); + CHECK_EQUAL(data1.size(), 1); + CHECK_EQUAL(data1[0], 0x01); + + etl::span data2 = data0.take(1); + + CHECK_EQUAL(data0.size(), 0); + CHECK_EQUAL(data2.size(), 1); + CHECK_EQUAL(data2[0], 0x02030405); + + data1 = data0.take(0); + + CHECK_EQUAL(data0.size(), 0); + CHECK_EQUAL(data1.size(), 0); + + CHECK_THROW({etl::span data3 = data0.take(1); (void) data3;}, etl::span_size_mismatch); + } + + //************************************************************************* + TEST(test_take_span_2) + { + + uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a }; + etl::span data0 = src; + + etl::span data1 = data0.take(2); + + CHECK_EQUAL(data0.size(), 2); + CHECK_EQUAL(data1.size(), 2); + CHECK_EQUAL(data1[0], 0x01020304); + CHECK_EQUAL(data1[1], 0x05060708); + + etl::span data2 = data0.take(1); + + CHECK_EQUAL(data0.size(), 1); + CHECK_EQUAL(data2.size(), 1); + CHECK_EQUAL(data2[0], 0x09); + } + + //************************************************************************* + TEST(test_take_span_const) + { + const uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a }; + etl::span data0 = src; + + etl::span data1 = data0.take(2); + + CHECK_EQUAL(data0.size(), 2); + CHECK_EQUAL(data1.size(), 2); + CHECK_EQUAL(data1[0], 0x01020304); + CHECK_EQUAL(data1[1], 0x05060708); + + etl::span data2 = data0.take(1); + + CHECK_EQUAL(data0.size(), 1); + CHECK_EQUAL(data2.size(), 1); + CHECK_EQUAL(data2[0], 0x09); + + data2 = data0.take(0); + + CHECK_EQUAL(data0.size(), 1); + CHECK_EQUAL(data2.size(), 0); + } + + //************************************************************************* + TEST(test_take_value) + { + uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a }; + etl::span data0 = src; + + uint8_t& data1 = data0.take(); + CHECK_EQUAL(data0.size(), 9); + CHECK_EQUAL(data1, 0x01); + + etl::be_uint32_t& data2 = data0.take(); + CHECK_EQUAL(data0.size(), 5); + CHECK_EQUAL(data2, 0x02030405); + + etl::be_uint32_t& data3 = data0.take(); + CHECK_EQUAL(data0.size(), 1); + CHECK_EQUAL(data3, 0x06070809); + + uint8_t& data4 = data0.take(); + CHECK_EQUAL(data0.size(), 0); + CHECK_EQUAL(data4, 0x0a); + + CHECK_THROW({uint8_t& data5 = data0.take(); (void) data5;}, etl::span_size_mismatch); + } + + //************************************************************************* + TEST(test_take_value_const) + { + const uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a }; + etl::span data0 = src; + + const uint8_t& data1 = data0.take(); + CHECK_EQUAL(data0.size(), 9); + CHECK_EQUAL(data1, 0x01); + + const etl::be_uint32_t& data2 = data0.take(); + CHECK_EQUAL(data0.size(), 5); + CHECK_EQUAL(data2, 0x02030405); + + const etl::be_uint32_t& data3 = data0.take(); + CHECK_EQUAL(data0.size(), 1); + CHECK_EQUAL(data3, 0x06070809); + + const uint8_t& data4 = data0.take(); + CHECK_EQUAL(data0.size(), 0); + CHECK_EQUAL(data4, 0x0a); + + CHECK_THROW({const uint8_t& data5 = data0.take(); (void) data5;}, etl::span_size_mismatch); + } + #include "etl/private/diagnostic_pop.h" }; }