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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ include(cmake/string_catalog.cmake)
add_versioned_package("gh:boostorg/mp11#boost-1.83.0")
fmt_recipe(10.2.1)
add_versioned_package("gh:intel/cpp-baremetal-concurrency#7c5b26c")
add_versioned_package("gh:intel/cpp-std-extensions#5530b5d")
add_versioned_package("gh:intel/cpp-std-extensions#73569fe")
add_versioned_package("gh:intel/cpp-baremetal-senders-and-receivers#73d95bc")

add_library(cib INTERFACE)
Expand Down
137 changes: 43 additions & 94 deletions include/flow/graph_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
#include <flow/detail/walk.hpp>
#include <flow/impl.hpp>

#include <stdx/ct_format.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>
Expand Down Expand Up @@ -52,31 +52,10 @@ template <typename T> using name_for = typename T::name_t;
});
}

template <typename Cond> struct sequence_conditions;

template <auto...> struct INFO_flow_name_;

template <auto...> struct INFO_step_a_name_;

template <auto...> struct INFO_step_a_condition_;

template <auto...> struct INFO_step_b_name_;

template <auto...> struct INFO_step_b_condition_;

template <auto...> struct INFO_sequence_condition_;

template <typename...> struct INFO_sequence_missing_predicate_;

template <typename...> constexpr bool ERROR_DETAILS_ = false;

template <auto...> struct INFO_missing_steps_;

template <auto...> struct INFO_duplicated_steps_;

template <stdx::ct_string Name,
template <stdx::ct_string, std::size_t> typename Impl>
struct graph_builder {
// NOLINTBEGIN(readability-function-cognitive-complexity)
template <typename Node, std::size_t N, std::size_t E>
[[nodiscard]] constexpr static auto make_graph(auto const &nodes,
auto const &edges) {
Expand All @@ -93,38 +72,26 @@ struct graph_builder {

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 &) {
if constexpr (not stdx::contains_type<edge_ps_t, P>) {
static_assert(
ERROR_DETAILS_<
INFO_flow_name_<Name>,
INFO_step_a_name_<lhs_t::ct_name>,
INFO_step_a_condition_<
lhs_t::condition.ct_name>,
INFO_step_b_name_<rhs_t::ct_name>,
INFO_step_b_condition_<
rhs_t::condition.ct_name>,
INFO_sequence_condition_<Cond::ct_name>,
INFO_sequence_missing_predicate_<P>>,

"The conditions on this sequence "
"(step_a >> step_b) are weaker than those on "
"step_a and/or step_b. The sequence could be "
"enabled while step_a and/or step_b is not. "
"Specifically, the sequence is missing the "
"predicate identified in "
"`INFO_sequence_missing_predicate_`. TIP: "
"Look for 'ERROR_DETAILS_` and `INFO_` in "
"the compiler error message for details on "
"the sequence, the step names, and the "
"conditions.");
}
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);

Expand All @@ -133,6 +100,7 @@ struct graph_builder {
edges);
return g;
}
// NOLINTEND(readability-function-cognitive-complexity)

template <typename Node, typename Graph>
[[nodiscard]] constexpr static auto is_source_of(Node const &node,
Expand Down Expand Up @@ -191,6 +159,15 @@ struct graph_builder {
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) ->
Expand All @@ -201,52 +178,24 @@ struct graph_builder {
using node_names_t = decltype(stdx::to_sorted_set(node_names));
using mentioned_node_names_t =
decltype(stdx::to_sorted_set(mentioned_node_names));

if constexpr (not std::is_same_v<node_names_t,
mentioned_node_names_t>) {
using missing_nodes_t =
boost::mp11::mp_set_difference<mentioned_node_names_t,
node_names_t>;

constexpr auto missing_nodes = missing_nodes_t{};
constexpr auto missing_nodes_ct_strings = stdx::transform(
[]<typename N>(N) { return stdx::ct_string_from_type(N{}); },
missing_nodes);

[&]<std::size_t... Is>(std::index_sequence<Is...>) {
using error_details_t = INFO_missing_steps_<stdx::get<Is>(
missing_nodes_ct_strings)...>;

static_assert(
ERROR_DETAILS_<INFO_flow_name_<Name>, error_details_t>,
"One or more steps are referenced in the flow but not "
"explicitly added with the * operator. The "
"beginning of this error shows you which steps are "
"missing.");
}(std::make_index_sequence<
stdx::tuple_size_v<decltype(missing_nodes)>>{});
}

if constexpr (stdx::tuple_size_v<node_names_t> !=
stdx::tuple_size_v<decltype(node_names)>) {
constexpr auto duplicates = stdx::transform(
[](auto e) {
return stdx::ct_string_from_type(stdx::get<0>(e));
},
stdx::filter<detail::is_duplicated>(stdx::gather(node_names)));

[&]<std::size_t... Is>(std::index_sequence<Is...>) {
using error_details_t =
INFO_duplicated_steps_<stdx::get<Is>(duplicates)...>;

static_assert(
ERROR_DETAILS_<INFO_flow_name_<Name>, error_details_t>,
"One or more steps are explicitly added more than once "
"using the * operator. The beginning of this "
"error shows you which steps are duplicated.");
}(std::make_index_sequence<
stdx::tuple_size_v<decltype(duplicates)>>{});
}
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>
Expand Down
21 changes: 16 additions & 5 deletions test/flow/fail/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
add_compile_fail_test(cyclic_flow.cpp LIBRARIES warnings cib)
add_compile_fail_test(only_reference_added.cpp LIBRARIES warnings cib)
add_compile_fail_test(mismatched_flow_runtime_conditional.cpp LIBRARIES
warnings cib)
add_compile_fail_test(node_explicitly_added_twice.cpp LIBRARIES warnings cib)
add_compile_fail_test(cyclic_flow.cpp LIBRARIES cib)

function(add_formatted_errors_tests)
add_compile_fail_test(only_reference_added.cpp LIBRARIES cib)
add_compile_fail_test(mismatched_flow_runtime_conditional.cpp LIBRARIES cib)
add_compile_fail_test(node_explicitly_added_twice.cpp LIBRARIES cib)
endfunction()

if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" AND ${CMAKE_CXX_COMPILER_VERSION}
VERSION_GREATER_EQUAL 15)
add_formatted_errors_tests()
endif()
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION}
VERSION_GREATER_EQUAL 13.2)
add_formatted_errors_tests()
endif()
2 changes: 1 addition & 1 deletion test/flow/fail/mismatched_flow_runtime_conditional.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <cib/cib.hpp>
#include <flow/flow.hpp>

// EXPECT: The conditions on this sequence
// EXPECT: The conditions on the sequence

namespace {
using namespace flow::literals;
Expand Down
4 changes: 2 additions & 2 deletions test/flow/fail/node_explicitly_added_twice.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#include <cib/cib.hpp>
#include <flow/flow.hpp>

// EXPECT: One or more steps are explicitly added more than once
// EXPECT: are explicitly added more than once

namespace {
using namespace flow::literals;

constexpr auto a = flow::milestone<"a">();

struct TestFlowAlpha : public flow::service<> {};
struct TestFlowAlpha : public flow::service<"alpha"> {};

struct FlowConfig {
constexpr static auto config = cib::config(
Expand Down
4 changes: 2 additions & 2 deletions test/flow/fail/only_reference_added.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#include <cib/cib.hpp>
#include <flow/flow.hpp>

// EXPECT: One or more steps are referenced in the flow but not explicitly
// EXPECT: One or more steps are referenced in the flow

namespace {
using namespace flow::literals;

constexpr auto a = flow::milestone<"a">();

struct TestFlowAlpha : public flow::service<> {};
struct TestFlowAlpha : public flow::service<"alpha"> {};

struct FlowConfig {
constexpr static auto config =
Expand Down