BLI: refactor IndexMask for better performance and memory usage #104629
|
@ -69,6 +69,64 @@ struct IndexMaskSegment {
|
|||
OffsetSpan<int64_t, int16_t> indices;
|
||||
};
|
||||
|
||||
struct Expr {
|
||||
enum class Type {
|
||||
Atomic,
|
||||
Union,
|
||||
Difference,
|
||||
Complement,
|
||||
Intersection,
|
||||
};
|
||||
Type type;
|
||||
|
||||
Expr(const Type type) : type(type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct AtomicExpr : public Expr {
|
||||
const IndexMask *mask;
|
||||
|
||||
AtomicExpr(const IndexMask &mask) : Expr(Type::Atomic), mask(&mask)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct UnionExpr : public Expr {
|
||||
Vector<const Expr *> children;
|
||||
|
||||
UnionExpr(Vector<const Expr *> children) : Expr(Type::Union), children(std::move(children))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct DifferenceExpr : public Expr {
|
||||
const Expr *base = nullptr;
|
||||
Vector<const Expr *> children;
|
||||
|
||||
DifferenceExpr(const Expr &base, Vector<const Expr *> children)
|
||||
: Expr(Type::Difference), base(&base), children(std::move(children))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ComplementExpr : public Expr {
|
||||
const Expr *base = nullptr;
|
||||
|
||||
ComplementExpr(const Expr &base) : Expr(Type::Complement), base(&base)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct IntersectionExpr : public Expr {
|
||||
Vector<const Expr *> children;
|
||||
|
||||
IntersectionExpr(Vector<const Expr *> children)
|
||||
: Expr(Type::Intersection), children(std::move(children))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class IndexMask {
|
||||
private:
|
||||
IndexMaskData data_;
|
||||
|
@ -98,6 +156,7 @@ class IndexMask {
|
|||
template<typename T>
|
||||
static IndexMask from_indices(Span<T> indices, LinearAllocator<> &allocator);
|
||||
static IndexMask from_bits(BitSpan bits, LinearAllocator<> &allocator, int64_t offset = 0);
|
||||
static IndexMask from_expr(const Expr &expr, IndexRange universe, LinearAllocator<> &allocator);
|
||||
|
||||
template<typename T> void to_indices(MutableSpan<T> r_indices) const;
|
||||
void to_bits(MutableBitSpan r_bits, int64_t offset = 0) const;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "BLI_array.hh"
|
||||
#include "BLI_enumerable_thread_specific.hh"
|
||||
#include "BLI_index_mask2.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_strict_flags.h"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_timeit.hh"
|
||||
|
@ -363,6 +364,74 @@ IndexMask IndexMask::from_bits(const BitSpan bits,
|
|||
return bits_to_index_mask(bits, offset, allocator);
|
||||
}
|
||||
|
||||
static Set<int64_t> eval_expr(const Expr &base_expr, const IndexRange universe)
|
||||
{
|
||||
Set<int64_t> result;
|
||||
switch (base_expr.type) {
|
||||
case Expr::Type::Atomic: {
|
||||
const AtomicExpr &expr = static_cast<const AtomicExpr &>(base_expr);
|
||||
expr.mask->foreach_index([&](const int64_t i) {
|
||||
BLI_assert(universe.contains(i));
|
||||
result.add_new(i);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case Expr::Type::Union: {
|
||||
const UnionExpr &expr = static_cast<const UnionExpr &>(base_expr);
|
||||
for (const Expr *child : expr.children) {
|
||||
const Set<int64_t> child_result = eval_expr(*child, universe);
|
||||
for (const int64_t i : child_result) {
|
||||
result.add(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Expr::Type::Difference: {
|
||||
const DifferenceExpr &expr = static_cast<const DifferenceExpr &>(base_expr);
|
||||
result = eval_expr(*expr.base, universe);
|
||||
for (const Expr *child : expr.children) {
|
||||
const Set<int64_t> child_result = eval_expr(*child, universe);
|
||||
for (const int64_t i : child_result) {
|
||||
result.remove(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Expr::Type::Complement: {
|
||||
const ComplementExpr &expr = static_cast<const ComplementExpr &>(base_expr);
|
||||
const Set<int64_t> child_result = eval_expr(*expr.base, universe);
|
||||
for (const int64_t i : universe) {
|
||||
if (!child_result.contains(i)) {
|
||||
result.add_new(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Expr::Type::Intersection: {
|
||||
const IntersectionExpr &expr = static_cast<const IntersectionExpr &>(base_expr);
|
||||
BLI_assert(!expr.children.is_empty());
|
||||
result = eval_expr(*expr.children.first(), universe);
|
||||
for (const Expr *child : expr.children.as_span().drop_front(1)) {
|
||||
const Set<int64_t> child_result = eval_expr(*child, universe);
|
||||
result.remove_if([&](const int64_t i) { return !child_result.contains(i); });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
IndexMask IndexMask::from_expr(const Expr &expr,
|
||||
const IndexRange universe,
|
||||
LinearAllocator<> &allocator)
|
||||
{
|
||||
const Set<int64_t> indices_set = eval_expr(expr, universe);
|
||||
Vector<int64_t> indices;
|
||||
indices.extend(indices_set.begin(), indices_set.end());
|
||||
std::sort(indices.begin(), indices.end());
|
||||
return IndexMask::from_indices<int64_t>(indices, allocator);
|
||||
}
|
||||
|
||||
template<typename T> void IndexMask::to_indices(MutableSpan<T> r_indices) const
|
||||
{
|
||||
unique_sorted_indices::from_index_mask(*this, r_indices);
|
||||
|
|
|
@ -198,4 +198,22 @@ TEST(index_mask2, ForeachRange)
|
|||
EXPECT_EQ(ranges[2], IndexRange(40, 2));
|
||||
}
|
||||
|
||||
TEST(index_mask2, Expr)
|
||||
{
|
||||
LinearAllocator<> allocator;
|
||||
|
||||
const IndexMask mask1(IndexRange(10, 5));
|
||||
const IndexMask mask2(IndexRange(40, 5));
|
||||
const IndexMask mask3 = IndexMask::from_indices<int>({12, 13, 20, 21, 22}, allocator);
|
||||
|
||||
const AtomicExpr expr1{mask1};
|
||||
const AtomicExpr expr2{mask2};
|
||||
const AtomicExpr expr3{mask3};
|
||||
const UnionExpr union_expr({&expr1, &expr2});
|
||||
const DifferenceExpr difference_expr(union_expr, {&expr3});
|
||||
|
||||
const IndexMask result = IndexMask::from_expr(difference_expr, IndexRange(100), allocator);
|
||||
std::cout << result << "\n";
|
||||
}
|
||||
|
||||
} // namespace blender::index_mask::tests
|
||||
|
|
Loading…
Reference in New Issue