Skip to content

Commit 659a4fb

Browse files
committed
okay just try the ms-stl strategy
1 parent 8a5f154 commit 659a4fb

File tree

4 files changed

+77
-113
lines changed

4 files changed

+77
-113
lines changed

libcxx/include/__ranges/as_const_view.h

Lines changed: 73 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -103,123 +103,86 @@ inline constexpr bool enable_borrowed_range<as_const_view<_Tp>> = enable_borrowe
103103
namespace views {
104104
namespace __as_const {
105105

106-
template <class _Case>
107-
concept __case = requires { _Case::__impl; };
108-
109-
template <class _Range>
110-
struct __already_constant_case {};
111-
template <class _Range>
112-
requires constant_range<all_t<_Range>>
113-
struct __already_constant_case<_Range> {
114-
_LIBCPP_HIDE_FROM_ABI static constexpr auto __impl(_Range& __range) noexcept(
115-
noexcept(views::all(std::forward<_Range>(__range)))) -> decltype(views::all(std::forward<_Range>(__range))) {
116-
return views::all(std::forward<_Range>(__range));
117-
}
118-
};
119-
120-
template <class _Range, class _UType = std::remove_cvref_t<_Range>>
121-
struct __empty_view_case {};
122-
template <class _Range, class _XType>
123-
requires(!__case<__already_constant_case<_Range>>)
124-
struct __empty_view_case<_Range, empty_view<_XType>> {
125-
_LIBCPP_HIDE_FROM_ABI static constexpr auto
126-
__impl(_Range&) noexcept(noexcept(auto(views::empty<const _XType>))) -> decltype(auto(views::empty<const _XType>)) {
127-
return auto(views::empty<const _XType>);
128-
}
129-
};
106+
template <class _Tp>
107+
inline constexpr bool __is_span_v = false; // true if and only if _Tp is a specialization of span
108+
template <class _Tp, size_t _Extent>
109+
inline constexpr bool __is_span_v<span<_Tp, _Extent>> = true;
130110

131-
template <class _Range, class _UType = std::remove_cvref_t<_Range>>
132-
struct __span_case {};
133-
template <class _Range, class _XType, size_t _Extent>
134-
requires(!__case<__already_constant_case<_Range>>)
135-
struct __span_case<_Range, span<_XType, _Extent>> {
136-
_LIBCPP_HIDE_FROM_ABI static constexpr auto __impl(_Range& __range) noexcept(noexcept(span<const _XType, _Extent>(
137-
std::forward<_Range>(__range)))) -> decltype(span<const _XType, _Extent>(std::forward<_Range>(__range))) {
138-
return span<const _XType, _Extent>(std::forward<_Range>(__range));
139-
}
111+
template <class _UType>
112+
struct __xtype {
113+
using type = void;
140114
};
141-
142-
template <class _Range, class _UType = std::remove_cvref_t<_Range>>
143-
struct __ref_view_case {};
144-
template <class _Range, class _XType>
145-
requires(!__case<__already_constant_case<_Range>>) && constant_range<const _XType>
146-
struct __ref_view_case<_Range, ref_view<_XType>> {
147-
_LIBCPP_HIDE_FROM_ABI static constexpr auto
148-
__impl(_Range& __range) noexcept(noexcept(ref_view(static_cast<const _XType&>(std::forward<_Range>(__range).base()))))
149-
-> decltype(ref_view(static_cast<const _XType&>(std::forward<_Range>(__range).base()))) {
150-
return ref_view(static_cast<const _XType&>(std::forward<_Range>(__range).base()));
151-
}
115+
template <class _XType>
116+
struct __xtype<empty_view<_XType>> {
117+
using type = _XType;
152118
};
153-
154-
template <class _Range, class _UType = std::remove_cvref_t<_Range>>
155-
struct __constant_range_case {};
156-
template <class _Range, class _UType>
157-
requires(!__case<__already_constant_case<_Range>>) && (!__case<__empty_view_case<_Range>>) &&
158-
(!__case<__span_case<_Range>>) &&
159-
(!__case<__ref_view_case<_Range>>) && is_lvalue_reference_v<_Range> && constant_range<const _UType> &&
160-
(!view<_UType>)
161-
struct __constant_range_case<_Range, _UType> {
162-
_LIBCPP_HIDE_FROM_ABI static constexpr auto
163-
__impl(_Range& __range) noexcept(noexcept(ref_view(static_cast<const _UType&>(std::forward<_Range>(__range)))))
164-
-> decltype(ref_view(static_cast<const _UType&>(std::forward<_Range>(__range)))) {
165-
return ref_view(static_cast<const _UType&>(std::forward<_Range>(__range)));
166-
}
119+
template <class _XType, size_t _Extent>
120+
struct __xtype<span<_XType, _Extent>> {
121+
using type = _XType;
122+
constexpr static size_t __extent = _Extent;
167123
};
168-
169-
template <class _Range>
170-
struct __otherwise_case {};
171-
template <class _Range>
172-
requires(!__case<__already_constant_case<_Range>>) && (!__case<__empty_view_case<_Range>>) &&
173-
(!__case<__span_case<_Range>>) && (!__case<__ref_view_case<_Range>>) &&
174-
(!__case<__constant_range_case<_Range>>)
175-
struct __otherwise_case<_Range> {
176-
_LIBCPP_HIDE_FROM_ABI static constexpr auto __impl(_Range& __range) noexcept(noexcept(
177-
as_const_view(std::forward<_Range>(__range)))) -> decltype(as_const_view(std::forward<_Range>(__range))) {
178-
return as_const_view(std::forward<_Range>(__range));
179-
}
124+
template <class _XType>
125+
struct __xtype<ref_view<_XType>> {
126+
using type = _XType;
180127
};
181128

182129
struct __fn : __range_adaptor_closure<__fn> {
183-
// [range.as.const.overview]: the basic `constant_range` case
184-
template <class _Range>
185-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range) noexcept(noexcept(
186-
__already_constant_case<_Range>::__impl(__range))) -> decltype(__already_constant_case<_Range>::__impl(__range)) {
187-
return __already_constant_case<_Range>::__impl(__range);
188-
}
189-
190-
// [range.as.const.overview]: the `empty_view` case
191-
template <class _Range>
192-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range) noexcept(
193-
noexcept(__empty_view_case<_Range>::__impl(__range))) -> decltype(__empty_view_case<_Range>::__impl(__range)) {
194-
return __empty_view_case<_Range>::__impl(__range);
195-
}
196-
197-
// [range.as.const.overview]: the `span` case
198-
template <class _Range>
199-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range) noexcept(
200-
noexcept(__span_case<_Range>::__impl(__range))) -> decltype(__span_case<_Range>::__impl(__range)) {
201-
return __span_case<_Range>::__impl(__range);
202-
}
203-
204-
// [range.as.const.overview]: the `ref_view` case
205-
template <class _Range>
206-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range) noexcept(
207-
noexcept(__ref_view_case<_Range>::__impl(__range))) -> decltype(__ref_view_case<_Range>::__impl(__range)) {
208-
return __ref_view_case<_Range>::__impl(__range);
209-
}
210-
211-
// [range.as.const.overview]: the second `constant_range` case
212-
template <class _Range>
213-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range) noexcept(noexcept(
214-
__constant_range_case<_Range>::__impl(__range))) -> decltype(__constant_range_case<_Range>::__impl(__range)) {
215-
return __constant_range_case<_Range>::__impl(__range);
216-
}
217-
218-
// [range.as.const.overview]: otherwise
219-
template <class _Range>
220-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range) noexcept(
221-
noexcept(__otherwise_case<_Range>::__impl(__range))) -> decltype(__otherwise_case<_Range>::__impl(__range)) {
222-
return __otherwise_case<_Range>::__impl(__range);
130+
// implementation strategy taken from Microsoft's STL
131+
enum class __strategy {
132+
__already_const,
133+
__empty_view,
134+
__span,
135+
__ref_view,
136+
__const_is_constant_range,
137+
__otherwise,
138+
__none,
139+
};
140+
141+
template <class _Type>
142+
static consteval pair<__strategy, bool> __choose_strategy() {
143+
using _UType = std::remove_cvref_t<_Type>;
144+
using _XType = __xtype<_UType>::type;
145+
146+
if constexpr (!requires { typename all_t<_Type>; }) {
147+
return {__strategy::__none, false};
148+
} else if constexpr (constant_range<all_t<_Type>>) {
149+
return {__strategy::__already_const, noexcept(views::all(std::declval<_Type>()))};
150+
} else if constexpr (__is_specialization_v<_UType, empty_view>) {
151+
return {__strategy::__empty_view, true};
152+
} else if constexpr (__is_span_v<_UType>) {
153+
return {__strategy::__span, true};
154+
} else if constexpr (__is_specialization_v<_UType, ref_view> && constant_range<const _XType>) {
155+
return {__strategy::__ref_view, noexcept(ref_view(static_cast<const _XType&>(std::declval<_Type>().base())))};
156+
} else if constexpr (is_lvalue_reference_v<_Type> && constant_range<const _UType> && !view<_UType>) {
157+
return {__strategy::__const_is_constant_range,
158+
noexcept(ref_view(static_cast<const _UType&>(std::declval<_Type>())))};
159+
} else {
160+
return {__strategy::__otherwise, noexcept(as_const_view(std::declval<_Type>()))};
161+
}
162+
}
163+
164+
template <class _Type>
165+
requires(__choose_strategy<_Type>().first != __strategy::__none)
166+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static auto
167+
operator()(_Type&& __range) noexcept(__choose_strategy<_Type>().second) {
168+
using _UType = std::remove_cvref_t<_Type>;
169+
using _XType = __xtype<_UType>::type;
170+
171+
constexpr auto __st = __choose_strategy<_Type>().first;
172+
173+
if constexpr (__st == __strategy::__already_const) {
174+
return views::all(std::forward<_Type>(__range));
175+
} else if constexpr (__st == __strategy::__empty_view) {
176+
return auto(views::empty<const _XType>);
177+
} else if constexpr (__st == __strategy::__span) {
178+
return span<const _XType, __xtype<_UType>::__extent>(std::forward<_Type>(__range));
179+
} else if constexpr (__st == __strategy::__ref_view) {
180+
return ref_view(static_cast<const _XType&>(std::forward<_Type>(__range).base()));
181+
} else if constexpr (__st == __strategy::__const_is_constant_range) {
182+
return ref_view(static_cast<const _UType&>(std::forward<_Type>(__range)));
183+
} else if constexpr (__st == __strategy::__otherwise) {
184+
return as_const_view(std::forward<_Type>(__range));
185+
}
223186
}
224187
};
225188

libcxx/test/std/containers/views/views.span/span.iterators/rbegin.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
// <span>
1111

12-
// constexpr reverse_iterator rbegin() const noexcept;
12+
// constexpr neverse_iterator rbegin() const noexcept;
1313
// constexpr const_reverse_iterator crbegin() const noexcept; // since C++23
1414

1515
#include <span>

libcxx/test/std/ranges/range.adaptors/range.as.const/adaptor.pass.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
// std::views::as_const
1212

13+
#include <array>
1314
#include <cassert>
1415
#include <functional>
1516
#include <ranges>
@@ -29,7 +30,6 @@ struct DefaultConstructibleView : std::ranges::view_base {
2930
};
3031
struct NoView {};
3132

32-
#if 0
3333
static_assert(std::is_invocable_v<decltype(std::views::as_const), DefaultConstructibleView>);
3434
static_assert(!std::is_invocable_v<decltype(std::views::as_const)>);
3535
static_assert(!std::is_invocable_v<decltype(std::views::as_const), NoView>);
@@ -38,7 +38,6 @@ static_assert(HasPipe<int (&)[10], decltype(std::views::as_const)>);
3838
static_assert(!HasPipe<int (&&)[10], decltype(std::views::as_const)>);
3939
static_assert(!HasPipe<NoView, decltype(std::views::as_const)>);
4040
static_assert(std::is_same_v<decltype(std::views::as_const), decltype(std::ranges::views::as_const)>);
41-
#endif
4241

4342
struct const_iterator_range {
4443
constexpr std::const_iterator<int*> begin() const { return {}; }

libcxx/test/support/test_iterators.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,12 @@ template <class It>
482482
three_way_contiguous_iterator(It) -> three_way_contiguous_iterator<It>;
483483
#endif // TEST_STD_VER > 17
484484

485+
#if TEST_STD_VER >= 23
485486
template <class Iter>
486487
TEST_CONSTEXPR Iter base(std::basic_const_iterator<Iter> i) {
487488
return i.base();
488489
}
490+
#endif
489491

490492
template <class Iter> // ADL base() for everything else (including pointers)
491493
TEST_CONSTEXPR Iter base(Iter i) { return i; }

0 commit comments

Comments
 (0)