Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 62 additions & 11 deletions docs/flows.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ Actions are added to the flow inside a component's `cib::config`.
struct morning {
constexpr auto config = cib::config(
cib::extend<MorningRoutine>(
WAKE_UP >>
selfcare::SHOWER >>
selfcare::GET_DRESSED >>
food::MAKE_COFFEE >>
food::DRINK_COFFEE));
*WAKE_UP >>
*selfcare::SHOWER >>
*selfcare::GET_DRESSED >>
*food::MAKE_COFFEE >>
*food::DRINK_COFFEE));
};
----

Expand All @@ -58,6 +58,17 @@ a shower. The flow library will order actions in a flow to respect these
dependencies. The actions will be executed in an order that respects all given
dependencies.

The `*` operator is used to explicitly add an action to the
flow. Without the `*` operator an action is just a reference.
A compile-time error will be triggered if an action is referenced without ever
being explicitly added to the flow. If an action is added under a compile-time
or runtime conditional, and the conditional is false, then it is as if the
action was never added at all.

The behavior of the `*` operator ensures that merely referencing an
action to create an ordering dependency doesn't unintentionally add the action
to the flow.

If we only use the `morning` component in our project, the `MorningRoutine` flow
graph would look like the following:

Expand Down Expand Up @@ -93,11 +104,11 @@ struct childcare {
constexpr auto config = cib::config(
cib::extend<MorningRoutine>(
food::MAKE_COFFEE >> // this step exists in the MorningRoutine flow
PACK_SCHOOL_LUNCHES >> // new
*PACK_SCHOOL_LUNCHES >> // new
food::DRINK_COFFEE >> // existing
food::MAKE_BREAKFAST >> // new
food::EAT_BREAKFAST >> // new
SEND_KIDS_TO_SCHOOL)); // new
*food::MAKE_BREAKFAST >> // new
*food::EAT_BREAKFAST >> // new
*SEND_KIDS_TO_SCHOOL)); // new
};
----

Expand Down Expand Up @@ -140,7 +151,7 @@ struct exercise {
constexpr auto config = cib::config(
cib::extend<MorningRoutine>(
morning::WAKE_UP >>
RIDE_STATIONARY_BIKE >>
*RIDE_STATIONARY_BIKE >>
selfcare::SHOWER));
};
----
Expand Down Expand Up @@ -321,7 +332,47 @@ namespace example_component {
constexpr auto config = cib::config(
cib::extend<MyFlow>(
// no order requirement between these actions
SOME_ACTION && SOME_OTHER_ACTION));
*SOME_ACTION && *SOME_OTHER_ACTION));
}
----

==== `operator*`

Explicitly add an action to the flow. Actions used in flow extensions without
the `*` will be treated as references only and will not be added to the
flow at that location. It is a compilation error if an action is not added
with a `*` in exactly one location in the overall config.

Actions can be added and ordered all at once:

[source,cpp]
----
namespace example_component {
constexpr auto config = cib::config(
cib::extend<MyFlow>(
// Add both actions and create an ordering between them.
*SOME_ACTION >> *SOME_OTHER_ACTION));
}
----

Actions can also be added and ordered seperately:

[source,cpp]
----
namespace other_component {
constexpr auto INIT_SOMETHING = ...

constexpr auto config = cib::config(
cib::extend<MyFlow>(*INIT_SOMETHING));
}

namespace example_component {
constexpr auto DO_A_THING = ...

constexpr auto config = cib::config(
cib::extend<MyFlow>(
other_component::INIT_SOMETHING >>
*DO_A_THING));
}
----

Expand Down
32 changes: 12 additions & 20 deletions examples/flow_daily_routine/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,10 @@ struct self_care_component_t {
// Extend flow services
constexpr static auto config = cib::config(

cib::extend<morning_routine_t>(self_care_component_t::WAKE_UP >>
self_care_component_t::EXERCISE >>
self_care_component_t::TAKE_BATH),
cib::extend<morning_routine_t>(*WAKE_UP >> *EXERCISE >> *TAKE_BATH),

cib::extend<evening_routine_t>(self_care_component_t::EXERCISE >>
self_care_component_t::TAKE_BATH >>
self_care_component_t::RELAX >>
self_care_component_t::GO_TO_BED));
cib::extend<evening_routine_t>(*EXERCISE >> *TAKE_BATH >> *RELAX >>
*GO_TO_BED));
};

struct food_component_t {
Expand All @@ -119,10 +115,10 @@ struct food_component_t {
constexpr static auto config = cib::config(

cib::extend<morning_routine_t>(self_care_component_t::TAKE_BATH >>
food_component_t::BREAKFAST),
*BREAKFAST),

cib::extend<evening_routine_t>(self_care_component_t::RELAX >>
food_component_t::DINNER >>
*DINNER >>
self_care_component_t::GO_TO_BED));
};

Expand All @@ -141,16 +137,13 @@ struct dress_up_component_t {
constexpr static auto config = cib::config(

cib::extend<morning_routine_t>(
self_care_component_t::WAKE_UP >>
dress_up_component_t::GET_READY_FOR_EXERCISE >>
self_care_component_t::WAKE_UP >> *GET_READY_FOR_EXERCISE >>
self_care_component_t::EXERCISE >>
self_care_component_t::TAKE_BATH >>
dress_up_component_t::GET_READY_TO_WORK >>
self_care_component_t::TAKE_BATH >> *GET_READY_TO_WORK >>
food_component_t::BREAKFAST),

cib::extend<evening_routine_t>(
dress_up_component_t::GET_READY_FOR_EXERCISE >>
self_care_component_t::EXERCISE));
cib::extend<evening_routine_t>(*GET_READY_FOR_EXERCISE >>
self_care_component_t::EXERCISE));
};

struct commute_component_t {
Expand All @@ -167,11 +160,10 @@ struct commute_component_t {
constexpr static auto config = cib::config(

cib::extend<morning_routine_t>(food_component_t::BREAKFAST >>
commute_component_t::GO_TO_OFFICE),
*GO_TO_OFFICE),

cib::extend<evening_routine_t>(
commute_component_t::RETURN_HOME >>
dress_up_component_t::GET_READY_FOR_EXERCISE));
*RETURN_HOME >> dress_up_component_t::GET_READY_FOR_EXERCISE));
};

struct daily_routine_component_t {
Expand Down Expand Up @@ -206,7 +198,7 @@ struct daily_routine_component_t {

// we need to extend the MainLoop as cib::top implements
// MainLoop service
cib::extend<cib::MainLoop>(DAILY_ROUTINES));
cib::extend<cib::MainLoop>(*DAILY_ROUTINES));
};

struct person_routine_proj {
Expand Down
8 changes: 8 additions & 0 deletions include/cib/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <cib/detail/config_item.hpp>
#include <cib/detail/exports.hpp>
#include <cib/detail/extend.hpp>
#include <cib/detail/runtime_conditional.hpp>

#include <stdx/compiler.hpp>

Expand All @@ -22,6 +23,7 @@ namespace cib {
* @see cib::extend
* @see cib::exports
* @see cib::conditional
* @see cib::runtime_conditional
*/
template <typename... Configs>
[[nodiscard]] CONSTEVAL auto config(Configs const &...configs) {
Expand Down Expand Up @@ -72,4 +74,10 @@ template <typename Predicate, typename... Configs>
Configs const &...configs) {
return detail::conditional<Predicate, Configs...>{configs...};
}

template <stdx::ct_string Name>
constexpr auto runtime_condition = []<typename P>(P) {
static_assert(std::is_default_constructible_v<P>);
return detail::runtime_condition<Name, P>{};
};
} // namespace cib
89 changes: 89 additions & 0 deletions include/cib/detail/runtime_conditional.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#pragma once

#include <cib/detail/config_details.hpp>
#include <cib/detail/config_item.hpp>
#include <cib/detail/extend.hpp>

#include <stdx/compiler.hpp>
#include <stdx/ct_format.hpp>
#include <stdx/tuple.hpp>
#include <stdx/tuple_algorithms.hpp>

namespace cib::detail {
namespace poison {
template <typename... Ts>
constexpr auto make_runtime_conditional(Ts &&...) = delete;
}

template <typename Cond, typename... Configs>
struct runtime_conditional : config_item {
detail::config<Configs...> body;

CONSTEVAL explicit runtime_conditional(Configs const &...configs)
: body{configs...} {}

[[nodiscard]] constexpr auto extends_tuple() const {
return stdx::transform(
[]<typename E>(E e) {
auto args_tuple = stdx::transform(
[]<typename Arg>(Arg) {
using poison::make_runtime_conditional;
return make_runtime_conditional(Cond{}, Arg{});
},
e.args_tuple);

return stdx::apply(
[]<typename... Args>(Args...) {
return extend<typename E::service_type, Args...>{
Args{}...};
},
args_tuple);
},
body.extends_tuple());
}

[[nodiscard]] constexpr auto exports_tuple() const {
return body.exports_tuple();
}
};

template <stdx::ct_string Name, typename... Ps> // FIXME: concept for Ps
struct runtime_condition {
constexpr static auto predicates = stdx::make_tuple(Ps{}...);

constexpr static auto ct_name = Name;

template <typename... Configs>
[[nodiscard]] CONSTEVAL auto operator()(Configs const &...configs) const {
return detail::runtime_conditional<runtime_condition<Name, Ps...>,
Configs...>{configs...};
}

explicit operator bool() const { return (Ps{}() and ...); }
};

template <stdx::ct_string LhsName, typename... LhsPs, stdx::ct_string RhsName,
typename... RhsPs>
[[nodiscard]] constexpr auto
operator and(runtime_condition<LhsName, LhsPs...> const &lhs,
runtime_condition<RhsName, RhsPs...> const &rhs) {
if constexpr ((sizeof...(LhsPs) + sizeof...(RhsPs)) == 0) {
return runtime_condition<"always">{};

} else if constexpr (sizeof...(LhsPs) == 0) {
return rhs;

} else if constexpr (sizeof...(RhsPs) == 0) {
return lhs;

} else {
constexpr auto name =
stdx::ct_format<"{} and {}">(CX_VALUE(LhsName), CX_VALUE(RhsName));

return runtime_condition<name, LhsPs..., RhsPs...>{};
}
}

using always_condition_t = runtime_condition<"always">;
constexpr auto always_condition = always_condition_t{};
} // namespace cib::detail
2 changes: 1 addition & 1 deletion include/flow/builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace flow {
template <stdx::ct_string Name = "">
using builder = graph<Name, graph_builder<impl>>;
using builder = graph<Name, graph_builder<Name, impl>>;

template <stdx::ct_string Name = "">
struct service : cib::builder_meta<builder<Name>, FunctionPtr> {};
Expand Down
44 changes: 39 additions & 5 deletions include/flow/detail/par.hpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
#pragma once

#include <flow/detail/walk.hpp>
#include <flow/subgraph_identity.hpp>

#include <stdx/tuple_algorithms.hpp>

namespace flow::dsl {
template <node Lhs, node Rhs> struct par {
template <subgraph Lhs, subgraph Rhs,
subgraph_identity Identity = subgraph_identity::REFERENCE>
struct par {
Lhs lhs;
Rhs rhs;

using is_node = void;
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) {
Expand All @@ -21,18 +28,45 @@ template <node Lhs, node Rhs> struct par {
}

friend constexpr auto tag_invoke(get_nodes_t, par const &p) {
return stdx::tuple_cat(get_nodes(p.lhs), get_nodes(p.rhs));
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 <node Lhs, node Rhs> par(Lhs, Rhs) -> par<Lhs, Rhs>;
template <subgraph Lhs, subgraph Rhs> par(Lhs, Rhs) -> par<Lhs, Rhs>;
} // namespace flow::dsl

template <flow::dsl::node Lhs, flow::dsl::node Rhs>
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};
}
Loading
Loading