7template <ComputeData InputType, ComputeData OutputType>
8class FunctionalOperation;
11 template <ComputeData In, ComputeData Out>
18 template <ComputeData T>
28template <
typename OpClass,
typename DataType>
30 && std::same_as<
typename OpClass::input_type, Datum<DataType>>;
63template <
typename Executor, ComputeData DataType>
80 : m_executor(
std::move(executor))
85 error<std::invalid_argument>(
86 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
87 std::source_location::current(),
88 "FluentExecutor requires non-null executor");
98 : m_executor(
std::move(executor))
103 error<std::invalid_argument>(
104 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
105 std::source_location::current(),
106 "FluentExecutor requires non-null executor");
152 template <
typename OpClass, ComputeData OutputType = DataType>
157 error<std::runtime_error>(
158 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
159 std::source_location::current(),
160 "Cannot continue chain after failed operation");
164 auto result = m_executor->template execute<OpClass, DataType, OutputType>(m_data);
166 m_successful =
false;
167 record_error(
"Operation " + std::string(
typeid(OpClass).
name()) +
" failed");
168 error<std::runtime_error>(
169 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
170 std::source_location::current(),
171 "Operation failed in fluent chain: {}", std::string(
typeid(OpClass).
name()));
175 next.m_operation_history = m_operation_history;
176 next.m_operation_history.push_back(
typeid(OpClass).
name());
178 }
catch (
const std::exception& e) {
179 m_successful =
false;
180 record_error(e.what());
182 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
183 std::source_location::current(),
184 "Exception in fluent chain: " + std::string(e.what()));
200 template <
typename OpClass, ComputeData OutputType = DataType>
205 error<std::runtime_error>(
206 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
207 std::source_location::current(),
208 "Cannot continue chain after failed operation: {}",
name);
212 auto result = m_executor->template execute_named<OpClass, DataType, OutputType>(
name, m_data);
214 m_successful =
false;
215 record_error(
"Named operation '" +
name +
"' failed");
216 error<std::runtime_error>(
217 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
218 std::source_location::current(),
219 "Named operation failed in fluent chain: {}",
name);
223 next.m_operation_history = m_operation_history;
224 next.m_operation_history.push_back(
name);
226 }
catch (
const std::exception& e) {
227 m_successful =
false;
228 record_error(e.what());
230 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
231 std::source_location::current(),
232 "Exception in named operation '{}': {}",
name, e.what());
244 template <
typename OpClass>
251 error<std::runtime_error>(
252 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
253 std::source_location::current(),
254 "Cannot continue chain after failed operation");
257 const std::string key =
typeid(OpClass).
name();
259 auto result = m_executor->template execute<OpClass, DataType, OutputType>(m_data);
261 m_successful =
false;
262 record_error(
"Operation " + key +
" failed");
263 error<std::runtime_error>(
264 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
265 std::source_location::current(),
266 "Operation failed in fluent chain: {}", key);
270 next.m_operation_history = m_operation_history;
271 next.m_operation_history.push_back(key);
273 }
catch (
const std::exception& e) {
274 m_successful =
false;
275 record_error(e.what());
277 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
278 std::source_location::current(),
279 "Exception in fluent chain: " + std::string(e.what()));
291 template <
typename OpClass>
298 error<std::runtime_error>(
299 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
300 std::source_location::current(),
301 "Cannot continue chain after failed operation: {}",
name);
305 auto result = m_executor->template execute_named<OpClass, DataType, OutputType>(
name, m_data);
307 m_successful =
false;
308 record_error(
"Named operation '" +
name +
"' failed");
309 error<std::runtime_error>(
310 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
311 std::source_location::current(),
312 "Named operation failed in fluent chain: {}",
name);
316 next.m_operation_history = m_operation_history;
317 next.m_operation_history.push_back(
name);
319 }
catch (
const std::exception& e) {
320 m_successful =
false;
321 record_error(e.what());
323 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
324 std::source_location::current(),
325 "Exception in named operation '{}': {}",
name, e.what());
342 template <
typename Func>
343 requires std::invocable<Func, const DataType&>
347 error<std::runtime_error>(
348 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
349 std::source_location::current(),
350 "Cannot continue chain after failed operation in apply");
353 using ResultType = std::invoke_result_t<Func, const DataType&>;
356 auto result = std::forward<Func>(func)(m_data.data);
359 next.m_operation_history = m_operation_history;
360 next.m_operation_history.push_back(
"custom_function");
362 }
catch (
const std::exception& e) {
363 m_successful =
false;
364 record_error(std::string(
"Custom function failed: ") + e.what());
366 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
367 std::source_location::current(),
368 "Exception in custom function: " + std::string(e.what()));
383 template <
typename Func>
384 requires std::invocable<Func, DataType&>
388 error<std::runtime_error>(
389 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
390 std::source_location::current(),
391 "Cannot continue chain after failed operation in tap");
395 std::forward<Func>(func)(m_data.data);
396 m_operation_history.emplace_back(
"tap");
398 }
catch (
const std::exception& e) {
399 m_successful =
false;
400 record_error(std::string(
"Tap function failed: ") + e.what());
402 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
403 std::source_location::current(),
404 "Exception in tap function: " + std::string(e.what()));
418 template <
typename OpClass>
421 if (condition && m_successful)
422 return then<OpClass>();
433 template <
typename OpClass,
typename Pred>
434 requires std::predicate<Pred, const DataType&>
437 if (m_successful && std::forward<Pred>(predicate)(m_data.data))
438 return then<OpClass>();
456 template <
typename... OpClasses>
460 error<std::runtime_error>(
461 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
462 std::source_location::current(),
463 "Cannot fork after failed operation");
466 return std::make_tuple(
467 m_executor->template execute<OpClasses, DataType>(m_data)...);
478 [[nodiscard]]
const DataType&
get()
const
481 error<std::runtime_error>(
482 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
483 std::source_location::current(),
484 "Cannot get result from failed chain");
496 error<std::runtime_error>(
497 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
498 std::source_location::current(),
499 "Cannot get mutable result from failed chain");
511 error<std::runtime_error>(
512 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
513 std::source_location::current(),
514 "Cannot consume result from failed chain");
516 return std::move(m_data.data);
530 error<std::runtime_error>(
531 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
532 std::source_location::current(),
533 "Cannot get datum from failed chain");
545 error<std::runtime_error>(
546 Journal::Component::Yantra, Journal::Context::ComputeMatrix,
547 std::source_location::current(),
548 "Cannot consume datum from failed chain");
550 return std::move(m_data);
564 result.
metadata[
"execution_history"] = m_operation_history;
565 result.
metadata[
"successful"] = m_successful;
566 if (!m_errors.empty())
567 result.
metadata[
"errors"] = m_errors;
576 [[nodiscard]] DataType
get_or(
const DataType& default_value)
const
578 return m_successful ? m_data.data : default_value;
587 template <
typename Generator>
588 requires std::invocable<Generator>
591 return m_successful ? m_data.data : std::forward<Generator>(generator)();
611 m_operation_history.clear();
645 [[nodiscard]]
const std::vector<std::string>&
get_history()
const {
return m_operation_history; }
651 [[nodiscard]]
const std::vector<std::string>&
get_errors()
const {
return m_errors; }
657 [[nodiscard]] std::shared_ptr<Executor>
get_executor()
const {
return m_executor; }
666 template <
typename E, ComputeData U>
675 template <ComputeData OutputType>
679 for (
auto& [k, v] : result.metadata)
680 next.
metadata.insert_or_assign(k, std::move(v));
681 next.
metadata.insert_or_assign(key, std::move(result.data));
698template <
typename Executor, ComputeData DataType>
703 std::forward<Datum<DataType>>(datum));
718template <
typename Executor, ComputeData DataType>
719auto make_fluent(std::shared_ptr<Executor> executor, DataType&& data)
Core::GlobalInputConfig input
auto fork()
Fork execution into multiple independent parallel paths.
FluentExecutor(std::shared_ptr< Executor > executor, DataType &&input)
Construct with executor and raw data (move, convenience entry point)
FluentExecutor & when(Pred &&predicate)
Execute an operation conditionally on a predicate over the raw data.
FluentExecutor & reset(const DataType &new_data)
Reset the chain with raw data (convenience overload)
const std::vector< std::string > & get_history() const
Get the ordered list of operation names executed so far.
Datum< DataType > consume_datum() &&
Move the full result Datum out of the chain.
void record_error(const std::string &err)
FluentExecutor & tap(Func &&func)
Apply a side-effect function without changing data or type.
std::shared_ptr< Executor > get_executor() const
Get the underlying executor.
DataType get_or(const DataType &default_value) const
Return the raw result or a fallback value if the chain failed.
FluentExecutor< Executor, OutputType > then(const std::string &name)
Chain a named operation fetched from the executor's pool.
auto apply(Func &&func)
Apply a custom transformation function within the chain.
DataType consume() &&
Move the final raw result out of the chain.
FluentExecutor(std::shared_ptr< Executor > executor, const Datum< DataType > &input)
Construct with executor and Datum input.
FluentExecutor & when(bool condition)
Execute an operation conditionally on a boolean flag.
FluentExecutor(std::shared_ptr< Executor > executor, Datum< DataType > &&input)
Construct with executor and Datum input (move)
std::shared_ptr< Executor > m_executor
const std::vector< std::string > & get_errors() const
Get all errors accumulated during the chain.
bool is_successful() const
Check whether all operations in the chain have succeeded.
DataType get_or_else(Generator &&generator) const
Return the raw result or invoke a generator if the chain failed.
const Datum< DataType > & get_datum() const
Get the full result Datum by const reference.
FluentExecutor< Executor, DataType > then()
Chain a FunctionalOperation child as an annotation of the current Datum.
std::vector< std::string > m_errors
FluentExecutor< Executor, DataType > then(const std::string &name)
Chain a named FunctionalOperation child from the executor's pool as an annotation of the current Datu...
Datum< DataType > absorbed(Datum< OutputType > &&result, const std::string &key) const
The current Datum with result's metadata merged in and its data stored under key.
FluentExecutor(std::shared_ptr< Executor > executor, const DataType &input)
Construct with executor and raw data (convenience entry point)
FluentExecutor & reset(const Datum< DataType > &new_datum)
Reset the chain with a new Datum, clearing history and errors.
DataType & get_mutable()
Get a mutable reference to the final raw result.
FluentExecutor< Executor, OutputType > then()
Chain an anonymous operation instance by type.
const DataType & get() const
Get the final raw result by const reference.
Datum< DataType > to_io() const
Return the result Datum with execution history appended to metadata.
std::vector< std::string > m_operation_history
Fluent interface for chaining operations on any executor.
Wraps a single callable as a ComputeOperation, for a wild or one-off idea that does not warrant a han...
OpClass derives from a FunctionalOperation whose input is DataType.
std::true_type functional_operation_base(const FunctionalOperation< In, Out > *)
auto make_fluent(std::shared_ptr< Executor > executor, Datum< DataType > &&datum)
Construct a FluentExecutor from a Datum with type deduction.
std::unordered_map< std::string, std::any > metadata
Associated metadata.
Input/Output container for computation pipeline data flow with structure preservation.