diff --git a/be/src/exprs/min_max_predicate.h b/be/src/exprs/min_max_predicate.h index 60b53d2056ec2..c7015acc46085 100644 --- a/be/src/exprs/min_max_predicate.h +++ b/be/src/exprs/min_max_predicate.h @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#pragma once + #include "column/chunk.h" #include "column/column_helper.h" #include "column/type_traits.h" @@ -145,4 +147,4 @@ class MinMaxPredicateBuilder { const JoinRuntimeFilter* _filter; }; -} // namespace starrocks \ No newline at end of file +} // namespace starrocks diff --git a/be/src/storage/CMakeLists.txt b/be/src/storage/CMakeLists.txt index 81aecf2b8531f..1e5389b1c79dc 100644 --- a/be/src/storage/CMakeLists.txt +++ b/be/src/storage/CMakeLists.txt @@ -135,6 +135,7 @@ set(STORAGE_FILES column_not_in_predicate.cpp column_null_predicate.cpp column_or_predicate.cpp + column_and_predicate.cpp column_expr_predicate.cpp conjunctive_predicates.cpp predicate_tree/predicate_tree.cpp diff --git a/be/src/storage/column_and_predicate.cpp b/be/src/storage/column_and_predicate.cpp new file mode 100644 index 0000000000000..871ab4a4bf848 --- /dev/null +++ b/be/src/storage/column_and_predicate.cpp @@ -0,0 +1,80 @@ +// Copyright 2021-present StarRocks, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "storage/column_and_predicate.h" + +namespace starrocks { +Status ColumnAndPredicate::evaluate(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const { + return _evaluate(column, selection, from, to); +} + +Status ColumnAndPredicate::evaluate_and(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const { + for (const ColumnPredicate* child : _child) { + RETURN_IF_ERROR(child->evaluate_and(column, selection, from, to)); + } + return Status::OK(); +} + +Status ColumnAndPredicate::evaluate_or(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const { + _buff.resize(column->size()); + RETURN_IF_ERROR(_evaluate(column, _buff.data(), from, to)); + const uint8_t* p = _buff.data(); + for (uint16_t i = from; i < to; i++) { + selection[i] |= p[i]; + } + return Status::OK(); +} + +std::string ColumnAndPredicate::debug_string() const { + std::stringstream ss; + ss << "AND("; + for (size_t i = 0; i < _child.size(); i++) { + if (i != 0) { + ss << ", "; + } + ss << i << ":" << _child[i]->debug_string(); + } + ss << ")"; + return ss.str(); +} + +Status ColumnAndPredicate::_evaluate(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const { + RETURN_IF_ERROR(_child[0]->evaluate(column, selection, from, to)); + for (size_t i = 1; i < _child.size(); i++) { + RETURN_IF_ERROR(_child[i]->evaluate_and(column, selection, from, to)); + } + return Status::OK(); +} + +// return false if page not satisfied +bool ColumnAndPredicate::zone_map_filter(const ZoneMapDetail& detail) const { + for (const ColumnPredicate* child : _child) { + RETURN_IF(!child->zone_map_filter(detail), false); + } + return true; +} + +Status ColumnAndPredicate::convert_to(const ColumnPredicate** output, const TypeInfoPtr& target_type_ptr, + ObjectPool* obj_pool) const { + ColumnAndPredicate* new_pred = + obj_pool->add(new ColumnAndPredicate(get_type_info(target_type_ptr.get()), _column_id)); + for (auto pred : _child) { + const ColumnPredicate* new_child = nullptr; + RETURN_IF_ERROR(pred->convert_to(&new_child, get_type_info(target_type_ptr.get()), obj_pool)); + new_pred->_child.emplace_back(new_child); + } + *output = new_pred; + return Status::OK(); +} +} // namespace starrocks \ No newline at end of file diff --git a/be/src/storage/column_and_predicate.h b/be/src/storage/column_and_predicate.h new file mode 100644 index 0000000000000..a64e380dde056 --- /dev/null +++ b/be/src/storage/column_and_predicate.h @@ -0,0 +1,58 @@ +// Copyright 2021-present StarRocks, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "storage/column_predicate.h" + +namespace starrocks { + +class ColumnAndPredicate final : public ColumnPredicate { +public: + explicit ColumnAndPredicate(const TypeInfoPtr& type_info, ColumnId cid) : ColumnPredicate(type_info, cid) {} + + template + ColumnAndPredicate(const TypeInfoPtr& type_info, ColumnId cid, const Container& c) + : ColumnPredicate(type_info, cid), _child(c.begin(), c.end()) {} + + void add_child(ColumnPredicate* child) { _child.emplace_back(child); } + + template + void add_child(Iterator begin, Iterator end) { + _child.insert(_child.end(), begin, end); + } + + Status evaluate(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const override; + Status evaluate_and(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const override; + Status evaluate_or(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const override; + + bool filter(const BloomFilter& bf) const override { return true; } + bool zone_map_filter(const ZoneMapDetail& detail) const override; + + bool can_vectorized() const override { return false; } + PredicateType type() const override { return PredicateType::kAnd; } + Datum value() const override { return {}; } + std::vector values() const override { return std::vector{}; } + + Status convert_to(const ColumnPredicate** output, const TypeInfoPtr& target_type_info, + ObjectPool* obj_pool) const override; + std::string debug_string() const override; + +private: + Status _evaluate(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const; + + std::vector _child; + mutable std::vector _buff; +}; +} // namespace starrocks \ No newline at end of file diff --git a/be/src/storage/column_expr_predicate.h b/be/src/storage/column_expr_predicate.h index fa410748395df..e427aa02efd9e 100644 --- a/be/src/storage/column_expr_predicate.h +++ b/be/src/storage/column_expr_predicate.h @@ -30,7 +30,7 @@ class Column; // And this class has a big limitation that it does not support range evaluatation. In another word, `from` supposed to be 0 always. // The fundamental reason is `ExprContext` requires `Column*` as a total piece, unless we can create a class to represent `ColumnSlice`. // And that task is almost impossible. -class ColumnExprPredicate : public ColumnPredicate { +class ColumnExprPredicate final : public ColumnPredicate { public: static StatusOr make_column_expr_predicate(TypeInfoPtr type_info, ColumnId column_id, RuntimeState* state, ExprContext* expr_ctx, @@ -86,7 +86,7 @@ class ColumnExprPredicate : public ColumnPredicate { mutable std::vector _tmp_select; }; -class ColumnTruePredicate : public ColumnPredicate { +class ColumnTruePredicate final : public ColumnPredicate { public: ColumnTruePredicate(TypeInfoPtr type_info, ColumnId column_id) : ColumnPredicate(std::move(type_info), column_id) {} ~ColumnTruePredicate() override = default; diff --git a/be/src/storage/column_in_predicate.cpp b/be/src/storage/column_in_predicate.cpp index 6294d81cdc27c..1287b107817c9 100644 --- a/be/src/storage/column_in_predicate.cpp +++ b/be/src/storage/column_in_predicate.cpp @@ -29,7 +29,7 @@ namespace starrocks { template -class ColumnInPredicate : public ColumnPredicate { +class ColumnInPredicate final : public ColumnPredicate { using ValueType = typename CppTypeTraits::CppType; static_assert(std::is_same_v); @@ -195,7 +195,7 @@ class ColumnInPredicate : public ColumnPredicate { // Template specialization for binary column template -class BinaryColumnInPredicate : public ColumnPredicate { +class BinaryColumnInPredicate final : public ColumnPredicate { public: BinaryColumnInPredicate(const TypeInfoPtr& type_info, ColumnId id, std::vector strings) : ColumnPredicate(type_info, id), _zero_padded_strs(std::move(strings)) { @@ -368,7 +368,7 @@ class BinaryColumnInPredicate : public ColumnPredicate { ItemHashSet _slices; }; -class DictionaryCodeInPredicate : public ColumnPredicate { +class DictionaryCodeInPredicate final : public ColumnPredicate { private: enum LogicOp { ASSIGN, AND, OR }; diff --git a/be/src/storage/column_not_in_predicate.cpp b/be/src/storage/column_not_in_predicate.cpp index d8463496ca186..0107075d767e9 100644 --- a/be/src/storage/column_not_in_predicate.cpp +++ b/be/src/storage/column_not_in_predicate.cpp @@ -25,7 +25,7 @@ namespace starrocks { template -class ColumnNotInPredicate : public ColumnPredicate { +class ColumnNotInPredicate final : public ColumnPredicate { using ValueType = typename CppTypeTraits::CppType; public: @@ -177,7 +177,7 @@ class ColumnNotInPredicate : public ColumnPredicate { // Template specialization for binary column template -class BinaryColumnNotInPredicate : public ColumnPredicate { +class BinaryColumnNotInPredicate final : public ColumnPredicate { public: BinaryColumnNotInPredicate(const TypeInfoPtr& type_info, ColumnId id, std::vector strings) : ColumnPredicate(type_info, id), _zero_padded_strs(std::move(strings)) { diff --git a/be/src/storage/column_null_predicate.cpp b/be/src/storage/column_null_predicate.cpp index df2f11b12aa4f..a46c3a08868be 100644 --- a/be/src/storage/column_null_predicate.cpp +++ b/be/src/storage/column_null_predicate.cpp @@ -23,7 +23,7 @@ namespace starrocks { -class ColumnIsNullPredicate : public ColumnPredicate { +class ColumnIsNullPredicate final : public ColumnPredicate { public: explicit ColumnIsNullPredicate(const TypeInfoPtr& type_info, ColumnId id) : ColumnPredicate(type_info, id) {} @@ -103,7 +103,7 @@ class ColumnIsNullPredicate : public ColumnPredicate { std::string debug_string() const override { return strings::Substitute("(ColumnId($0) IS NULL)", _column_id); } }; -class ColumnNotNullPredicate : public ColumnPredicate { +class ColumnNotNullPredicate final : public ColumnPredicate { public: explicit ColumnNotNullPredicate(const TypeInfoPtr& type_info, ColumnId id) : ColumnPredicate(type_info, id) {} diff --git a/be/src/storage/column_or_predicate.cpp b/be/src/storage/column_or_predicate.cpp index f4e900ab81349..e74d68b7abb45 100644 --- a/be/src/storage/column_or_predicate.cpp +++ b/be/src/storage/column_or_predicate.cpp @@ -68,4 +68,17 @@ Status ColumnOrPredicate::convert_to(const ColumnPredicate** output, const TypeI return Status::OK(); } +std::string ColumnOrPredicate::debug_string() const { + std::stringstream ss; + ss << "OR("; + for (size_t i = 0; i < _child.size(); i++) { + if (i != 0) { + ss << ", "; + } + ss << i << ":" << _child[i]->debug_string(); + } + ss << ")"; + return ss.str(); +} + } // namespace starrocks diff --git a/be/src/storage/column_or_predicate.h b/be/src/storage/column_or_predicate.h index 1ffd6a74e09f7..d8be6b1dd8049 100644 --- a/be/src/storage/column_or_predicate.h +++ b/be/src/storage/column_or_predicate.h @@ -59,6 +59,8 @@ class ColumnOrPredicate : public ColumnPredicate { Status convert_to(const ColumnPredicate** output, const TypeInfoPtr& target_type_info, ObjectPool* obj_pool) const override; + std::string debug_string() const override; + private: Status _evaluate(const Column* column, uint8_t* selection, uint16_t from, uint16_t to) const; diff --git a/be/test/CMakeLists.txt b/be/test/CMakeLists.txt index 82974f736b79f..51f9fcbf983d9 100644 --- a/be/test/CMakeLists.txt +++ b/be/test/CMakeLists.txt @@ -357,6 +357,8 @@ set(EXEC_FILES ./storage/persistent_index_consistency_test.cpp ./storage/meta_reader_test.cpp ./storage/dictionary_cache_manager_test.cpp + ./storage/column_or_predicate_test.cpp + ./storage/column_and_predicate_test.cpp ./runtime/agg_state_desc_test.cpp ./runtime/buffer_control_block_test.cpp ./runtime/data_stream_mgr_test.cpp diff --git a/be/test/storage/column_and_predicate_test.cpp b/be/test/storage/column_and_predicate_test.cpp new file mode 100644 index 0000000000000..b6e385a7b4845 --- /dev/null +++ b/be/test/storage/column_and_predicate_test.cpp @@ -0,0 +1,121 @@ +// Copyright 2021-present StarRocks, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "storage/column_and_predicate.h" + +#include + +#include "storage/rowset/block_split_bloom_filter.h" +#include "testutil/column_test_helper.h" + +namespace starrocks { +class ColumnAndPredicateTest : public ::testing::Test { +public: + void SetUp() override { + _left.reset(new_column_ge_predicate(get_type_info(TYPE_INT), 0, "10")); + _right.reset(new_column_le_predicate(get_type_info(TYPE_INT), 0, "20")); + _pred = std::make_unique(get_type_info(TYPE_INT), 0); + _pred->add_child(_left.get()); + _pred->add_child(_right.get()); + + std::vector values = {5, 15, 17, 25, 0, 0}; + std::vector null_values = {0, 0, 0, 0, 1, 1}; + _col = ColumnTestHelper::build_nullable_column(values, null_values); + } + +protected: + std::unique_ptr _left; + std::unique_ptr _right; + std::unique_ptr _pred; + ColumnPtr _col; + BlockSplitBloomFilter _bf; + ObjectPool _pool; +}; + +TEST_F(ColumnAndPredicateTest, basic) { + ASSERT_TRUE(_pred->filter(_bf)); + ASSERT_FALSE(_pred->can_vectorized()); + ASSERT_EQ(_pred->type(), PredicateType::kAnd); + ASSERT_TRUE(_pred->value().is_null()); + ASSERT_EQ(_pred->values().size(), 0); + ASSERT_EQ(_pred->debug_string(), "AND(0:(columnId(0)>=10), 1:(columnId(0)<=20))"); +} + +TEST_F(ColumnAndPredicateTest, evaluate) { + std::vector buff = {0, 0, 0, 0, 0, 0}; + auto st = _pred->evaluate(_col.get(), buff.data(), 0, 6); + ASSERT_TRUE(st.ok()); + + std::vector result = {0, 1, 1, 0, 0, 0}; + ASSERT_EQ(buff, result); +} + +TEST_F(ColumnAndPredicateTest, evaluate_and) { + std::vector buff = {1, 1, 0, 1, 1, 1}; + auto st = _pred->evaluate_and(_col.get(), buff.data(), 0, 6); + ASSERT_TRUE(st.ok()); + + std::vector result = {0, 1, 0, 0, 0, 0}; + ASSERT_EQ(buff, result); +} + +TEST_F(ColumnAndPredicateTest, evaluate_or) { + std::vector buff = {0, 0, 0, 0, 1, 0}; + auto st = _pred->evaluate_or(_col.get(), buff.data(), 0, 6); + ASSERT_TRUE(st.ok()); + + std::vector result = {0, 1, 1, 0, 1, 0}; + ASSERT_EQ(buff, result); +} + +TEST_F(ColumnAndPredicateTest, zonemap_filter) { + Datum min_value_1((int32_t)10); + Datum max_value_1((int32_t)20); + ZoneMapDetail zone_map_1(min_value_1, max_value_1, false); + ASSERT_TRUE(_pred->zone_map_filter(zone_map_1)); + + Datum min_value_2((int32_t)5); + Datum max_value_2((int32_t)25); + ZoneMapDetail zone_map_2(min_value_2, max_value_2, false); + ASSERT_TRUE(_pred->zone_map_filter(zone_map_2)); + + Datum min_value_3((int32_t)1); + Datum max_value_3((int32_t)5); + ZoneMapDetail zone_map_3(min_value_3, max_value_3, false); + ASSERT_FALSE(_pred->zone_map_filter(zone_map_3)); + + Datum min_value_4((int32_t)30); + Datum max_value_4((int32_t)40); + ZoneMapDetail zone_map_4(min_value_4, max_value_4, false); + ASSERT_FALSE(_pred->zone_map_filter(zone_map_4)); + + Datum min_value_5((int32_t)5); + Datum max_value_5((int32_t)25); + ZoneMapDetail zone_map_5(min_value_5, max_value_5, false); + ASSERT_TRUE(_pred->zone_map_filter(zone_map_5)); + + Datum min_value_6((int32_t)15); + Datum max_value_6((int32_t)40); + ZoneMapDetail zone_map_6(min_value_6, max_value_6, false); + ASSERT_TRUE(_pred->zone_map_filter(zone_map_6)); +} + +TEST_F(ColumnAndPredicateTest, convert_to) { + const ColumnPredicate* new_pred = nullptr; + Status st = _pred->convert_to(&new_pred, get_type_info(TYPE_INT), &_pool); + ASSERT_TRUE(st.ok()); + ASSERT_EQ(new_pred->debug_string(), "AND(0:(columnId(0)>=10), 1:(columnId(0)<=20))"); +} + +} // namespace starrocks diff --git a/be/test/storage/column_or_predicate_test.cpp b/be/test/storage/column_or_predicate_test.cpp new file mode 100644 index 0000000000000..cfd893dde4520 --- /dev/null +++ b/be/test/storage/column_or_predicate_test.cpp @@ -0,0 +1,76 @@ +// Copyright 2021-present StarRocks, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "storage/column_or_predicate.h" + +#include + +#include "testutil/column_test_helper.h" + +namespace starrocks { +class ColumnOrPredicateTest : public ::testing::Test { +public: + void SetUp() override { + _left.reset(new_column_eq_predicate(get_type_info(TYPE_INT), 0, "100")); + _right.reset(new_column_eq_predicate(get_type_info(TYPE_INT), 0, "200")); + _pred = std::make_unique(get_type_info(TYPE_INT), 0); + _pred->add_child(_left.get()); + _pred->add_child(_right.get()); + + std::vector values = {10, 100, 200, 0, 0}; + std::vector null_values = {0, 0, 0, 1, 1}; + _col = ColumnTestHelper::build_nullable_column(values, null_values); + } + +protected: + std::unique_ptr _left; + std::unique_ptr _right; + std::unique_ptr _pred; + ColumnPtr _col; +}; + +TEST_F(ColumnOrPredicateTest, basic) { + ASSERT_EQ(PredicateType::kOr, _pred->type()); + ASSERT_FALSE(_pred->can_vectorized()); + ASSERT_EQ(_pred->debug_string(), "OR(0:(columnId(0)=100), 1:(columnId(0)=200))"); +} + +TEST_F(ColumnOrPredicateTest, evaluate) { + std::vector buff = {0, 0, 0, 0, 0}; + auto st = _pred->evaluate(_col.get(), buff.data(), 0, 5); + ASSERT_TRUE(st.ok()); + + std::vector result = {0, 1, 1, 0, 0}; + ASSERT_EQ(buff, result); +} + +TEST_F(ColumnOrPredicateTest, evaluate_and) { + std::vector buff = {1, 1, 0, 1, 1}; + auto st = _pred->evaluate_and(_col.get(), buff.data(), 0, 5); + ASSERT_TRUE(st.ok()); + + std::vector result = {0, 1, 0, 0, 0}; + ASSERT_EQ(buff, result); +} + +TEST_F(ColumnOrPredicateTest, evaluate_or) { + std::vector buff = {1, 1, 1, 1, 0}; + auto st = _pred->evaluate_or(_col.get(), buff.data(), 0, 5); + ASSERT_TRUE(st.ok()); + + std::vector result = {1, 1, 1, 1, 0}; + ASSERT_EQ(buff, result); +} + +} // namespace starrocks diff --git a/be/test/storage/column_predicate_test.cpp b/be/test/storage/column_predicate_test.cpp index a73121d9a0157..a54a6e8a5c7dc 100644 --- a/be/test/storage/column_predicate_test.cpp +++ b/be/test/storage/column_predicate_test.cpp @@ -18,7 +18,6 @@ #include "gtest/gtest.h" #include "storage/chunk_helper.h" -#include "storage/column_or_predicate.h" #include "testutil/assert.h" namespace starrocks { @@ -1957,75 +1956,6 @@ TEST(ColumnPredicateTest, test_not_null) { } } -// NOLINTNEXTLINE -TEST(ColumnPredicateTest, test_or) { - { - std::unique_ptr p1(new_column_eq_predicate(get_type_info(TYPE_INT), 0, "100")); - std::unique_ptr p2(new_column_eq_predicate(get_type_info(TYPE_INT), 0, "200")); - - auto p = std::make_unique(get_type_info(TYPE_INT), 0); - p->add_child(p1.get()); - p->add_child(p2.get()); - - auto c = ChunkHelper::column_from_field_type(TYPE_INT, true); - c->append_datum(10); - c->append_datum(100); - c->append_datum(200); - (void)c->append_nulls(2); - - ASSERT_EQ(PredicateType::kOr, p->type()); - ASSERT_FALSE(p->can_vectorized()); - - // --------------------------------------------- - // evaluate() - // --------------------------------------------- - std::vector buff(5); - p->evaluate(c.get(), buff.data(), 0, 5); - ASSERT_EQ("0,1,1,0,0", to_string(buff)); - - p->evaluate(c.get(), buff.data(), 1, 3); - ASSERT_EQ("0,1,1,0,0", to_string(buff)); - - // --------------------------------------------- - // evaluate_and() - // --------------------------------------------- - buff.assign(5, 1); - p->evaluate_and(c.get(), buff.data(), 0, 5); - ASSERT_EQ("0,1,1,0,0", to_string(buff)); - - p->evaluate_and(c.get(), buff.data(), 1, 3); - ASSERT_EQ("0,1,1,0,0", to_string(buff)); - - buff.assign(5, 0); - p->evaluate_and(c.get(), buff.data(), 0, 5); - ASSERT_EQ("0,0,0,0,0", to_string(buff)); - - buff[2] = 1; - p->evaluate_and(c.get(), buff.data(), 0, 5); - ASSERT_EQ("0,0,1,0,0", to_string(buff)); - - p->evaluate_and(c.get(), buff.data(), 2, 4); - ASSERT_EQ("0,0,1,0,0", to_string(buff)); - - // --------------------------------------------- - // evaluate_or() - // --------------------------------------------- - buff.assign(5, 0); - p->evaluate_or(c.get(), buff.data(), 0, 5); - ASSERT_EQ("0,1,1,0,0", to_string(buff)); - - p->evaluate_or(c.get(), buff.data(), 2, 4); - ASSERT_EQ("0,1,1,0,0", to_string(buff)); - - buff.assign(5, 1); - p->evaluate_or(c.get(), buff.data(), 0, 5); - ASSERT_EQ("1,1,1,1,1", to_string(buff)); - - p->evaluate_or(c.get(), buff.data(), 2, 4); - ASSERT_EQ("1,1,1,1,1", to_string(buff)); - } -} - #define ZMF(min, max) zone_map_filter(ZoneMapDetail(min, max)) // NOLINTNEXTLINE