Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement P2474R2 views::repeat #3142

Merged
merged 39 commits into from
Jan 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4ff0a17
Implement P2474R2 views::repeat
SuperWig Oct 4, 2022
80d2204
Whitespace
SuperWig Oct 4, 2022
5ff30e2
Add _HAS_CXX23 guards
SuperWig Oct 4, 2022
bb314fd
don't know how that happened.
SuperWig Oct 4, 2022
ff4130e
5th time's the charm.
SuperWig Oct 4, 2022
409fb75
Increase test coverage slightly.
SuperWig Oct 5, 2022
1db12e8
[skip ci] Small visualizer change.
SuperWig Oct 6, 2022
5373dd6
Merge remote-tracking branch 'upstream/main' into repeat
SuperWig Oct 12, 2022
755a628
index_type should be _Ugly
SuperWig Oct 12, 2022
4bbe250
Add _STD qualification, also std:: -> _STD
SuperWig Oct 12, 2022
144c5e1
Alow for _Iterator to be moved
SuperWig Oct 12, 2022
b7f303e
iterator debug
SuperWig Oct 12, 2022
436ec04
simple noexcept
SuperWig Oct 13, 2022
f05637a
Test updates
SuperWig Oct 13, 2022
db180a0
static_cast -> forward and _Wx -> _Ty
SuperWig Oct 13, 2022
5a9670f
remove std::
SuperWig Oct 13, 2022
380f8f0
Merge remote-tracking branch 'upstream/main' into repeat
SuperWig Oct 15, 2022
07b4abc
formatting
SuperWig Oct 15, 2022
3f32ce0
Add pipe test
SuperWig Oct 15, 2022
1877813
Clean up constructors
SuperWig Oct 15, 2022
3b5c7e5
Correct noexcept spec of views::take and views::drop
SuperWig Oct 15, 2022
03d6e19
Move _Range_val_t
SuperWig Oct 15, 2022
d022a93
Format
SuperWig Oct 15, 2022
e61f8e9
Minor changes
SuperWig Oct 21, 2022
fdbb127
Simple CR fixes
SuperWig Oct 22, 2022
64abf5b
Debug check improvements
SuperWig Oct 23, 2022
540c26d
cat
SuperWig Oct 23, 2022
3fac277
Merge remote-tracking branch 'upstream/main' into repeat
SuperWig Oct 27, 2022
664a916
Add negative overflow death test.
SuperWig Oct 27, 2022
448dd5c
Add check for overflow when decrementing
SuperWig Nov 5, 2022
26958f1
formatting
SuperWig Nov 5, 2022
f47ddaf
Merge branch 'main' into repeat
StephanTLavavej Nov 12, 2022
4677d5f
Most of Casey's comments
SuperWig Jan 17, 2023
307056b
format
SuperWig Jan 17, 2023
c92be7e
Whoopsie daisy. Should have restored from main instead of a prior com…
SuperWig Jan 18, 2023
29cc254
before begin and update death test .
SuperWig Jan 20, 2023
d01b498
Merge remote-tracking branch 'upstream/main' into repeat
SuperWig Jan 25, 2023
4dade06
Consistency is hard
SuperWig Jan 25, 2023
e0401a1
Code review feedback.
StephanTLavavej Jan 26, 2023
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
40 changes: 39 additions & 1 deletion stl/debugger/STL.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -1828,7 +1828,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
</Type>

<Type Name="std::ranges::single_view&lt;*&gt;">
<DisplayString>{{ _Val._Val }}</DisplayString>
<DisplayString>[{ _Val._Val }]</DisplayString>
<Expand>
<ArrayItems>
<Size>1</Size>
Expand Down Expand Up @@ -1862,6 +1862,44 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
</Expand>
</Type>

<Type Name="std::ranges::repeat_view&lt;*,*&gt;">
<DisplayString>[{_Value._Val} x {_Bound}]</DisplayString>
<Expand>
<Item Name="[size]">_Bound</Item>
<CustomListItems Optional="true">
<Variable Name="idx" InitialValue="0" />

<Loop>
<Break Condition="idx == _Bound"/>
<Item>_Value._Val</Item>
<Exec>++idx</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>

<Type Name="std::ranges::repeat_view&lt;*,std::unreachable_sentinel_t&gt;">
<DisplayString>[{_Value._Val} x +&#8734;]</DisplayString>
<Expand>
<Item Name="[+&#8734;]">_Value._Val</Item>
</Expand>
</Type>

<Type Name="std::ranges::repeat_view&lt;*,*&gt;::_Iterator">
<DisplayString>{*_Value}</DisplayString>
<Expand>
<Item Name="[ptr]">_Value</Item>
<Item Name="[index]">_Current</Item>
</Expand>
</Type>

<Type Name="std::ranges::repeat_view&lt;*,std::unreachable_sentinel_t&gt;::_Iterator">
<DisplayString>{*_Value}</DisplayString>
<Expand>
<Item Name="[ptr]">_Value</Item>
</Expand>
</Type>

<Type Name="std::ranges::view_interface&lt;*&gt;">
<DisplayString>{{ size={size()} }}</DisplayString>
<Expand>
Expand Down
268 changes: 267 additions & 1 deletion stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -1383,7 +1383,235 @@ namespace ranges {
};

_EXPORT_STD inline constexpr _Iota_fn iota;

class _Take_fn;
class _Drop_fn;
} // namespace views

#if _HAS_CXX23
_EXPORT_STD template <move_constructible _Ty, semiregular _Bo = unreachable_sentinel_t>
requires (is_object_v<_Ty> && same_as<_Ty, remove_cv_t<_Ty>>
&& (_Integer_like<_Bo> || same_as<_Bo, unreachable_sentinel_t>) )
class repeat_view : public view_interface<repeat_view<_Ty, _Bo>> {
private:
friend views::_Take_fn;
friend views::_Drop_fn;

class _Iterator {
private:
friend repeat_view;
using _Index_type = conditional_t<same_as<_Bo, unreachable_sentinel_t>, ptrdiff_t, _Bo>;

const _Ty* _Value{};
/* [[no_unique_address]] */ _Index_type _Current{};

constexpr explicit _Iterator(const _Ty* _Val, _Index_type _Bo_ = _Index_type{}) noexcept // strengthened
: _Value(_Val), _Current(_Bo_) {
if constexpr (_Signed_integer_like<_Bo>) {
_STL_INTERNAL_CHECK(_Current >= 0);
}
}

public:
using iterator_concept = random_access_iterator_tag;
using iterator_category = random_access_iterator_tag;
using value_type = _Ty;
using difference_type =
conditional_t<_Signed_integer_like<_Index_type>, _Index_type, _Iota_diff_t<_Index_type>>;

_Iterator() = default;

_NODISCARD constexpr const _Ty& operator*() const noexcept {
return *_Value;
}

constexpr _Iterator& operator++() noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Current < (numeric_limits<_Index_type>::max)(),
"cannot increment repeat_view iterator past end (integer overflow)");
#endif
++_Current;
return *this;
}
constexpr _Iterator operator++(int) noexcept /* strengthened */ {
auto _Tmp = *this;
++*this;
return _Tmp;
}

constexpr _Iterator& operator--() noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (is_same_v<_Bo, unreachable_sentinel_t>) {
_STL_VERIFY(_Current > (numeric_limits<_Index_type>::min)(),
"cannot decrement repeat_view iterator before begin (integer overflow)");
} else {
_STL_VERIFY(_Current > 0, "cannot decrement below 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
--_Current;
return *this;
}
constexpr _Iterator operator--(int) noexcept /* strengthened */ {
auto _Tmp = *this;
--*this;
return _Tmp;
}

constexpr _Iterator& operator+=(difference_type _Off) noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
if (_Off > 0) {
_STL_VERIFY(_Current <= (numeric_limits<_Index_type>::max)() - static_cast<_Index_type>(_Off),
"cannot advance repeat_view iterator past end (integer overflow)");
} else {
_STL_VERIFY(_Current >= (numeric_limits<_Index_type>::min)() - static_cast<_Index_type>(_Off),
"cannot advance repeat_view iterator before begin (integer overflow)");
}

if constexpr (!is_same_v<_Bo, unreachable_sentinel_t>) {
_STL_VERIFY(_Current + _Off >= 0, "cannot subtract below 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
_Current += _Off;
return *this;
}
constexpr _Iterator& operator-=(difference_type _Off) noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
if (_Off < 0) {
_STL_VERIFY(_Current <= (numeric_limits<_Index_type>::max)() + static_cast<_Index_type>(_Off),
"cannot advance repeat_view iterator past end (integer overflow)");
} else {
_STL_VERIFY(_Current >= (numeric_limits<_Index_type>::min)() + static_cast<_Index_type>(_Off),
"cannot advance repeat_view iterator before begin (integer overflow)");
}

if constexpr (!is_same_v<_Bo, unreachable_sentinel_t>) {
_STL_VERIFY(_Current - _Off >= 0, "cannot subtract below 0");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
_Current -= _Off;
return *this;
}
_NODISCARD constexpr const _Ty& operator[](difference_type _Idx) const noexcept {
return *(*this + _Idx);
}

_NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept
/* strengthened */ {
return _Left._Current == _Right._Current;
}
_NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept
/* strengthened */ {
return _Left._Current <=> _Right._Current;
}

_NODISCARD_FRIEND constexpr _Iterator operator+(_Iterator _Iter, difference_type _Off) noexcept
/* strengthened */ {
_Iter += _Off;
return _Iter;
}
_NODISCARD_FRIEND constexpr _Iterator operator+(difference_type _Off, _Iterator _Iter) noexcept
/* strengthened */ {
_Iter += _Off;
return _Iter;
}

_NODISCARD_FRIEND constexpr _Iterator operator-(_Iterator _Iter, difference_type _Off) noexcept
/* strengthened */ {
_Iter -= _Off;
return _Iter;
}
_NODISCARD_FRIEND constexpr difference_type operator-(
const _Iterator& _Left, const _Iterator& _Right) noexcept /* strengthened */ {
return static_cast<difference_type>(
static_cast<difference_type>(_Left._Current) - static_cast<difference_type>(_Right._Current));
}
};

/* [[no_unique_address]] */ _Movable_box<_Ty> _Value{};
/* [[no_unique_address]] */ _Bo _Bound{};

template <class _Tuple, size_t... _Indices>
_NODISCARD_CTOR constexpr repeat_view(_Tuple& _Val, index_sequence<_Indices...>, _Bo _Bound_) noexcept(
is_nothrow_constructible_v<_Ty, tuple_element_t<_Indices, _Tuple>...>)
: _Value(in_place, _Tuple_get<_Indices>(_STD move(_Val))...), _Bound(_STD move(_Bound_)) {}

public:
// clang-format off
repeat_view() requires default_initializable<_Ty> = default;
// clang-format on

_NODISCARD_CTOR constexpr explicit repeat_view(const _Ty& _Value_, _Bo _Bound_ = _Bo{}) noexcept(
is_nothrow_copy_constructible_v<_Ty>) // strengthened
requires copy_constructible<_Ty>
: _Value(in_place, _Value_), _Bound(_STD move(_Bound_)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Signed_integer_like<_Bo>) {
_STL_VERIFY(_Bound >= 0, "Bound must be >= 0");
}
#endif
}
_NODISCARD_CTOR constexpr explicit repeat_view(_Ty&& _Value_, _Bo _Bound_ = _Bo{}) noexcept(
is_nothrow_move_constructible_v<_Ty>) // strengthened
: _Value(in_place, _STD move(_Value_)), _Bound(_STD move(_Bound_)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Signed_integer_like<_Bo>) {
_STL_VERIFY(_Bound >= 0, "Bound must be >= 0");
}
#endif
}
template <class... _TArgs, class... _BArgs>
requires constructible_from<_Ty, _TArgs...> && constructible_from<_Bo, _BArgs...>
// clang-format off
_NODISCARD_CTOR constexpr explicit repeat_view(piecewise_construct_t,
tuple<_TArgs...> _Val_args, tuple<_BArgs...> _Bound_args = tuple<>{})
noexcept(is_nothrow_constructible_v<_Ty, _TArgs...>) // strengthened
// clang-format on
: repeat_view(_Val_args, index_sequence_for<_TArgs...>{}, _STD make_from_tuple<_Bo>(_Bound_args)) {}

_NODISCARD constexpr _Iterator begin() const noexcept /* strengthened */ {
return _Iterator{_STD addressof(*_Value)};
}
_NODISCARD constexpr auto end() const noexcept // strengthened
{
if constexpr (same_as<_Bo, unreachable_sentinel_t>) {
return unreachable_sentinel;
} else {
return _Iterator{_STD addressof(*_Value), _Bound};
}
}

_NODISCARD constexpr auto size() const noexcept // strengthened
requires (!same_as<_Bo, unreachable_sentinel_t>)
{
return _STD _To_unsigned_like(_Bound);
}
};

template <class _Ty, class _Bo>
repeat_view(_Ty, _Bo) -> repeat_view<_Ty, _Bo>;

namespace views {
struct _Repeat_fn {
template <class _Ty>
_NODISCARD constexpr auto operator()(_Ty&& _Value) const
noexcept(noexcept(repeat_view(_STD forward<_Ty>(_Value))))
requires requires { repeat_view(_STD forward<_Ty>(_Value)); }
{
return repeat_view(_STD forward<_Ty>(_Value));
}

template <class _Ty1, class _Ty2>
_NODISCARD constexpr auto operator()(_Ty1&& _Val1, _Ty2&& _Val2) const
noexcept(noexcept(repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2))))
requires requires { repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2)); }
{
return repeat_view(_STD forward<_Ty1>(_Val1), _STD forward<_Ty2>(_Val2));
}
};

_EXPORT_STD inline constexpr _Repeat_fn repeat;
} // namespace views
#endif // _HAS_CXX23

template <class _Ty, class _Elem, class _Traits>
concept _Stream_extractable = requires(basic_istream<_Elem, _Traits>& __is, _Ty& __t) { __is >> __t; };
Expand Down Expand Up @@ -2723,6 +2951,7 @@ namespace ranges {
_Reconstruct_span,
_Reconstruct_string_view,
_Reconstruct_iota_view,
_Reconstruct_repeat_view,
_Reconstruct_subrange,
_Take_view
};
Expand All @@ -2740,6 +2969,12 @@ namespace ranges {
} else if constexpr (_Random_sized_range<_Ty> && _Is_specialization_v<_Ty, iota_view>) {
return {_St::_Reconstruct_iota_view,
noexcept(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()))};
#if _HAS_CXX23
} else if constexpr (_Is_specialization_v<_Ty, repeat_view>) {
using _Range_val_t = range_value_t<_Ty>;
return {_St::_Reconstruct_repeat_view,
is_nothrow_constructible_v<_Range_val_t, _Forward_like_t<_Rng, _Range_val_t>>};
#endif // _HAS_CXX23
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange_v<_Ty>) {
return {_St::_Reconstruct_subrange,
noexcept(subrange(_RANGES begin(_STD declval<_Rng&>()),
Expand All @@ -2763,6 +2998,10 @@ namespace ranges {
return remove_cvref_t<_Rng>{};
} else if constexpr (_Strat == _St::_Take_view) {
return take_view(_STD forward<_Rng>(_Range), _Count);
#if _HAS_CXX23
} else if constexpr (!sized_range<_Rng> && _Strat == _St::_Reconstruct_repeat_view) {
return repeat_view(_STD forward_like<_Rng>(*_Range._Value), _Count);
#endif
} else {
// it's a "reconstructible range"; return the same kind of range with a restricted extent
_Count = (_STD min)(_RANGES distance(_Range), _Count);
Expand All @@ -2775,6 +3014,10 @@ namespace ranges {
} else if constexpr (_Strat == _St::_Reconstruct_iota_view) {
using _Vt = range_value_t<_Rng>;
return iota_view<_Vt, _Vt>(_First, _First + _Count);
#if _HAS_CXX23
} else if constexpr (_Strat == _St::_Reconstruct_repeat_view) {
return repeat_view(_STD forward_like<_Rng>(*_Range._Value), _Count);
#endif
} else if constexpr (_Strat == _St::_Reconstruct_subrange) {
return subrange(_First, _First + _Count);
} else {
Expand Down Expand Up @@ -3104,7 +3347,14 @@ namespace ranges {
namespace views {
class _Drop_fn {
private:
enum class _St { _Empty, _Reconstruct_span, _Reconstruct_subrange, _Reconstruct_other, _Drop_view };
enum class _St {
_Empty,
_Reconstruct_span,
_Reconstruct_subrange,
_Reconstruct_repeat,
_Reconstruct_other,
_Drop_view
};

template <class _Rng>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
Expand All @@ -3116,6 +3366,12 @@ namespace ranges {
return {_St::_Reconstruct_span, true};
} else if constexpr (_Is_specialization_v<_Ty, basic_string_view>) {
return {_St::_Reconstruct_other, true};
#if _HAS_CXX23
} else if constexpr (_Is_specialization_v<_Ty, repeat_view>) {
using _Range_val_t = range_value_t<_Ty>;
return {_St::_Reconstruct_repeat,
is_nothrow_constructible_v<_Range_val_t, _Forward_like_t<_Rng, _Range_val_t>>};
#endif // _HAS_CXX23
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange_v<_Ty>) {
if constexpr (sized_sentinel_for<sentinel_t<_Ty>, iterator_t<_Ty>>) {
return {_St::_Reconstruct_subrange,
Expand Down Expand Up @@ -3149,6 +3405,16 @@ namespace ranges {
return remove_cvref_t<_Rng>{};
} else if constexpr (_Strat == _St::_Drop_view) {
return drop_view(_STD forward<_Rng>(_Range), _Count);
#if _HAS_CXX23
} else if constexpr (_Strat == _St::_Reconstruct_repeat) {
if constexpr (sized_range<_Rng>) {
const auto _Size = _RANGES distance(_Range);
_Count = _Size - (_STD min)(_Size, _Count);
return repeat_view(_STD forward_like<_Rng>(*_Range._Value), _Count);
} else {
return _Range;
}
#endif // _HAS_CXX23
} else {
// it's a "reconstructible range"; return the same kind of range with a restricted extent
_Count = (_STD min)(_RANGES distance(_Range), _Count);
Expand Down
Loading