MEL
Microthread & Execution library
Condition.h
1 #pragma once
2 /*
3  * SPDX-FileCopyrightText: 2022 Daniel Barrientos <danivillamanin@gmail.com>
4  *
5  * SPDX-License-Identifier: MIT
6  */
7 
8 #include <execution/Executor.h>
9 #include <preprocessor/utils.h>
10 #include <tuple>
11 
12 namespace mel
13 {
14  namespace execution
15  {
19  namespace flow
20  {
21  // for internal use by condition function
22 #define CONDITION_SELECT_JOB( idx ) \
23  if constexpr ( tsize > idx ) \
24  { \
25  using FlowType = std::tuple_element_t<idx, TupleType>; \
26  static_assert( \
27  std::is_invocable<FlowType, ExFuture<ExecutorAgent, TArg>>::value, \
28  "execution::condition bad functor signature" ); \
29  launch( source.agent, \
30  [source, result, fls = std::move( fls )]() mutable noexcept \
31  { \
32  if constexpr ( std::is_nothrow_invocable< \
33  FlowType, \
34  ExFuture<ExecutorAgent, TArg>>::value ) \
35  result.assign( std::get<idx>( fls )( source ) ); \
36  else \
37  { \
38  try \
39  { \
40  result.assign( std::get<idx>( fls )( source ) ); \
41  } \
42  catch ( ... ) \
43  { \
44  result.setError( std::current_exception() ); \
45  } \
46  } \
47  } ); \
48  } \
49  else \
50  { \
51  launch( source.agent, \
52  [result]() mutable noexcept \
53  { \
54  result.setError( std::out_of_range( \
55  "execution::condition. Index '" TOSTRING( \
56  idx ) "' is greater than maximum case " \
57  "index " TOSTRING( tsize ) ) ); \
58  } ); \
59  }
69  template <class ExecutorAgent, class TArg, class F, class... Flows>
70  auto condition( ExFuture<ExecutorAgent, TArg> source, F selector,
71  Flows... flows )
72  {
73 
74  typedef
76  typedef typename ::mel::execution::_private::GetReturn<
77  ExFuture<ExecutorAgent, TArg>, Flows...>::type ResultTuple;
78  using ResultType = std::tuple_element_t<0, ResultTuple>;
79  ResultType result( source.agent );
80  source.subscribeCallback(
81  // need to bind de source future to not get lost and input
82  // pointing to unknown place
83 
84  [source, selector = std::move( selector ),
85  fls = std::make_tuple( std::move( flows )... ), result](
86  ValueType&
87  input ) mutable noexcept( std::
88  is_nothrow_invocable<
89  F, TArg>::value )
90  {
91  // lanzar tarea para deteccion noexcept, ¿para todo
92  // junto? creo que sí...
93  if ( input.isValid() )
94  {
95  using TupleType = decltype( fls );
96  // Evaluate index
97  size_t idx = selector( input.value() );
98  constexpr size_t tsize =
99  std::tuple_size<TupleType>::value;
100  switch ( idx )
101  {
102  case 0:
103 
104  // //codigo a pelo para temas de depuracion
105  // if constexpr (tsize>0)
106  // {
107  // using FlowType =
108  // std::tuple_element_t<0,TupleType>;
109  // launch(source.agent,[source,result,fls =
110  // std::move(fls)]() mutable noexcept
111  // {
112  // if constexpr
113  // (std::is_nothrow_invocable<FlowType,ExFuture<ExecutorAgent,TArg>>::value)
114  // result.assign(std::get<0>(fls)(source));
115  // else
116  // {
117  // try
118  // {
119  // result.assign(std::get<0>(fls)(source));
120  // }catch(...)
121  // {
122  // result.setError(std::current_exception());
123  // }
124  // }
125  // }
126  // );
127  // }else{
128  // launch(source.agent,[result]( ) mutable
129  // noexcept {
130  // result.setError(std::out_of_range("triqui"));
131  // });
132  // }
133  CONDITION_SELECT_JOB( 0 )
134  break;
135  case 1:
136  CONDITION_SELECT_JOB( 1 )
137  break;
138  case 2:
139  CONDITION_SELECT_JOB( 2 )
140  break;
141  case 3:
142  CONDITION_SELECT_JOB( 3 )
143  break;
144  case 4:
145  CONDITION_SELECT_JOB( 4 )
146  break;
147  case 5:
148  CONDITION_SELECT_JOB( 5 )
149  break;
150  case 6:
151  CONDITION_SELECT_JOB( 6 )
152  break;
153  case 7:
154  CONDITION_SELECT_JOB( 7 )
155  break;
156  case 8:
157  CONDITION_SELECT_JOB( 8 )
158  break;
159  case 9:
160  CONDITION_SELECT_JOB( 9 )
161  break;
162  }
163  }
164  else
165  {
166  // set error as task in executor
167  std::exception_ptr err = input.error();
168  launch( source.agent,
169  [result, err]() mutable noexcept
170  { result.setError( std::move( err ) ); } );
171  }
172  } );
173  return result;
174  }
175 
176  namespace _private
177  {
178  template <class F, class... FTypes> struct ApplyCondition
179  {
180  template <class S, class... Fs>
181  ApplyCondition( S&& selector, Fs&&... fs )
182  : mSelector( std::forward<F>( selector ) ),
183  mFuncs( std::forward<Fs>( fs )... )
184  {
185  }
186  F mSelector;
187  std::tuple<FTypes...> mFuncs;
188  template <class TArg, class ExecutorAgent>
189  auto operator()( ExFuture<ExecutorAgent, TArg> inputFut )
190  {
191  return condition( inputFut,
192  std::forward<F>( mSelector ),
193  std::forward<FTypes>(
194  std::get<FTypes>( mFuncs ) )... );
195  }
196  };
197  } // namespace _private
198 
200  template <class F, class... FTypes>
201  _private::ApplyCondition<F, FTypes...>
202  condition( F&& selector, FTypes&&... functions )
203  {
204  return _private::ApplyCondition<F, FTypes...>(
205  std::forward<F>( selector ),
206  std::forward<FTypes>( functions )... );
207  }
208  } // namespace flow
209  } // namespace execution
210 } // namespace mel
int subscribeCallback(F &&f) const
Subscribe callback to be executed when future is ready (valid or error)
Definition: Future.h:681
Executor< ExecutorAgent > agent
execution agent associated with this instance
Definition: ExFuture.h:54
FlowsResult< typename ::mel::execution::_private::GetReturn< ExFuture< ExecutorAgent, TArg >, Flows... >::type > launch(ExFuture< ExecutorAgent, TArg > source, Flows... flows)
Launch given set of flows.
Definition: Launch.h:85
auto condition(ExFuture< ExecutorAgent, TArg > source, F selector, Flows... flows)
Select functor to execute.
Definition: Condition.h:70
Definition: Callback_Impl.h:11