Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d45638f
product_query changes
beojan Jan 23, 2026
bb44f6b
Part 1(!!!) of change to allow specifying creator
beojan Jan 26, 2026
e8b9e25
Apply clang-format fixes
github-actions[bot] Jan 26, 2026
33567e4
Format Jsonnet files
beojan Jan 26, 2026
e481316
Update Spack config to use C++23
beojan Jan 29, 2026
99750c2
Undo changes to input_arguments.cpp
beojan Jan 30, 2026
dcc0b77
Add back operator== for product_query
beojan Jan 30, 2026
01de027
Compendium including introducing phlex(::experimental)::identifier
beojan Jan 30, 2026
993ce71
Apply clang-format fixes
github-actions[bot] Jan 30, 2026
ffb510c
Remove get_string_view()
beojan Jan 31, 2026
9a6e391
Move more of the product_query implementation out of line
beojan Jan 31, 2026
4e130f8
Fix build error
beojan Feb 2, 2026
7a36733
Merge branch 'main' into new-product-query-api
beojan Feb 3, 2026
c70c5db
Fix merge commit errors
beojan Feb 4, 2026
7df7b33
Merge branch 'main' into new-product-query-api
beojan Feb 18, 2026
b4ee412
Fix errors
beojan Feb 18, 2026
521de38
Apply clang-format fixes
github-actions[bot] Feb 18, 2026
2186615
gcc is fine with that consteval, but clang isn't
beojan Feb 18, 2026
fde87c8
Improve coverage
beojan Feb 18, 2026
4223a41
Make algorithm_name use identifiers
beojan Feb 19, 2026
f88cbfe
Merge remote-tracking branch 'upstream/main' into new-product-query-api
beojan Feb 19, 2026
6a83597
Merge branch 'new-product-query-api' into new-product-query
beojan Feb 19, 2026
d4bbfca
Fix failing test
beojan Feb 20, 2026
6cc0c94
type_id now has an std::hash
beojan Feb 23, 2026
86d2af7
Make type_id std::hash const
beojan Feb 23, 2026
b95c7bf
Preparatory changes to tests
beojan Feb 24, 2026
ef91458
Preparatory changes
beojan Feb 24, 2026
588c3e6
[WIP] Workaround for FORM
knoepfel Feb 27, 2026
a72d95d
Merge branch 'main' into new-product-query
knoepfel Feb 27, 2026
4b37aca
Address merge conflicts
knoepfel Feb 27, 2026
f2361a5
Fix product_specification creation from product_query
knoepfel Mar 2, 2026
f4b4c50
Fix FORM test
beojan Mar 2, 2026
3c48ce0
Apply clang-format fixes
github-actions[bot] Mar 2, 2026
3b27805
Address review comments
beojan Mar 4, 2026
dbc49a6
Apply YAML formatter fixes
github-actions[bot] Mar 4, 2026
7eff32f
Apply clang-format fixes
github-actions[bot] Mar 4, 2026
249e236
Make default constructed identifiers valid
beojan Mar 4, 2026
9c84445
Merge branch 'main' into new-product-query
beojan Mar 4, 2026
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
8 changes: 7 additions & 1 deletion .github/workflows/codeql-analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,13 @@ jobs:
fi

determine-languages:
needs: [pre-check, detect-changes-cpp, detect-changes-python, detect-changes-actions]
needs:
[
pre-check,
detect-changes-cpp,
detect-changes-python,
detect-changes-actions,
]
if: always() && needs.pre-check.result == 'success'
runs-on: ubuntu-latest
outputs:
Expand Down
8 changes: 4 additions & 4 deletions form/form_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace {
auto segment_id = store.index()->to_string();

std::cout << "\n=== FormOutputModule::save_data_products ===\n";
std::cout << "Creator: " << creator << "\n";
std::cout << "Creator: " << creator.full() << "\n";
std::cout << "Segment ID: " << segment_id << "\n";
std::cout << "Number of products: " << store.size() << "\n";

Expand All @@ -81,10 +81,10 @@ namespace {
// product_ptr: pointer to the actual product data
assert(product_ptr && "store should not contain null product_ptr");

std::cout << " Product: " << product_name << "\n";
std::cout << " Product: " << product_name.full() << "\n";

// Create FORM product with metadata
products.emplace_back(product_name, // label, from map key
products.emplace_back(product_name.name().trans_get_string(), // label, from map key
product_ptr->address(), // data, from phlex product_base
&product_ptr->type() // type, from phlex product_base
);
Expand All @@ -95,7 +95,7 @@ namespace {
// Write all products to FORM
// Pass segment_id once for entire collection (not duplicated in each product)
// No need to check if products is empty - already checked store.empty() above
m_form_interface->write(creator, segment_id, products);
m_form_interface->write(creator.full(), segment_id, products);
std::cout << "Wrote " << products.size() << " products to FORM\n";
}

Expand Down
4 changes: 2 additions & 2 deletions phlex/core/consumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ namespace phlex::experimental {

std::string consumer::full_name() const { return name_.full(); }

std::string const& consumer::plugin() const noexcept { return name_.plugin(); }
std::string const& consumer::algorithm() const noexcept { return name_.algorithm(); }
identifier const& consumer::plugin() const noexcept { return name_.plugin(); }
identifier const& consumer::algorithm() const noexcept { return name_.algorithm(); }

std::vector<std::string> const& consumer::when() const noexcept { return predicates_; }
}
4 changes: 2 additions & 2 deletions phlex/core/consumer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace phlex::experimental {
consumer(algorithm_name name, std::vector<std::string> predicates);

std::string full_name() const;
std::string const& plugin() const noexcept;
std::string const& algorithm() const noexcept;
identifier const& plugin() const noexcept;
identifier const& algorithm() const noexcept;
std::vector<std::string> const& when() const noexcept;

private:
Expand Down
6 changes: 3 additions & 3 deletions phlex/core/declared_fold.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ namespace phlex::experimental {
{
auto& result = results_.at(store->index()->hash());
if constexpr (requires { send(*result); }) {
store->add_product(output()[0].name(), send(*result));
store->add_product(output()[0], send(*result));
} else {
store->add_product(output()[0].name(), std::move(result));
store->add_product(output()[0], std::move(result));
}
// Reclaim some memory; it would be better to erase the entire entry from the map,
// but that is not thread-safe.
Expand All @@ -198,7 +198,7 @@ namespace phlex::experimental {
InitTuple initializer_;
input_retriever_types<input_parameter_types> input_{input_arguments<input_parameter_types>()};
product_specifications output_;
std::string partition_;
identifier partition_;
tbb::flow::function_node<flush_message> flush_receiver_;
join_or_none_t<num_inputs> join_;
tbb::flow::multifunction_node<messages_t<num_inputs>, message_tuple<1>> fold_;
Expand Down
6 changes: 4 additions & 2 deletions phlex/core/declared_provider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ namespace phlex::experimental {
AlgorithmBits alg,
product_query output) :
declared_provider{std::move(name), output},
output_{output.spec()},
output_{algorithm_name::create(std::string_view(identifier(output.creator))),
output.suffix.value_or(identifier("")),
output.type},
provider_{g,
concurrency,
[this, ft = alg.release_algorithm()](index_message const& index_msg, auto& output) {
Expand All @@ -66,7 +68,7 @@ namespace phlex::experimental {
++calls_;

products new_products;
new_products.add(output_.name(), std::move(result));
new_products.add(output_, std::move(result));
auto store = std::make_shared<product_store>(
index, this->full_name(), std::move(new_products));

Expand Down
2 changes: 1 addition & 1 deletion phlex/core/declared_unfold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace phlex::experimental {

generator::generator(product_store_const_ptr const& parent,
std::string node_name,
algorithm_name node_name,
std::string const& child_layer_name) :
parent_{std::const_pointer_cast<product_store>(parent)},
node_name_{std::move(node_name)},
Expand Down
5 changes: 3 additions & 2 deletions phlex/core/declared_unfold.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "phlex/model/algorithm_name.hpp"
#include "phlex/model/data_cell_index.hpp"
#include "phlex/model/handle.hpp"
#include "phlex/model/identifier.hpp"
#include "phlex/model/product_specification.hpp"
#include "phlex/model/product_store.hpp"
#include "phlex/utilities/simple_ptr_map.hpp"
Expand All @@ -34,7 +35,7 @@ namespace phlex::experimental {
class generator {
public:
explicit generator(product_store_const_ptr const& parent,
std::string node_name,
algorithm_name node_name,
std::string const& child_layer_name);
flush_counts_ptr flush_result() const;

Expand All @@ -47,7 +48,7 @@ namespace phlex::experimental {
private:
product_store_const_ptr make_child(std::size_t i, products new_products);
product_store_ptr parent_;
std::string node_name_;
algorithm_name node_name_;
std::string const& child_layer_name_;
std::map<data_cell_index::hash_type, std::size_t> child_counts_;
};
Expand Down
2 changes: 1 addition & 1 deletion phlex/core/detail/filter_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ namespace phlex::experimental {

// Fill slots in the order of the input arguments to the downstream node.
for (std::size_t i = 0; i != nargs_; ++i) {
if (elem[i] or not store->contains_product((*product_names_)[i].spec().full()))
if (elem[i] or not store->contains_product((*product_names_)[i].spec()))
continue;
elem[i] = store;
}
Expand Down
6 changes: 4 additions & 2 deletions phlex/core/detail/make_algorithm_name.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#include "phlex/core/detail/make_algorithm_name.hpp"
#include "phlex/configuration.hpp"
#include "phlex/model/algorithm_name.hpp"
#include "phlex/model/identifier.hpp"

namespace phlex::experimental::detail {
algorithm_name make_algorithm_name(configuration const* config, std::string name)
algorithm_name make_algorithm_name(configuration const* config, std::string_view name)
{
return {config ? config->get<std::string>("module_label") : "", std::move(name)};
return {config ? identifier(config->get<std::string_view>("module_label")) : ""_id,
identifier(name)};
}
}
4 changes: 2 additions & 2 deletions phlex/core/detail/make_algorithm_name.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// This simple utility is placed in an implementation file to avoid including the
// phlex/configuration.hpp in framework code.

#include <string>
#include <string_view>

namespace phlex {
class configuration;
Expand All @@ -14,7 +14,7 @@ namespace phlex::experimental {
class algorithm_name;

namespace detail {
algorithm_name make_algorithm_name(configuration const* config, std::string name);
algorithm_name make_algorithm_name(configuration const* config, std::string_view name);
}
}

Expand Down
8 changes: 4 additions & 4 deletions phlex/core/edge_creation_policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace phlex::experimental {
product_query const& query) const
{
// TODO: Update later with correct querying
auto [b, e] = producers_.equal_range(query.suffix.value_or(""_id).trans_get_string());
auto [b, e] = producers_.equal_range(query.suffix.value_or(""_id));
if (b == e) {
spdlog::debug(
"Failed to find an algorithm that creates {} products. Assuming it comes from a provider",
Expand All @@ -19,9 +19,9 @@ namespace phlex::experimental {
}
std::map<std::string, named_output_port const*> candidates;
for (auto const& [key, producer] : std::ranges::subrange{b, e}) {
// TODO: Definitely not right yet
if (producer.node.plugin() == std::string_view(identifier(query.creator)) ||
producer.node.algorithm() == std::string_view(identifier(query.creator))) {
// TODO: Getting there -- this whole thing needs to be replaced with something
// that indexes all the fields from the beginning.
if (producer.node.plugin() == query.creator || producer.node.algorithm() == query.creator) {
if (query.type != producer.type) {
spdlog::debug("Matched ({}) from {} but types don't match (`{}` vs `{}`). Excluding "
"from candidate list.",
Expand Down
5 changes: 3 additions & 2 deletions phlex/core/edge_creation_policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define PHLEX_CORE_EDGE_CREATION_POLICY_HPP

#include "phlex/core/message.hpp"
#include "phlex/model/identifier.hpp"
#include "phlex/model/product_specification.hpp"
#include "phlex/model/type_id.hpp"

Expand All @@ -12,7 +13,7 @@
#include <string>

namespace phlex::experimental {
using product_name_t = std::string;
using product_name_t = identifier;

class edge_creation_policy {
public:
Expand Down Expand Up @@ -44,7 +45,7 @@ namespace phlex::experimental {
std::multimap<product_name_t, named_output_port> result;
for (auto const& [node_name, node] : nodes) {
for (auto const& product_name : node->output()) {
if (empty(product_name.name()))
if (product_name.name().empty())
continue;

result.emplace(product_name.name(),
Expand Down
2 changes: 1 addition & 1 deletion phlex/core/edge_maker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
namespace phlex::experimental {
using namespace std::string_literals;

using product_name_t = std::string;
using product_name_t = identifier;

index_router::provider_input_ports_t make_provider_edges(index_router::head_ports_t head_ports,
declared_providers& providers);
Expand Down
10 changes: 5 additions & 5 deletions phlex/core/index_router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,15 @@ namespace phlex::experimental {
void detail::multilayer_slot::put_message(data_cell_index_ptr const& index,
std::size_t message_id)
{
auto const layer = static_cast<std::string_view>(layer_);
if (layer == index->layer_name()) {
if (layer_ == index->layer_name()) {
broadcaster_.try_put({.index = index, .msg_id = message_id, .cache = false});
return;
}

// Flush values are only used for indices that are *not* the "lowest" in the branch
// of the hierarchy.
++counter_;
broadcaster_.try_put({.index = index->parent(layer), .msg_id = message_id});
broadcaster_.try_put({.index = index->parent(layer_), .msg_id = message_id});
}

void detail::multilayer_slot::put_end_token(data_cell_index_ptr const& index)
Expand All @@ -119,7 +118,7 @@ namespace phlex::experimental {

bool detail::multilayer_slot::is_parent_of(data_cell_index_ptr const& index) const
{
return index->parent(static_cast<std::string_view>(layer_)) != nullptr;
return index->parent(layer_) != nullptr;
}

//========================================================================================
Expand Down Expand Up @@ -197,7 +196,8 @@ namespace phlex::experimental {
return;
}

auto broadcaster = index_node_for(index->layer_name());
std::string const layerish_path{static_cast<std::string_view>(index->layer_name())};
auto broadcaster = index_node_for(layerish_path);
if (broadcaster) {
broadcaster->try_put({.index = index, .msg_id = message_id});
}
Expand Down
29 changes: 28 additions & 1 deletion phlex/core/input_arguments.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
#include "phlex/core/product_query.hpp"
#include "phlex/model/handle.hpp"

#include "fmt/format.h"

#include <algorithm>
#include <cstddef>
#include <ranges>
#include <string>
#include <tuple>
#include <utility>
Expand All @@ -18,7 +22,30 @@
product_query query;
auto retrieve(message const& msg) const
{
return msg.store->get_handle<handle_arg_t>(query.spec().name());
namespace views = std::ranges::views;
auto const& store = msg.store;
// TODO: This needs to be replaced with a properly engineered solution
auto all_products = std::ranges::subrange(store->begin(), store->end()) | views::keys;
auto products =
all_products |
views::filter([this](product_specification const& spec) { return query.match(spec); }) |
views::transform([](product_specification const& spec) { return std::cref(spec); }) |
std::ranges::to<std::vector>();
if (products.empty()) {
throw std::runtime_error(fmt::format(
"No products found matching the query {}\n Store (id {} from {}) contains:\n - {}",
query,
store->index()->to_string(),
store->source().full(),
fmt::join(all_products | views::transform(&product_specification::full), "\n - ")));

Check warning on line 40 in phlex/core/input_arguments.hpp

View check run for this annotation

Codecov / codecov/patch

phlex/core/input_arguments.hpp#L35-L40

Added lines #L35 - L40 were not covered by tests
}
if (products.size() > 1) {
throw std::runtime_error(fmt::format(
"Multiple products found matching the query {}:\n - {}",
query,
fmt::join(products | views::transform(&product_specification::full), "\n - ")));

Check warning on line 46 in phlex/core/input_arguments.hpp

View check run for this annotation

Codecov / codecov/patch

phlex/core/input_arguments.hpp#L43-L46

Added lines #L43 - L46 were not covered by tests
}
return store->get_handle<handle_arg_t>(products[0]);
}
};

Expand Down
6 changes: 4 additions & 2 deletions phlex/core/message.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "phlex/core/message.hpp"
#include "phlex/model/data_cell_index.hpp"

#include "fmt/format.h"

#include <algorithm>
#include <iterator>
#include <stdexcept>
Expand All @@ -26,8 +28,8 @@
auto const [b, e] = std::tuple{cbegin(product_labels), cend(product_labels)};
auto it = std::find(b, e, product_label);
if (it == e) {
throw std::runtime_error("Algorithm does not accept product '" + product_label.spec().name() +
"'.");
throw std::runtime_error(
fmt::format("Algorithm does not accept product '{}'.", product_label));

Check warning on line 32 in phlex/core/message.cpp

View check run for this annotation

Codecov / codecov/patch

phlex/core/message.cpp#L31-L32

Added lines #L31 - L32 were not covered by tests
}
return std::distance(b, it);
}
Expand Down
12 changes: 8 additions & 4 deletions phlex/core/product_query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ namespace phlex {
// Check if a product_specification satisfies this query
bool product_query::match(experimental::product_specification const& spec) const
{
// string comparisons for now for a gradual transition
if (std::string_view(experimental::identifier(creator)) != spec.algorithm()) {
experimental::identifier tmp_creator{this->creator};
if (tmp_creator != spec.algorithm() && tmp_creator != spec.plugin()) {
return false;
}
if (type != spec.type()) {
return false;
}
if (suffix) {
if (std::string_view(*suffix) != spec.name()) {
if (*suffix != spec.name()) {
return false;
}
}
Expand All @@ -58,8 +58,12 @@ namespace phlex {
throw std::logic_error("Product suffixes are (temporarily) mandatory");
}
// Not efficient, but this should be temporary
return experimental::product_specification::create(suffix->trans_get_string());
using namespace phlex::experimental;
auto const& creator_identifier = static_cast<experimental::identifier const&>(creator);
return product_specification{
algorithm_name::create(static_cast<std::string_view>(creator_identifier)), *suffix, type};
}

bool product_query::operator==(product_query const& rhs) const
{
using experimental::identifier;
Expand Down
1 change: 1 addition & 0 deletions phlex/core/product_query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
experimental::product_specification spec() const;
};

inline std::string format_as(product_query const& q) { return q.to_string(); }

Check warning on line 85 in phlex/core/product_query.hpp

View check run for this annotation

Codecov / codecov/patch

phlex/core/product_query.hpp#L85

Added line #L85 was not covered by tests
using product_queries = std::vector<product_query>;
namespace detail {
// C is a container of product_queries
Expand Down
Loading
Loading