Skip to content

Commit bbb58b9

Browse files
etl::span: Add advance(), copy(), reinterpret_as()
1 parent 37539a2 commit bbb58b9

File tree

4 files changed

+268
-0
lines changed

4 files changed

+268
-0
lines changed

include/etl/file_error_numbers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,6 @@ SOFTWARE.
105105
#define ETL_BASE64_FILE_ID "72"
106106
#define ETL_SINGLETON_BASE_FILE_ID "73"
107107
#define ETL_UNALIGNED_TYPE_FILE_ID "74"
108+
#define ETL_SPAN_FILE_ID "75"
109+
108110
#endif

include/etl/span.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ SOFTWARE.
3232
#define ETL_SPAN_INCLUDED
3333

3434
#include "platform.h"
35+
36+
#include "error_handler.h"
37+
#include "exception.h"
38+
#include "alignment.h"
3539
#include "iterator.h"
3640
#include "algorithm.h"
3741
#include "circular_iterator.h"
@@ -55,6 +59,34 @@ SOFTWARE.
5559

5660
namespace etl
5761
{
62+
//***************************************************************************
63+
///\ingroup span
64+
/// Exception base for span
65+
//***************************************************************************
66+
class span_exception : public exception
67+
{
68+
public:
69+
70+
span_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
71+
: exception(reason_, file_name_, line_number_)
72+
{
73+
}
74+
};
75+
76+
//***************************************************************************
77+
///\ingroup span
78+
/// Bad alignment exception.
79+
//***************************************************************************
80+
class span_alignment_exception : public span_exception
81+
{
82+
public:
83+
84+
span_alignment_exception(string_type file_name_, numeric_type line_number_)
85+
: span_exception(ETL_ERROR_TEXT("span:alignment", ETL_SPAN_FILE_ID"A"), file_name_, line_number_)
86+
{
87+
}
88+
};
89+
5890
//***************************************************************************
5991
/// Span - Fixed Extent
6092
//***************************************************************************
@@ -426,6 +458,18 @@ namespace etl
426458
: etl::span<element_type, etl::dynamic_extent>(pbegin + offset, pbegin + offset + count);
427459
}
428460

461+
//*************************************************************************
462+
/// Reinterpret the span as a span with different element type.
463+
//*************************************************************************
464+
template<typename TNew>
465+
ETL_NODISCARD ETL_CONSTEXPR14 etl::span<TNew, etl::dynamic_extent> reinterpret_as() const
466+
{
467+
ETL_ASSERT(etl::is_aligned<etl::alignment_of<TNew>::value>(pbegin), ETL_ERROR(span_alignment_exception));
468+
469+
return etl::span<TNew, etl::dynamic_extent>(reinterpret_cast<TNew*>(pbegin),
470+
Extent * sizeof(element_type) / sizeof(TNew));
471+
}
472+
429473
private:
430474

431475
pointer pbegin;
@@ -812,6 +856,28 @@ namespace etl
812856
: etl::span<element_type, etl::dynamic_extent>(pbegin + offset, pbegin + offset + count);
813857
}
814858

859+
//*************************************************************************
860+
/// Moves the pointer to the first element of the span further by a specified number of elements.
861+
///\tparam elements Number of elements to move forward
862+
//*************************************************************************
863+
void advance(size_t elements) ETL_NOEXCEPT
864+
{
865+
elements = etl::min(elements, size());
866+
pbegin += elements;
867+
}
868+
869+
//*************************************************************************
870+
/// Reinterpret the span as a span with different element type.
871+
//*************************************************************************
872+
template<typename TNew>
873+
ETL_NODISCARD ETL_CONSTEXPR14 etl::span<TNew, etl::dynamic_extent> reinterpret_as() const
874+
{
875+
ETL_ASSERT(etl::is_aligned<etl::alignment_of<TNew>::value>(pbegin), ETL_ERROR(span_alignment_exception));
876+
877+
return etl::span<TNew, etl::dynamic_extent>(reinterpret_cast<TNew*>(pbegin),
878+
(pend - pbegin) * sizeof(element_type) / sizeof(TNew));
879+
}
880+
815881
private:
816882

817883
pointer pbegin;
@@ -884,6 +950,33 @@ namespace etl
884950
etl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
885951
}
886952

953+
//*************************************************************************
954+
/// Copy complete element data from one span to another. If the destination
955+
/// span is bigger than the source span, only the initial part of
956+
/// destination span is overwritten.
957+
///\param src Source
958+
///\param dst Destination
959+
///\return true, if copy was successful (including empty source span, or
960+
/// spans pointing to the same address)
961+
///\return false, if the destination span is shorter than the source span.
962+
//*************************************************************************
963+
template <typename T1, size_t N1, typename T2, size_t N2>
964+
typename etl::enable_if<etl::is_same<typename etl::remove_cv<T1>::type, typename etl::remove_cv<T2>::type>::value &&
965+
!etl::is_const<T2>::value, bool>::type
966+
copy(const etl::span<T1, N1>& src, const etl::span<T2, N2>& dst)
967+
{
968+
if (src.empty() || (src.begin() == dst.begin()))
969+
{
970+
return true;
971+
}
972+
if (src.size() > dst.size())
973+
{
974+
return false;
975+
}
976+
(void) etl::copy(src.begin(), src.end(), dst.begin());
977+
return true;
978+
}
979+
887980
//*************************************************************************
888981
/// Template deduction guides.
889982
//*************************************************************************

test/test_span_dynamic_extent.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ SOFTWARE.
3030

3131
#include "etl/span.h"
3232
#include "etl/array.h"
33+
#include "etl/unaligned_type.h"
3334

3435
#include <array>
3536
#include <vector>
@@ -1244,6 +1245,108 @@ namespace
12441245
}
12451246
}
12461247

1248+
//*************************************************************************
1249+
TEST(test_advance)
1250+
{
1251+
{
1252+
uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
1253+
etl::span<uint8_t> data0 = data;
1254+
1255+
CHECK_EQUAL(data0.size(), 5);
1256+
data0.advance(1);
1257+
CHECK_EQUAL(data0.size(), 4);
1258+
CHECK_EQUAL(data0[0], 0x02);
1259+
data0.advance(2);
1260+
CHECK_EQUAL(data0.size(), 2);
1261+
CHECK_EQUAL(data0[0], 0x04);
1262+
data0.advance(1);
1263+
CHECK_EQUAL(data0.size(), 1);
1264+
CHECK_EQUAL(data0[0], 0x05);
1265+
data0.advance(1);
1266+
CHECK_EQUAL(data0.size(), 0);
1267+
}
1268+
{
1269+
const uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
1270+
etl::span<const uint8_t> data0 = data;
1271+
1272+
CHECK_EQUAL(data0.size(), 5);
1273+
data0.advance(1);
1274+
CHECK_EQUAL(data0.size(), 4);
1275+
CHECK_EQUAL(data0[0], 0x02);
1276+
data0.advance(2);
1277+
CHECK_EQUAL(data0.size(), 2);
1278+
CHECK_EQUAL(data0[0], 0x04);
1279+
data0.advance(1);
1280+
CHECK_EQUAL(data0.size(), 1);
1281+
CHECK_EQUAL(data0[0], 0x05);
1282+
data0.advance(1);
1283+
CHECK_EQUAL(data0.size(), 0);
1284+
data0.advance(1);
1285+
CHECK_EQUAL(data0.size(), 0);
1286+
data0.advance(100);
1287+
CHECK_EQUAL(data0.size(), 0);
1288+
}
1289+
}
1290+
1291+
//*************************************************************************
1292+
TEST(test_reinterpret_as)
1293+
{
1294+
uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
1295+
etl::span<uint8_t> data0 = data;
1296+
1297+
etl::span<etl::be_uint16_t> data1 = data0.reinterpret_as<etl::be_uint16_t>();
1298+
1299+
CHECK_EQUAL(data1.size(), 2);
1300+
CHECK(data1[0] == 0x102);
1301+
CHECK(data1[1] == 0x304);
1302+
}
1303+
1304+
//*************************************************************************
1305+
TEST(test_reinterpret_as_aligned)
1306+
{
1307+
uint32_t data[] = { 0x01020304, 0x020406080, 0x03400560};
1308+
etl::span<uint32_t> data0 = data;
1309+
CHECK_EQUAL(data0.size(), 3);
1310+
1311+
etl::span<uint8_t> data1 = data0.reinterpret_as<uint8_t>();
1312+
CHECK_EQUAL(data1.size(), 12);
1313+
1314+
etl::span<uint16_t> data2 = data1.subspan(2).reinterpret_as<uint16_t>();
1315+
CHECK_EQUAL(data2.size(), 5);
1316+
1317+
CHECK_THROW(data2 = data1.subspan(1).reinterpret_as<uint16_t>(), etl::span_alignment_exception);
1318+
}
1319+
1320+
//*************************************************************************
1321+
TEST(test_copy)
1322+
{
1323+
uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
1324+
uint8_t dst[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1325+
etl::span<uint8_t> data0 = src;
1326+
etl::span<uint8_t> data1 = dst;
1327+
1328+
CHECK_EQUAL(etl::copy(data0, data1), true);
1329+
CHECK(std::equal(data0.begin(), data0.end(), data1.begin()));
1330+
1331+
data1 = data1.subspan(1);
1332+
1333+
CHECK_EQUAL(etl::copy(data0, data1), true);
1334+
CHECK(std::equal(data0.begin(), data0.end(), data1.begin()));
1335+
1336+
data1 = data1.subspan(1);
1337+
1338+
CHECK_EQUAL(etl::copy(data0, data1), false);
1339+
1340+
data0 = data0.subspan(0, 0);
1341+
1342+
CHECK_EQUAL(etl::copy(data0, data1), true);
1343+
1344+
data0 = src;
1345+
data1 = src;
1346+
1347+
CHECK_EQUAL(etl::copy(data0, data1), true);
1348+
}
1349+
12471350
#include "etl/private/diagnostic_pop.h"
12481351
};
12491352
}

test/test_span_fixed_extent.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ SOFTWARE.
3030

3131
#include "etl/span.h"
3232
#include "etl/array.h"
33+
#include "etl/unaligned_type.h"
3334

3435
#include <array>
3536
#include <vector>
@@ -1166,6 +1167,75 @@ namespace
11661167
}
11671168
}
11681169

1170+
//*************************************************************************
1171+
TEST(test_reinterpret_as)
1172+
{
1173+
uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
1174+
etl::span<uint8_t, 5> data0 = data;
1175+
1176+
etl::span<etl::be_uint16_t> data1 = data0.reinterpret_as<etl::be_uint16_t>();
1177+
1178+
CHECK_EQUAL(data1.size(), 2);
1179+
CHECK(data1[0] == 0x102);
1180+
CHECK(data1[1] == 0x304);
1181+
}
1182+
1183+
//*************************************************************************
1184+
TEST(test_reinterpret_as_aligned)
1185+
{
1186+
uint32_t data[] = { 0x01020304, 0x020406080, 0x03400560};
1187+
etl::span<uint32_t, 3> data0 = data;
1188+
CHECK_EQUAL(data0.size(), 3);
1189+
1190+
etl::span<uint8_t> data1 = data0.reinterpret_as<uint8_t>();
1191+
CHECK_EQUAL(data1.size(), 12);
1192+
1193+
etl::span<uint16_t> data2 = data1.subspan(2).reinterpret_as<uint16_t>();
1194+
CHECK_EQUAL(data2.size(), 5);
1195+
1196+
CHECK_THROW(data2 = data1.subspan(1).reinterpret_as<uint16_t>(), etl::span_alignment_exception);
1197+
}
1198+
1199+
//*************************************************************************
1200+
TEST(test_copy)
1201+
{
1202+
uint8_t src[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
1203+
uint8_t dst[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1204+
{
1205+
etl::span<uint8_t, 5> data0 = src;
1206+
etl::span<uint8_t, 6> data1 = dst;
1207+
1208+
CHECK_EQUAL(etl::copy(data0, data1), true);
1209+
CHECK(std::equal(data0.begin(), data0.end(), data1.begin()));
1210+
}
1211+
{
1212+
etl::span<uint8_t, 5> data0 = src;
1213+
etl::span<uint8_t, 5> data1(&dst[1], 5);
1214+
1215+
CHECK_EQUAL(etl::copy(data0, data1), true);
1216+
CHECK(std::equal(data0.begin(), data0.end(), data1.begin()));
1217+
}
1218+
1219+
{
1220+
etl::span<uint8_t, 5> data0 = src;
1221+
etl::span<uint8_t, 4> data1(&dst[2], 4);
1222+
1223+
CHECK_EQUAL(etl::copy(data0, data1), false);
1224+
}
1225+
{
1226+
etl::span<uint8_t, 0> data0(&src[0], 0);
1227+
etl::span<uint8_t, 6> data1 = dst;
1228+
1229+
CHECK_EQUAL(etl::copy(data0, data1), true);
1230+
}
1231+
{
1232+
etl::span<uint8_t, 5> data0 = src;
1233+
etl::span<uint8_t, 5> data1 = src;
1234+
1235+
CHECK_EQUAL(etl::copy(data0, data1), true);
1236+
}
1237+
}
1238+
11691239
#include "etl/private/diagnostic_pop.h"
11701240
};
11711241
}

0 commit comments

Comments
 (0)