Skip to content

Instantly share code, notes, and snippets.

@ericniebler
Created November 18, 2022 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericniebler/8e07f57a50d4de989d26bf15159a4730 to your computer and use it in GitHub Desktop.
Save ericniebler/8e07f57a50d4de989d26bf15159a4730 to your computer and use it in GitHub Desktop.
An example of how arbitrarily-named customization points can be generically forwarded
#if defined(__has_feature)
#if __has_feature(__cpp_static_call_operator)
#define STATIC_CALL_OPERATOR(...) static __VA_ARGS__ operator() STATIC_CALL_OPERATOR_
#define STATIC_CALL_OPERATOR_(...) (__VA_ARGS__)
#endif
#endif
#ifndef STATIC_CALL_OPERATOR
#define STATIC_CALL_OPERATOR(...) __VA_ARGS__ operator() STATIC_CALL_OPERATOR_
#define STATIC_CALL_OPERATOR_(...) (__VA_ARGS__) const
#endif
template <class A, class B>
inline constexpr bool __same_as = false;
template <class A>
inline constexpr bool __same_as<A, A> = true;
template <class _T>
inline constexpr auto __v = _T::value;
template <class _From, class _To>
struct __copy_cvref {
using type = _To;
};
template <class _From, class _To>
struct __copy_cvref<_From&, _To> {
using type = _To&;
};
template <class _From, class _To>
struct __copy_cvref<_From const&, _To> {
using type = _To const&;
};
template <class _From, class _To>
struct __copy_cvref<_From&&, _To> {
using type = _To&&;
};
template <class _From, class _To>
struct __copy_cvref<_From const&&, _To> {
using type = _To const&&;
};
template <class _From, class _To>
using __copy_cvref_t = typename __copy_cvref<_From, _To>::type;
template <class _Ty>
_Ty&& __declval() noexcept;
template <class _Ty>
_Ty __decay_fn(const _Ty&) noexcept;
template <class _Ty>
using __decay_t = decltype(__decay_fn(__declval<_Ty>()));
template <class _Fn, class... _As>
using __call_result_t = decltype(__declval<_Fn>()(__declval<_As>()...));
template <class _Ty>
using __t = typename _Ty::type;
template <class _Ty>
struct _X {
using type = struct _ {
using type = _Ty;
};
};
template <class _Ty>
using __x = __t<_X<_Ty>>;
template <class...>
concept __always_true = true;
template <bool>
struct __i {
template <template <class...> class _Fn, class... _Args>
using __g = _Fn<_Args...>;
};
template <template <class...> class _Fn, class... _Args>
using __meval =
typename __i<__always_true<_Args...>>::
template __g<_Fn, _Args...>;
template <class _Fn, class... _Args>
using __minvoke =
__meval<_Fn::template __f, _Args...>;
template <class _Fn, class... _Args>
concept __minvocable =
requires {
typename __minvoke<_Fn, _Args...>;
};
template <template <class...> class _Fn>
struct __q {
template <class... _Args>
using __f = __meval<_Fn, _Args...>;
};
template <bool>
struct __if_ {
template <class _True, class...>
using __f = _True;
};
template <>
struct __if_<false> {
template <class, class _False>
using __f = _False;
};
template <class _Pred, class _True, class... _False>
requires (sizeof...(_False) <= 1)
using __if = __minvoke<__if_<__v<_Pred>>, _True, _False...>;
template <bool _Pred, class _True, class... _False>
requires (sizeof...(_False) <= 1)
using __if_c = __minvoke<__if_<_Pred>, _True, _False...>;
template <class _Derived>
struct __to {
template <class _Ty>
STATIC_CALL_OPERATOR(auto)(_Ty&& __self) noexcept
-> decltype(static_cast<__copy_cvref_t<_Ty&&, _Derived>>((_Ty&&) __self)) {
return static_cast<__copy_cvref_t<_Ty&&, _Derived>>((_Ty&&) __self);
}
};
struct __ident {
template <class _Ty>
STATIC_CALL_OPERATOR(_Ty&&)(_Ty&& __t) noexcept {
return (_Ty&&) __t;
}
};
template <class _SecondFn, class _FirstFn>
struct __compose {
template <class _Ty>
STATIC_CALL_OPERATOR(auto)(_Ty&& __t) noexcept
-> decltype(_SecondFn{}(_FirstFn{}((_Ty&&) __t))) {
return _SecondFn{}(_FirstFn{}((_Ty&&) __t));
}
};
template <class _Derived, class _GetBaseFn>
using __fwd_base_t = __decay_t<decltype(_GetBaseFn{}(__declval<_Derived>()))>;
template <class _Ty>
struct __mconst {
template <class...>
using __f = _Ty;
};
struct __forwarding_base
: __mconst<__forwarding_base>
{};
struct __forwarding_rebase {
template <class _Derived, class _GetBaseFn, class _GetSelfFn>
using __f =
typename __fwd_base_t<_Derived, _GetBaseFn>::__forwarding
::template __rebind_t<__compose<_GetBaseFn, _GetSelfFn>{}>;
};
template <class _Derived, class _GetBaseFn, class _GetSelfFn>
using __forwarding_base_t =
__minvoke<
__if_c<
__minvocable<__forwarding_rebase, _Derived, _GetBaseFn, _GetSelfFn>,
__forwarding_rebase,
__forwarding_base>,
_Derived,
_GetBaseFn,
_GetSelfFn>;
template <class... _Ts>
requires (sizeof...(_Ts) >= 3) && (sizeof...(_Ts) <= 5)
struct __forwarding;
template <class _Env>
struct __forward {
template <class... Ts>
using __f = __forwarding<_Env, Ts...>;
};
template <class _DerivedId, class _Query, class _QueryFn, class _GetBaseFn, class _GetSelfFn>
struct __forwarding<_DerivedId, _Query, _QueryFn, _GetBaseFn, _GetSelfFn>
: __forwarding_base_t<__t<_DerivedId>, _GetBaseFn, _GetSelfFn>
, private _Query::template __forward<
__t<_DerivedId>,
__compose<_QueryFn, _GetSelfFn>{},
__forward<_DerivedId>> {
template <auto _RebaseFn>
using __rebind_t =
__forwarding<_DerivedId, _Query, _QueryFn, _GetBaseFn, decltype(_RebaseFn)>;
};
template <class _Derived,
class _Query,
auto _QueryFn,
auto _GetBaseFn = __ident{}, // _Derived -> _Base
auto _GetSelfFn = __to<_Derived>{}> // __forwarding<Derived....> -> _Derived
using __with_query_forwarding =
__forwarding<
__x<_Derived>,
_Query,
decltype(_QueryFn),
decltype(_GetBaseFn),
decltype(_GetSelfFn)>;
template <class _Fn, class... _Ts>
using __apply =
typename _Fn::template __f<_Ts...>;
namespace __detail {
void get_scheduler();
struct get_scheduler_t {
template <class _Derived, auto _GetSchedulerFn, class _SelfT = __mconst<_Derived>>
struct __forward {
template <class... _Ts>
friend auto get_scheduler(get_scheduler_t, const __apply<_SelfT, _Ts...>& __self)
-> decltype(_GetSchedulerFn(__self)) {
return _GetSchedulerFn(__self);
}
};
template <class _Ty>
STATIC_CALL_OPERATOR(auto)(_Ty&& __t)
-> decltype(get_scheduler(__declval<get_scheduler_t>(), (_Ty&&) __t)) {
return get_scheduler(get_scheduler_t{}, (_Ty&&) __t);
}
};
void get_stop_token();
struct get_stop_token_t {
template <class _Derived, auto _GetStopTokenFn, class _SelfT = __mconst<_Derived>>
struct __forward {
template <class... _Ts>
friend auto get_stop_token(get_stop_token_t, const __apply<_SelfT, _Ts...>& __self)
-> decltype(_GetStopTokenFn(__self)) {
return _GetStopTokenFn(__self);
}
};
template <class _Ty>
STATIC_CALL_OPERATOR(auto)(_Ty&& __t)
-> decltype(get_stop_token(__declval<get_stop_token_t>(), (_Ty&&) __t)) {
return get_stop_token(get_stop_token_t{}, (_Ty&&) __t);
}
};
}
using __detail::get_scheduler_t;
inline constexpr get_scheduler_t get_scheduler{};
using __detail::get_stop_token_t;
inline constexpr get_stop_token_t get_stop_token{};
struct in_place_stop_token {};
namespace __env {
struct __empty {};
template <class _Derived, auto _Query, class _Value, class _Base>
struct __with_query
: __with_query_forwarding<
_Derived,
decltype(_Query),
[](const auto& __self) -> _Value { return __self.__value_; },
[]<class _Ty>(_Ty&& __self) noexcept -> __copy_cvref_t<_Ty&&, _Base> {
return ((_Ty&&) __self).__base_;
}> {
explicit __with_query(_Value __value)
: __value_((_Value&&) __value)
, __base_{}
{}
__with_query(_Value __value, _Base __base)
: __value_((_Value&&) __value)
, __base_((_Base&&) __base)
{}
_Value __value_;
[[no_unique_address]] _Base __base_;
};
template <class _Scheduler, class _Base = __empty>
struct __with_scheduler
: __with_query<__with_scheduler<_Scheduler, _Base>, get_scheduler, _Scheduler, _Base> {
using __with_scheduler::__with_query::__with_query;
};
template <class _StopToken, class _Base = __empty>
struct __with_stop_token
: __with_query<__with_stop_token<_StopToken, _Base>, get_stop_token, _StopToken, _Base> {
using __with_stop_token::__with_query::__with_query;
};
}
using __env::__with_scheduler;
using __env::__with_stop_token;
extern "C" int printf(char const*, ...);
int main() {
__with_scheduler<int> e{42};
int i = get_scheduler(e);
__with_scheduler<char const*, decltype((e))> e2{"42", e};
char const* sz = get_scheduler(e2);
__with_stop_token<in_place_stop_token, decltype((e))> e3{{}, e};
in_place_stop_token stok = get_stop_token(e3);
int i2 = get_scheduler(e3);
printf("i2 = %d\n", i2);
e.__value_++;
i2 = get_scheduler(e3);
printf("i2 = %d\n", i2);
__with_scheduler<char const*, decltype((e3))> e4{"hello", e3};
in_place_stop_token stok2 = get_stop_token(e4);
char const* sz2 = get_scheduler(e4);
printf("i2 = %s\n", sz2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment