Skip to content
Open
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
101 changes: 35 additions & 66 deletions include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2005-2024 Intel Corporation
Copyright (c) 2005-2025 Intel Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -23,83 +23,59 @@ namespace tbb {
namespace detail {
namespace d2 {

template <typename Input, typename Output>
struct declare_body_types {
using input_type = Input;
using output_type = Output;
template <typename Input>
struct declare_input_type {
using input_type = std::decay_t<Input>;
};

struct NoInputBody {};
template <>
struct declare_input_type<d1::flow_control> {};

template <typename Output>
struct declare_body_types<NoInputBody, Output> {
using output_type = Output;
template <typename Input, typename Output>
struct body_types : declare_input_type<Input> {
using output_type = std::decay_t<Output>;
};

template <typename T> struct body_types;

template <typename T, typename Input, typename Output>
struct body_types<Output (T::*)(const Input&) const> : declare_body_types<Input, Output> {};

template <typename T, typename Input, typename Output>
struct body_types<Output (T::*)(const Input&)> : declare_body_types<Input, Output> {};

template <typename T, typename Input, typename Output>
struct body_types<Output (T::*)(Input&) const> : declare_body_types<Input, Output> {};

template <typename T, typename Input, typename Output>
struct body_types<Output (T::*)(Input&)> : declare_body_types<Input, Output> {};

template <typename T, typename Output>
struct body_types<Output (T::*)(d1::flow_control&) const> : declare_body_types<NoInputBody, Output> {};

template <typename T, typename Output>
struct body_types<Output (T::*)(d1::flow_control&)> : declare_body_types<NoInputBody, Output> {};

template <typename Input, typename Output>
struct body_types<Output (*)(Input&)> : declare_body_types<Input, Output> {};
template <typename P>
struct extract_callable_object_types;

template <typename Input, typename Output>
struct body_types<Output (*)(const Input&)> : declare_body_types<Input, Output> {};
template <typename Body, typename Input, typename Output>
struct extract_callable_object_types<Output (Body::*)(Input)> : body_types<Input, Output> {};

template <typename Output>
struct body_types<Output (*)(d1::flow_control&)> : declare_body_types<NoInputBody, Output> {};
template <typename Body, typename Input, typename Output>
struct extract_callable_object_types<Output (Body::*)(Input) const> : body_types<Input, Output> {};

template <typename Body>
using input_t = typename body_types<Body>::input_type;
template <typename Body, typename = void>
struct extract_body_types;

// Body is represented as a callable object - extract types from the pointer to operator()
template <typename Body>
using output_t = typename body_types<Body>::output_type;

template <typename T, typename Input, typename Output>
auto decide_on_operator_overload(Output (T::*name)(const Input&) const)->decltype(name);

template <typename T, typename Input, typename Output>
auto decide_on_operator_overload(Output (T::*name)(const Input&))->decltype(name);
struct extract_body_types<Body, tbb::detail::void_t<decltype(&Body::operator())>>
: extract_callable_object_types<decltype(&Body::operator())> {};

template <typename T, typename Input, typename Output>
auto decide_on_operator_overload(Output (T::*name)(Input&) const)->decltype(name);

template <typename T, typename Input, typename Output>
auto decide_on_operator_overload(Output (T::*name)(Input&))->decltype(name);
// Body is represented as a pointer to function
template <typename Input, typename Output>
struct extract_body_types<Output (*)(Input)> : body_types<Input, Output> {};

// Body is represented as a pointer to member function
template <typename Input, typename Output>
auto decide_on_operator_overload(Output (*name)(const Input&))->decltype(name);
struct extract_body_types<Output (Input::*)() const> : body_types<Input, Output> {};

// Body is represented as a pointer to member object
template <typename Input, typename Output>
auto decide_on_operator_overload(Output (*name)(Input&))->decltype(name);
struct extract_body_types<Output Input::*> : body_types<Input, Output> {};

template <typename Body>
decltype(decide_on_operator_overload(&Body::operator())) decide_on_callable_type(int);
using input_type = typename extract_body_types<Body>::input_type;

template <typename Body>
decltype(decide_on_operator_overload(std::declval<Body>())) decide_on_callable_type(...);
using output_type = typename extract_body_types<Body>::output_type;

// Deduction guides for Flow Graph nodes

template <typename GraphOrSet, typename Body>
input_node(GraphOrSet&&, Body)
->input_node<output_t<decltype(decide_on_callable_type<Body>(0))>>;
->input_node<output_type<Body>>;

#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET

Expand Down Expand Up @@ -134,7 +110,7 @@ queue_node(const NodeSet&)

template <typename GraphOrProxy, typename Sequencer>
sequencer_node(GraphOrProxy&&, Sequencer)
->sequencer_node<input_t<decltype(decide_on_callable_type<Sequencer>(0))>>;
->sequencer_node<input_type<Sequencer>>;

#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename NodeSet, typename Compare>
Expand Down Expand Up @@ -181,17 +157,14 @@ join_node(const node_set<order::preceding, Successor, Successors...>)

template <typename GraphOrProxy, typename Body, typename... Bodies>
join_node(GraphOrProxy&&, Body, Bodies...)
->join_node<std::tuple<input_t<decltype(decide_on_callable_type<Body>(0))>,
input_t<decltype(decide_on_callable_type<Bodies>(0))>...>,
key_matching<join_key_t<output_t<decltype(decide_on_callable_type<Body>(0))>>>>;
->join_node<std::tuple<input_type<Body>, input_type<Bodies>...>,
key_matching<join_key_t<output_type<Body>>>>;

#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename... Predecessors>
indexer_node(const node_set<order::following, Predecessors...>&)
->indexer_node<typename Predecessors::output_type...>;
#endif

#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename NodeSet>
limiter_node(const NodeSet&, size_t)
->limiter_node<decide_on_set_t<NodeSet>>;
Expand All @@ -210,16 +183,12 @@ template <typename GraphOrSet, typename Body, typename Policy>
function_node(GraphOrSet&&,
size_t, Body,
Policy, node_priority_t = no_priority)
->function_node<input_t<decltype(decide_on_callable_type<Body>(0))>,
output_t<decltype(decide_on_callable_type<Body>(0))>,
Policy>;
->function_node<input_type<Body>, output_type<Body>, Policy>;

template <typename GraphOrSet, typename Body>
function_node(GraphOrSet&&, size_t,
Body, node_priority_t = no_priority)
->function_node<input_t<decltype(decide_on_callable_type<Body>(0))>,
output_t<decltype(decide_on_callable_type<Body>(0))>,
queueing>;
->function_node<input_type<Body>, output_type<Body>, queueing>;

template <typename Output>
struct continue_output {
Expand Down
61 changes: 61 additions & 0 deletions test/conformance/conformance_flowgraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -811,4 +811,65 @@ void test_with_reserving_join_node_class() {
if at least one successor accepts the tuple must consume messages");
}
}

#if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
namespace deduction_guides_testing {

template <typename Input, typename Output>
struct callable_object_body_base {
using input_type = std::decay_t<Input>;
using output_type = std::decay_t<Output>;
};

template <typename Input, typename Output, bool IsConst>
struct callable_object_body : callable_object_body_base<Input, Output> {
Output operator()(Input) { return Output{}; }
};

template <typename Input, typename Output>
struct callable_object_body<Input, Output, /*IsConst = */true> : callable_object_body_base<Input, Output> {
Output operator()(Input) const { return Output{}; }
};

template <typename Input, typename Output>
Output function_body(Input) { return Output{}; }

template <typename Output>
struct Input {
Output member_object_body;
Output member_function_body() const { return Output{}; }
};

template <typename Body>
struct read_types {
using input_type = typename Body::input_type;
using output_type = typename Body::output_type;
};

template <typename Input, typename Output>
struct read_types<Output (Input::*)> {
using input_type = std::decay_t<Input>;
using output_type = std::decay_t<Output>;
};

template <typename Input, typename Output>
struct read_types<Output (Input::*)() const> {
using input_type = std::decay_t<Input>;
using output_type = std::decay_t<Output>;
};

template <typename Input, typename Output>
struct read_types<Output (*)(Input)> {
using input_type = std::decay_t<Input>;
using output_type = std::decay_t<Output>;
};

template <typename Body>
using input_type = typename read_types<Body>::input_type;

template <typename Body>
using output_type = typename read_types<Body>::output_type;

} // namespace deduction_guides_testing
#endif
#endif // __TBB_test_conformance_conformance_flowgraph_H
89 changes: 66 additions & 23 deletions test/conformance/conformance_function_node.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2020-2023 Intel Corporation
Copyright (c) 2020-2025 Intel Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -32,47 +32,90 @@ using output_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/true
*/
#if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT

int function_body_f(const int&) { return 1; }
template <typename... T>
struct print;

template <typename Body>
void test_deduction_guides_common(Body body) {
using input_type = deduction_guides_testing::input_type<Body>;
using output_type = deduction_guides_testing::output_type<Body>;

using namespace tbb::flow;
graph g;

function_node f1(g, unlimited, body);
static_assert(std::is_same_v<decltype(f1), function_node<int, int>>);
static_assert(std::is_same_v<decltype(f1), function_node<input_type, output_type>>);

function_node f2(g, unlimited, body, rejecting());
static_assert(std::is_same_v<decltype(f2), function_node<int, int, rejecting>>);
function_node f2(g, unlimited, body, rejecting{});
static_assert(std::is_same_v<decltype(f2), function_node<input_type, output_type, rejecting>>);

function_node f3(g, unlimited, body, node_priority_t(5));
static_assert(std::is_same_v<decltype(f3), function_node<int, int>>);
function_node f3(g, unlimited, body, node_priority_t{5});
static_assert(std::is_same_v<decltype(f3), function_node<input_type, output_type>>);

function_node f4(g, unlimited, body, rejecting(), node_priority_t(5));
static_assert(std::is_same_v<decltype(f4), function_node<int, int, rejecting>>);
function_node f4(g, unlimited, body, rejecting{}, node_priority_t{5});
static_assert(std::is_same_v<decltype(f4), function_node<input_type, output_type, rejecting>>);

#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
function_node f5(follows(f2), unlimited, body);
static_assert(std::is_same_v<decltype(f5), function_node<int, int>>);
function_node<int, std::decay_t<input_type>> pred_f(g, unlimited, [](int) {
return std::decay_t<input_type>{};
});

function_node<output_type, int> succ_f(g, unlimited, [](const output_type&) {
return 1;
});

function_node f5(follows(pred_f), unlimited, body);
static_assert(std::is_same_v<decltype(f5), function_node<input_type, output_type>>);

function_node f6(follows(pred_f), unlimited, body, rejecting{});
static_assert(std::is_same_v<decltype(f6), function_node<input_type, output_type, rejecting>>);

function_node f7(follows(pred_f), unlimited, body, node_priority_t{5});
static_assert(std::is_same_v<decltype(f7), function_node<input_type, output_type>>);

function_node f8(follows(pred_f), unlimited, body, rejecting{}, node_priority_t{5});
static_assert(std::is_same_v<decltype(f8), function_node<input_type, output_type, rejecting>>);

function_node f9(precedes(succ_f), unlimited, body);
static_assert(std::is_same_v<decltype(f9), function_node<input_type, output_type>>);

function_node f10(precedes(succ_f), unlimited, body, rejecting{});
static_assert(std::is_same_v<decltype(f10), function_node<input_type, output_type, rejecting>>);

function_node f6(follows(f5), unlimited, body, rejecting());
static_assert(std::is_same_v<decltype(f6), function_node<int, int, rejecting>>);
function_node f11(precedes(succ_f), unlimited, body, node_priority_t{5});
static_assert(std::is_same_v<decltype(f11), function_node<input_type, output_type>>);

function_node f7(follows(f6), unlimited, body, node_priority_t(5));
static_assert(std::is_same_v<decltype(f7), function_node<int, int>>);
function_node f12(precedes(succ_f), unlimited, body, rejecting{}, node_priority_t{5});
static_assert(std::is_same_v<decltype(f12), function_node<input_type, output_type, rejecting>>);
#endif

function_node f13(f1);
static_assert(std::is_same_v<decltype(f13), decltype(f1)>);
g.wait_for_all();
}

function_node f8(follows(f7), unlimited, body, rejecting(), node_priority_t(5));
static_assert(std::is_same_v<decltype(f8), function_node<int, int, rejecting>>);
#endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename Input, typename Output>
void test_deduction_guides_body_types() {
using namespace deduction_guides_testing;

function_node f9(f1);
static_assert(std::is_same_v<decltype(f9), function_node<int, int>>);
using mutable_callable_type = callable_object_body<Input, Output, false>;
using const_callable_type = callable_object_body<Input, Output, true>;
test_deduction_guides_common(mutable_callable_type{});
test_deduction_guides_common(const_callable_type{});
test_deduction_guides_common(function_body<Input, Output>);
#if __TBB_CPP17_INVOKE_PRESENT
using pure_input_type = std::decay_t<Input>;
test_deduction_guides_common(&pure_input_type::member_object_body);
test_deduction_guides_common(&pure_input_type::member_function_body);
#endif
}

void test_deduction_guides() {
test_deduction_guides_common([](const int&)->int { return 1; });
test_deduction_guides_common([](const int&) mutable ->int { return 1; });
test_deduction_guides_common(function_body_f);
using output_type = int;
using input_type = deduction_guides_testing::Input<output_type>;

test_deduction_guides_body_types<input_type, output_type>();
test_deduction_guides_body_types<const input_type&, output_type>();
}

#endif
Expand Down
Loading