rename chapters

This commit is contained in:
Amar Mahmutbegovic
2025-02-09 13:11:21 +01:00
parent 8634accda5
commit 526e6ec009
2928 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
#pragma once
#include <flow/common.hpp>
#include <flow/graph_builder.hpp>
#include <flow/impl.hpp>
#include <stdx/compiler.hpp>
#include <stdx/ct_string.hpp>
#include <stdx/panic.hpp>
namespace flow {
template <stdx::ct_string Name = "">
using builder = graph<Name, graph_builder<Name, impl>>;
template <stdx::ct_string Name = ""> struct service {
using builder_t = builder<Name>;
using interface_t = FunctionPtr;
CONSTEVAL static auto uninitialized() -> interface_t {
return [] {
using namespace stdx::literals;
stdx::panic<"Attempting to run flow ("_cts + Name +
") before it is initialized"_cts>();
};
}
};
} // namespace flow

View File

@@ -0,0 +1,5 @@
#pragma once
namespace flow {
using FunctionPtr = auto (*)() -> void;
} // namespace flow

View File

@@ -0,0 +1,72 @@
#pragma once
#include <flow/detail/walk.hpp>
#include <flow/subgraph_identity.hpp>
#include <stdx/tuple_algorithms.hpp>
namespace flow::dsl {
template <subgraph Lhs, subgraph Rhs,
subgraph_identity Identity = subgraph_identity::REFERENCE>
struct par {
Lhs lhs;
Rhs rhs;
using is_subgraph = void;
constexpr auto operator*() const {
return par<Lhs, Rhs, subgraph_identity::VALUE>{Lhs{}, Rhs{}};
}
private:
friend constexpr auto tag_invoke(get_initials_t, par const &p) {
return stdx::tuple_cat(get_initials(p.lhs), get_initials(p.rhs));
}
friend constexpr auto tag_invoke(get_finals_t, par const &p) {
return stdx::tuple_cat(get_finals(p.lhs), get_finals(p.rhs));
}
friend constexpr auto tag_invoke(get_nodes_t, par const &p) {
if constexpr (Identity == subgraph_identity::VALUE) {
auto all_nodes = stdx::to_unsorted_set(
stdx::tuple_cat(get_all_mentioned_nodes(p.lhs),
get_all_mentioned_nodes(p.rhs)));
return stdx::transform([](auto const &n) { return *n; }, all_nodes);
} else {
return stdx::tuple_cat(get_nodes(p.lhs), get_nodes(p.rhs));
}
}
friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, par const &p) {
return stdx::tuple_cat(get_all_mentioned_nodes(p.lhs),
get_all_mentioned_nodes(p.rhs));
}
friend constexpr auto tag_invoke(get_edges_t, par const &p) {
return stdx::tuple_cat(get_edges(p.lhs), get_edges(p.rhs));
}
};
template <subgraph Lhs, subgraph Rhs> par(Lhs, Rhs) -> par<Lhs, Rhs>;
} // namespace flow::dsl
template <flow::dsl::subgraph Lhs, flow::dsl::subgraph Rhs>
[[nodiscard]] constexpr auto operator&&(Lhs const &lhs, Rhs const &rhs) {
return flow::dsl::par{lhs, rhs};
}
template <typename Cond, flow::dsl::subgraph Lhs, flow::dsl::subgraph Rhs,
flow::subgraph_identity Identity>
constexpr auto make_runtime_conditional(Cond,
flow::dsl::par<Lhs, Rhs, Identity>) {
auto lhs = make_runtime_conditional(Cond{}, Lhs{});
auto rhs = make_runtime_conditional(Cond{}, Rhs{});
using lhs_t = decltype(lhs);
using rhs_t = decltype(rhs);
return flow::dsl::par<lhs_t, rhs_t, Identity>{lhs, rhs};
}

View File

@@ -0,0 +1,86 @@
#pragma once
#include <cib/detail/runtime_conditional.hpp>
#include <flow/detail/walk.hpp>
#include <flow/subgraph_identity.hpp>
#include <stdx/tuple_algorithms.hpp>
namespace flow::dsl {
template <subgraph Lhs, subgraph Rhs,
subgraph_identity Identity = subgraph_identity::REFERENCE,
typename Cond = cib::detail::always_condition_t>
struct seq {
Lhs lhs;
Rhs rhs;
using is_subgraph = void;
constexpr auto operator*() const {
return seq<Lhs, Rhs, subgraph_identity::VALUE, Cond>{Lhs{}, Rhs{}};
}
private:
friend constexpr auto tag_invoke(get_initials_t, seq const &s) {
return get_initials(s.lhs);
}
friend constexpr auto tag_invoke(get_finals_t, seq const &s) {
return get_finals(s.rhs);
}
friend constexpr auto tag_invoke(get_nodes_t, seq const &s) {
if constexpr (Identity == subgraph_identity::VALUE) {
auto all_nodes = stdx::to_unsorted_set(
stdx::tuple_cat(get_all_mentioned_nodes(s.lhs),
get_all_mentioned_nodes(s.rhs)));
return stdx::transform([](auto const &n) { return *n; }, all_nodes);
} else {
return stdx::tuple_cat(get_nodes(s.lhs), get_nodes(s.rhs));
}
}
friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, seq const &s) {
return stdx::tuple_cat(get_all_mentioned_nodes(s.lhs),
get_all_mentioned_nodes(s.rhs));
}
friend constexpr auto tag_invoke(get_edges_t, seq const &s) {
auto is = get_initials(s.rhs);
auto fs = get_finals(s.lhs);
return stdx::tuple_cat(
get_edges(s.lhs), get_edges(s.rhs),
transform(
[]<typename P>(P const &) {
return edge<stdx::tuple_element_t<0, P>,
stdx::tuple_element_t<1, P>, Cond>{};
},
cartesian_product_copy(fs, is)));
}
};
template <subgraph Lhs, subgraph Rhs> seq(Lhs, Rhs) -> seq<Lhs, Rhs>;
} // namespace flow::dsl
template <flow::dsl::subgraph Lhs, flow::dsl::subgraph Rhs>
[[nodiscard]] constexpr auto operator>>(Lhs const &lhs, Rhs const &rhs) {
return flow::dsl::seq{lhs, rhs};
}
template <typename Cond, flow::dsl::subgraph Lhs, flow::dsl::subgraph Rhs,
flow::subgraph_identity Identity, typename EdgeCond>
constexpr auto
make_runtime_conditional(Cond, flow::dsl::seq<Lhs, Rhs, Identity, EdgeCond>) {
auto lhs = make_runtime_conditional(Cond{}, Lhs{});
auto rhs = make_runtime_conditional(Cond{}, Rhs{});
using lhs_t = decltype(lhs);
using rhs_t = decltype(rhs);
using cond_t = decltype(EdgeCond{} and Cond{});
return flow::dsl::seq<lhs_t, rhs_t, Identity, cond_t>{lhs, rhs};
}

View File

@@ -0,0 +1,103 @@
#pragma once
#include <flow/subgraph_identity.hpp>
#include <stdx/concepts.hpp>
#include <stdx/tuple.hpp>
#include <stdx/type_traits.hpp>
#include <utility>
namespace flow::dsl {
template <typename T>
concept subgraph = requires { typename stdx::remove_cvref_t<T>::is_subgraph; };
template <typename Source, typename Dest, typename Cond> struct edge {
using source_t = Source;
using dest_t = Dest;
using cond_t = Cond;
};
constexpr inline class get_initials_t {
template <subgraph N>
friend constexpr auto tag_invoke(get_initials_t, N &&n) {
return stdx::make_tuple(std::forward<N>(n));
}
public:
template <typename... Ts>
constexpr auto operator()(Ts &&...ts) const
noexcept(noexcept(tag_invoke(std::declval<get_initials_t>(),
std::forward<Ts>(ts)...)))
-> decltype(tag_invoke(*this, std::forward<Ts>(ts)...)) {
return tag_invoke(*this, std::forward<Ts>(ts)...);
}
} get_initials{};
constexpr inline class get_finals_t {
template <subgraph N>
friend constexpr auto tag_invoke(get_finals_t, N &&n) {
return stdx::make_tuple(std::forward<N>(n));
}
public:
template <typename... Ts>
constexpr auto operator()(Ts &&...ts) const
noexcept(noexcept(tag_invoke(std::declval<get_finals_t>(),
std::forward<Ts>(ts)...)))
-> decltype(tag_invoke(*this, std::forward<Ts>(ts)...)) {
return tag_invoke(*this, std::forward<Ts>(ts)...);
}
} get_finals{};
constexpr inline class get_nodes_t {
template <subgraph N> friend constexpr auto tag_invoke(get_nodes_t, N &&n) {
if constexpr (std::remove_cvref_t<N>::identity ==
subgraph_identity::REFERENCE) {
return stdx::tuple{};
} else {
return stdx::make_tuple(std::forward<N>(n));
}
}
public:
template <typename... Ts>
constexpr auto operator()(Ts &&...ts) const
noexcept(noexcept(tag_invoke(std::declval<get_nodes_t>(),
std::forward<Ts>(ts)...)))
-> decltype(tag_invoke(*this, std::forward<Ts>(ts)...)) {
return tag_invoke(*this, std::forward<Ts>(ts)...);
}
} get_nodes{};
constexpr inline class get_all_mentioned_nodes_t {
template <subgraph N>
friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, N &&n) {
return stdx::make_tuple(std::forward<N>(n));
}
public:
template <typename... Ts>
constexpr auto operator()(Ts &&...ts) const
noexcept(noexcept(tag_invoke(std::declval<get_all_mentioned_nodes_t>(),
std::forward<Ts>(ts)...)))
-> decltype(tag_invoke(*this, std::forward<Ts>(ts)...)) {
return tag_invoke(*this, std::forward<Ts>(ts)...);
}
} get_all_mentioned_nodes{};
constexpr inline class get_edges_t {
friend constexpr auto tag_invoke(get_edges_t, subgraph auto const &) {
return stdx::tuple{};
}
public:
template <typename... Ts>
constexpr auto operator()(Ts &&...ts) const
noexcept(noexcept(tag_invoke(std::declval<get_edges_t>(),
std::forward<Ts>(ts)...)))
-> decltype(tag_invoke(*this, std::forward<Ts>(ts)...)) {
return tag_invoke(*this, std::forward<Ts>(ts)...);
}
} get_edges{};
} // namespace flow::dsl

View File

@@ -0,0 +1,9 @@
#pragma once
#include <flow/builder.hpp>
#include <flow/common.hpp>
#include <flow/detail/par.hpp>
#include <flow/detail/seq.hpp>
#include <flow/impl.hpp>
#include <flow/run.hpp>
#include <flow/step.hpp>

View File

@@ -0,0 +1,296 @@
#pragma once
#include <flow/common.hpp>
#include <flow/detail/walk.hpp>
#include <flow/impl.hpp>
#include <stdx/ct_string.hpp>
#include <stdx/cx_multimap.hpp>
#include <stdx/cx_set.hpp>
#include <stdx/cx_vector.hpp>
#include <stdx/span.hpp>
#include <stdx/static_assert.hpp>
#include <stdx/tuple_algorithms.hpp>
#include <stdx/type_traits.hpp>
#include <stdx/utility.hpp>
#include <boost/mp11/set.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
#include <iterator>
#include <optional>
#include <utility>
namespace flow {
namespace detail {
template <typename T> using is_duplicated = std::bool_constant<(T::size() > 1)>;
template <typename CTNode, typename Output>
concept is_output_compatible = requires(CTNode n) {
{ Output::create_node(n) } -> std::same_as<typename Output::node_t>;
};
} // namespace detail
template <typename T> using name_for = typename T::name_t;
[[nodiscard]] constexpr auto edge_size(auto const &nodes,
auto const &edges) -> std::size_t {
auto const edge_capacities = transform(
[&]<typename N>(N const &) {
return edges.fold_left(
std::size_t{}, []<typename E>(auto acc, E const &) {
if constexpr (std::is_same_v<name_for<typename E::source_t>,
name_for<N>> or
std::is_same_v<name_for<typename E::dest_t>,
name_for<N>>) {
return ++acc;
} else {
return acc;
}
});
},
nodes);
return edge_capacities.fold_left(std::size_t{1}, [](auto acc, auto next) {
return std::max(acc, next);
});
}
template <stdx::ct_string Name,
template <stdx::ct_string, std::size_t> typename Impl>
struct graph_builder {
// NOLINTBEGIN(readability-function-cognitive-complexity)
template <typename Output, std::size_t N, std::size_t E>
[[nodiscard]] constexpr static auto make_graph(auto const &nodes,
auto const &edges) {
using output_node_t = typename Output::node_t;
using graph_t = stdx::cx_multimap<output_node_t, output_node_t, N, E>;
graph_t g{};
for_each([&]<typename Node>(Node n) { g.put(Output::create_node(n)); },
nodes);
auto const named_nodes = stdx::apply_indices<name_for>(nodes);
for_each(
[&]<typename Lhs, typename Rhs, typename Cond>(
dsl::edge<Lhs, Rhs, Cond> const &) {
auto lhs = get<name_for<Lhs>>(named_nodes);
auto rhs = get<name_for<Rhs>>(named_nodes);
using lhs_t = std::remove_cvref_t<decltype(lhs)>;
using rhs_t = std::remove_cvref_t<decltype(rhs)>;
using lhs_cond_t = std::remove_cvref_t<decltype(lhs.condition)>;
using rhs_cond_t = std::remove_cvref_t<decltype(rhs.condition)>;
using edge_ps_t = decltype(Cond::predicates);
auto node_ps = stdx::to_unsorted_set(stdx::tuple_cat(
lhs_t::condition.predicates, rhs_t::condition.predicates));
stdx::for_each(
[&]<typename P>(P const &) {
STATIC_ASSERT(
(stdx::contains_type<edge_ps_t, P>),
"The conditions on the sequence ({} >> {})[{}] are "
"weaker than those on {}[{}] or {}[{}]. "
"Specifically, the sequence is missing the "
"predicate: {}",
CX_VALUE(lhs_t::ct_name), CX_VALUE(rhs_t::ct_name),
CX_VALUE(Cond::ct_name), CX_VALUE(lhs_t::ct_name),
CX_VALUE(lhs_cond_t::ct_name),
CX_VALUE(rhs_t::ct_name),
CX_VALUE(rhs_cond_t::ct_name), CX_VALUE(P));
},
node_ps);
g.put(Output::create_node(lhs), Output::create_node(rhs));
},
edges);
return g;
}
// NOLINTEND(readability-function-cognitive-complexity)
template <typename Node, typename Graph>
[[nodiscard]] constexpr static auto is_source_of(Node const &node,
Graph const &g) -> bool {
return std::find_if(g.begin(), g.end(), [&](auto const &entry) {
return entry.value.contains(node);
}) == g.end();
}
template <typename Graph>
[[nodiscard]] constexpr static auto get_sources(Graph const &g)
-> stdx::cx_set<typename Graph::key_type, Graph::capacity()> {
stdx::cx_set<typename Graph::key_type, Graph::capacity()> s;
for (auto const &entry : g) {
s.insert(entry.key);
}
for (auto const &entry : g) {
for (auto const &dst : entry.value) {
s.erase(dst);
}
}
return s;
}
template <typename Output, typename Graph>
[[nodiscard]] constexpr static auto
topo_sort(Graph &g) -> std::optional<Output> {
stdx::cx_vector<typename Graph::key_type, Graph::capacity()>
ordered_list{};
auto sources = get_sources(g);
while (not sources.empty()) {
auto n = sources.pop_back();
ordered_list.push_back(n);
if (g.contains(n)) {
auto ms = g.get(n);
if (ms.empty()) {
g.erase(n);
} else {
for (auto const &entry : ms) {
g.erase(n, entry);
if (is_source_of(entry, g)) {
sources.insert(entry);
}
}
}
}
}
if (not g.empty()) {
return {};
}
using span_t =
stdx::span<typename Graph::key_type const, Graph::capacity()>;
return std::optional<Output>{std::in_place, span_t{ordered_list}};
}
template <typename T>
constexpr static auto error_steps =
stdx::transform([](auto N) { return stdx::ct_string_from_type(N); },
T{})
.join(stdx::ct_string{""}, [](auto x, auto y) {
using namespace stdx::literals;
return x + ", "_cts + y;
});
constexpr static void check_for_missing_nodes(auto nodes,
auto mentioned_nodes) {
constexpr auto get_name = []<typename N>(N) ->
typename N::name_t { return {}; };
auto node_names = stdx::transform(get_name, nodes);
auto mentioned_node_names = stdx::transform(get_name, mentioned_nodes);
using node_names_t = decltype(stdx::to_sorted_set(node_names));
using mentioned_node_names_t =
decltype(stdx::to_sorted_set(mentioned_node_names));
using missing_nodes_t =
boost::mp11::mp_set_difference<mentioned_node_names_t,
node_names_t>;
STATIC_ASSERT(
(std::is_same_v<node_names_t, mentioned_node_names_t>),
"One or more steps are referenced in the flow ({}) but not "
"explicitly added with the * operator. The missing steps are: {}.",
CX_VALUE(Name), CX_VALUE(error_steps<missing_nodes_t>));
constexpr auto duplicates = stdx::transform(
[](auto e) { return stdx::get<0>(e); },
stdx::filter<detail::is_duplicated>(stdx::gather(node_names)));
using duplicate_nodes_t = decltype(duplicates);
STATIC_ASSERT(
stdx::tuple_size_v<duplicate_nodes_t> == 0,
"One or more steps in the flow ({}) are explicitly added more than "
"once using the * operator. The duplicate steps are: {}.",
CX_VALUE(Name), CX_VALUE(error_steps<duplicate_nodes_t>));
}
template <typename Graph>
[[nodiscard]] constexpr static auto build(Graph const &input) {
auto nodes = flow::dsl::get_nodes(input);
auto mentioned_nodes = flow::dsl::get_all_mentioned_nodes(input);
check_for_missing_nodes(nodes, mentioned_nodes);
auto node_set = stdx::to_unsorted_set(nodes);
auto edges = stdx::to_unsorted_set(flow::dsl::get_edges(input));
constexpr auto node_capacity = stdx::tuple_size_v<decltype(node_set)>;
constexpr auto edge_capacity = edge_size(node_set, edges);
using output_t = Impl<Graph::name, node_capacity>;
static_assert(
all_of(
[]<typename N>(N const &) {
return detail::is_output_compatible<N, output_t>;
},
node_set),
"Output node type is not compatible with given input nodes");
auto g =
make_graph<output_t, node_capacity, edge_capacity>(node_set, edges);
return topo_sort<output_t>(g);
}
template <typename Initialized> class built_flow {
constexpr static auto built() {
constexpr auto v = Initialized::value;
constexpr auto built = build(v);
static_assert(built.has_value(),
"Topological sort failed: cycle in flow");
constexpr auto functionPtrs = built->functionPtrs;
constexpr auto size = std::size(functionPtrs);
constexpr auto name = built->name;
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return detail::inlined_func_list<name, functionPtrs[Is]...>{};
}(std::make_index_sequence<size>{});
}
constexpr static auto run() { built()(); }
public:
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr explicit(false) operator FunctionPtr() const { return run; }
constexpr auto operator()() const -> void { run(); }
constexpr static bool active = decltype(built())::active;
};
template <typename Initialized>
[[nodiscard]] constexpr static auto render() -> built_flow<Initialized> {
return {};
}
};
template <stdx::ct_string Name = "",
typename Renderer = graph_builder<Name, impl>,
flow::dsl::subgraph... Fragments>
class graph {
template <typename Tag>
friend constexpr auto tag_invoke(Tag, graph const &g) {
return g.fragments.apply([](auto const &...frags) {
return stdx::tuple_cat(Tag{}(frags)...);
});
}
public:
template <flow::dsl::subgraph... Ns>
[[nodiscard]] constexpr auto add(Ns &&...ns) {
return fragments.apply([&](auto &...frags) {
return graph<Name, Renderer, Fragments...,
stdx::remove_cvref_t<Ns>...>{
{frags..., std::forward<Ns>(ns)...}};
});
}
template <typename BuilderValue>
[[nodiscard]] constexpr static auto build() {
return Renderer::template render<BuilderValue>();
}
constexpr static auto name = Name;
stdx::tuple<Fragments...> fragments;
};
} // namespace flow

View File

@@ -0,0 +1,77 @@
#include <flow/detail/walk.hpp>
#include <stdx/tuple_algorithms.hpp>
#include <set>
#include <string>
#include <string_view>
namespace flow {
using VizFunctionPtr = auto (*)() -> std::string;
struct graphviz_builder {
template <typename Graph>
[[nodiscard]] static auto build(Graph const &input) {
auto const nodes = flow::dsl::get_nodes(input);
auto const edges = flow::dsl::get_edges(input);
using nodes_t = std::set<std::string_view>;
nodes_t sources{};
nodes_t sinks{};
for_each(
[&]<typename Node>(Node const &) {
sources.insert(Node::name_t::value);
sinks.insert(Node::name_t::value);
},
nodes);
for_each(
[&]<typename Edge>(Edge const &) {
sinks.erase(Edge::source_t::name_t::value);
sources.erase(Edge::dest_t::name_t::value);
},
edges);
std::string output{"digraph "};
output += std::string_view{Graph::name};
output += " {\n";
for (auto const &node : sources) {
output += "start -> " + std::string{node} + '\n';
}
for_each(
[&]<typename Edge>(Edge const &) {
output += std::string{Edge::source_t::name_t::value};
output += " -> ";
output += std::string{Edge::dest_t::name_t::value};
output += '\n';
},
edges);
for (auto const &node : sinks) {
output += std::string{node} + " -> end\n";
}
output += "}";
return output;
}
template <typename Initialized> class built_flow {
static auto built() {
auto const v = Initialized::value;
return build(v);
}
static auto run() -> std::string { return built(); }
public:
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr explicit(false) operator VizFunctionPtr() const {
return run;
}
auto operator()() const -> std::string { return run(); }
constexpr static bool active = true;
};
template <typename Initialized>
[[nodiscard]] constexpr static auto render() -> built_flow<Initialized> {
return {};
}
};
} // namespace flow

View File

@@ -0,0 +1,79 @@
#pragma once
#include <flow/common.hpp>
#include <flow/log.hpp>
#include <log/env.hpp>
#include <log/level.hpp>
#include <log/log.hpp>
#include <stdx/ct_string.hpp>
#include <stdx/span.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
#include <iterator>
namespace flow {
namespace detail {
template <stdx::ct_string FlowName, typename CTNode>
constexpr auto run_func() -> void {
if (CTNode::condition) {
if constexpr (not FlowName.empty()) {
using log_spec_t =
decltype(get_log_spec<CTNode, log_spec_id_t<FlowName>>());
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
CIB_LOG(typename log_spec_t::flavor, "flow.{}({})",
typename CTNode::type_t{}, typename CTNode::name_t{});
}
typename CTNode::func_t{}();
}
}
} // namespace detail
template <stdx::ct_string Name, std::size_t NumSteps> struct impl {
using node_t = FunctionPtr;
std::array<FunctionPtr, NumSteps> functionPtrs{};
constexpr static auto name = Name;
template <typename CTNode>
constexpr static auto create_node(CTNode) -> node_t {
constexpr auto fp = detail::run_func<Name, CTNode>;
return fp;
}
constexpr explicit(true) impl(stdx::span<node_t const, NumSteps> steps) {
std::copy(std::cbegin(steps), std::cend(steps),
std::begin(functionPtrs));
}
};
namespace detail {
template <stdx::ct_string Name, auto... FuncPtrs> struct inlined_func_list {
constexpr static auto active = sizeof...(FuncPtrs) > 0;
constexpr static auto ct_name = Name;
__attribute__((flatten, always_inline)) auto operator()() const -> void {
constexpr static bool loggingEnabled = not Name.empty();
constexpr auto name =
stdx::ct_string_to_type<Name, sc::string_constant>();
if constexpr (loggingEnabled) {
using log_spec_t = decltype(get_log_spec<inlined_func_list>());
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
CIB_LOG(typename log_spec_t::flavor, "flow.start({})", name);
}
(FuncPtrs(), ...);
if constexpr (loggingEnabled) {
using log_spec_t = decltype(get_log_spec<inlined_func_list>());
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
CIB_LOG(typename log_spec_t::flavor, "flow.end({})", name);
}
}
};
} // namespace detail
} // namespace flow

View File

@@ -0,0 +1,36 @@
#pragma once
#include <log/log.hpp>
#include <stdx/ct_string.hpp>
#include <type_traits>
namespace flow {
struct default_log_spec {
using flavor = logging::default_flavor_t;
constexpr static auto level = logging::level::TRACE;
};
template <stdx::ct_string, typename...>
constexpr auto log_spec = default_log_spec{};
template <stdx::ct_string Name> struct log_spec_id_t {
constexpr static auto ct_name = Name;
};
template <typename T, typename Fallback = log_spec_id_t<"default">,
typename... DummyArgs>
requires(sizeof...(DummyArgs) == 0)
constexpr static auto get_log_spec() {
using log_spec_t = decltype(log_spec<T::ct_name, DummyArgs...>);
if constexpr (std::is_same_v<log_spec_t, default_log_spec const>) {
if constexpr (Fallback::ct_name == stdx::ct_string{"default"}) {
return log_spec<Fallback::ct_name, DummyArgs...>;
} else {
return get_log_spec<Fallback>();
}
} else {
return log_spec_t{};
}
}
} // namespace flow

View File

@@ -0,0 +1,14 @@
#pragma once
#include <cib/built.hpp>
#include <flow/common.hpp>
namespace flow {
/**
* Run the flow given by 'Tag'.
*
* @tparam Tag Type of the flow to be ran. This is the name of the flow::builder
* used to declare and build the flow.
*/
template <typename Tag> FunctionPtr &run = cib::service<Tag>;
} // namespace flow

View File

@@ -0,0 +1,95 @@
#pragma once
#include <cib/detail/runtime_conditional.hpp>
#include <cib/func_decl.hpp>
#include <flow/common.hpp>
#include <flow/log.hpp>
#include <flow/subgraph_identity.hpp>
#include <sc/string_constant.hpp>
#include <stdx/compiler.hpp>
#include <stdx/ct_string.hpp>
#include <stdx/type_traits.hpp>
#include <type_traits>
namespace flow {
template <stdx::ct_string Type, stdx::ct_string Name,
subgraph_identity Identity, typename Cond, typename F>
struct ct_node {
using is_subgraph = void;
using type_t =
decltype(stdx::ct_string_to_type<Type, sc::string_constant>());
using name_t =
decltype(stdx::ct_string_to_type<Name, sc::string_constant>());
using func_t = F;
constexpr static auto ct_name = Name;
constexpr static auto identity = Identity;
constexpr static auto condition = Cond{};
constexpr auto operator*() const {
if constexpr (Identity == subgraph_identity::REFERENCE) {
return ct_node<Type, Name, subgraph_identity::VALUE, Cond, F>{};
} else {
return ct_node{};
}
}
};
namespace detail {
template <stdx::ct_string Type, stdx::ct_string Name, typename F>
[[nodiscard]] constexpr auto make_node() {
return ct_node<Type, Name, subgraph_identity::REFERENCE,
cib::detail::always_condition_t, F>{};
}
constexpr auto empty_func = []() {};
} // namespace detail
template <stdx::ct_string Name, typename F>
requires(stdx::is_function_object_v<F> and std::is_empty_v<F>)
[[nodiscard]] constexpr auto action(F const &) {
return detail::make_node<"action", Name, F>();
}
template <stdx::ct_string Name> [[nodiscard]] constexpr auto action() {
return action<Name>(cib::func_decl<Name>);
}
template <stdx::ct_string Name> [[nodiscard]] constexpr auto step() {
return action<Name>(cib::func_decl<Name>);
}
template <stdx::ct_string Name> [[nodiscard]] constexpr auto milestone() {
return detail::make_node<"milestone", Name, decltype(detail::empty_func)>();
}
inline namespace literals {
template <stdx::ct_string S> [[nodiscard]] constexpr auto operator""_action() {
return action<S>();
}
template <stdx::ct_string S> [[nodiscard]] constexpr auto operator""_step() {
return action<S>();
}
template <stdx::ct_string S>
[[nodiscard]] constexpr auto operator""_milestone() {
return milestone<S>();
}
} // namespace literals
template <typename Cond, stdx::ct_string Type, stdx::ct_string Name,
subgraph_identity Identity, typename NodeCond, typename F>
constexpr auto
make_runtime_conditional(Cond, ct_node<Type, Name, Identity, NodeCond, F>) {
if constexpr (Identity == subgraph_identity::VALUE) {
return ct_node<Type, Name, Identity, decltype(NodeCond{} and Cond{}),
F>{};
} else {
return ct_node<Type, Name, Identity, NodeCond, F>{};
}
}
} // namespace flow

View File

@@ -0,0 +1,5 @@
#pragma once
namespace flow {
enum class subgraph_identity { VALUE, REFERENCE };
}