A lightweight, header-only C++17 library for enforcing and validating the correct execution order of functions in a pipeline. It ensures that functions are only executed if their dependencies (prerequisite functions) have been called, making it ideal for building robust, dependency-aware workflows.
The name SoutienFlow (from French "SoutienFlow", meaning "support") reflects the library's purpose of supporting and enabling robust, dependency-aware workflows.
- Dependency Validation: Ensures functions are only executed if their dependencies have been called.
- Header-Only: Easy to integrate into any C++ project—just include the header file.
- Flexible Pipelines: Supports arbitrary dependency chains and complex workflows.
- Clear Error Reporting: Provides informative messages when dependencies are not met.
- Lightweight: No external dependencies—pure C++17.
#include "SoutienFlow.h"
int main() {
auto a = []() { std::cout << "a() executed\n"; };
auto b = []() { std::cout << "b() executed\n"; };
auto c = []() { std::cout << "c() executed\n"; };
auto d = []() { std::cout << "d() executed\n"; };
auto task_a = SoutienFlow::createGuardedFunction(a, "a");
task_a(); // Executes a()
auto task_b = SoutienFlow::createGuardedFunction(b, "b");
auto task_c = GUARDED_FUNCTION(c, task_a, task_b); // Requires a() and b()
task_c(); // Fails because b() has not been executed
auto task_d = GUARDED_FUNCTION(d, task_c); // Requires c()
task_d(); // Fails because c() was not executed
}Output:
a() executed
Dependency `b` not met. Blocking `c`
Dependency `c` not met. Blocking `d`
- Download or copy the header file
SoutienFlow.hpp. - Include it in your project:
#include "SoutienFlow.h"
- Use the
SoutienFlownamespace and helper macros to define and enforce your pipelines.
-
GuardedFunction<Func, Requirements...>:- Wraps a function and its dependencies.
- Ensures the function is only executed if all dependencies are satisfied.
-
createGuardedFunction(Func func, const char* name, Dependencies... deps):- Creates a
GuardedFunctionwith the given function, name, and dependencies.
- Creates a
-
GUARDED_FUNCTION(func, ...):- A macro for creating a
GuardedFunctionwith automatic name inference.
- A macro for creating a
-
operator():- Executes the function if all dependencies are satisfied.
- Prints an error message if any dependency is not met.
-
satisfied():- Returns
trueif the function has been executed,falseotherwise.
- Returns
-
name():- Returns the name of the function.
- Enforce Correct Execution Order: Prevent bugs caused by out-of-order execution.
- Declarative Pipelines: Clearly define dependencies between functions.
- Debugging Made Easy: Get clear error messages when dependencies are not met.
- No Overhead: Header-only design ensures minimal impact on your project.
Here’s a concise list of possible improvements for your library:
- Problem: Currently, each
GuardedFunctionstores its dependencies by value, so changes to one instance don’t affect others. - Improvement: Use
std::shared_ptrorstd::reference_wrapperto share dependency states across instances.
- Problem: The library only supports
voidfunctions. - Improvement: Modify
operator()to return astd::optionalor propagate results from dependencies to dependent functions.
- Problem: Dependencies cannot pass data to dependent functions.
- Improvement: Allow dependencies to return values that are passed as arguments to dependent functions.
- Problem: Cyclic dependencies (e.g.,
ArequiresB, andBrequiresA) can cause infinite loops or undefined behavior. - Improvement: Implement cycle detection by tracking the call stack during execution and throwing an error if a cycle is detected.
- Problem: Errors only report direct unmet dependencies, not the root cause (e.g.,
Afails becauseBfails becauseCfails). - Improvement: Recursively check and report the full chain of unmet dependencies.
- Problem: Error messages are hardcoded to
std::cout. - Improvement: Allow users to inject a custom logger or error handler (e.g., a lambda or function pointer).
- Problem: The library is not thread-safe.
- Improvement: Add support for concurrent execution by using mutexes or atomic variables to protect shared state.
- Problem: If a dependency is never satisfied, the function will never execute.
- Improvement: Add a timeout mechanism to cancel execution if dependencies are not met within a specified time.
- Problem: The library only supports linear dependencies.
- Improvement: Extend the library to support dependency graphs, where a function can have multiple independent dependency chains.
- Problem: Dependency errors are only detected at runtime.
- Improvement: Use
constexpror template metaprogramming to detect invalid dependencies at compile time.
Contributions are welcome! If you find a bug or have a feature request, please open an issue or submit a pull request.
This project is licensed under the MIT License. See the LICENSE file for details.