diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index 7e992b9af333a..8b6c9d5e21b85 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -167,6 +167,7 @@ foreach(t DeviceMetricsInfo DeviceSpec DeviceSpecHelpers + Expressions ExternalFairMQDeviceProxy FairMQOptionsRetriever FairMQResizableBuffer diff --git a/Framework/Core/include/Framework/Expressions.h b/Framework/Core/include/Framework/Expressions.h index 5c9d3b55e6518..cd06a4b4979e6 100644 --- a/Framework/Core/include/Framework/Expressions.h +++ b/Framework/Core/include/Framework/Expressions.h @@ -10,11 +10,11 @@ #ifndef O2_FRAMEWORK_EXPRESSIONS_H_ #define O2_FRAMEWORK_EXPRESSIONS_H_ -#include "Framework/Kernels.h" - +#include #include #include #include +#include namespace o2::framework::expressions { @@ -55,22 +55,6 @@ struct BinaryOpNode { Op op; }; -struct ArrowDatumSpec { - // datum spec either contains an index, a value of a literal or a binding label - std::variant datum; - explicit ArrowDatumSpec(size_t index) : datum{index} {} - explicit ArrowDatumSpec(LiteralNode::var_t literal) : datum{literal} {} - explicit ArrowDatumSpec(std::string binding) : datum{binding} {} - ArrowDatumSpec() : datum{std::monostate{}} {} -}; - -struct ArrowKernelSpec { - std::unique_ptr kernel = nullptr; - ArrowDatumSpec left; - ArrowDatumSpec right; - ArrowDatumSpec result; -}; - /// A generic tree node struct Node { Node(LiteralNode v) : self{v}, left{nullptr}, right{nullptr} @@ -145,7 +129,6 @@ struct Filter { std::unique_ptr node; }; - } // namespace o2::framework::expressions #endif // O2_FRAMEWORK_EXPRESSIONS_H_ diff --git a/Framework/Core/src/ExpressionHelpers.h b/Framework/Core/src/ExpressionHelpers.h new file mode 100644 index 0000000000000..027f31bb60175 --- /dev/null +++ b/Framework/Core/src/ExpressionHelpers.h @@ -0,0 +1,39 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ +#define O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ +#include "Framework/Expressions.h" + +namespace o2::framework::expressions +{ +struct ArrowDatumSpec { + // datum spec either contains an index, a value of a literal or a binding label + std::variant datum; + explicit ArrowDatumSpec(size_t index) : datum{index} {} + explicit ArrowDatumSpec(LiteralNode::var_t literal) : datum{literal} {} + explicit ArrowDatumSpec(std::string binding) : datum{binding} {} + ArrowDatumSpec() : datum{std::monostate{}} {} +}; + +bool operator==(ArrowDatumSpec const& lhs, ArrowDatumSpec const& rhs); + +std::ostream& operator<<(std::ostream& os, ArrowDatumSpec const& spec); + +struct ArrowKernelSpec { + std::unique_ptr kernel = nullptr; + ArrowDatumSpec left; + ArrowDatumSpec right; + ArrowDatumSpec result; +}; + +std::vector createKernelsFromFilter(Filter const& filter); +} // namespace o2::framework::expressions + +#endif // O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ diff --git a/Framework/Core/src/Expressions.cxx b/Framework/Core/src/Expressions.cxx index eb3f5798487d4..b59e6eb0f03c0 100644 --- a/Framework/Core/src/Expressions.cxx +++ b/Framework/Core/src/Expressions.cxx @@ -8,7 +8,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/Expressions.h" +#include "../src/ExpressionHelpers.h" #include "Framework/VariantHelpers.h" #include @@ -53,16 +53,37 @@ struct BinaryOpNodeHelper { } }; +bool operator==(ArrowDatumSpec const& lhs, ArrowDatumSpec const& rhs) +{ + return (lhs.datum == rhs.datum); +} + +std::ostream& operator<<(std::ostream& os, ArrowDatumSpec const& spec) +{ + std::visit( + overloaded{ + [&os](LiteralNode::var_t&& arg) -> void { + std::visit( + [&os](auto&& arg) { os << arg; }, + arg); + }, + [&os](size_t&& arg) { os << arg; }, + [&os](std::string&& arg) { os << arg; }, + [](auto&&) {}}, + spec.datum); + return os; +} + /// helper struct used to parse trees struct NodeRecord { /// pointer to the actual tree node Node* node_ptr = nullptr; - explicit NodeRecord(Node* node_) : node_ptr(node_) {} + size_t index = 0; + explicit NodeRecord(Node* node_, size_t index_) : node_ptr(node_), index{index_} {} }; std::vector createKernelsFromFilter(Filter const& filter) { - std::vector datums; std::vector kernelSpecs; std::stack path; auto isLeaf = [](Node const* const node) { @@ -70,10 +91,8 @@ std::vector createKernelsFromFilter(Filter const& filter) }; size_t index = 0; - // create and put output datum - datums.emplace_back(ArrowDatumSpec{index++}); // insert the top node into stack - path.emplace(filter.node.get()); + path.emplace(filter.node.get(), index++); // while the stack is not empty while (path.empty() == false) { @@ -85,50 +104,47 @@ std::vector createKernelsFromFilter(Filter const& filter) bool leftLeaf = isLeaf(left); bool rightLeaf = isLeaf(right); + auto processLeaf = [](Node const* const node) { + return std::visit( + overloaded{ + [lh = LiteralNodeHelper{}](LiteralNode node) { return lh(node); }, + [bh = BindingNodeHelper{}](BindingNode node) { return bh(node); }, + [](auto&&) { return ArrowDatumSpec{}; }}, + node->self); + }; + + // create kernel spec, pop the node and add its children + auto&& kernel = + std::visit( + overloaded{ + [bh = BinaryOpNodeHelper{}](BinaryOpNode node) { return bh(node); }, + [](auto&&) { return ArrowKernelSpec{}; }}, + top.node_ptr->self); + kernel.result = ArrowDatumSpec{top.index}; + path.pop(); + size_t li = 0; size_t ri = 0; - size_t ti = index; - - auto processLeaf = [&datums](Node const* const node) { - datums.push_back( - std::visit( - overloaded{ - [lh = LiteralNodeHelper{}](LiteralNode node) { return lh(node); }, - [bh = BindingNodeHelper{}](BindingNode node) { return bh(node); }, - [](auto&&) { return ArrowDatumSpec{}; }}, - node->self)); - }; if (leftLeaf) { - processLeaf(left); + kernel.left = processLeaf(left); } else { - datums.emplace_back(ArrowDatumSpec{index++}); + li = index; + kernel.left = ArrowDatumSpec{index++}; } - li = datums.size() - 1; if (rightLeaf) { - processLeaf(right); + kernel.right = processLeaf(right); } else { - datums.emplace_back(ArrowDatumSpec{index++}); + ri = index; + kernel.right = ArrowDatumSpec{index++}; } - ri = datums.size() - 1; - // create kernel spec, pop the node and add its children - auto&& kernel = - std::visit( - overloaded{ - [bh = BinaryOpNodeHelper{}](BinaryOpNode node) { return bh(node); }, - [](auto&&) { return ArrowKernelSpec{}; }}, - top.node_ptr->self); - kernel.left = ArrowDatumSpec{li}; - kernel.right = ArrowDatumSpec{ri}; - kernel.result = ArrowDatumSpec{ti}; kernelSpecs.push_back(std::move(kernel)); - path.pop(); if (!leftLeaf) - path.emplace(left); + path.emplace(left, li); if (!rightLeaf) - path.emplace(right); + path.emplace(right, ri); } return kernelSpecs; } diff --git a/Framework/Core/test/test_Expressions.cxx b/Framework/Core/test/test_Expressions.cxx new file mode 100644 index 0000000000000..7d41db5d9a8ff --- /dev/null +++ b/Framework/Core/test/test_Expressions.cxx @@ -0,0 +1,50 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test Framework Expressions +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include "../src/ExpressionHelpers.h" +#include + +using namespace o2::framework::expressions; + +namespace nodes +{ +static BindingNode pt{"pt"}; +static BindingNode phi{"phi"}; +static BindingNode eta{"eta"}; +} // namespace nodes + +BOOST_AUTO_TEST_CASE(TestTreeParsing) +{ + Filter f = ((nodes::phi > 1) && (nodes::phi < 2)) && (nodes::eta < 1); + auto specs = createKernelsFromFilter(f); + BOOST_REQUIRE_EQUAL(specs[0].left, ArrowDatumSpec{1u}); + BOOST_REQUIRE_EQUAL(specs[0].right, ArrowDatumSpec{2u}); + BOOST_REQUIRE_EQUAL(specs[0].result, ArrowDatumSpec{0u}); + + BOOST_REQUIRE_EQUAL(specs[1].left, ArrowDatumSpec{std::string{"eta"}}); + BOOST_REQUIRE_EQUAL(specs[1].right, ArrowDatumSpec{LiteralNode::var_t{1}}); + BOOST_REQUIRE_EQUAL(specs[1].result, ArrowDatumSpec{2u}); + + BOOST_REQUIRE_EQUAL(specs[2].left, ArrowDatumSpec{3u}); + BOOST_REQUIRE_EQUAL(specs[2].right, ArrowDatumSpec{4u}); + BOOST_REQUIRE_EQUAL(specs[2].result, ArrowDatumSpec{1u}); + + BOOST_REQUIRE_EQUAL(specs[3].left, ArrowDatumSpec{std::string{"phi"}}); + BOOST_REQUIRE_EQUAL(specs[3].right, ArrowDatumSpec{LiteralNode::var_t{2}}); + BOOST_REQUIRE_EQUAL(specs[3].result, ArrowDatumSpec{4u}); + + BOOST_REQUIRE_EQUAL(specs[4].left, ArrowDatumSpec{std::string{"phi"}}); + BOOST_REQUIRE_EQUAL(specs[4].right, ArrowDatumSpec{LiteralNode::var_t{1}}); + BOOST_REQUIRE_EQUAL(specs[4].result, ArrowDatumSpec{3u}); +}