Skip to content

Commit

Permalink
Make span std compliant (#317)
Browse files Browse the repository at this point in the history
* add missing overloads for span::first + span::last

The C++20 standard defines additional overloads for first and last:

  template< std::size_t Count >
  constexpr std::span<element_type, Count> first() const;
  constexpr std::span<element_type, std::dynamic_extent> first( size_type Count ) const;

  template< std::size_t Count >
  constexpr std::span<element_type, Count> last() const;
  constexpr std::span<element_type, std::dynamic_extent> last( size_type Count ) const;

etl implements only the first (= template) variants so far. To be able to
compile valid C++20 code the missing overload should be added.

* remove explicit specifier for span conversion operator

The C++20 standard allows to assign a span of non-const elements to a span of
const elements. Example:

    std::span<const int> cintspan;
    std::span<int> intspan;
    cintspan = intspan;

This is enabled in the STL by using an explicit specifier with a constant
expression for one of the conversion constructors:

    template< class R >
    explicit(extent != std::dynamic_extent)
    constexpr span( R&& r );

The explicit specifier together with a constant expression is a C++20 feature
and therefore can't be used within etl. To be able to compile valid C++20
code which uses the conversion on assignment, the explicit specifier has to
be removed.

* remove explicit specifier for span conversion operator

The C++20 standard allows to assign an array of elements directly (without
explicitly using a conversion constructor). Example:

    const int data = { 1, 2, 3 };
    std::span<const int> cintspan;
    cintspan = data;

To be able to compile valid C++20 code which uses the conversion on assignment,
the explicit specifier of the array-conversion constructor has to be removed.
  • Loading branch information
mampfes authored Dec 9, 2020
1 parent e425e25 commit 927bb3c
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 3 deletions.
22 changes: 19 additions & 3 deletions include/etl/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ namespace etl
/// data() and size() member functions.
//*************************************************************************
template <typename TSpan>
ETL_CONSTEXPR explicit span(TSpan& a) ETL_NOEXCEPT
ETL_CONSTEXPR span(TSpan& a) ETL_NOEXCEPT
: mbegin(a.data())
, mend(a.data() + a.size())
{
Expand All @@ -98,7 +98,7 @@ namespace etl
/// data() and size() member functions.
//*************************************************************************
template <typename TSpan>
ETL_CONSTEXPR explicit span(const TSpan& a) ETL_NOEXCEPT
ETL_CONSTEXPR span(const TSpan& a) ETL_NOEXCEPT
: mbegin(a.data())
, mend(a.data() + a.size())
{
Expand Down Expand Up @@ -128,7 +128,7 @@ namespace etl
/// Construct from C array
//*************************************************************************
template<const size_t ARRAY_SIZE>
ETL_CONSTEXPR explicit span(element_type(&begin_)[ARRAY_SIZE]) ETL_NOEXCEPT
ETL_CONSTEXPR span(element_type(&begin_)[ARRAY_SIZE]) ETL_NOEXCEPT
: mbegin(begin_)
, mend(begin_ + ARRAY_SIZE)
{
Expand Down Expand Up @@ -258,6 +258,14 @@ namespace etl
return etl::span<element_type, COUNT>(mbegin, mbegin + COUNT);
}

//*************************************************************************
/// Obtains a span that is a view over the first count elements of this span.
//*************************************************************************
ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> first(size_t count) const
{
return etl::span<element_type, etl::dynamic_extent>(mbegin, mbegin + count);
}

//*************************************************************************
/// Obtains a span that is a view over the last COUNT elements of this span.
//*************************************************************************
Expand All @@ -267,6 +275,14 @@ namespace etl
return etl::span<element_type, COUNT>(mend - COUNT, mend);
}

//*************************************************************************
/// Obtains a span that is a view over the last count elements of this span.
//*************************************************************************
ETL_CONSTEXPR etl::span<element_type, etl::dynamic_extent> last(size_t count) const
{
return etl::span<element_type, etl::dynamic_extent>(mend - count, mend);
}

//*************************************************************************
/// Obtains a span that is a view from OFFSET over the next COUNT elements of this span.
/// Enabled for COUNT == etl::dynamic_extent
Expand Down
69 changes: 69 additions & 0 deletions test/test_span.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,20 @@ namespace
CHECK(isEqual);
}

//*************************************************************************
TEST(test_implicit_constructor_c_array_2)
{
CView view;

view = ccdata;

CHECK_EQUAL(SIZE, view.size());
CHECK_EQUAL(SIZE, view.max_size());

bool isEqual = std::equal(view.begin(), view.end(), ccdata);
CHECK(isEqual);
}

#if ETL_USING_STL && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED)
//*************************************************************************
TEST(test_cpp17_deduced_constructor)
Expand Down Expand Up @@ -392,6 +406,19 @@ namespace
}
}

//*************************************************************************
TEST(test_assignment_operator)
{
View view(etldata);
CView cview = view;

CHECK_EQUAL(etldata.size(), view.size());
CHECK_EQUAL(etldata.max_size(), view.max_size());

bool isEqual = std::equal(view.begin(), view.end(), etldata.begin());
CHECK(isEqual);
}

//*************************************************************************
TEST(test_empty)
{
Expand Down Expand Up @@ -461,6 +488,27 @@ namespace
CHECK_EQUAL(first.size(), cresult.size());
}

//*************************************************************************
TEST(test_first_2)
{
std::vector<int> original = {1, 2, 3, 4, 5, 6, 7, 8};
std::vector<int> first = {1, 2, 3, 4, 5, 6};
View view(original);
CView cview(original);

bool isEqual;

auto result = view.first(6);
isEqual = std::equal(result.begin(), result.end(), first.begin());
CHECK(isEqual);
CHECK_EQUAL(first.size(), result.size());

auto cresult = cview.first(6);
isEqual = std::equal(cresult.begin(), cresult.end(), first.begin());
CHECK(isEqual);
CHECK_EQUAL(first.size(), cresult.size());
}

//*************************************************************************
TEST(test_last)
{
Expand All @@ -484,6 +532,27 @@ namespace
CHECK_EQUAL(last.size(), cresult.size());
}

//*************************************************************************
TEST(test_last_2)
{
std::vector<int> original = {1, 2, 3, 4, 5, 6, 7, 8};
std::vector<int> last = {3, 4, 5, 6, 7, 8};
View view(original);
CView cview(original);

bool isEqual;

auto result = view.last(6);
isEqual = std::equal(result.begin(), result.end(), last.begin());
CHECK(isEqual);
CHECK_EQUAL(last.size(), result.size());

auto cresult = cview.last(6);
isEqual = std::equal(cresult.begin(), cresult.end(), last.begin());
CHECK(isEqual);
CHECK_EQUAL(last.size(), cresult.size());
}

//*************************************************************************
TEST(test_subspan)
{
Expand Down

0 comments on commit 927bb3c

Please sign in to comment.