GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
56 / 56
100.0%
Branches:
38 / 46
82.6%
Functions:
6 / 6
100.0%

scene/holder_index.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file holder_index.cpp
3 /// @brief Re-indexing changed relationship cells, and finding a target's live holders.
4 #include "ernie/scene/holder_index.h"
5
6 #include "ernie/util/algorithm.h"
7
8 #include <algorithm>
9 #include <unordered_set>
10
11 namespace ernie {
12 namespace {
13
14 642 bool IsRelationship(ColumnType type) {
15 642 return type == ColumnType::Relationship || type == ColumnType::Relationships;
16 }
17
18 /// @return The targets of a relationship cell, without the unset one.
19 8712 std::vector<PathId> Targets(const PrimStore& store, BucketId bucket, const Column& column,
20 std::uint32_t row) {
21 8712 std::vector<PathId> targets =
22 8712 column.values->Type() == ColumnType::Relationship
23
2/2
✓ Branch 0 taken 8705 times.
✓ Branch 1 taken 7 times.
8712 ? std::vector<PathId>{store.Read<Target>(bucket, column.attribute)[row].path}
24 8712 : Map(store.Read<std::vector<Target>>(bucket, column.attribute)[row], &Target::path);
25 8712 std::erase(targets, kNoPath);
26 8712 return targets;
27 }
28
29 /// @return Whether the prim is alive and its relationship still targets `target`.
30 11 bool Holds(const PrimStore& store, PrimId prim, AttributeId attribute, PathId target) {
31
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 time.
11 if (!store.Alive(prim)) {
32 return false;
33 }
34 10 const BucketId bucket = store.PrimBucket(prim);
35 10 const Column* column = store.GetBucket(bucket).Find(attribute);
36
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
10 if (column == nullptr || !IsRelationship(column->values->Type())) {
37 1 return false;
38 }
39 9 const std::vector<PathId> targets = Targets(store, bucket, *column, store.PrimRow(prim));
40 9 return std::ranges::find(targets, target) != targets.end();
41 9 }
42
43 } // namespace
44
45 62 void HolderIndex::Update(const PrimStore& store) {
46 62 const ChangeSet changes = store.ChangesSince(cursor_);
47
2/2
✓ Branch 0 taken 633 times.
✓ Branch 1 taken 62 times.
695 for (const ChangeSet::Values& values : changes.values) {
48 633 const Bucket& bucket = store.GetBucket(values.bucket);
49 633 const Column& column = *bucket.Find(values.attribute);
50
3/4
✓ Branch 1 taken 633 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 580 times.
✓ Branch 4 taken 53 times.
633 if (!IsRelationship(column.values->Type())) {
51 580 continue;
52 }
53
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 53 times.
126 for (const RowRange range : values.rows) {
54
2/2
✓ Branch 0 taken 8703 times.
✓ Branch 1 taken 73 times.
8776 for (std::uint32_t row = range.begin; row < range.end; ++row) {
55
1/2
✓ Branch 1 taken 8703 times.
✗ Branch 2 not taken.
8703 Index(bucket.prims[row], values.attribute,
56
1/2
✓ Branch 1 taken 8703 times.
✗ Branch 2 not taken.
17406 Targets(store, values.bucket, column, row));
57 }
58 }
59 }
60 62 cursor_ = changes.version;
61 62 }
62
63 8703 void HolderIndex::Index(PrimId prim, AttributeId attribute, std::vector<PathId> targets) {
64 8703 const Cell cell = Key(prim, attribute);
65 8703 const auto found = targets_.find(cell);
66
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8700 times.
8703 if (found != targets_.end()) {
67
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
7 for (const PathId old : found->second) {
68 4 holders_[old].erase(cell);
69 }
70 }
71
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8703 times.
8715 for (const PathId target : targets) {
72 12 holders_[target][cell] = prim.generation;
73 }
74
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8692 times.
8703 if (!targets.empty()) {
75 11 targets_[cell] = std::move(targets);
76
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8690 times.
8692 } else if (found != targets_.end()) {
77 2 targets_.erase(found);
78 }
79 8703 }
80
81 6 std::vector<PrimId> HolderIndex::Find(const PrimStore& store, PathId target) const {
82 6 std::vector<PrimId> found;
83 6 const auto holders = holders_.find(target);
84
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (holders == holders_.end()) {
85 return found;
86 }
87 6 std::unordered_set<std::uint32_t> slots;
88
3/4
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 6 times.
28 for (const auto& [cell, generation] : holders->second) {
89 11 const PrimId prim{static_cast<std::uint32_t>(cell >> 32), generation};
90 // Cells of removed prims, or of prims since moved to a bucket without the attribute, stay
91 // until their slot's next prim writes them.
92
3/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 3 times.
11 if (Holds(store, prim, static_cast<AttributeId>(cell), target) &&
93
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
8 slots.insert(prim.slot).second) {
94
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 found.push_back(prim);
95 }
96 }
97 6 return found;
98 6 }
99
100 } // namespace ernie
101