GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
173 / 173
100.0%
Branches:
70 / 84
83.3%
Functions:
40 / 40, 4 excl
100.0%

scene/schema.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file schema.h
3 /// @brief The schema registry: prim types, API schemas and their attributes, declared once.
4 #pragma once
5
6 #include "ernie/export.h"
7 #include "ernie/geometry/bounds.h"
8 #include "ernie/scene/storage.h"
9 #include "ernie/scene/tokens.h"
10 #include "ernie/scene/value.h"
11
12 #include <array>
13 #include <cstdint>
14 #include <optional>
15 #include <span>
16 #include <string>
17 #include <string_view>
18 #include <vector>
19
20 namespace ernie {
21
22 /// What changed about a prim, as bit flags; each attribute declares which it raises.
23 enum class Dirty : std::uint32_t {
24 None = 0,
25 Added = 1u << 0,
26 Removed = 1u << 1,
27 Transform = 1u << 2,
28 Topology = 1u << 3,
29 Points = 1u << 4,
30 Primvars = 1u << 5,
31 Material = 1u << 6,
32 Params = 1u << 7,
33 Visibility = 1u << 8,
34 };
35
36 constexpr Dirty operator|(Dirty a, Dirty b) {
37 return static_cast<Dirty>(static_cast<std::uint32_t>(a) | static_cast<std::uint32_t>(b));
38 }
39 162 constexpr Dirty operator&(Dirty a, Dirty b) {
40 162 return static_cast<Dirty>(static_cast<std::uint32_t>(a) & static_cast<std::uint32_t>(b));
41 }
42 constexpr Dirty& operator|=(Dirty& a, Dirty b) {
43 return a = a | b;
44 }
45 /// @return Whether `bits` has any of `flags`.
46 162 constexpr bool Any(Dirty bits, Dirty flags) {
47
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 89 times.
162 return (bits & flags) != Dirty::None;
48 }
49
50 /// @brief A limit of an attribute's numbers, inclusive or not.
51 struct Bound {
52 double value = 0.0;
53 bool exclusive = false;
54 };
55 constexpr Bound AtLeast(double value) {
56 return {value, false};
57 }
58 constexpr Bound Above(double value) {
59 return {value, true};
60 }
61 constexpr Bound AtMost(double value) {
62 return {value, false};
63 }
64 constexpr Bound Below(double value) {
65 return {value, true};
66 }
67
68 /// @brief What users need to author an attribute without reading code, and what it checks.
69
1/2
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
8478 struct AttributeMeta {
70 std::string_view doc{};
71 std::string_view label{};
72 std::string_view group{};
73 /// A slider's range in editors; 0 and 0 for none.
74 double min = 0.0;
75 double max = 0.0;
76 /// What `Set` accepts, per component.
77 std::optional<Bound> lower{};
78 std::optional<Bound> upper{};
79 bool finite = false;
80 /// The tokens a token attribute takes; any when empty.
81 std::vector<std::string_view> options{};
82 bool color = false;
83 bool asset = false;
84 /// A tensor of integers rather than floats.
85 bool integer = false;
86 /// A tensor of raw bytes, in elements of any type.
87 bool bytes = false;
88 /// A tensor's vector size: (n, components) or flat; 0 for a flat array.
89 std::uint8_t components = 0;
90 /// The ranks a tensor may have, as a dense grid's 3; none for flat or vector arrays.
91 std::vector<std::int64_t> ranks{};
92 Dirty dirty = Dirty::Params;
93 /// Resolved from the nearest ancestor authoring it (other than as "inherited") into its
94 /// `ResolvedName` column.
95 bool inherited = false;
96 };
97
98 /// @brief One declared attribute.
99 struct AttributeDef {
100 std::string_view name;
101 ColumnType type = ColumnType::Double;
102 Value fallback;
103 AttributeMeta meta;
104 };
105
106 enum class SchemaKind : std::uint8_t {
107 /// A base of other types, never a prim's own type.
108 Abstract,
109 /// A prim type.
110 Concrete,
111 /// An API schema applied once (`MaterialBindingAPI`).
112 SingleApply,
113 /// An API schema applied under instance names (`CollectionAPI:<name>`).
114 MultipleApply,
115 };
116
117 class Scene;
118
119 /// @brief A bucket's prims as an extent function reads them: columns by attribute name, and the
120 /// scene for rules that read other prims.
121 struct ExtentRows {
122 const PrimStore& store;
123 BucketId bucket = 0;
124 const Scene* scene = nullptr;
125
126 /// @return The column of a declared attribute.
127 328 template <typename T> std::span<const T> Column(std::string_view attribute) const {
128 328 const std::optional<Token> token = store.Paths().Names().Find(attribute);
129
8/16
std::span<double const, 18446744073709551615ul> ernie::ExtentRows::Column<double>(std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 225 times.
✗ Branch 1 not taken.
std::span<ernie::Target const, 18446744073709551615ul> ernie::ExtentRows::Column<ernie::Target>(std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
std::span<ernie::Tensor const, 18446744073709551615ul> ernie::ExtentRows::Column<ernie::Tensor>(std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
std::span<glm::vec<2, double, (glm::qualifier)0> const, 18446744073709551615ul> ernie::ExtentRows::Column<glm::vec<2, double, (glm::qualifier)0> >(std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
std::span<int const, 18446744073709551615ul> ernie::ExtentRows::Column<int>(std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
std::span<std::vector<ernie::Target, std::allocator<ernie::Target> > const, 18446744073709551615ul> ernie::ExtentRows::Column<std::vector<ernie::Target, std::allocator<ernie::Target> > >(std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
std::span<std::vector<float, std::allocator<float> > const, 18446744073709551615ul> ernie::ExtentRows::Column<std::vector<float, std::allocator<float> > >(std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
std::span<unsigned int const, 18446744073709551615ul> ernie::ExtentRows::Column<unsigned int>(std::basic_string_view<char, std::char_traits<char> >) const:
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
328 return token ? store.Read<T>(bucket, *token) : std::span<const T>();
130 }
131 27 std::string_view Text(Token token) const {
132 27 return store.Paths().Names().Text(token);
133 }
134 /// @return The live prim a relationship targets, or none.
135 std::optional<PrimId> Resolve(const Target& target) const;
136 /// @return The extent of the prim a relationship targets, brought into a row's own space
137 /// through the transforms between; none when it targets none or that has none.
138 std::optional<Box> TargetExtent(const Target& target, std::uint32_t row) const;
139 };
140
141 /// Computes the extents of a bucket's rows [begin, end) into `out`, one box each, in each prim's
142 /// own space. Written as a loop over columns, as the GPU kernels are.
143 using ExtentFunction = void (*)(const ExtentRows& rows, RowRange range, std::span<Box> out);
144
145 /// @brief Fills `out` with `extent(row)` for each row of `range`: the loop every extent function
146 /// runs.
147 template <typename Extent>
148 242 void ComputeRows(RowRange range, std::span<Box> out, const Extent& extent) {
149
38/38
void ernie::ComputeRows<ernie::(anonymous namespace)::AtmosphereExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::AtmosphereExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
void ernie::ComputeRows<ernie::(anonymous namespace)::DenseFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::DenseFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
void ernie::ComputeRows<ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::FileFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
void ernie::ComputeRows<ernie::(anonymous namespace)::InstancerExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::InstancerExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
void ernie::ComputeRows<ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::NanoVdbFieldExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
void ernie::ComputeRows<ernie::(anonymous namespace)::PointBasedExtent<false>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::PointBasedExtent<false>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
void ernie::ComputeRows<ernie::(anonymous namespace)::PointBasedExtent<true>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::PointBasedExtent<true>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
void ernie::ComputeRows<ernie::(anonymous namespace)::TerrainExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::TerrainExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
void ernie::ComputeRows<ernie::(anonymous namespace)::VolumeExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::(anonymous namespace)::VolumeExtent(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
void ernie::ComputeRows<ernie::CentredExtent<&(auto ernie::(anonymous namespace)::RadiusHalves<false>(ernie::ExtentRows const&))>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&(auto ernie::(anonymous namespace)::RadiusHalves<false>(ernie::ExtentRows const&))>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
void ernie::ComputeRows<ernie::CentredExtent<&(auto ernie::(anonymous namespace)::RadiusHalves<true>(ernie::ExtentRows const&))>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&(auto ernie::(anonymous namespace)::RadiusHalves<true>(ernie::ExtentRows const&))>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
void ernie::ComputeRows<ernie::CentredExtent<&(auto ernie::(anonymous namespace)::RoundHalves<false>(ernie::ExtentRows const&))>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&(auto ernie::(anonymous namespace)::RoundHalves<false>(ernie::ExtentRows const&))>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
void ernie::ComputeRows<ernie::CentredExtent<&(auto ernie::(anonymous namespace)::RoundHalves<true>(ernie::ExtentRows const&))>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&(auto ernie::(anonymous namespace)::RoundHalves<true>(ernie::ExtentRows const&))>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
void ernie::ComputeRows<ernie::CentredExtent<&ernie::(anonymous namespace)::CubeHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&ernie::(anonymous namespace)::CubeHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
void ernie::ComputeRows<ernie::CentredExtent<&ernie::(anonymous namespace)::CylinderLightHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&ernie::(anonymous namespace)::CylinderLightHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
void ernie::ComputeRows<ernie::CentredExtent<&ernie::(anonymous namespace)::EmitterHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&ernie::(anonymous namespace)::EmitterHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
void ernie::ComputeRows<ernie::CentredExtent<&ernie::(anonymous namespace)::PlaneHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&ernie::(anonymous namespace)::PlaneHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
void ernie::ComputeRows<ernie::CentredExtent<&ernie::(anonymous namespace)::RectHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&ernie::(anonymous namespace)::RectHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
void ernie::ComputeRows<ernie::CentredExtent<&ernie::(anonymous namespace)::SphereHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1}>(ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>, ernie::CentredExtent<&ernie::(anonymous namespace)::SphereHalves>(ernie::ExtentRows const&, ernie::RowRange, std::span<ernie::Box, 18446744073709551615ul>)::{lambda(unsigned int)#1} const&):
✓ Branch 0 taken 12764 times.
✓ Branch 1 taken 185 times.
13063 for (std::uint32_t row = range.begin; row < range.end; ++row) {
150 12821 out[row - range.begin] = extent(row);
151 }
152 242 }
153
154 /// The extent function of prims centred on their origin. `kHalves(rows)` reads the columns once
155 /// and returns each row's half-size by row.
156 template <auto kHalves>
157 209 void CentredExtent(const ExtentRows& rows, RowRange range, std::span<Box> out) {
158 209 const auto half = kHalves(rows);
159 209 ComputeRows(range, out,
160 209 [&](std::uint32_t row) { return Box::Around(glm::dvec3(0.0), half(row)); });
161 209 }
162
163 /// @brief How a prim type is bounded, as USD's Boundable and non-Boundable bases divide them.
164 struct ExtentRule {
165 enum class Kind : std::uint8_t {
166 /// The base's rule.
167 Inherit,
168 /// An extent from the prim's attributes.
169 Computed,
170 /// Bounds only through its descendants (Xform, Scope).
171 Descendants,
172 /// Infinite: left out of framing (distant and dome lights, skies).
173 Unbounded,
174 /// Not geometric (cameras, materials, render settings).
175 None,
176 };
177 Kind kind = Kind::Inherit;
178 ExtentFunction compute = nullptr;
179 /// Reads other prims (a volume its fields), so it is computed afresh rather than cached.
180 bool readsOtherPrims = false;
181 };
182 /// An extent from other prims' (a volume's from its fields).
183 constexpr ExtentRule ComputedFromOtherPrims(ExtentFunction compute) {
184 return {ExtentRule::Kind::Computed, compute, true};
185 }
186 constexpr ExtentRule ComputedExtent(ExtentFunction compute) {
187 return {ExtentRule::Kind::Computed, compute};
188 }
189 inline constexpr ExtentRule kInheritExtent{};
190 inline constexpr ExtentRule kDescendantsExtent{ExtentRule::Kind::Descendants};
191 inline constexpr ExtentRule kUnbounded{ExtentRule::Kind::Unbounded};
192 inline constexpr ExtentRule kNoExtent{ExtentRule::Kind::None};
193
194 /// @brief A prim type or API schema: its base, attributes and extent rule.
195 struct SchemaDef {
196 std::string_view name;
197 const SchemaDef* base = nullptr;
198 SchemaKind kind = SchemaKind::Concrete;
199 std::string_view doc;
200 std::vector<AttributeDef> attributes;
201 ExtentRule extent;
202 /// Namespaces (`xformOp:`) or `*` whose undeclared attributes the type takes.
203 std::vector<std::string_view> openNamespaces;
204 /// API schemas every prim of the type has, as UsdLux's lights have `CollectionAPI:lightLink`.
205 std::vector<std::string_view> builtinApis;
206 /// Fallbacks the type changes for attributes of its bases or built-in schemas, as
207 /// DistantLight's brighter intensity.
208 std::vector<std::pair<std::string_view, Value>> fallbackOverrides;
209 /// The prim types an API schema may be applied to, as MeshLightAPI's Mesh; any when empty.
210 std::vector<std::string_view> appliesTo;
211
212 bool IsA(const SchemaDef& other) const;
213 bool IsOpen(std::string_view attribute) const;
214 /// @return The attribute, declared here or by a base.
215 const AttributeDef* Find(std::string_view attribute) const;
216 /// @return Every attribute, the bases' first.
217 std::vector<const AttributeDef*> AllAttributes() const;
218 /// @return The built-in API schemas of the type and its bases.
219 std::vector<std::string_view> AllBuiltinApis() const;
220 /// @return The fallback the type or its nearest base gives an attribute in place of its
221 /// declaration's, or null.
222 const Value* FallbackOverride(std::string_view attribute) const;
223 /// @return The type's fallback for an attribute: its own or a base's override, else the
224 /// declaration's.
225 1613 const Value& Fallback(const AttributeDef& def) const {
226
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
1613 const Value* override = FallbackOverride(def.name);
227
4/4
<unknown function 225>:
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 1 time.
<unknown function 69>:
✓ Branch 0 taken 1465 times.
✓ Branch 1 taken 1 time.
1613 return override != nullptr ? *override : def.fallback;
228 }
229 /// @return The rule, the nearest base's when inherited.
230 ExtentRule Extent() const;
231
232 /// @return This type or the nearest base `test` accepts, or null.
233 37494 template <typename Test> const SchemaDef* FirstInLineage(const Test& test) const {
234
3/4
✓ Branch 0 taken 14255 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17519 times.
✓ Branch 3 taken 730 times.
94852 for (const SchemaDef* type = this; type != nullptr; type = type->base) {
235
4/4
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 14162 times.
✓ Branch 2 taken 12207 times.
✓ Branch 3 taken 5312 times.
78772 if (test(*type)) {
236 return type;
237 }
238 }
239 return nullptr;
240 }
241 };
242
243 /// @return Whether `schema` is `base` or derives from it; false for no schema.
244 6339 inline bool IsA(const SchemaDef* schema, const SchemaDef& base) {
245
4/4
✓ Branch 0 taken 6037 times.
✓ Branch 1 taken 302 times.
✓ Branch 3 taken 728 times.
✓ Branch 4 taken 5309 times.
6339 return schema != nullptr && schema->IsA(base);
246 }
247
248 /// @brief Schemas of one family, as USD groups them in modules, documented on one reference page.
249 2336 struct SchemaFamily {
250 /// The page's file name, without `.md`.
251 std::string_view name;
252 std::string_view title;
253 /// The USD module its schemas mirror, as `UsdGeom`, and its documentation; empty for none.
254 std::string_view usdModule;
255 std::string_view usdUrl;
256 /// The schemas mirroring USD's, then Ernie's own.
257 std::vector<const SchemaDef*> usd;
258 std::vector<const SchemaDef*> ernie;
259 };
260
261 /// @return The registry, by family: every schema is in one.
262 std::span<const SchemaFamily> SchemaFamilies();
263 /// @return Every registered schema, bases before the types deriving from them.
264 std::span<const SchemaDef* const> Schemas();
265 /// @return The schema named `name`, or null.
266 const SchemaDef* FindSchema(std::string_view name);
267 /// @return Every attribute declared inherited, once each.
268 std::span<const AttributeDef* const> InheritedAttributes();
269 /// @return The inherited attribute named `name`, or null.
270 const AttributeDef* FindInherited(std::string_view name);
271 /// @return The column holding an inherited attribute's resolved values:
272 /// `ernie:resolved:visibility`.
273 2004 inline std::string ResolvedName(std::string_view attribute) {
274
2/4
✓ Branch 2 taken 2004 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2004 times.
✗ Branch 6 not taken.
4008 return std::string(tokens::kResolvedPrefix) + std::string(attribute);
275 }
276
277 /// What a multiple-apply schema's attribute names hold in place of the instance's name.
278 inline constexpr std::string_view kInstanceName = "__INSTANCE_NAME__";
279
280 /// @brief An applied API schema: `"MaterialBindingAPI"`, or `"CollectionAPI:lights"`.
281 struct ERNIE_API ApiName {
282 394 const SchemaDef* schema = nullptr;
283 std::string_view instance;
284
285 /// @throws std::invalid_argument for an unknown API schema or a missing or extra instance.
286 static ApiName Parse(std::string_view api);
287 /// @return A declared name with the instance's name in place of `kInstanceName`.
288 std::string Attribute(std::string_view declared) const;
289 /// @return The name `Parse` reads.
290 std::string ToString() const;
291
3/4
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 295 times.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
394 bool operator==(const ApiName&) const = default;
292 };
293
294 /// @brief Checks a value against a declared attribute's limits and options; the scene checks its
295 /// type as it converts it.
296 /// @param attribute The attribute's name, an instance's for a multiple-apply schema's.
297 /// @throws std::invalid_argument naming the prim, the attribute and the reason.
298 void Validate(const AttributeDef& def, std::string_view attribute, const Value& value,
299 const Path& path);
300 /// @brief Checks an array for a declared tensor attribute: its element type and vector size.
301 /// @throws std::invalid_argument naming the prim, the attribute and the reason.
302 void ValidateArray(const AttributeDef& def, std::string_view attribute, const Tensor& array,
303 const Path& path);
304
305 /// @brief The tokens of an enum a token attribute takes, in enumerator order.
306 template <typename E> struct ChoiceTokens;
307
308 /// @brief A token attribute read and written as the enum `E` (`ChoiceTokens<E>`).
309 template <typename E> struct Choice {};
310
311 } // namespace ernie
312