13 { t.template execute<int, int, int>(std::declval<int>()) };
40template <
typename Executor, ComputeData DataType>
52 : m_executor(
std::move(executor))
57 throw std::invalid_argument(
"FluentExecutor requires non-null executor");
65 : m_executor(
std::move(executor))
66 , m_data(
std::move(input))
70 throw std::invalid_argument(
"FluentExecutor requires non-null executor");
81 template <
typename OpClass, ComputeData OutputType = DataType>
85 throw std::runtime_error(
"Cannot continue chain after failed operation");
89 auto result = m_executor->template execute<OpClass, DataType, OutputType>(m_data);
92 record_error(
"Operation " + std::string(
typeid(OpClass).name()) +
" failed");
93 throw std::runtime_error(
"Operation failed in fluent chain: " + std::string(
typeid(OpClass).name()));
97 next.m_operation_history = m_operation_history;
98 next.m_operation_history.push_back(
typeid(OpClass).name());
100 }
catch (
const std::exception& e) {
101 m_successful =
false;
102 record_error(e.what());
114 template <
typename OpClass, ComputeData OutputType = DataType>
118 throw std::runtime_error(
"Cannot continue chain after failed operation");
122 auto result = m_executor->template execute<OpClass, DataType, OutputType>(name, m_data);
124 m_successful =
false;
125 record_error(
"Named operation '" + name +
"' failed");
126 throw std::runtime_error(
"Named operation failed in fluent chain: " + name);
130 next.m_operation_history = m_operation_history;
131 next.m_operation_history.push_back(name);
133 }
catch (
const std::exception& e) {
134 m_successful =
false;
135 record_error(e.what());
146 template <
typename Func>
147 requires std::invocable<Func, const DataType&>
151 throw std::runtime_error(
"Cannot continue chain after failed operation");
154 using ResultType = std::invoke_result_t<Func, const DataType&>;
157 auto result = std::forward<Func>(func)(m_data);
159 next.m_operation_history = m_operation_history;
160 next.m_operation_history.push_back(
"custom_function");
162 }
catch (
const std::exception& e) {
163 m_successful =
false;
164 record_error(std::string(
"Custom function failed: ") + e.what());
174 template <
typename Func>
175 requires std::invocable<Func, DataType&>
179 throw std::runtime_error(
"Cannot continue chain after failed operation");
183 std::forward<Func>(func)(m_data);
184 m_operation_history.emplace_back(
"tap");
186 }
catch (
const std::exception& e) {
187 m_successful =
false;
188 record_error(std::string(
"Tap function failed: ") + e.what());
199 template <
typename OpClass>
202 if (condition && m_successful) {
203 return then<OpClass>();
214 template <
typename OpClass,
typename Pred>
215 requires std::predicate<Pred, const DataType&>
218 if (m_successful && std::forward<Pred>(predicate)(m_data)) {
219 return then<OpClass>();
229 template <
typename... OpClasses>
233 throw std::runtime_error(
"Cannot fork after failed operation");
236 return std::make_tuple(
237 m_executor->template execute<OpClasses, DataType>(m_data)...);
244 const DataType&
get()
const
247 throw std::runtime_error(
"Cannot get result from failed chain");
259 throw std::runtime_error(
"Cannot get result from failed chain");
271 throw std::runtime_error(
"Cannot consume result from failed chain");
273 return std::move(m_data);
283 result.
metadata[
"execution_history"] = m_operation_history;
284 result.
metadata[
"successful"] = m_successful;
285 if (!m_errors.empty()) {
286 result.
metadata[
"errors"] = m_errors;
296 DataType
get_or(
const DataType& default_value)
const
298 return m_successful ? m_data : default_value;
306 template <
typename Generator>
307 requires std::invocable<Generator>
310 return m_successful ? m_data : std::forward<Generator>(generator)();
321 [[nodiscard]]
const std::vector<std::string>&
get_history()
const {
return m_operation_history; }
326 [[nodiscard]]
const std::vector<std::string>&
get_errors()
const {
return m_errors; }
342 m_operation_history.clear();
356 m_errors.push_back(error);
363template <
typename Executor, ComputeData DataType>
364auto make_fluent(std::shared_ptr<Executor> executor, DataType&& data)
368 std::forward<DataType>(data));
auto fork()
Fork execution into multiple paths.
FluentExecutor(std::shared_ptr< Executor > executor, DataType &&input)
Move constructor for efficiency.
FluentExecutor & when(Pred &&predicate)
Conditional execution with predicate.
FluentExecutor & reset(const DataType &new_data)
Reset with new data.
const std::vector< std::string > & get_history() const
Get operation history.
FluentExecutor & tap(Func &&func)
Apply function with side effects (doesn't change data type)
std::shared_ptr< Executor > get_executor() const
Get the executor.
DataType get_or(const DataType &default_value) const
Get or provide default value.
auto apply(Func &&func)
Apply custom transformation function.
DataType consume() &&
Move the result out.
FluentExecutor & when(bool condition)
Conditional execution.
std::shared_ptr< Executor > m_executor
const std::vector< std::string > & get_errors() const
Get accumulated errors.
bool is_successful() const
Check if all operations succeeded.
DataType get_or_else(Generator &&generator) const
Get or compute default value.
FluentExecutor< Executor, OutputType > then(const std::string &name)
Chain named operation.
std::vector< std::string > m_errors
FluentExecutor(std::shared_ptr< Executor > executor, const DataType &input)
Construct with executor and initial data.
DataType & get_mutable()
Get mutable reference to the result.
FluentExecutor< Executor, OutputType > then()
Chain operation execution by type.
const DataType & get() const
Get the final result.
IO< DataType > to_io() const
Extract to IO wrapper with metadata.
std::vector< std::string > m_operation_history
void record_error(const std::string &error)
Fluent interface for chaining operations on any executor.
Defines requirements for executor types that can be used with FluentExecutor.
auto make_fluent(std::shared_ptr< Executor > executor, DataType &&data)
Helper to create FluentExecutor with type deduction.
std::unordered_map< std::string, std::any > metadata
Associated metadata.
Input/Output container for computation pipeline data flow with structure preservation.