7#ifndef MAQUETTE_EXPRESSIVE_H
8#define MAQUETTE_EXPRESSIVE_H
24template <
typename... T,
typename... U>
struct common_type<std::tuple<T...>, std::tuple<U...>>
26 using type = std::tuple<typename std::common_type<T, U>::type...>;
34template <
bool b,
bool... bools>
inline constexpr bool all()
36 return b && all<bools...>();
39template <>
constexpr bool all<true>()
43template <>
constexpr bool all<false>()
63 using return_type = Ret;
64 using arguments_type = std::tuple<Args...>;
65 static constexpr std::size_t arguments_count =
sizeof...(Args);
71 using return_type = Ret;
72 using arguments_type = std::tuple<Args...>;
73 static constexpr std::size_t arguments_count =
sizeof...(Args);
77template <
typename Ret,
typename Class,
typename... Args>
struct Callable_traits<Ret (Class::*)(Args...) const>
79 using return_type = Ret;
80 using arguments_type = std::tuple<Args...>;
81 static constexpr std::size_t arguments_count =
sizeof...(Args);
88template <
typename Callable, std::
size_t I>
89using argument_type =
typename std::tuple_element<I, typename Callable_traits<Callable>::arguments_type>::type;
91template <
typename Callable>
constexpr auto arguments_count()
96template <
typename Functor,
typename Interface>
97using functor_has_interface = std::is_convertible<Interface, typename Callable_traits<Functor>::arguments_type>;
99template <
typename Functor,
typename... Args>
100using callable_with = std::is_convertible<arguments_type<void(Args...)>, arguments_type<Functor>>;
107 using functors_type = std::tuple<Functors...>;
109 template <std::
size_t I>
using return_type = return_type<typename std::tuple_element<I, functors_type>::type>;
111 template <std::
size_t I>
static constexpr std::size_t arguments_count()
116 using arguments_type =
typename std::common_type<typename Callable_traits<Functors>::arguments_type...>::type;
121 static_assert(meta::all<functor_has_interface<Functors, arguments_type>::value...>(),
122 "incompatible functors (arguments differs)");
126 template <
typename... Args>
static constexpr bool call_check()
129 return meta::all<callable_with<Functors, Args...>::value...>();
132 template <std::
size_t I>
constexpr auto const &f()
const
134 return std::get<I>(functors);
137 functors_type functors;
146 static constexpr std::size_t arguments_count()
156 template <
typename... Args>
static constexpr bool call_check()
158 return callable_with<F, Args...>::value;
175 using value_type =
typename base_t::return_type;
181 template <
typename... Args>
182 constexpr typename std::enable_if<base_t::template call_check<Args...>(), value_type>::type
operator()(
185 return base_t::f(args...);
189template <
typename F>
constexpr auto expression(F f)
205template <
typename F>
constexpr auto use(F f)
210template <
typename F>
constexpr auto function(F f)
212 return make_expression_t<F>(f);
220 constexpr literal_t(T
const &value) : value(value)
223 constexpr T operator()(Args...)
const
243template <
typename... Args,
typename T>
constexpr auto literal(T t)
264 template <
typename T>
constexpr auto operator()(T t)
272template <
typename Operator,
typename T>
273using applied_unary_type =
decltype(std::declval<Operator>()(std::declval<T>()));
275template <
typename Op,
typename T>
276constexpr auto is_applicable_unary_impl(
int) ->
decltype(std::declval<applied_unary_type<Op, T>>(),
bool())
281template <
typename Op,
typename T>
constexpr bool is_applicable_unary_impl(...)
286template <
typename A,
typename Operator,
typename B>
287using applied_binary_type =
decltype(std::declval<Operator>()(std::declval<A>(), std::declval<B>()));
289template <
typename A,
typename Op,
typename B>
290constexpr auto is_applicable_binary_impl(
int) ->
decltype(std::declval<applied_binary_type<A, Op, B>>(),
bool())
295template <
typename A,
typename Op,
typename B>
constexpr bool is_applicable_binary_impl(...)
302template <
typename Operator,
typename T>
constexpr bool is_applicable_unary()
304 return is_applicable_unary_impl<Operator, T>(0);
307template <
typename A,
typename Operator,
typename B>
constexpr bool is_applicable_binary()
309 return is_applicable_binary_impl<A, Operator, B>(0);
314template <
typename Operator,
typename F>
struct unop_t;
318 using return_type =
typename unop_t<Operator, F>::value_type;
319 using arguments_type =
typename unop_t<Operator, F>::arguments_type;
326 using value_type = applied_unary_type<Operator, typename base_t::return_type>;
330 static_assert(is_applicable_unary<Operator, typename base_t::return_type>(),
"incompatible functor value");
333 template <
typename... Args>
constexpr value_type operator()(Args... args)
const
335 static_assert(base_t::template call_check<Args...>(),
"wrong arguments types or count");
337 return impl(args...);
340 template <
typename... Args>
constexpr value_type impl(Args... args)
const
342 return Operator{}(base_t::f(args...));
348template <
typename FL,
typename Operator,
typename FR>
struct symetric_binop_t;
352 using return_type =
typename symetric_binop_t<FL, Operator, FR>::value_type;
353 using arguments_type =
typename symetric_binop_t<FL, Operator, FR>::arguments_type;
354 static constexpr std::size_t arguments_count = std::tuple_size<arguments_type>::arguments_count;
357template <
typename FL,
typename Operator,
typename FR>
362 using FL_return_type =
typename base_t::template return_type<0>;
363 using FR_return_type =
typename base_t::template return_type<1>;
365 using value_type = applied_binary_type<FL_return_type, Operator, FR_return_type>;
369 static_assert(is_applicable_binary<FL_return_type, Operator, FR_return_type>(),
370 "incompatible functors value types");
373 template <
typename... Args>
constexpr value_type operator()(Args... args)
const
375 static_assert(base_t::template call_check<Args...>(),
"wrong arguments types or count");
377 return Operator::operator()(base_t::template f<0>()(args...), base_t::template f<1>()(args...));
380 template <
typename... Args>
constexpr value_type impl(Args... args)
const
382 return Operator::operator()(base_t::template f<0>()(args...), base_t::template f<1>()(args...));
391template <
typename F>
constexpr auto operator-(F f)
396template <
typename F1,
typename F2>
constexpr auto operator+(F1 f1, F2 f2)
398 return symetric_binop_t<F1, std::plus<void>, F2>{f1, f2};
401template <
typename F1,
typename F2>
constexpr auto operator-(F1 f1, F2 f2)
403 return symetric_binop_t<F1, std::minus<void>, F2>{f1, f2};
406template <
typename F1,
typename F2>
constexpr auto operator*(F1 f1, F2 f2)
408 return symetric_binop_t<F1, std::multiplies<void>, F2>{f1, f2};
411template <
typename F1,
typename F2>
constexpr auto operator/(F1 f1, F2 f2)
413 return symetric_binop_t<F1, std::divides<void>, F2>{f1, f2};
416template <
typename F1,
typename F2>
constexpr auto operator%(F1 f1, F2 f2)
418 return symetric_binop_t<F1, std::modulus<void>, F2>{f1, f2};
423template <
typename Outer,
typename... Inners>
struct compose_t;
427 using return_type =
typename compose_t<Outer, Inners...>::value_type;
428 using arguments_type =
typename compose_t<Outer, Inners...>::arguments_type;
429 static constexpr std::size_t arguments_count = std::tuple_size<arguments_type>::value;
435 using value_type = return_type<Outer>;
437 constexpr compose_t(Outer outer, Inners... inners) :
base_t(inners...), outer(outer)
440 static_assert(
sizeof...(Inners) == arguments_count<Outer>(),
"wrong functors count");
443 static_assert(composable_check(std::index_sequence_for<Inners...>{}),
"uncomposable functors");
446 template <
typename... Args>
constexpr value_type operator()(Args... args)
const
448 static_assert(base_t::template call_check<Args...>(),
"wrong arguments type or count");
450 return impl(std::index_sequence_for<Inners...>{}, args...);
455 template <std::size_t... Is,
typename... Args>
456 constexpr value_type impl(std::index_sequence<Is...>, Args... args)
const
458 return outer(base_t::template f<Is>()(args...)...);
462 template <std::size_t... Is>
static constexpr bool composable_check(std::index_sequence<Is...>)
464 return meta::all<std::is_convertible<return_type<Inners>, argument_type<Outer, Is>>::value...>();
474 using value_type = return_type<Outer>;
476 constexpr compose_t(Outer outer, Inner inner) :
base_t(inner), outer(outer)
478 static_assert(arguments_count<Outer>() == 1,
"wrong functors count");
481 static_assert(std::is_convertible<return_type<Inner>, argument_type<Outer, 0>>::value,
"uncomposable functors");
484 template <
typename... Args>
constexpr value_type operator()(Args... args)
const
486 static_assert(base_t::template call_check<Args...>(),
"wrong arguments type or count");
487 return impl(args...);
490 template <
typename... Args>
constexpr value_type impl(Args... args)
const
492 return outer(base_t::f(args...));
503 using value_type =
typename base_t::return_type;
509 template <
typename... Args>
constexpr value_type operator()(Args... args)
const
511 static_assert(base_t::template call_check<Args...>(),
"wrong arguments type or count");
512 return impl(args...);
515 template <
typename... Args>
constexpr value_type impl(Args... args)
const
530template <
typename F,
typename... Fs>
constexpr auto compose(F f, Fs... fs)
537template <
typename F>
constexpr auto chain(F f)
539 return expression(f);
551template <
typename Inner,
typename Outer>
constexpr auto operator>>(Inner inner, Outer outer)
565template <
typename Inner,
typename Outer>
constexpr auto operator<<(Outer outer, Inner inner)
580template <
typename F1,
typename F2,
typename... Fs>
constexpr auto chain(F1 f1, F2 f2, Fs... fs)
582 return f1 >> chain(f2, fs...);
589template <
typename T> std::ostream &
operator<<(std::ostream &os, std::negate<T>
const &)
594template <
typename T> std::ostream &
operator<<(std::ostream &os, std::plus<T>
const &)
598template <
typename T> std::ostream &
operator<<(std::ostream &os, std::minus<T>
const &)
602template <
typename T> std::ostream &
operator<<(std::ostream &os, std::multiplies<T>
const &)
606template <
typename T> std::ostream &
operator<<(std::ostream &os, std::divides<T>
const &)
610template <
typename T> std::ostream &
operator<<(std::ostream &os, std::modulus<T>
const &)
615template <
typename T,
typename... Args> std::ostream &
operator<<(std::ostream &os, literal_t<T, Args...>
const &l)
617 return os << l.value;
620template <
typename Operator,
typename F> std::ostream &
operator<<(std::ostream &os, unop_t<Operator, F>
const &f)
622 return os << Operator{} << f.f;
625template <
typename F1,
typename Operator,
typename F2>
626std::ostream &
operator<<(std::ostream &os, symetric_binop_t<F1, Operator, F2>
const &f)
628 return os << f.f1 << Operator{} << f.f2;
constexpr auto compose(F f, Fs... fs)
Mathematical function composition
Definition expressive.hpp:530
constexpr auto literal(T t)
Transforms literals into operator friendly classes.
Definition expressive.hpp:243
constexpr auto operator<<(Outer outer, Inner inner)
Mathematical function composition
Definition expressive.hpp:565
constexpr auto operator>>(Inner inner, Outer outer)
Mathematical function composition
Definition expressive.hpp:551
constexpr auto use(F f)
Transforms functions into operator friendly classes.
Definition expressive.hpp:205
Simulation of coalescence-based models of molecular evolution.
Definition coalescence.hpp:21
Definition expressive.hpp:57
Definition expressive.hpp:433
Definition expressive.hpp:142
Definition expressive.hpp:106
Transforms literals into operator friendly classes.
Definition expressive.hpp:263
Definition expressive.hpp:218
Definition expressive.hpp:173
Definition expressive.hpp:359
Definition expressive.hpp:324