-
Notifications
You must be signed in to change notification settings - Fork 38
/
operator.hpp
192 lines (154 loc) · 5.92 KB
/
operator.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#ifndef KGR_KANGARU_INCLUDE_KANGARU_OPERATOR_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_OPERATOR_HPP
#include "container.hpp"
#include "detail/lazy_base.hpp"
#include "detail/operator_service_helper.hpp"
namespace kgr {
namespace detail {
/*
* Base class for invokers. Implements the call operator that invoke the function.
*/
template<typename Base, typename Map>
struct invoker_base : protected Base {
using Base::Base;
template<typename F, typename... Args, enable_if_t<is_invoke_valid<Map, decay_t<F>, Args...>::value, int> = 0>
invoke_function_result_t<Map, decay_t<F>, Args...> operator()(F&& f, Args&&... args) {
kgr::container& c = this->container();
return c.invoke<Map>(std::forward<F>(f), std::forward<Args>(args)...);
}
sink operator()(not_invokable_error = {}, ...) = delete;
inline friend auto service_map(invoker_base const&) -> select_operator_service<Base> { return {}; }
};
template<typename Base>
struct invoker_base<Base, map<>> : protected Base {
using Base::Base;
using map_t = map<>;
template<typename F, typename... Args, enable_if_t<is_invoke_valid<map_t, decay_t<F>, Args...>::value, int> = 0>
invoke_function_result_t<map_t, decay_t<F>, Args...> operator()(F&& f, Args&&... args) {
kgr::container& c = this->container();
return c.invoke<map_t>(std::forward<F>(f), std::forward<Args>(args)...);
}
template<typename Map, typename F, typename... Args, enable_if_t<is_map<Map>::value && is_invoke_valid<Map, decay_t<F>, Args...>::value, int> = 0>
invoke_function_result_t<Map, decay_t<F>, Args...> operator()(Map map, F&& f, Args&&... args) {
kgr::container& c = this->container();
return c.invoke(map, std::forward<F>(f), std::forward<Args>(args)...);
}
sink operator()(not_invokable_error = {}, ...) = delete;
};
/*
* Base class for generators. Implements the call operator that create services.
*/
template<typename Base, typename T>
struct generator_base : protected Base {
static_assert(!is_single<T>::value, "Generator only work with non-single services.");
using Base::Base;
template<typename... Args, enable_if_t<is_service_valid<T, Args...>::value, int> = 0>
service_type<T> operator()(Args&&... args) {
kgr::container& c = Base::container();
return c.service<T>(std::forward<Args>(args)...);
}
template<typename U = T, enable_if_t<std::is_default_constructible<service_error<U>>::value, int> = 0>
sink operator()(service_error<U> = {}) = delete;
template<typename... Args>
sink operator()(service_error<T, identity_t<Args>...>, Args&&...) = delete;
inline friend auto service_map(generator_base const&) -> select_operator_service<Base> { return {}; }
};
/*
* Base class for any non forking operators.
*
* Hold a non-owning reference to the container as a pointer.
*/
struct operator_base {
explicit operator_base(kgr::container& c) noexcept : _container{&c} {}
inline auto container() noexcept -> kgr::container& {
return *_container;
}
inline auto container() const noexcept -> kgr::container const& {
return *_container;
}
kgr::container* _container;
};
/*
* Base class for any forking operators.
*
* Hold a fork of the container as a member value.
*/
struct forked_operator_base {
explicit forked_operator_base(kgr::container&& c) noexcept : _container{std::move(c)} {}
inline auto container() noexcept -> kgr::container& {
return _container;
}
inline auto container() const noexcept -> kgr::container const& {
return _container;
}
kgr::container _container;
};
} // namespace detail
/**
* Function object that calls container::invoke.
*
* Useful when dealing with higer order functions or to convey intent.
*/
template<typename Map>
struct mapped_invoker : detail::invoker_base<detail::operator_base, Map> {
using detail::invoker_base<detail::operator_base, Map>::invoker_base;
template<typename M>
mapped_invoker(const mapped_invoker<M>& other) :
detail::invoker_base<detail::operator_base, Map>{other.container()} {}
inline friend auto service_map(mapped_invoker const&) -> detail::operator_service<mapped_invoker> { return detail::sink{}; }
};
/**
* Function object that calls container::invoke.
*
* This version forks the container.
*
* Useful when dealing with higer order functions or to convey intent.
*/
template<typename Map>
struct forked_mapped_invoker : detail::invoker_base<detail::forked_operator_base, Map> {
using detail::invoker_base<detail::forked_operator_base, Map>::invoker_base;
template<typename M>
forked_mapped_invoker(forked_mapped_invoker<M>&& other) :
detail::invoker_base<detail::forked_operator_base, Map>{std::move(other.container())} {}
inline friend auto service_map(forked_mapped_invoker const&) -> detail::forked_operator_service<all, forked_mapped_invoker> { return detail::sink{}; }
};
/**
* Function object that calls creates a service.
* Basically a factory function for a particular service.
*
* Useful to convey intent or contraining usage of the container.
*/
template<typename T>
using generator = detail::generator_base<detail::operator_base, T>;
/**
* Function object that calls creates a service.
* Basically a factory function for a particular service.
*
* This version forks the container.
*
* Useful to convey intent or contraining usage of the container.
*/
template<typename T>
using forked_generator = detail::generator_base<detail::forked_operator_base, T>;
/**
* A proxy class that delays the construction of a service until usage.
*/
template<typename T>
using lazy = detail::lazy_base<detail::operator_base, T>;
/**
* A proxy class that delays the construction of a service until usage.
*
* This will fork the container when the proxy is created.
*/
template<typename T>
using forked_lazy = detail::lazy_base<detail::forked_operator_base, T>;
/**
* Alias to the default invoker
*/
using invoker = mapped_invoker<map<>>;
/**
* Alias to the default forked invoker
*/
using forked_invoker = forked_mapped_invoker<map<>>;
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_OPERATOR_HPP