Skip to content

Commit c5518bd

Browse files
committed
fix string_view operator ambiguities, implement typed placeholders, fix test errors
1 parent b6f52fa commit c5518bd

File tree

5 files changed

+194
-79
lines changed

5 files changed

+194
-79
lines changed

include/rsl/expect

Lines changed: 176 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -85,36 +85,39 @@ struct BinaryExpr {
8585
}
8686
}
8787

88-
constexpr decltype(auto) eval(auto const& args) const {
88+
template <typename T>
89+
constexpr decltype(auto) eval(T&& args) const {
8990
auto descend = [&](auto&& obj) {
9091
constexpr auto evaluatable = requires {
91-
{ obj.eval(args) } -> _impl::is_non_void;
92+
{ obj.eval(std::forward<T>(args)) } -> _impl::is_non_void;
9293
};
9394

9495
if constexpr (evaluatable) {
95-
return obj.eval(args);
96+
return obj.eval(std::forward<T>(args));
9697
} else {
9798
return obj;
9899
}
99100
};
100101

101-
return eval_operator(descend(rhs), descend(lhs));
102+
return eval_operator(descend(std::forward_like<T>(lhs)), descend(std::forward_like<T>(rhs)));
102103
}
103104

104-
constexpr auto eval_verbose(auto const& args, std::vector<std::string>& failed_terms) const {
105+
template <typename T>
106+
constexpr auto eval_verbose(T&& args, std::vector<std::string>& failed_terms) const {
105107
auto descend = [&](auto&& obj) {
106108
constexpr auto evaluatable = requires {
107-
{ obj.eval_verbose(args, failed_terms) } -> _impl::is_non_void;
109+
{ obj.eval_verbose(std::forward<T>(args), failed_terms) } -> _impl::is_non_void;
108110
};
109111

110112
if constexpr (evaluatable) {
111-
return obj.eval_verbose(args, failed_terms);
113+
return obj.eval_verbose(std::forward<T>(args), failed_terms);
112114
} else {
113115
return obj;
114116
}
115117
};
116118

117-
auto result = eval_operator(descend(rhs), descend(lhs));
119+
auto result =
120+
eval_operator(descend(std::forward_like<T>(lhs)), descend(std::forward_like<T>(rhs)));
118121
if (!result) {
119122
failed_terms.push_back(to_string(args));
120123
}
@@ -162,70 +165,72 @@ struct BinaryExpr {
162165
}
163166
}
164167

165-
static constexpr decltype(auto) eval_operator(auto lhs, auto rhs) {
168+
template <typename T2, typename T1>
169+
static constexpr decltype(auto) eval_operator(T1&& rhs, T2&& lhs) {
170+
// TODO args are flipped - why?
166171
using enum std::meta::operators;
167172
/* */ if constexpr (OP == op_plus) {
168-
return lhs + rhs;
173+
return std::forward<T1>(lhs) + std::forward<T2>(rhs);
169174
} else if constexpr (OP == op_minus) {
170-
return lhs - rhs;
175+
return std::forward<T1>(lhs) - std::forward<T2>(rhs);
171176
} else if constexpr (OP == op_star) {
172-
return lhs * rhs;
177+
return std::forward<T1>(lhs) * std::forward<T2>(rhs);
173178
} else if constexpr (OP == op_slash) {
174-
return lhs / rhs;
179+
return std::forward<T1>(lhs) / std::forward<T2>(rhs);
175180
} else if constexpr (OP == op_percent) {
176-
return lhs % rhs;
181+
return std::forward<T1>(lhs) % std::forward<T2>(rhs);
177182
} else if constexpr (OP == op_caret) {
178-
return lhs ^ rhs;
183+
return std::forward<T1>(lhs) ^ std::forward<T2>(rhs);
179184
} else if constexpr (OP == op_ampersand) {
180-
return lhs & rhs;
185+
return std::forward<T1>(lhs) & std::forward<T2>(rhs);
181186
} else if constexpr (OP == op_pipe) {
182-
return lhs | rhs;
187+
return std::forward<T1>(lhs) | std::forward<T2>(rhs);
183188
} else if constexpr (OP == op_equals) {
184-
return lhs = rhs;
189+
return std::forward<T1>(lhs) = std::forward<T2>(rhs);
185190
} else if constexpr (OP == op_plus_equals) {
186-
return lhs += rhs;
191+
return std::forward<T1>(lhs) += std::forward<T2>(rhs);
187192
} else if constexpr (OP == op_minus_equals) {
188-
return lhs -= rhs;
193+
return std::forward<T1>(lhs) -= std::forward<T2>(rhs);
189194
} else if constexpr (OP == op_star_equals) {
190-
return lhs *= rhs;
195+
return std::forward<T1>(lhs) *= std::forward<T2>(rhs);
191196
} else if constexpr (OP == op_slash_equals) {
192-
return lhs /= rhs;
197+
return std::forward<T1>(lhs) /= std::forward<T2>(rhs);
193198
} else if constexpr (OP == op_percent_equals) {
194-
return lhs %= rhs;
199+
return std::forward<T1>(lhs) %= std::forward<T2>(rhs);
195200
} else if constexpr (OP == op_caret_equals) {
196-
return lhs ^= rhs;
201+
return std::forward<T1>(lhs) ^= std::forward<T2>(rhs);
197202
} else if constexpr (OP == op_ampersand_equals) {
198-
return lhs &= rhs;
203+
return std::forward<T1>(lhs) &= std::forward<T2>(rhs);
199204
} else if constexpr (OP == op_pipe_equals) {
200-
return lhs |= rhs;
205+
return std::forward<T1>(lhs) |= std::forward<T2>(rhs);
201206
} else if constexpr (OP == op_equals_equals) {
202-
return lhs == rhs;
207+
return std::forward<T1>(lhs) == std::forward<T2>(rhs);
203208
} else if constexpr (OP == op_exclamation_equals) {
204-
return lhs != rhs;
209+
return std::forward<T1>(lhs) != std::forward<T2>(rhs);
205210
} else if constexpr (OP == op_less) {
206-
return lhs < rhs;
211+
return std::forward<T1>(lhs) < std::forward<T2>(rhs);
207212
} else if constexpr (OP == op_greater) {
208-
return lhs > rhs;
213+
return std::forward<T1>(lhs) > std::forward<T2>(rhs);
209214
} else if constexpr (OP == op_less_equals) {
210-
return lhs <= rhs;
215+
return std::forward<T1>(lhs) <= std::forward<T2>(rhs);
211216
} else if constexpr (OP == op_greater_equals) {
212-
return lhs >= rhs;
217+
return std::forward<T1>(lhs) >= std::forward<T2>(rhs);
213218
} else if constexpr (OP == op_spaceship) {
214-
return lhs <=> rhs;
219+
return std::forward<T1>(lhs) <=> std::forward<T2>(rhs);
215220
} else if constexpr (OP == op_ampersand_ampersand) {
216-
return lhs && rhs;
221+
return std::forward<T1>(lhs) && std::forward<T2>(rhs);
217222
} else if constexpr (OP == op_pipe_pipe) {
218-
return lhs || rhs;
223+
return std::forward<T1>(lhs) || std::forward<T2>(rhs);
219224
} else if constexpr (OP == op_less_less) {
220-
return lhs << rhs;
225+
return std::forward<T1>(lhs) << std::forward<T2>(rhs);
221226
} else if constexpr (OP == op_greater_greater) {
222-
return lhs >> rhs;
227+
return std::forward<T1>(lhs) >> std::forward<T2>(rhs);
223228
} else if constexpr (OP == op_less_less_equals) {
224-
return lhs <<= rhs;
229+
return std::forward<T1>(lhs) <<= std::forward<T2>(rhs);
225230
} else if constexpr (OP == op_greater_greater_equals) {
226-
return lhs >>= rhs;
231+
return std::forward<T1>(lhs) >>= std::forward<T2>(rhs);
227232
} else if constexpr (OP == op_comma) {
228-
return lhs, rhs;
233+
return std::forward<T1>(lhs), std::forward<T2>(rhs);
229234
}
230235
}
231236

@@ -249,28 +254,101 @@ struct BinaryExpr {
249254
}
250255
};
251256

252-
template <std::size_t Idx>
257+
namespace _impl {
258+
template <auto V>
259+
struct value {};
260+
261+
template <typename T>
262+
constexpr inline auto non_special_members =
263+
define_static_array(members_of(^^T, std::meta::access_context::current()) |
264+
std::views::filter([](std::meta::info R) {
265+
return (is_function(R) or is_nonstatic_data_member(R)) and
266+
not is_special_member_function(R);
267+
}));
268+
269+
template <std::size_t Idx, typename T>
270+
decltype(auto) operator->*(T&& obj, value<Idx>) {
271+
static constexpr auto member = non_special_members<std::remove_cvref_t<T>>[Idx];
272+
// if constexpr (is_function(member)) {
273+
// // TODO check for getter annotation
274+
// if constexpr (is_static_member(member)) {
275+
// return [:member:];
276+
// } else {
277+
// return [&]<typename... Ts>(Ts&&... args) {
278+
// return std::forward<T>(obj).[:member:](std::forward<Ts>(args)...);
279+
// };
280+
// }
281+
// } else
282+
if constexpr (is_nonstatic_data_member(member)) {
283+
return std::forward<T>(obj).[:member:];
284+
} else if constexpr (requires {
285+
{ get<Idx>(std::forward<T>(obj)) };
286+
}) {
287+
return get<Idx>(std::forward<T>(obj));
288+
} else {
289+
static_assert(false, std::string("Cannot get member") + util::utos(Idx));
290+
}
291+
}
292+
} // namespace _impl
293+
294+
template <std::size_t... Idx>
253295
struct Placeholder {
254-
constexpr decltype(auto) eval(auto const& args) const {
255-
static constexpr auto placeholder_count =
256-
std::tuple_size_v<std::remove_cvref_t<decltype(args)>>;
257-
static_assert(Idx < placeholder_count,
258-
std::string("Placeholder $") + util::utos(Idx) + " has no associated value");
259-
return get<Idx>(args);
296+
template <typename T>
297+
constexpr decltype(auto) eval(T&& args) const {
298+
return (std::forward<T>(args)->*...->*_impl::value<Idx>{});
260299
}
261300

262-
constexpr auto eval_verbose(auto const& args, std::vector<std::string>& failed_terms) const {
263-
return eval(args);
301+
template <typename T>
302+
constexpr auto eval_verbose(T&& args, std::vector<std::string>& failed_terms) const {
303+
return eval(std::forward<T>(args));
264304
}
265305

266-
constexpr std::string to_string(auto const& args) const {
306+
template <typename T>
307+
constexpr std::string to_string(T&& args) const {
267308
// TODO constexpr
268-
return std::format("{}", get<Idx>(args));
309+
if constexpr (requires {
310+
{ std::format("{}", eval(std::forward<T>(args))) };
311+
}) {
312+
return std::format("{}", eval(std::forward<T>(args)));
313+
}
314+
// TODO emit type name
315+
return "<obj>";
269316
}
270317

271318
constexpr std::string to_string(std::vector<std::string_view> const& replacements) const {
272-
return std::string(replacements[Idx]);
319+
// TODO emit member names
320+
return std::string(replacements[Idx...[0]]);
321+
}
322+
323+
// TODO wrap call and subscript
324+
};
325+
326+
template <typename T, std::size_t... I>
327+
struct PlaceholderFor {
328+
struct Lazy;
329+
330+
consteval {
331+
std::vector<std::meta::info> members;
332+
auto idx = 0;
333+
for (auto member : _impl::non_special_members<std::remove_cvref_t<T>>) {
334+
std::meta::info type;
335+
if (is_class_type(remove_cvref(type_of(member)))) {
336+
type = substitute(^^PlaceholderFor,
337+
{remove_cvref(type_of(member)),
338+
std::meta::reflect_constant(I)...,
339+
std::meta::reflect_constant(idx++)});
340+
} else {
341+
// TODO does this need special handling for functions?
342+
type = substitute(^^Placeholder,
343+
{std::meta::reflect_constant(I)..., std::meta::reflect_constant(idx++)});
344+
}
345+
346+
members.push_back(data_member_spec(type, {.name = identifier_of(member)}));
347+
}
348+
define_aggregate(^^Lazy, members);
273349
}
350+
351+
Lazy* operator->() const { return nullptr; }
274352
};
275353

276354
template <typename T>
@@ -430,8 +508,54 @@ constexpr inline struct {
430508
namespace rsl {
431509
// using rsl::_expect_impl::expect;
432510
using rsl::_expect_impl::Placeholder;
511+
template <typename T, std::size_t Idx>
512+
using TypedPlaceholder = _expect_impl::PlaceholderFor<T, Idx>;
513+
514+
namespace typed_placeholders {
515+
template <typename T>
516+
constexpr inline TypedPlaceholder<T, 0> _0{};
517+
template <typename T>
518+
constexpr inline TypedPlaceholder<T, 1> _1{};
519+
template <typename T>
520+
constexpr inline TypedPlaceholder<T, 2> _2{};
521+
template <typename T>
522+
constexpr inline TypedPlaceholder<T, 3> _3{};
523+
template <typename T>
524+
constexpr inline TypedPlaceholder<T, 4> _4{};
525+
template <typename T>
526+
constexpr inline TypedPlaceholder<T, 5> _5{};
527+
template <typename T>
528+
constexpr inline TypedPlaceholder<T, 6> _6{};
529+
template <typename T>
530+
constexpr inline TypedPlaceholder<T, 7> _7{};
531+
template <typename T>
532+
constexpr inline TypedPlaceholder<T, 8> _8{};
533+
template <typename T>
534+
constexpr inline TypedPlaceholder<T, 9> _9{};
535+
} // namespace typed_placeholders
433536

434537
namespace placeholders {
538+
template <typename T>
539+
constexpr inline auto p0 = typed_placeholders::_0<T>;
540+
template <typename T>
541+
constexpr inline auto p1 = typed_placeholders::_1<T>;
542+
template <typename T>
543+
constexpr inline auto p2 = typed_placeholders::_2<T>;
544+
template <typename T>
545+
constexpr inline auto p3 = typed_placeholders::_3<T>;
546+
template <typename T>
547+
constexpr inline auto p4 = typed_placeholders::_4<T>;
548+
template <typename T>
549+
constexpr inline auto p5 = typed_placeholders::_5<T>;
550+
template <typename T>
551+
constexpr inline auto p6 = typed_placeholders::_6<T>;
552+
template <typename T>
553+
constexpr inline auto p7 = typed_placeholders::_7<T>;
554+
template <typename T>
555+
constexpr inline auto p8 = typed_placeholders::_8<T>;
556+
template <typename T>
557+
constexpr inline auto p9 = typed_placeholders::_9<T>;
558+
435559
constexpr inline Placeholder<0> _0{};
436560
constexpr inline Placeholder<1> _1{};
437561
constexpr inline Placeholder<2> _2{};
@@ -442,6 +566,5 @@ constexpr inline Placeholder<6> _6{};
442566
constexpr inline Placeholder<7> _7{};
443567
constexpr inline Placeholder<8> _8{};
444568
constexpr inline Placeholder<9> _9{};
445-
446569
} // namespace placeholders
447570
} // namespace rsl

include/rsl/string_view

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -319,16 +319,6 @@ constexpr bool operator==(basic_string_view<CharT, Traits> lhs,
319319
return lhs.compare(rhs) == 0;
320320
}
321321

322-
//? compat
323-
template <typename CharT, typename Traits>
324-
constexpr bool operator==(basic_string_view<CharT, Traits> lhs,
325-
std::type_identity_t<std::basic_string_view<CharT, Traits>> rhs) noexcept {
326-
if (lhs.size() != rhs.size()) {
327-
return false;
328-
}
329-
return lhs.compare(rhs) == 0;
330-
}
331-
332322
template <typename CharT, typename Traits>
333323
constexpr auto operator<=>(basic_string_view<CharT, Traits> lhs,
334324
std::type_identity_t<basic_string_view<CharT, Traits>> rhs) noexcept {
@@ -339,18 +329,6 @@ constexpr auto operator<=>(basic_string_view<CharT, Traits> lhs,
339329
}
340330
}
341331

342-
//? compat
343-
template <typename CharT, typename Traits>
344-
constexpr auto operator<=>(basic_string_view<CharT, Traits> lhs,
345-
std::type_identity_t<std::basic_string_view<CharT, Traits>> rhs) noexcept {
346-
if constexpr (requires { typename Traits::comparison_category; }) {
347-
return static_cast<typename Traits::comparison_category>(lhs.compare(rhs) <=> 0);
348-
} else {
349-
return static_cast<std::weak_ordering>(lhs.compare(rhs) <=> 0);
350-
}
351-
}
352-
353-
354332
// basic_string_view typedef-names
355333
using string_view = basic_string_view<char>;
356334
using u8string_view = basic_string_view<char8_t>;

test/expect/expect.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <rsl/expect>
66

7+
namespace {
78
TEST(Expect, Logic) {
89
using namespace rsl::placeholders;
910
ASSERT_TRUE(expect(_0 > 1)(10));
@@ -21,4 +22,17 @@ TEST(Expect, ArrayOfChecks) {
2122
int x = 50;
2223
ASSERT_TRUE(check(x));
2324
}
25+
}
26+
27+
struct TestStruct {
28+
int a;
29+
char b;
30+
};
31+
32+
TEST(Expect, Typed) {
33+
using namespace rsl::typed_placeholders;
34+
auto x = TestStruct(42, 'd');
35+
ASSERT_TRUE(expect(_0<TestStruct>->a == 42)(x));
36+
ASSERT_TRUE(expect(_0<TestStruct>->b == 'd')(x));
37+
}
2438
}

0 commit comments

Comments
 (0)