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 | 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 | 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 | 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 | 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 | 633 | if (!IsRelationship(column.values->Type())) { | |
| 51 | 580 | continue; | |
| 52 | } | ||
| 53 | 126 | for (const RowRange range : values.rows) { | |
| 54 | 8776 | for (std::uint32_t row = range.begin; row < range.end; ++row) { | |
| 55 | 8703 | Index(bucket.prims[row], values.attribute, | |
| 56 | 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 | 8703 | if (found != targets_.end()) { | |
| 67 | 7 | for (const PathId old : found->second) { | |
| 68 | 4 | holders_[old].erase(cell); | |
| 69 | } | ||
| 70 | } | ||
| 71 | 8715 | for (const PathId target : targets) { | |
| 72 | 12 | holders_[target][cell] = prim.generation; | |
| 73 | } | ||
| 74 | 8703 | if (!targets.empty()) { | |
| 75 | 11 | targets_[cell] = std::move(targets); | |
| 76 | 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 | 6 | if (holders == holders_.end()) { | |
| 85 | return found; | ||
| 86 | } | ||
| 87 | 6 | std::unordered_set<std::uint32_t> slots; | |
| 88 | 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 | 11 | if (Holds(store, prim, static_cast<AttributeId>(cell), target) && | |
| 93 | 8 | slots.insert(prim.slot).second) { | |
| 94 | 7 | found.push_back(prim); | |
| 95 | } | ||
| 96 | } | ||
| 97 | 6 | return found; | |
| 98 | 6 | } | |
| 99 | |||
| 100 | } // namespace ernie | ||
| 101 |