Skip to content

Commit f670710

Browse files
committed
improve implementation, introduce negated checks
1 parent e2dd081 commit f670710

1 file changed

Lines changed: 71 additions & 37 deletions

File tree

include/chroma

Lines changed: 71 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ consteval void panic(T const& message) {
2929
constexpr struct unchecked_context {
3030
template <typename F>
3131
static auto operator()(F&& f) {
32-
return [&]<typename... Ts>[[=unchecked_context{}]](Ts&&... args)
32+
return [&]<typename... Ts>[[= unchecked_context{}]](Ts&&... args)
3333
#ifndef __clang__
3434
-> std::invoke_result_t<F, Ts...>
3535
#endif
@@ -46,42 +46,93 @@ consteval std::vector<std::meta::info> annotations_of_with_type(std::meta::info
4646
using std::meta::annotations_of_with_type;
4747
#endif
4848

49+
template <typename... Ts>
50+
struct AssumedColors {};
51+
52+
consteval bool is_viable(std::meta::info fnc, std::meta::info type) {
53+
if (fnc == std::meta::info()) {
54+
return true;
55+
}
56+
57+
auto is_convertible = [&](std::meta::info r) { return is_convertible_type(r, type); };
58+
59+
for (auto annotation : annotations_of(fnc) | std::views::transform(std::meta::type_of)) {
60+
if (annotation == ^^unchecked_context) {
61+
return true;
62+
}
63+
if (is_specialization(annotation, ^^AssumedColors) and
64+
std::ranges::any_of(template_arguments_of(annotation), is_convertible)) {
65+
return true;
66+
}
67+
}
68+
69+
for (auto parameter : parameters_of(fnc) | std::views::transform(std::meta::type_of)) {
70+
if (is_specialization(parameter, template_of(^^callable_from)) and
71+
is_convertible(template_arguments_of(parameter)[0])) {
72+
return true;
73+
}
74+
}
75+
return false;
76+
}
4977
} // namespace _chroma_impl
5078

5179
using _chroma_impl::unchecked;
5280

81+
template <typename... Ts>
82+
constexpr _chroma_impl::AssumedColors<Ts...> assume_color{};
83+
84+
namespace chroma {
5385
template <typename T>
54-
struct callable_from {
86+
struct color {
87+
protected:
88+
constexpr color() = default;
89+
friend T;
90+
};
91+
} // namespace chroma
92+
93+
template <typename T>
94+
struct callable_from : chroma::color<T> {
95+
consteval explicit(false) callable_from(chroma::color<T>) {}
5596
consteval explicit(false) callable_from(_chroma_impl::unchecked_context) {}
5697

5798
consteval explicit(false)
5899
callable_from(std::meta::access_context ctx = std::meta::access_context::current()) {
59-
bool is_unchecked =
60-
ctx.scope() == std::meta::info() or
61-
_chroma_impl::annotations_of_with_type(ctx.scope(), ^^_chroma_impl::unchecked_context).size() != 0;
62-
auto is_valid = [](std::meta::info type) {
63-
return has_template_arguments(type) and
64-
(template_of(type) == template_of(^^callable_from)) and
65-
std::ranges::any_of(template_arguments_of(type),
66-
[](std::meta::info r) { return is_convertible_type(r, ^^T); });
67-
};
68-
bool constrains_callee =
69-
is_function(ctx.scope()) and
70-
std::ranges::any_of(parameters_of(ctx.scope()),
71-
[&](std::meta::info p) { return is_valid(remove_cvref(type_of(p))); });
72-
73-
if (not(is_unchecked or constrains_callee)) {
74-
_chroma_impl::panic(T::error_message);
100+
if (not _chroma_impl::is_viable(ctx.scope(), ^^T)) {
101+
panic(T::error_message);
75102
}
76103
}
77104

105+
template <typename U>
106+
requires std::convertible_to<T, U>
107+
operator callable_from<U>() const {
108+
return unchecked;
109+
}
110+
78111
callable_from(callable_from const&) = delete;
79112
callable_from& operator=(callable_from const&) = delete;
80113
callable_from(callable_from&&) = default;
81114
callable_from& operator=(callable_from&&) = default;
82115
constexpr ~callable_from() = default;
83116
};
84117

118+
template <typename T>
119+
struct not_callable_from {
120+
consteval explicit(false) not_callable_from(unchecked_context) {}
121+
122+
consteval explicit(false)
123+
not_callable_from(std::meta::access_context ctx = std::meta::access_context::current()) {
124+
if (_chroma_impl::is_viable(ctx.scope(), ^^T)) {
125+
panic(T::error_message);
126+
}
127+
}
128+
129+
not_callable_from(not_callable_from const&) = delete;
130+
not_callable_from& operator=(not_callable_from const&) = delete;
131+
not_callable_from(not_callable_from&&) = default;
132+
not_callable_from& operator=(not_callable_from&&) = default;
133+
constexpr ~not_callable_from() = default;
134+
};
135+
85136
namespace _chroma_impl {
86137
constexpr struct {
87138
template <typename F>
@@ -94,23 +145,6 @@ constexpr struct {
94145
}
95146
} eval_rhs;
96147
} // namespace _chroma_impl
97-
#define $unchecked ::_chroma_impl::eval_rhs->*[&][[= unchecked]]
98-
99-
#define PARENS ()
100-
101-
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
102-
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
103-
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
104-
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
105-
#define EXPAND1(...) __VA_ARGS__
106148

107-
#define FOR_EACH(macro, ...) \
108-
__VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__)))
109-
#define FOR_EACH_HELPER(macro, a1, ...) \
110-
macro(a1) __VA_OPT__(, ) \
111-
__VA_OPT__(FOR_EACH_AGAIN PARENS(macro, __VA_ARGS__))
112-
#define FOR_EACH_AGAIN() FOR_EACH_HELPER
113-
114-
#define UNCHECKED_COLOR(name) callable_from<name> = {std::meta::access_context::unchecked()}
115-
116-
#define $with(...) ::_chroma_impl::eval_rhs->*[&](FOR_EACH(UNCHECKED_COLOR, __VA_ARGS__))
149+
#define $unchecked ::_chroma_impl::eval_rhs->*[&][[= unchecked]]
150+
#define $with(...) ::_chroma_impl::eval_rhs->*[&][[= assume_color<__VA_ARGS__>]]

0 commit comments

Comments
 (0)