Skip to content

Commit bb44f6b

Browse files
committed
Part 1(!!!) of change to allow specifying creator
This handles the API change, and ports the existing creator name check to work with the new product_query.
1 parent d45638f commit bb44f6b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+529
-289
lines changed

CMakePresets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"hidden": false,
66
"cacheVariables": {
77
"CMAKE_EXPORT_COMPILE_COMMANDS": "YES",
8-
"CMAKE_CXX_STANDARD": "20",
8+
"CMAKE_CXX_STANDARD": "23",
99
"CMAKE_CXX_STANDARD_REQUIRED": "YES",
1010
"CMAKE_CXX_EXTENSIONS": "NO",
1111
"CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "CetProvideDependency"

phlex/configuration.cpp

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,53 @@
11
#include "phlex/configuration.hpp"
22
#include "phlex/core/product_query.hpp"
33

4-
#include <ranges>
4+
#include <algorithm>
55
#include <string>
6+
#include <string_view>
7+
8+
namespace {
9+
std::optional<std::string> value_if_exists(boost::json::object const& obj,
10+
std::string_view parameter)
11+
{
12+
if (!obj.contains(parameter)) {
13+
return std::nullopt;
14+
}
15+
auto const& val = obj.at(parameter);
16+
if (!val.is_string()) {
17+
std::string kind;
18+
switch (val.kind()) {
19+
case boost::json::kind::null:
20+
// seems reasonable to interpret this as if the value were not provided
21+
return std::nullopt;
22+
break;
23+
case boost::json::kind::bool_:
24+
kind = "bool"s;
25+
break;
26+
case boost::json::kind::int64:
27+
kind = "std::int64_t"s;
28+
break;
29+
case boost::json::kind::uint64:
30+
kind = "std::uint64_t"s;
31+
break;
32+
case boost::json::kind::double_:
33+
kind = "double"s;
34+
break;
35+
case boost::json::kind::array:
36+
kind = "array"s;
37+
break;
38+
case boost::json::kind::object:
39+
kind = "object"s;
40+
break;
41+
default:
42+
kind = "HOW??"s;
43+
break;
44+
}
45+
throw std::runtime_error(fmt::format(
46+
"Error retrieving parameter '{}'. Should be a string but is instead a {}", parameter, kind));
47+
}
48+
return std::string(val.get_string());
49+
}
50+
}
651

752
namespace phlex {
853
std::vector<std::string> configuration::keys() const
@@ -25,7 +70,13 @@ namespace phlex {
2570
{
2671
using detail::value_decorate_exception;
2772
auto query_object = jv.as_object();
28-
return product_query{{value_decorate_exception<std::string>(query_object, "product")},
29-
value_decorate_exception<std::string>(query_object, "layer")};
73+
auto creator = value_decorate_exception<std::string>(query_object, "creator");
74+
auto layer = value_decorate_exception<std::string>(query_object, "layer");
75+
auto suffix = value_if_exists(query_object, "suffix");
76+
auto stage = value_if_exists(query_object, "stage");
77+
return product_tag{.creator = std::move(creator),
78+
.layer = std::move(layer),
79+
.suffix = std::move(suffix),
80+
.stage = std::move(stage)};
3081
}
3182
}

phlex/core/detail/filter_impl.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,8 @@
55
#include <string>
66

77
namespace {
8-
phlex::product_query const output_dummy{
9-
phlex::experimental::product_specification{
10-
phlex::experimental::algorithm_name{"for_output_only", ""},
11-
"for_output_only",
12-
phlex::experimental::type_id{}},
13-
"dummy_layer"};
8+
phlex::product_query const output_dummy = phlex::product_tag{
9+
.creator = "for_output_only"s, .layer = "dummy_layer"s, .suffix = "for_output_only"s};
1410
phlex::product_queries const for_output_only{output_dummy};
1511
}
1612

phlex/core/edge_creation_policy.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,55 +9,55 @@ namespace phlex::experimental {
99
edge_creation_policy::named_output_port const* edge_creation_policy::find_producer(
1010
product_query const& query) const
1111
{
12-
auto const& spec = query.spec();
13-
auto [b, e] = producers_.equal_range(spec.name());
12+
// TODO: Update later with correct querying
13+
auto [b, e] = producers_.equal_range(query.suffix().value_or(""));
1414
if (b == e) {
1515
spdlog::debug(
1616
"Failed to find an algorithm that creates {} products. Assuming it comes from a provider",
17-
spec.name());
17+
query.suffix().value_or("\"\""));
1818
return nullptr;
1919
}
2020
std::map<std::string, named_output_port const*> candidates;
2121
for (auto const& [key, producer] : std::ranges::subrange{b, e}) {
22-
if (producer.node.match(spec.qualifier())) {
23-
if (spec.type() != producer.type) {
24-
spdlog::debug("Matched {} ({}) from {} but types don't match (`{}` vs `{}`). Excluding "
22+
// TODO: Definitely not right yet
23+
if (producer.node.plugin() == query.creator() ||
24+
producer.node.algorithm() == query.creator()) {
25+
if (query.type() != producer.type) {
26+
spdlog::debug("Matched ({}) from {} but types don't match (`{}` vs `{}`). Excluding "
2527
"from candidate list.",
26-
spec.full(),
2728
query.to_string(),
2829
producer.node.full(),
29-
spec.type(),
30+
query.type(),
3031
producer.type);
3132
} else {
32-
if (spec.type().exact_compare(producer.type)) {
33-
spdlog::debug("Matched {} ({}) from {} and types match. Keeping in candidate list.",
34-
spec.full(),
33+
if (query.type().exact_compare(producer.type)) {
34+
spdlog::debug("Matched ({}) from {} and types match. Keeping in candidate list.",
3535
query.to_string(),
3636
producer.node.full());
3737
} else {
38-
spdlog::warn("Matched {} ({}) from {} and types match, but not exactly (produce {} and "
38+
spdlog::warn("Matched ({}) from {} and types match, but not exactly (produce {} and "
3939
"consume {}). Keeping in candidate list!",
40-
spec.full(),
4140
query.to_string(),
4241
producer.node.full(),
43-
spec.type().exact_name(),
42+
query.type().exact_name(),
4443
producer.type.exact_name());
4544
}
4645
candidates.emplace(producer.node.full(), &producer);
4746
}
4847
}
48+
else {
49+
spdlog::error("Creator name mismatch between ({}) and {}", query.to_string(), producer.node.full());
50+
}
4951
}
5052

5153
if (candidates.empty()) {
52-
throw std::runtime_error("Cannot identify product matching the specified label " +
53-
spec.full());
54+
throw std::runtime_error("Cannot identify product matching the query " + query.to_string());
5455
}
5556

5657
if (candidates.size() > 1ull) {
57-
std::string msg =
58-
fmt::format("More than one candidate matches the specification {}: \n - {}\n",
59-
spec.full(),
60-
fmt::join(std::views::keys(candidates), "\n - "));
58+
std::string msg = fmt::format("More than one candidate matches the query {}: \n - {}\n",
59+
query.to_string(),
60+
fmt::join(std::views::keys(candidates), "\n - "));
6161
throw std::runtime_error(msg);
6262
}
6363

phlex/core/input_arguments.cpp

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,22 @@
22

33
#include "fmt/format.h"
44

5-
#include <algorithm>
6-
#include <set>
75
#include <stdexcept>
8-
#include <vector>
96

107
namespace phlex::experimental::detail {
118
void verify_no_duplicate_input_products(std::string const& algorithm_name,
12-
product_queries to_sort)
9+
product_queries input_queries)
1310
{
14-
std::sort(begin(to_sort), end(to_sort));
15-
std::set unique_and_sorted(begin(to_sort), end(to_sort));
16-
product_queries duplicates;
17-
std::set_difference(begin(to_sort),
18-
end(to_sort),
19-
begin(unique_and_sorted),
20-
end(unique_and_sorted),
21-
std::back_inserter(duplicates));
22-
if (empty(duplicates)) {
23-
return;
11+
for (std::size_t i = 0; i < input_queries.size(); ++i) {
12+
for (std::size_t j = i + 1; j < input_queries.size(); ++j) {
13+
if (input_queries[i].match(input_queries[j]) || input_queries[j].match(input_queries[i])) {
14+
throw std::runtime_error(
15+
fmt::format("The algorithm {} has at least one duplicate input:\n- {}\n- {}\n",
16+
algorithm_name,
17+
input_queries[i].to_string(),
18+
input_queries[j].to_string()));
19+
}
20+
}
2421
}
25-
26-
std::string error =
27-
fmt::format("Algorithm '{}' uses the following products more than once:\n", algorithm_name);
28-
for (auto const& label : duplicates) {
29-
error += fmt::format(" - '{}'\n", label.to_string());
30-
}
31-
throw std::runtime_error(error);
3222
}
3323
}

phlex/core/product_query.cpp

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,60 @@
33
#include "fmt/format.h"
44

55
namespace phlex {
6-
void product_query::set_type(experimental::type_id&& type) {
7-
type_id_ = std::move(type);
8-
}
9-
6+
void product_query::set_type(experimental::type_id&& type) { type_id_ = std::move(type); }
7+
8+
// Check that all products selected by /other/ would satisfy this query
9+
bool product_query::match(product_query const& other) const
10+
{
11+
if (creator_ != other.creator_) {
12+
return false;
13+
}
14+
if (layer_ != other.layer_) {
15+
return false;
16+
}
17+
if (suffix_ && suffix_ != other.suffix_) {
18+
return false;
19+
}
20+
if (stage_ && stage_ != other.stage_) {
21+
return false;
22+
}
23+
// Special case. If other has an unset type_id, ignore this in case it just hasn't been set yet
24+
if (type_id_.valid() && other.type_id_.valid() && type_id_ != other.type_id_) {
25+
return false;
26+
}
27+
return true;
28+
}
29+
30+
// Check if a product_specification satisfies this query
31+
bool product_query::match(experimental::product_specification const& spec) const
32+
{
33+
if (creator_ != spec.algorithm()) {
34+
return false;
35+
}
36+
if (type_id_ != spec.type()) {
37+
return false;
38+
}
39+
if (suffix_) {
40+
if (*suffix_ != spec.name()) {
41+
return false;
42+
}
43+
}
44+
return true;
45+
}
46+
1047
std::string product_query::to_string() const
1148
{
1249
if (suffix_) {
1350
return fmt::format("{}/{} ϵ {}", creator_, *suffix_, layer_);
1451
}
1552
return fmt::format("{} ϵ {}", creator_, layer_);
1653
}
54+
55+
experimental::product_specification product_query::spec() const
56+
{
57+
if (!suffix()) {
58+
throw std::logic_error("Product suffixes are (temporarily) mandatory");
59+
}
60+
return experimental::product_specification::create(*suffix());
61+
}
1762
}

phlex/core/product_query.hpp

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#ifndef PHLEX_CORE_PRODUCT_QUERY_HPP
22
#define PHLEX_CORE_PRODUCT_QUERY_HPP
33

4+
#include "phlex/model/product_specification.hpp"
45
#include "phlex/model/type_id.hpp"
56

6-
#include <iosfwd>
77
#include <optional>
88
#include <string>
99
#include <vector>
@@ -24,7 +24,7 @@ namespace phlex {
2424

2525
required_creator_name(std::string_view rhs) : content_(rhs) {}
2626

27-
T&& release() {return std::move(content_);}
27+
T&& release() { return std::move(content_); }
2828

2929
private:
3030
std::string content_;
@@ -42,7 +42,7 @@ namespace phlex {
4242

4343
required_layer_name(std::string_view rhs) : content_(rhs) {}
4444

45-
T&& release() {return std::move(content_);}
45+
T&& release() { return std::move(content_); }
4646

4747
private:
4848
std::string content_;
@@ -55,20 +55,46 @@ namespace phlex {
5555
std::optional<std::string> suffix;
5656
std::optional<std::string> stage;
5757
};
58-
58+
5959
class product_query {
6060
public:
6161
product_query() = default; // Required by boost JSON
62-
product_query(product_tag&& tag) : creator_(tag.creator.release()), layer_(tag.layer.release()), suffix_(std::move(tag.suffix)), stage_(std::move(tag.stage)) {}
62+
product_query(product_tag&& tag) :
63+
creator_(tag.creator.release()),
64+
layer_(tag.layer.release()),
65+
suffix_(std::move(tag.suffix)),
66+
stage_(std::move(tag.stage))
67+
{
68+
if (creator_.empty()) {
69+
throw std::runtime_error("Cannot specify product with empty creator name.");
70+
}
71+
if (layer_.empty()) {
72+
throw std::runtime_error("Cannot specify the empty string as a data layer.");
73+
}
74+
}
6375
void set_type(experimental::type_id&& type);
6476

65-
std::string const& creator() const noexcept {return creator_;}
66-
std::string const& layer() const noexcept {return layer_;}
67-
std::optional<std::string> const& suffix() const noexcept {return suffix_;}
68-
std::optional<std::string> const& stage() const noexcept {return stage_;}
69-
experimental::type_id const& type() const noexcept {return type_id_;}
77+
std::string const& creator() const noexcept { return creator_; }
78+
std::string const& layer() const noexcept { return layer_; }
79+
std::optional<std::string> const& suffix() const noexcept { return suffix_; }
80+
std::optional<std::string> const& stage() const noexcept { return stage_; }
81+
experimental::type_id const& type() const noexcept { return type_id_; }
82+
83+
// Check that all products selected by /other/ would satisfy this query
84+
bool match(product_query const& other) const;
85+
86+
// Check if a product_specification satisfies this query
87+
bool match(experimental::product_specification const& spec) const;
88+
7089
std::string to_string() const;
7190

91+
// temporary additional members for transition
92+
experimental::product_specification spec() const;
93+
bool operator==(product_query const& rhs) const
94+
{
95+
return this->spec() == rhs.spec() && this->layer_ == rhs.layer_;
96+
}
97+
7298
private:
7399
std::string creator_;
74100
std::string layer_;
@@ -78,8 +104,6 @@ namespace phlex {
78104
};
79105

80106
using product_queries = std::vector<product_query>;
81-
std::ostream& operator<<(std::ostream& os, product_query const& label);
82-
83107
namespace detail {
84108
// C is a container of product_queries
85109
template <typename C, typename T>
@@ -94,7 +118,7 @@ namespace phlex {
94118
template <typename T>
95119
void set_type(C& container)
96120
{
97-
container.at(index_).set_type(make_type_id<T>());
121+
container.at(index_).set_type(experimental::make_type_id<T>());
98122
++index_;
99123
}
100124

0 commit comments

Comments
 (0)