Blender V4.3
BLI_index_mask_expression_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "BLI_array.hh"
7#include "BLI_rand.hh"
8#include "BLI_set.hh"
9#include "BLI_strict_flags.h"
10#include "BLI_timeit.hh"
11
12#include "testing/testing.h"
13
15
16TEST(index_mask_expression, Union)
17{
18 IndexMaskMemory memory;
19 const IndexMask mask_a = IndexMask::from_initializers({5, IndexRange(50, 100), 100'000}, memory);
20 const IndexMask mask_b = IndexMask::from_initializers({IndexRange(10, 10), 60, 200}, memory);
21
22 ExprBuilder builder;
23 const Expr &expr = builder.merge({&mask_a, &mask_b});
24 const IndexMask union_mask = evaluate_expression(expr, memory);
25
26 EXPECT_EQ(union_mask,
28 {5, IndexRange(10, 10), IndexRange(50, 100), 200, 100'000}, memory));
29}
30
31TEST(index_mask_expression, UnionMulti)
32{
33 IndexMaskMemory memory;
34 const IndexMask mask_a = IndexMask::from_initializers({3, 5, 6, 8, 9}, memory);
35 const IndexMask mask_b = IndexMask::from_initializers({4, 6, 7, 12}, memory);
36 const IndexMask mask_c = IndexMask::from_initializers({0, 5}, memory);
37 const IndexMask mask_d = IndexMask::from_initializers({6, 7, 10}, memory);
38
39 ExprBuilder builder;
40 const Expr &expr = builder.merge({&mask_a, &mask_b, &mask_c, &mask_d});
41 const IndexMask union_mask = evaluate_expression(expr, memory);
42
43 EXPECT_EQ(union_mask, IndexMask::from_initializers({0, 3, 4, 5, 6, 7, 8, 9, 10, 12}, memory));
44}
45
46TEST(index_mask_expression, IntersectMulti)
47{
48 IndexMaskMemory memory;
49 const IndexMask mask_a = IndexMask::from_initializers({3, 5, 6, 8, 9}, memory);
50 const IndexMask mask_b = IndexMask::from_initializers({2, 5, 6, 10}, memory);
51 const IndexMask mask_c = IndexMask::from_initializers({4, 5, 6}, memory);
52 const IndexMask mask_d = IndexMask::from_initializers({1, 5, 10}, memory);
53
54 ExprBuilder builder;
55 const Expr &expr = builder.intersect({&mask_a, &mask_b, &mask_c, &mask_d});
56 const IndexMask intersect_mask = evaluate_expression(expr, memory);
57
58 EXPECT_EQ(intersect_mask, IndexMask::from_initializers({5}, memory));
59}
60
61TEST(index_mask_expression, DifferenceMulti)
62{
63 IndexMaskMemory memory;
64 const IndexMask mask_a = IndexMask::from_initializers({1, 2, 3, 5, 6, 7, 9, 10}, memory);
65 const IndexMask mask_b = IndexMask::from_initializers({2, 5, 6, 10}, memory);
66 const IndexMask mask_c = IndexMask::from_initializers({4, 5, 6}, memory);
67 const IndexMask mask_d = IndexMask::from_initializers({1, 5, 10}, memory);
68
69 ExprBuilder builder;
70 const Expr &expr = builder.subtract(&mask_a, {&mask_b, &mask_c, &mask_d});
71 const IndexMask difference_mask = evaluate_expression(expr, memory);
72
73 EXPECT_EQ(difference_mask, IndexMask::from_initializers({3, 7, 9}, memory));
74}
75
76TEST(index_mask_expression, Intersection)
77{
78 IndexMaskMemory memory;
79 const IndexMask mask_a = IndexMask::from_initializers({5, IndexRange(50, 100), 100'000}, memory);
81 {5, 6, IndexRange(100, 100), 80000, 100'000}, memory);
82
83 ExprBuilder builder;
84 const Expr &expr = builder.intersect({&mask_a, &mask_b});
85 const IndexMask intersection_mask = evaluate_expression(expr, memory);
86
87 EXPECT_EQ(intersection_mask,
88 IndexMask::from_initializers({5, IndexRange(100, 50), 100'000}, memory));
89}
90
91TEST(index_mask_expression, Difference)
92{
93 IndexMaskMemory memory;
94 const IndexMask mask_a = IndexMask::from_initializers({5, IndexRange(50, 100), 100'000}, memory);
95 const IndexMask mask_b = IndexMask::from_initializers({5, 60, IndexRange(100, 20)}, memory);
96
97 ExprBuilder builder;
98 const Expr &expr = builder.subtract(&mask_a, {&mask_b});
99 const IndexMask difference_mask = evaluate_expression(expr, memory);
100
101 EXPECT_EQ(difference_mask,
103 {IndexRange(50, 10), IndexRange(61, 39), IndexRange(120, 30), 100'000}, memory));
104}
105
106TEST(index_mask_expression, FizzBuzz)
107{
108 IndexMaskMemory memory;
109 const IndexMask mask_3 = IndexMask::from_every_nth(3, 11, 0, memory); /* 0 - 30 */
110 const IndexMask mask_5 = IndexMask::from_every_nth(5, 11, 0, memory); /* 0 - 50 */
111
112 {
113 ExprBuilder builder;
114 const Expr &expr = builder.merge({&mask_3, &mask_5});
115 const IndexMask result = evaluate_expression(expr, memory);
116 EXPECT_EQ(
117 result,
119 {0, 3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30, 35, 40, 45, 50}, memory));
120 }
121 {
122 ExprBuilder builder;
123 const Expr &expr = builder.intersect({&mask_3, &mask_5});
124 const IndexMask result = evaluate_expression(expr, memory);
125 EXPECT_EQ(result, IndexMask::from_initializers({0, 15, 30}, memory));
126 }
127 {
128 ExprBuilder builder;
129 const Expr &expr = builder.subtract(&mask_3, {&mask_5});
130 const IndexMask result = evaluate_expression(expr, memory);
131 EXPECT_EQ(result, IndexMask::from_initializers({3, 6, 9, 12, 18, 21, 24, 27}, memory));
132 }
133 {
134 ExprBuilder builder;
135 const Expr &expr = builder.merge(
136 {&builder.intersect({&mask_3, &mask_5}), &builder.subtract(&mask_3, {&mask_5})});
137 const IndexMask &result = evaluate_expression(expr, memory);
138 EXPECT_EQ(result,
139 IndexMask::from_initializers({0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30}, memory));
140 }
141}
142
143TEST(index_mask_expression, UnionToFullRange)
144{
145 IndexMaskMemory memory;
146 const IndexMask mask_1 = IndexMask::from_initializers({2, 4, 5, 7}, memory);
147 const IndexMask mask_2 = IndexMask::from_initializers({6, 8}, memory);
148 const IndexMask mask_3 = IndexMask::from_initializers({1, 3}, memory);
149
150 ExprBuilder builder;
151 const Expr &expr = builder.merge({&mask_1, &mask_2, &mask_3});
152 const IndexMask result = evaluate_expression(expr, memory);
153 EXPECT_TRUE(result.to_range().has_value());
154 EXPECT_EQ(*result.to_range(), IndexRange::from_begin_end_inclusive(1, 8));
155 EXPECT_EQ(result.segments_num(), 1);
156}
157
158TEST(index_mask_expression, UnionIndividualIndices)
159{
160 IndexMaskMemory memory;
161 const IndexMask mask_1 = IndexMask::from_initializers({3}, memory);
162 const IndexMask mask_2 = IndexMask::from_initializers({6}, memory);
163 const IndexMask mask_3 = IndexMask::from_initializers({5}, memory);
164
165 ExprBuilder builder;
166 const Expr &expr = builder.merge({&mask_1, &mask_2, &mask_3});
167 const IndexMask result = evaluate_expression(expr, memory);
168 EXPECT_EQ(result, IndexMask::from_initializers({3, 5, 6}, memory));
169 EXPECT_EQ(result.segments_num(), 1);
170}
171
172TEST(index_mask_expression, UnionLargeRanges)
173{
174 IndexMaskMemory memory;
175 const IndexMask mask_a(IndexRange(0, 1'000'000));
176 const IndexMask mask_b(IndexRange(900'000, 1'100'000));
177
178 ExprBuilder builder;
179 const Expr &expr = builder.merge({&mask_a, &mask_b});
180 const IndexMask result_mask = evaluate_expression(expr, memory);
181
182 EXPECT_EQ(result_mask, IndexMask(IndexRange(0, 2'000'000)));
183}
184
185TEST(index_mask_expression, SubtractSmall)
186{
187 IndexMaskMemory memory;
188 const IndexMask mask_a = IndexMask::from_initializers({3, 4, 5, 6, 7, 8, 9}, memory);
189 const IndexMask mask_b = IndexMask::from_initializers({5, 7}, memory);
190 const IndexMask mask_c = IndexMask::from_initializers({8}, memory);
191
192 ExprBuilder builder;
193 const Expr &expr = builder.subtract(&mask_a, {&mask_b, &mask_c});
194 const IndexMask result = evaluate_expression(expr, memory);
195
196 EXPECT_EQ(result, IndexMask::from_initializers({3, 4, 6, 9}, memory));
197 EXPECT_EQ(result.segments_num(), 1);
198}
199
200TEST(index_mask_expression, RangeTerms)
201{
202 IndexMaskMemory memory;
203 ExprBuilder builder;
204
205 const IndexRange range_a = IndexRange::from_begin_end(30'000, 50'000);
206 const IndexRange range_b = IndexRange::from_begin_end(40'000, 100'000);
207 const IndexRange range_c = IndexRange::from_begin_end(45'000, 48'000);
208
209 const Expr &expr = builder.subtract(&builder.merge({range_a, range_b}), {range_c});
210 const IndexMask result_mask = evaluate_expression(expr, memory);
211
212 EXPECT_EQ(result_mask,
214 IndexRange::from_begin_end(48'000, 100'000)},
215 memory));
216}
217
218TEST(index_mask_expression, SingleMask)
219{
220 IndexMaskMemory memory;
221 const IndexMask mask = IndexMask::from_initializers({5, 6, 8, 9}, memory);
222
223 ExprBuilder builder;
224 const Expr &expr = builder.merge({&mask});
225 const IndexMask result = evaluate_expression(expr, memory);
226
227 EXPECT_EQ(result, mask);
228}
229
230TEST(index_mask_expression, SubtractSelf)
231{
232 IndexMaskMemory memory;
233 const IndexMask mask = IndexMask ::from_initializers({6, 8, 10, 100}, memory);
234
235 ExprBuilder builder;
236 const Expr &expr = builder.subtract(&mask, {&mask});
237 const IndexMask result = evaluate_expression(expr, memory);
238
239 EXPECT_TRUE(result.is_empty());
240}
241
242/* Disable benchmark by default. */
243#if 0
244TEST(index_mask_expression, Benchmark)
245{
246# ifdef NDEBUG
247 const int64_t iterations = 100;
248# else
249 const int64_t iterations = 1;
250# endif
251
252 for ([[maybe_unused]] const int64_t _1 : IndexRange(5)) {
254 const IndexMask a = IndexMask::from_every_nth(3, 1'000'000, 0, m);
255 const IndexMask b = IndexMask::from_every_nth(100, 5'000, 0, m);
256 ExprBuilder builder;
257 const Expr &expr = builder.merge({&a, &b});
258
259 SCOPED_TIMER("benchmark");
260 for ([[maybe_unused]] const int64_t _2 : IndexRange(iterations)) {
261 IndexMaskMemory memory;
262 const IndexMask result = evaluate_expression(expr, memory);
263 UNUSED_VARS(result);
264 }
265 }
266}
267#endif
268
269} // namespace blender::index_mask::tests
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
#define SCOPED_TIMER(name)
Definition BLI_timeit.hh:61
#define UNUSED_VARS(...)
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
static constexpr IndexRange from_begin_end_inclusive(const int64_t begin, const int64_t last)
const IntersectionExpr & intersect(const Span< Term > terms)
const UnionExpr & merge(const Span< Term > terms)
const DifferenceExpr & subtract(const Term &main_term, const Span< Term > subtract_terms)
static IndexMask from_every_nth(int64_t n, int64_t indices_num, const int64_t initial_offset, IndexMaskMemory &memory)
static IndexMask from_initializers(const Span< Initializer > initializers, IndexMaskMemory &memory)
local_group_size(16, 16) .push_constant(Type b
IndexMask evaluate_expression(const Expr &expression, IndexMaskMemory &memory)
__int64 int64_t
Definition stdint.h:89