funcy  1.6.1
variable.h
1 #pragma once
2 
3 #include <funcy/concepts.h>
4 #include <funcy/util/traverse.h>
5 
6 #include <limits>
7 #include <tuple>
8 #include <type_traits>
9 
10 namespace funcy
11 {
13  template < class, int >
14  struct Variable;
15 
16  template < class T, class Other >
17  struct ContainsType : std::false_type
18  {
19  };
20 
21  template < class T >
22  struct ContainsType< T, T > : std::true_type
23  {
24  };
25 
26  template < class T, class Gradient >
27  struct ContainsType< T, std::tuple< T, Gradient > > : std::true_type
28  {
29  };
30 
31  template < class T, class Value >
32  struct ContainsType< T, std::tuple< Value, T > > : std::true_type
33  {
34  };
35 
36  namespace detail
37  {
38  template < class Arg, class Extended >
39  struct Assign;
40 
41  template < class Arg, class Gradient >
42  struct Assign< Arg, std::tuple< Arg, Gradient > >
43  {
44  static auto apply( Arg& t, const std::tuple< Arg, Gradient >& x )
45  {
46  t = std::get< 0 >( x );
47  }
48  };
49 
50  template < class Arg, class Value >
51  struct Assign< Arg, std::tuple< Value, Arg > >
52  {
53  static auto apply( Arg& t, const std::tuple< Value, Arg >& x )
54  {
55  t = std::get< 1 >( x );
56  }
57  };
58 
59  template < class Arg >
60  struct Assign< Arg, Arg >
61  {
62  static void apply( Arg& t, const Arg& x )
63  {
64  t = x;
65  }
66  };
67 
68  template < class T, class Other >
69  struct ExtractReturnValue;
70 
71  template < class T >
72  struct ExtractReturnValue< T, T >
73  {
74  static const T& apply( const T& x )
75  {
76  return x;
77  }
78  };
79 
80  template < class T, class Gradient >
81  struct ExtractReturnValue< T, std::tuple< T, Gradient > >
82  {
83  static const T& apply( const std::tuple< T, Gradient >& x )
84  {
85  return std::get< 0 >( x );
86  }
87  };
88 
89  template < class T, class Value >
90  struct ExtractReturnValue< T, std::tuple< Value, T > >
91  {
92  static const T& apply( const std::tuple< Value, T >& x )
93  {
94  return std::get< 1 >( x );
95  }
96  };
97 
98  template < bool >
99  struct Update
100  {
101  template < class T, class Arg >
102  static void apply( T& t, const Arg& x )
103  {
104  Assign< T, Arg >::apply( t, x );
105  }
106  };
107 
108  template <>
109  struct Update< false >
110  {
111  template < class T, class Arg >
112  static void apply( const T&, const Arg& )
113  {
114  }
115  };
116  } // namespace detail
118 
120  template < class T, int id >
121  struct Variable
122  {
123  Variable() = default;
124 
125  constexpr explicit Variable( const T& t_ ) : t( t_ )
126  {
127  }
128 
129  constexpr explicit Variable( T&& t_ ) : t( std::move( t_ ) )
130  {
131  }
132 
134  template < int index, class Arg >
135  void update( const Arg& t_ )
136  {
137  detail::Update< index == id >::apply( t, t_ );
138  }
139 
141  constexpr const T& operator()() const noexcept
142  {
143  return t;
144  }
145 
147  template < int index, class Arg, class = std::enable_if_t< id == index > >
148  const T& d1( const Arg& dt ) const noexcept
149  {
150  return detail::ExtractReturnValue< T, Arg >::apply( dt );
151  }
152 
153  private:
154  T t;
155  };
156 
158  template < int id, class T >
160  {
161  return Variable< T, id >( t );
162  }
163 
165  namespace detail
166  {
168  template < class >
169  struct IsVariable : std::false_type
170  {
171  };
172 
173  template < class T, int n >
174  struct IsVariable< Variable< T, n > > : std::true_type
175  {
176  };
177 
178  template < class, int >
179  struct HasVariableWithId : std::false_type
180  {
181  };
182 
183  template < class Type, int id0, int id >
184  struct HasVariableWithId< funcy::Variable< Type, id0 >, id >
185  : std::integral_constant< bool, id == id0 >
186  {
187  };
188 
189  namespace has
190  {
192  template < Function F >
193  using Variable = meta::AnyOf< F, IsVariable >;
194 
195  template < class F, int id >
196  struct VariableId
197  {
198  template < class G >
199  struct HasVariable
200  {
201  static constexpr bool value = HasVariableWithId< G, id >::value;
202  };
203  static constexpr bool value = meta::AnyOf< F, HasVariable >::value;
204  };
205  } // namespace has
206 
207  constexpr bool greater( int a, int b )
208  {
209  return a > b;
210  }
211 
212  template < class F, class G >
213  struct Max
214  : std::integral_constant< int, greater( F::value, G::value ) ? F::value : G::value >
215  {
216  };
217 
218  template < class F, class G >
219  struct Min
220  : std::integral_constant< int, greater( G::value, F::value ) ? F::value : G::value >
221  {
222  };
223 
224  namespace detail
225  {
226  template < class Type >
227  struct MaxVariableId
228  : std::integral_constant< int, std::numeric_limits< int >::lowest() >
229  {
230  };
231 
232  template < class T, int id >
233  struct MaxVariableId< funcy::Variable< T, id > > : std::integral_constant< int, id >
234  {
235  };
236 
237  template < class T, int id >
238  struct MaxVariableId< const funcy::Variable< T, id > >
239  : std::integral_constant< int, id >
240  {
241  };
242 
243  template < class Type >
244  struct MinVariableId : std::integral_constant< int, std::numeric_limits< int >::max() >
245  {
246  };
247 
248  template < class T, int id >
249  struct MinVariableId< funcy::Variable< T, id > > : std::integral_constant< int, id >
250  {
251  };
252 
253  template < class T, int id >
254  struct MinVariableId< const funcy::Variable< T, id > >
255  : std::integral_constant< int, id >
256  {
257  };
258  } // namespace detail
259 
260  template < class F >
261  using MaxVariableId = meta::Traverse< F, detail::MaxVariableId, Max >;
262 
263  template < class F >
264  using MinVariableId = meta::Traverse< F, detail::MinVariableId, Min >;
265 
266  template < class F, int id >
267  struct VariableType
268  {
269  using type = void;
270  };
271 
272  template < class T, int id >
273  struct VariableType< Variable< T, id >, id >
274  {
275  using type = T;
276  };
277 
278  template < class T, int id >
279  struct VariableType< const Variable< T, id >, id >
280  {
281  using type = T;
282  };
283 
284  template < class T, class >
285  struct ChooseTypeImpl
286  {
287  using type = T;
288  };
289 
290  template < class T >
291  struct ChooseTypeImpl< void, T >
292  {
293  using type = T;
294  };
295 
296  template <>
297  struct ChooseTypeImpl< void, void >
298  {
299  using type = void;
300  };
301 
302  template < class F, class G >
303  struct ChooseType
304  {
305  using type = typename ChooseTypeImpl< typename F::type, typename G::type >::type;
306  };
307 
308  template < class F, int id >
309  struct VariableT
310  {
311  template < class G >
312  using Extractor = VariableType< G, id >;
313 
314  using type = typename meta::Traverse< std::decay_t< F >, Extractor, ChooseType >::type;
315  };
316  } // namespace detail
318 
320  template < class F, int id >
321  using Variable_t = typename detail::VariableT< F, id >::type;
322 
323  namespace static_check
324  {
325  namespace has
326  {
328  template < Function T >
329  constexpr bool variable()
330  {
331  return detail::has::Variable< std::decay_t< T > >::value;
332  }
333 
335  template < class T, int id >
336  constexpr bool variable_id()
337  {
338  return detail::has::VariableId< std::decay_t< T >, id >::value;
339  }
340  } // namespace has
341 
343  template < class F, class Type, int id >
344  constexpr bool check_argument()
345  {
346  return ContainsType< Variable_t< F, id >, Type >::value;
347  }
348  } // namespace static_check
349 } // namespace funcy
typename detail::VariableT< F, id >::type Variable_t
Get underlying type of variable with index id.
Definition: variable.h:321
const T & d1(const Arg &dt) const noexcept
First directional derivative. Only available if id==index.
Definition: variable.h:148
Variable< T, id > variable(const T &t)
Generate variable from input type.
Definition: variable.h:159
Main namespace of the funcy library.
Independent variable. Can be uniquely identified by its id.
Definition: variable.h:121
constexpr const T & operator()() const noexcept
Value of the variable.
Definition: variable.h:141
void update(const Arg &t_)
Update variable if index==id.
Definition: variable.h:135