Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions stl/inc/spanstream
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ public:
explicit basic_ispanstream(_STD span<_Elem> _Span, ios_base::openmode _Which = ios_base::in)
: _Mybase(_STD addressof(_Buf)), _Buf(_Span, _Which | ios_base::in) {}

explicit basic_ispanstream(_STD span<const _Elem> _Span)
: basic_ispanstream(_STD span<_Elem>{const_cast<_Elem*>(_Span.data()), _Span.size()}) {}

basic_ispanstream(const basic_ispanstream&) = delete;

basic_ispanstream(basic_ispanstream&& _Right) : _Mybase(_STD move(_Right)), _Buf(_STD move(_Right._Buf)) {
Expand All @@ -217,8 +220,7 @@ public:
requires (
!convertible_to<_ReadOnlyRange, _STD span<_Elem>> && convertible_to<_ReadOnlyRange, _STD span<const _Elem>>)
explicit basic_ispanstream(_ReadOnlyRange&& _Range)
: basic_ispanstream(
_STD span<_Elem>{const_cast<_Elem*>(_RANGES data(_Range)), static_cast<size_t>(_RANGES size(_Range))}) {}
: basic_ispanstream(static_cast<_STD span<const _Elem>>(_STD forward<_ReadOnlyRange>(_Range))) {}

basic_ispanstream& operator=(const basic_ispanstream&) = delete;

Expand Down Expand Up @@ -251,8 +253,8 @@ public:
requires (
!convertible_to<_ReadOnlyRange, _STD span<_Elem>> && convertible_to<_ReadOnlyRange, _STD span<const _Elem>>)
void span(_ReadOnlyRange&& _Range) noexcept {
this->span(
_STD span<_Elem>{const_cast<_Elem*>(_RANGES data(_Range)), static_cast<size_t>(_RANGES size(_Range))});
const auto _Sp = static_cast<_STD span<const _Elem>>(_STD forward<_ReadOnlyRange>(_Range));
this->span(_STD span<_Elem>{const_cast<_Elem*>(_Sp.data()), _Sp.size()});
}

private:
Expand Down
56 changes: 56 additions & 0 deletions tests/std/tests/P0448R4_spanstream/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <cassert>
#include <ios>
#include <limits>
#include <list>
#include <ranges>
#include <span>
#include <spanstream>
#include <string_view>
Expand All @@ -29,6 +31,28 @@ constexpr array input_std_array{'1', ' ', '2', ' ', '3', ' ', '4', ' ', '5'};
template <>
inline constexpr array input_std_array<wchar_t>{L'1', L' ', L'2', L' ', L'3', L' ', L'4', L' ', L'5'};

template <class CharT>
list<CharT> li{};
// Neither sized_range nor contiguous_range.
template <class CharT>
struct SpecialRange {
auto begin() {
return std::begin(li<CharT>);
}
auto end() {
return std::end(li<CharT>);
}
operator span<const CharT>() const {
return span<const CharT>(input_view<CharT>);
}
};
template <class CharT>
constexpr bool ranges::enable_borrowed_range<SpecialRange<CharT>> = true;

static_assert(!ranges::sized_range<SpecialRange<char>>);
static_assert(!ranges::contiguous_range<SpecialRange<char>>);
static_assert(ranges::borrowed_range<SpecialRange<char>>);

template <class Spanbuf>
class basic_test_buf : public Spanbuf {
public:
Expand Down Expand Up @@ -626,6 +650,30 @@ void test_ispanstream() {
assert(static_cast<test_buf*>(range_constructed.rdbuf())->epptr() == nullptr);
}

Comment thread
StephanTLavavej marked this conversation as resolved.
{ // GH-4879 <spanstream>: The span constructed by basic_ispanstream's range constructor may be ill-formed
const CharT buffer[17]{};
span<const CharT> span_const_elem{buffer};
basic_ispanstream<CharT> span_const_elem_constructed{span_const_elem};
assert(span_const_elem_constructed.span().data() == buffer);
assert(static_cast<test_buf*>(span_const_elem_constructed.rdbuf())->eback() == buffer);
assert(static_cast<test_buf*>(span_const_elem_constructed.rdbuf())->gptr() == buffer);
assert(static_cast<test_buf*>(span_const_elem_constructed.rdbuf())->egptr() == end(buffer));
assert(static_cast<test_buf*>(span_const_elem_constructed.rdbuf())->pbase() == nullptr);
assert(static_cast<test_buf*>(span_const_elem_constructed.rdbuf())->pptr() == nullptr);
assert(static_cast<test_buf*>(span_const_elem_constructed.rdbuf())->epptr() == nullptr);

SpecialRange<CharT> special_range{};
auto rr = static_cast<span<const CharT>>(special_range);
basic_ispanstream<CharT> special_range_constructed{special_range};
assert(special_range_constructed.span().data() == rr.data());
assert(static_cast<test_buf*>(special_range_constructed.rdbuf())->eback() == rr.data());
assert(static_cast<test_buf*>(special_range_constructed.rdbuf())->gptr() == rr.data());
assert(static_cast<test_buf*>(special_range_constructed.rdbuf())->egptr() == rr.data() + rr.size());
assert(static_cast<test_buf*>(special_range_constructed.rdbuf())->pbase() == nullptr);
assert(static_cast<test_buf*>(special_range_constructed.rdbuf())->pptr() == nullptr);
assert(static_cast<test_buf*>(special_range_constructed.rdbuf())->epptr() == nullptr);
}

{ // span
Comment thread
StephanTLavavej marked this conversation as resolved.
CharT buffer[10];
basic_ispanstream<CharT> is{span<CharT>{buffer}};
Expand All @@ -646,6 +694,14 @@ void test_ispanstream() {
assert(is.span().data() == input_range.data());
assert(is.span().size() == input_range.size());

// also test GH-4879 for basic_ispanstream::span(ROS&&)
is.span(span<const CharT>{other_buffer});
assert(is.span().data() == other_buffer);
assert(is.span().size() == size(other_buffer));
is.span(SpecialRange<CharT>{});
assert(is.span().data() == input_range.data());
assert(is.span().size() == input_range.size());

if constexpr (is_same_v<CharT, char>) {
const char const_buffer[] = "1 2 3 4 5";
basic_ispanstream<CharT> is_const_buffer{span<const CharT>{const_buffer}};
Expand Down