/
utility.hpp
129 lines (112 loc) · 3.58 KB
/
utility.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#pragma once
#include <type_traits>
#include <utility>
#include <observable/value.hpp>
#include <observable/expressions/tree.hpp>
namespace observable { inline namespace expr { namespace expr_detail {
//! Check if a type is either an expression_node or an observable
//! value<ValueType, EqualityComparator>.
//!
//! The static member ``value`` will be true if the provided type is either an
//! observable value<ValueType, EqualityComparator> or an
//! expression_node.
//!
//! \ingroup observable_detail
template <typename T>
struct is_observable :
std::integral_constant<bool, is_value<T>::value ||
is_expression_node<T>::value>
{ };
//! Check if any of the provided types are observable.
//!
//! The static member ``value`` will be true if at least one of the provided types
//! is an observable value<ValueType, EqualityComparator> or an expression_node.
//!
//! \ingroup observable_detail
template <typename ... T>
struct are_any_observable;
//! \cond
template <typename H, typename ... T>
struct are_any_observable<H, T ...> :
std::integral_constant<bool, are_any_observable<H>::value ||
are_any_observable<T ...>::value>
{ };
template <typename T>
struct are_any_observable<T> : is_observable<T>
{ };
//! \endcond
//! \cond
template <typename T>
struct val_type_ { using type = T; };
template <typename T, typename ... R>
struct val_type_<value<T, R ...>> { using type = T; };
template <typename T>
struct val_type_<expression_node<T>> { using type = T; };
//! \endcond
//! Extract the value type from an expression_node or observable
//! value<ValueType, EqualityComparator>.
//!
//! \ingroup observable_detail
template <typename T>
struct val_type : val_type_<std::decay_t<T>> { };
//! Convenience typedef for extracting the value type from an expression_node or
//! observable value<ValueType, EqualityComparator>.
//!
//! \see val_type
//! \ingroup observable_detail
template <typename T>
using val_type_t = typename val_type<T>::type;
//! Computes the type of the expression_node created for an expression with
//! callable ``Op`` and corresponding arguments.
//!
//! \ingroup observable_detail
template <typename Op, typename ... Args>
struct result_node
{
using type = expression_node<
std::decay_t<
std::result_of_t<
std::decay_t<Op>(val_type_t<Args> ...)>>>;
};
//! Type of the expression_node created for an expression with callable ``Op`` and
//! corresponding arguments.
//!
//! \ingroup observable_detail
template <typename Op, typename ... Args>
using result_node_t = typename result_node<Op, Args ...>::type;
//! Create a node from a regular type.
//!
//! \ingroup observable_detail
template <typename T>
inline auto make_node(T && val)
{
return expression_node<val_type_t<T>> { std::forward<T>(val) };
}
//! Create a node from an observable value reference.
//!
//! \ingroup observable_detail
template <typename T, typename ... R>
inline auto make_node(value<T, R ...> & val)
{
return expression_node<T> { val };
}
//! Create a node from a temporary expression_node.
//!
//! \ingroup observable_detail
template <typename T>
inline auto make_node(expression_node<T> && node)
{
return std::move(node);
}
//! Create a node from an operator and an arbitrary number of arguments.
//!
//! \ingroup observable_detail
template <typename Op, typename ... Args>
inline auto make_node(Op && op, Args && ... args)
{
return result_node_t<Op, Args ...> {
std::forward<Op>(op),
make_node(std::forward<Args>(args)) ...
};
}
} } }