GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
383 / 444
86.3%
Branches:
459 / 790
58.1%
Functions:
51 / 56
91.1%

scene/json.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file json.cpp
3 /// @brief Reading scene files into the typed API and writing them back.
4 #include "ernie/scene/json.h"
5
6 #include "ernie/scene/json_value.h"
7 #include "ernie/scene/scene.h"
8 #include "ernie/scene/tokens.h"
9 #include "ernie/scene/xform.h"
10 #include "ernie/util/algorithm.h"
11 #include "ernie/util/file.h"
12 #include "ernie/util/profiler.h"
13 #include "ernie/util/text.h"
14
15 #include <glm/gtc/matrix_access.hpp>
16
17 #include <algorithm>
18 #include <array>
19 #include <charconv>
20 #include <cmath>
21 #include <cstdlib>
22 #include <stdexcept>
23
24 namespace ernie {
25 namespace {
26
27 // Reading.
28
29
4/6
glm::vec<2, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<2>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
glm::vec<3, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<3>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 1 time.
glm::vec<4, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<4>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
108 template <glm::length_t N> glm::vec<N, double> Vector(const Json& json) {
30
7/12
glm::vec<2, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<2>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
glm::vec<3, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<3>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 35 times.
glm::vec<4, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<4>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
108 if (!json.is_array() || json.size() != N) {
31
2/12
glm::vec<2, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<2>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
glm::vec<3, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<3>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
glm::vec<4, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<4>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 throw std::invalid_argument("takes " + std::to_string(N) + " numbers");
32 }
33 glm::vec<N, double> vector;
34
6/6
glm::vec<2, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<2>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
glm::vec<3, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<3>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 35 times.
glm::vec<4, double, (glm::qualifier)0> ernie::(anonymous namespace)::Vector<4>(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&):
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 48 times.
452 for (glm::length_t i = 0; i < N; ++i) {
35 345 vector[i] = json[static_cast<std::size_t>(i)].get<double>();
36 }
37 107 return vector;
38 }
39
40 8 glm::dquat Quaternion(const Json& json) {
41 8 const glm::dvec4 wxyz = Vector<4>(json);
42 8 return {wxyz[0], wxyz[1], wxyz[2], wxyz[3]};
43 }
44
45 10 glm::dmat4 Matrix(const Json& json) {
46
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (!json.is_array() || json.size() != 4) {
47
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("takes 4 rows of 4 numbers");
48 }
49 glm::dmat4 matrix;
50
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 10 times.
50 for (int row = 0; row < 4; ++row) {
51 40 const glm::dvec4 numbers = Vector<4>(json[static_cast<std::size_t>(row)]);
52
2/2
✓ Branch 0 taken 160 times.
✓ Branch 1 taken 40 times.
200 for (int column = 0; column < 4; ++column) {
53
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 160 times.
160 matrix[column][row] = numbers[column];
54 }
55 }
56 10 return matrix;
57 }
58
59 10 bool IsMatrix(const Json& json) {
60
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 return json.size() == 4 && std::ranges::all_of(json, [](const Json& row) {
61
2/4
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
40 return row.is_array() && row.size() == 4;
62 10 });
63 }
64
65 /// @return The column type an undeclared attribute's JSON suggests.
66 35 ColumnType Infer(std::string_view name, const Json& json) {
67
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 3 times.
35 if (name.starts_with(tokens::kOrient)) {
68 return ColumnType::Quat;
69 }
70
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 1 time.
32 if (json.is_boolean()) {
71 return ColumnType::Bool;
72 }
73
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 4 times.
31 if (json.is_number_integer()) {
74 return ColumnType::Int;
75 }
76
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
62 if (json.is_number()) {
77 return ColumnType::Double;
78 }
79
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 7 times.
27 if (json.is_string()) {
80 return ColumnType::TokenValue;
81 }
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!json.is_array()) {
83
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("is not a value");
84 }
85
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 1 time.
41 if (!json.empty() && std::ranges::all_of(json, [](const Json& j) { return j.is_string(); })) {
86 return ColumnType::TokenArray;
87 }
88
3/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 10 times.
19 if (!json.empty() && json.front().is_array()) {
89
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 return IsMatrix(json) ? ColumnType::Matrix : ColumnType::Tensor;
90 }
91 9 static constexpr std::array kVectors{ColumnType::Vec2, ColumnType::Vec3, ColumnType::Vec4};
92
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 return json.size() >= 2 && json.size() <= 4 ? kVectors[json.size() - 2]
93 : ColumnType::FloatArray;
94 }
95
96 416 Value ReadValue(const Json& json, ColumnType type) {
97
12/14
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 173 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 78 times.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 14 times.
✓ Branch 11 taken 17 times.
✓ Branch 12 taken 18 times.
✗ Branch 13 not taken.
416 switch (type) {
98 13 case ColumnType::Bool:
99 13 return json.get<bool>();
100 25 case ColumnType::Int:
101 25 return json.get<int>();
102 173 case ColumnType::Double:
103 173 return json.get<double>();
104 24 case ColumnType::Vec2:
105 24 return Vector<2>(json);
106 23 case ColumnType::Vec3:
107 23 return Vector<3>(json);
108 ✗ case ColumnType::Vec4:
109 ✗ return Vector<4>(json);
110 3 case ColumnType::Quat:
111 3 return Quaternion(json);
112 10 case ColumnType::Matrix:
113 10 return Matrix(json);
114 78 case ColumnType::TokenValue:
115 78 return json.get<std::string>();
116 18 case ColumnType::Relationship:
117
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
36 return Path(json.get<std::string>());
118 14 case ColumnType::Relationships: {
119 14 std::vector<Path> targets;
120
6/14
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 12 taken 14 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 28 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 14 times.
✓ Branch 18 taken 14 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
56 for (const Json& target : json.is_string() ? Json::array({json}) : json) {
121
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
28 targets.emplace_back(target.get<std::string>());
122 14 }
123 14 return targets;
124 14 }
125 17 case ColumnType::FloatArray:
126 17 return json.get<std::vector<float>>();
127 18 case ColumnType::TokenArray:
128 18 return json.get<std::vector<std::string>>();
129 case ColumnType::Tensor:
130 break;
131 }
132
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("is an array, not a value");
133
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ }
134
135 /// @return Nested arrays as a CPU tensor: int32 for integer attributes, bytes for raw ones and
136 /// float32 for the rest.
137 61 Tensor ReadTensor(const Json& json, const AttributeMeta* meta) {
138 61 std::vector<std::int64_t> shape;
139
3/4
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 61 times.
145 for (const Json* level = &json; level->is_array(); level = &level->front()) {
140
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 shape.push_back(static_cast<std::int64_t>(level->size()));
141
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if (level->empty()) {
142 break;
143 }
144 }
145 61 std::vector<double> numbers;
146 456 const auto flatten = [&](const auto& self, const Json& level, std::size_t depth) -> void {
147
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 128 times.
395 if (depth == shape.size()) {
148 267 numbers.push_back(level.get<double>());
149 267 return;
150 }
151
2/4
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 128 times.
128 if (!level.is_array() || static_cast<std::int64_t>(level.size()) != shape[depth]) {
152
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("rows of an array are all one length");
153 }
154
2/2
✓ Branch 6 taken 334 times.
✓ Branch 7 taken 128 times.
718 for (const Json& item : level) {
155 334 self(self, item, depth + 1);
156 }
157 61 };
158
1/2
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
61 flatten(flatten, json, 0);
159 61 const auto copy = [&]<typename T>(std::type_identity<T>) {
160 61 std::vector<T> values(numbers.size());
161 61 std::ranges::transform(numbers, values.begin(),
162 [](double number) { return static_cast<T>(number); });
163
4/12
auto ernie::(anonymous namespace)::ReadTensor(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, ernie::AttributeMeta const*)::{lambda<typename $T0>(std::type_identity<$T0>)#1}::operator()<float>(std::type_identity<float>) const:
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
auto ernie::(anonymous namespace)::ReadTensor(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, ernie::AttributeMeta const*)::{lambda<typename $T0>(std::type_identity<$T0>)#1}::operator()<int>(std::type_identity<int>) const:
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
auto ernie::(anonymous namespace)::ReadTensor(nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, ernie::AttributeMeta const*)::{lambda<typename $T0>(std::type_identity<$T0>)#1}::operator()<unsigned char>(std::type_identity<unsigned char>) const:
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
61 return Tensor::Copy<T>(values, shape);
164 61 };
165
2/4
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 61 times.
61 if (meta != nullptr && meta->bytes) {
166
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ return copy(std::type_identity<std::uint8_t>{});
167 }
168
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 32 times.
61 if (meta != nullptr && meta->integer) {
169
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 return copy(std::type_identity<std::int32_t>{});
170 }
171
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 return copy(std::type_identity<float>{});
172 61 }
173
174 27 RotationOrder ReadRotationOrder(const Json& json) {
175 27 const std::string name =
176
2/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
81 std::string(tokens::kXformOpPrefix) + "rotate" + json.get<std::string>();
177 36 for (const RotationOrder order : {RotationOrder::XYZ, RotationOrder::XZY, RotationOrder::YXZ,
178
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 1 time.
63 RotationOrder::YZX, RotationOrder::ZXY, RotationOrder::ZYX}) {
179
3/4
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 36 times.
62 if (RotateOp(order) == name) {
180 26 return order;
181 }
182 }
183
1/2
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 throw std::invalid_argument("rotationOrder is one of XYZ, XZY, YXZ, YZX, ZXY or ZYX");
184 }
185
186 } // namespace
187
188 33 XformOps ReadXform(const Json& json) {
189 33 XformOps xform;
190
5/8
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 82 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 51 times.
✓ Branch 13 taken 31 times.
82 for (const auto& [key, value] : json.items()) {
191
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 43 times.
51 if (key == "translate") {
192
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
16 xform.translate = Vector<3>(value);
193
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 38 times.
43 } else if (key == "rotate") {
194
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 xform.rotate = Vector<3>(value);
195
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 11 times.
38 } else if (key == "rotationOrder") {
196
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 1 time.
27 xform.rotationOrder = ReadRotationOrder(value);
197
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
11 } else if (key == "orient") {
198
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 xform.orient = Quaternion(value);
199
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
6 } else if (key == "scale") {
200
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
12 xform.scale = value.is_number() ? glm::dvec3(value.get<double>()) : Vector<3>(value);
201 } else {
202
2/4
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
3 throw std::invalid_argument("has no op '" + key + "'");
203 }
204 33 }
205 31 return xform;
206 }
207
208 480 void LoadAttribute(Scene& scene, PrimId prim, const std::string& name, const Json& json,
209 std::span<const Tensor> arrays, std::optional<double> time) {
210 543 const auto write = [&](Tensor array) {
211
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 61 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
65 time ? scene.WriteAt(prim, name, *time, std::move(array))
212
5/6
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 1 time.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 60 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
64 : scene.Write(prim, name, std::move(array));
213 62 };
214 480 const AttributeDef* def = scene.Declaration(prim, name);
215
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 477 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
480 if (json.is_object() && json.contains(kArray)) {
216 3 const auto index = json[kArray].get<std::size_t>();
217
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if (index >= arrays.size()) {
218
3/6
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
3 throw std::invalid_argument("names array " + std::to_string(index) + " of " +
219
2/4
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
3 std::to_string(arrays.size()));
220 }
221
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 write(arrays[index]);
222 2 return;
223 }
224
2/2
✓ Branch 0 taken 442 times.
✓ Branch 1 taken 35 times.
477 const ColumnType type = def != nullptr ? def->type : Infer(name, json);
225
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 416 times.
477 if (type == ColumnType::Tensor) {
226
3/4
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 60 times.
✓ Branch 5 taken 1 time.
61 write(ReadTensor(json, def != nullptr ? &def->meta : nullptr));
227 } else {
228 416 const Value value = ReadValue(json, type);
229
5/6
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 400 times.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 396 times.
✓ Branch 7 taken 4 times.
414 time ? scene.SetAt(prim, name, *time, value) : scene.Set(prim, name, value);
230 410 }
231 }
232
233 namespace {
234
235 /// Authors an attribute's samples: `"radius.timeSamples": {"0": 1, "24": 2}`, as USD writes them.
236 8 void LoadSamples(Scene& scene, PrimId prim, const std::string& name, const Json& json,
237 std::span<const Tensor> arrays) {
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!json.is_object()) {
239
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("maps time codes to values");
240 }
241
5/8
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 24 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 16 times.
✓ Branch 12 taken 8 times.
24 for (const auto& [time, value] : json.items()) {
242 16 std::size_t end = 0;
243
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 const double code = std::stod(time, &end);
244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (end != time.size()) {
245
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ throw std::invalid_argument("'" + time + "' is no time code");
246 }
247
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 LoadAttribute(scene, prim, name, value, arrays, code);
248 8 }
249 8 }
250
251 /// @return The scene's message without the prim it opens with ("'/Ball' (Sphere) has ..."), which
252 /// the problem names already.
253 15 std::string WithoutPrim(std::string what, const Path& path) {
254 30 const std::string prim = "'" + path.String() + "'";
255
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 10 times.
15 if (what.starts_with(prim)) {
256
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 what.erase(0, prim.size());
257
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
5 if (what.starts_with(" (")) {
258
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 what.erase(0, what.find(')') + 1);
259 }
260
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 what.erase(0, what.find_first_not_of(": "));
261 }
262 15 return what;
263 15 }
264
265 /// Runs `load`, a problem it throws recorded in `problems` when given, else thrown on.
266 /// @return Whether it loaded.
267 template <typename Load>
268 767 bool Attempt(std::vector<SceneProblem>* problems, const Path& path, std::string_view key,
269 const Load& load) {
270 try {
271
8/8
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✓ Branch 1 taken 175 times.
✓ Branch 2 taken 2 times.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2} const&):
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 2 times.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3} const&):
✓ Branch 1 taken 454 times.
✓ Branch 2 taken 8 times.
bool ernie::(anonymous namespace)::Attempt<ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 3 times.
767 load();
272 return true;
273
8/16
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2} const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3} const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
30 } catch (const std::exception& error) {
274
16/32
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2} const&):
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3} const&):
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 8 times.
✗ Branch 12 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
15 const SceneProblem problem{path.String(), std::string(key),
275 15 WithoutPrim(error.what(), path)};
276
6/8
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2} const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3} const&):
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
bool ernie::(anonymous namespace)::Attempt<ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
15 if (problems == nullptr) {
277
4/16
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2} const&):
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3} const&):
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
6 throw std::invalid_argument(problem.Message());
278 }
279
4/8
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#2} const&):
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::(anonymous namespace)::LoadPrim(ernie::Scene&, ernie::Path const&, nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> const&, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#3} const&):
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
bool ernie::(anonymous namespace)::Attempt<ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1}>(std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*, ernie::Path const&, std::basic_string_view<char, std::char_traits<char> >, ernie::LoadScene(ernie::Scene&, std::basic_string_view<char, std::char_traits<char> >, std::span<ernie::Tensor const, 18446744073709551615ul>, std::vector<ernie::SceneProblem, std::allocator<ernie::SceneProblem> >*)::{lambda()#1} const&):
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
12 problems->push_back(problem);
280 return false;
281 15 }
282 }
283
284 177 void LoadPrim(Scene& scene, const Path& path, const Json& json, std::span<const Tensor> arrays,
285 std::vector<SceneProblem>* problems) {
286 177 PrimId prim;
287 177 const bool defined = Attempt(problems, path, "", [&] {
288
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 176 times.
177 if (!json.is_object()) {
289
1/2
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 throw std::invalid_argument("a prim is an object");
290 }
291
3/4
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 1 time.
186 prim = json.contains(kTypeName) || !scene.Has(path)
292
10/12
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 166 times.
✓ Branch 3 taken 175 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 174 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 174 times.
✓ Branch 9 taken 1 time.
✓ Branch 10 taken 174 times.
✓ Branch 11 taken 1 time.
✓ Branch 12 taken 1 time.
✗ Branch 13 not taken.
537 ? scene.Define(path, json.value(kTypeName, std::string()))
293
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 : scene.Require(path);
294 175 });
295
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 175 times.
177 if (!defined) {
296 2 return;
297 }
298
5/8
✓ Branch 2 taken 175 times.
✗ Branch 3 not taken.
✓ Branch 9 taken 47 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 222 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 47 times.
✓ Branch 15 taken 175 times.
572 for (const Json& api : json.value(kApis, Json::array())) {
299
3/4
✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 45 times.
✓ Branch 7 taken 2 times.
139 Attempt(problems, path, kApis, [&] { scene.ApplyApi(prim, api.get<std::string>()); });
300 175 }
301
5/8
✓ Branch 3 taken 666 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 666 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 839 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 666 times.
✓ Branch 13 taken 173 times.
839 for (const auto& [key, value] : json.items()) {
302
4/4
✓ Branch 0 taken 501 times.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 462 times.
666 if (key == kTypeName || key == kApis) {
303 204 continue;
304 }
305
2/2
✓ Branch 1 taken 460 times.
✓ Branch 2 taken 2 times.
462 Attempt(problems, path, key, [&] {
306
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 452 times.
462 if (key == kXform) {
307 10 SetXform(scene, path, ReadXform(value));
308
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 444 times.
452 } else if (key.ends_with(kTimeSamples)) {
309
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 LoadSamples(scene, prim, key.substr(0, key.size() - kTimeSamples.size()), value,
310 arrays);
311 } else {
312 444 LoadAttribute(scene, prim, key, value, arrays);
313 }
314 454 });
315 348 }
316 }
317
318 // Writing.
319
320 1149 Json Finite(double number) {
321
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1148 times.
1149 if (!std::isfinite(number)) {
322
1/2
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 throw std::invalid_argument("JSON has no NaN or infinite numbers");
323 }
324 1148 return number;
325 }
326
327 /// @return A float as the double of its shortest decimal form, so it prints as written.
328 188 Json Shortest(float number) {
329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
188 if (!std::isfinite(number)) {
330 ✗ return Finite(number);
331 }
332 188 std::array<char, 32> text{};
333 188 const auto end = std::to_chars(text.data(), text.data() + text.size(), number).ptr;
334 188 *end = '\0';
335 188 return std::strtod(text.data(), nullptr);
336 }
337
338 187 template <typename Vector> Json Components(const Vector& vector) {
339 187 Json json = Json::array();
340
6/14
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<2, double, (glm::qualifier)0> >(glm::vec<2, double, (glm::qualifier)0> const&):
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 54 times.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<2, float, (glm::qualifier)0> >(glm::vec<2, float, (glm::qualifier)0> const&):
✗ Branch 0 not taken.
✗ Branch 1 not taken.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<2, int, (glm::qualifier)0> >(glm::vec<2, int, (glm::qualifier)0> const&):
✗ Branch 0 not taken.
✗ Branch 1 not taken.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<3, double, (glm::qualifier)0> >(glm::vec<3, double, (glm::qualifier)0> const&):
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 68 times.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<3, float, (glm::qualifier)0> >(glm::vec<3, float, (glm::qualifier)0> const&):
✗ Branch 0 not taken.
✗ Branch 1 not taken.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<4, double, (glm::qualifier)0> >(glm::vec<4, double, (glm::qualifier)0> const&):
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 65 times.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<4, float, (glm::qualifier)0> >(glm::vec<4, float, (glm::qualifier)0> const&):
✗ Branch 0 not taken.
✗ Branch 1 not taken.
759 for (glm::length_t i = 0; i < vector.length(); ++i) {
341 if constexpr (std::is_same_v<typename Vector::value_type, float>) {
342
0/12
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<2, float, (glm::qualifier)0> >(glm::vec<2, float, (glm::qualifier)0> const&):
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<3, float, (glm::qualifier)0> >(glm::vec<3, float, (glm::qualifier)0> const&):
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<4, float, (glm::qualifier)0> >(glm::vec<4, float, (glm::qualifier)0> const&):
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ json.push_back(Shortest(vector[i]));
343 } else if constexpr (std::is_same_v<typename Vector::value_type, double>) {
344
6/12
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<2, double, (glm::qualifier)0> >(glm::vec<2, double, (glm::qualifier)0> const&):
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 108 times.
✗ Branch 6 not taken.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<3, double, (glm::qualifier)0> >(glm::vec<3, double, (glm::qualifier)0> const&):
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 204 times.
✗ Branch 6 not taken.
nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void> ernie::(anonymous namespace)::Components<glm::vec<4, double, (glm::qualifier)0> >(glm::vec<4, double, (glm::qualifier)0> const&):
✓ Branch 2 taken 260 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 260 times.
✗ Branch 6 not taken.
572 json.push_back(Finite(vector[i]));
345 } else {
346
0/2
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ json.push_back(vector[i]);
347 }
348 }
349 187 return json;
350 ✗ }
351
352 } // namespace
353
354 1599 Json ToJson(const Value& value) {
355 1599 return std::visit(
356 145 [](const auto& v) -> Json {
357 using V = std::decay_t<decltype(v)>;
358 if constexpr (std::is_same_v<V, std::monostate>) {
359 return nullptr;
360 } else if constexpr (std::is_same_v<V, float>) {
361 return Shortest(v);
362 } else if constexpr (std::is_same_v<V, double>) {
363 return Finite(v);
364 } else if constexpr (std::is_same_v<V, glm::dquat>) {
365 5 return Components(glm::dvec4(v.w, v.x, v.y, v.z));
366 } else if constexpr (std::is_same_v<V, glm::dmat4>) {
367 14 Json rows = Json::array();
368
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
70 for (int row = 0; row < 4; ++row) {
369
2/4
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 56 times.
✗ Branch 6 not taken.
56 rows.push_back(Components(glm::row(v, row)));
370 }
371 28 return rows;
372 14 } else if constexpr (std::is_same_v<V, Path>) {
373 return v.String();
374 } else if constexpr (std::is_same_v<V, std::vector<Path>>) {
375
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 return Map(v, [](const Path& path) { return path.String(); });
376 } else if constexpr (std::is_same_v<V, std::vector<float>>) {
377
1/2
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
84 return Map(v, Shortest);
378 } else if constexpr (requires { V::length(); }) {
379 return Components(v);
380 } else {
381 return v;
382 }
383 },
384 1599 value.Raw());
385 }
386
387 namespace {
388
389 /// @return A CPU tensor as arrays nested by its shape.
390 48 Json WriteTensor(const Tensor& tensor) {
391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (!tensor.OnHost()) {
392
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("a GPU tensor cannot be written");
393 }
394 48 std::vector<Json> numbers;
395
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 20 times.
48 const DType type = tensor.Type();
396
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 20 times.
48 if (type == DType::Float16 || type == DType::Float32) {
397
2/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
56 numbers = Map(CopyFloats(tensor, "a tensor"), Shortest);
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 } else if (type == DType::Float64) {
399
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const Tensor packed = tensor.Contiguous();
400
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ numbers = Map(std::span(packed.As<double>(), static_cast<std::size_t>(packed.Elements())),
401 ✗ Finite);
402 ✗ } else {
403
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 numbers =
404
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 Map(CopyInts(tensor, "a tensor"), [](std::int64_t number) { return Json(number); });
405 }
406
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 const std::vector<std::int64_t>& shape = tensor.Shape();
407 48 std::size_t next = 0;
408 145 const auto nest = [&](const auto& self, std::size_t depth) -> Json {
409 97 Json level = Json::array();
410
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 const auto count = depth < shape.size() ? static_cast<std::size_t>(shape[depth]) : 1;
411
2/2
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 97 times.
344 for (std::size_t i = 0; i < count; ++i) {
412
5/8
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 198 times.
✓ Branch 3 taken 49 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 198 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 247 times.
✗ Branch 10 not taken.
247 level.push_back(depth + 1 < shape.size() ? self(self, depth + 1) : numbers[next++]);
413 }
414 97 return level;
415 ✗ };
416
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
96 return nest(nest, 0);
417 48 }
418
419 7 Json WriteSamples(std::span<const TimeSample> samples) {
420 7 Json json = Json::object();
421
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7 times.
21 for (const TimeSample& sample : samples) {
422
3/6
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 14 times.
✗ Branch 8 not taken.
28 json[Finite(sample.time).dump()] =
423
4/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
42 sample.tensor.Empty() ? ToJson(sample.value) : WriteTensor(sample.tensor);
424 }
425 7 return json;
426 ✗ }
427
428 /// @return A prim as scene files write it: type, API schemas, then attributes and their samples
429 /// by name.
430 90 Json WritePrim(const Scene& scene, const Path& path) {
431 90 const PrimId prim = *scene.Find(path);
432 90 Json json = Json::object();
433
3/4
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 15 times.
90 if (const std::string_view type = scene.TypeName(prim); !type.empty()) {
434
2/4
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
75 json[kTypeName] = type;
435 }
436
3/4
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 73 times.
90 if (const std::vector<std::string> apis = scene.AppliedApis(prim); !apis.empty()) {
437
2/4
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
17 json[kApis] = apis;
438 90 }
439
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 std::vector<std::string> names = scene.Attributes(path);
440 90 std::ranges::sort(names);
441
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 89 times.
290 for (const std::string& name : names) {
442 201 try {
443
1/2
✓ Branch 1 taken 201 times.
✗ Branch 2 not taken.
201 const Tensor* tensor = scene.Read(prim, name);
444
11/16
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 157 times.
✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 157 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 156 times.
✓ Branch 10 taken 1 time.
✓ Branch 12 taken 200 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 200 times.
✗ Branch 16 not taken.
✓ Branch 20 taken 156 times.
✓ Branch 21 taken 44 times.
✓ Branch 23 taken 1 time.
✗ Branch 24 not taken.
358 json[name] = tensor != nullptr ? WriteTensor(*tensor) : ToJson(*scene.Get(prim, name));
445
1/2
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
200 if (const std::span<const TimeSample> samples = scene.Samples(prim, name);
446
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 193 times.
200 !samples.empty()) {
447
4/8
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
7 json[name + std::string(kTimeSamples)] = WriteSamples(samples);
448 }
449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 } catch (const std::exception& error) {
450
5/14
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 13 not taken.
✓ Branch 15 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
2 throw std::invalid_argument(SceneProblem{path.String(), name, error.what()}.Message());
451 1 }
452 }
453 89 return json;
454 91 }
455
456 /// Prints JSON with 2-space indents, keeping arrays of scalars on one line.
457 6289 void Print(const Json& json, std::size_t indent, std::string& out) {
458
2/2
✓ Branch 1 taken 2106 times.
✓ Branch 2 taken 4183 times.
6289 const std::string pad(indent + 2, ' ');
459
4/4
✓ Branch 0 taken 2106 times.
✓ Branch 1 taken 4183 times.
✓ Branch 2 taken 2023 times.
✓ Branch 3 taken 83 times.
6289 if (json.is_object() && !json.empty()) {
460
1/2
✓ Branch 1 taken 2023 times.
✗ Branch 2 not taken.
2023 out += "{\n";
461
3/4
✓ Branch 4 taken 7883 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5860 times.
✓ Branch 7 taken 2023 times.
17789 for (auto item = json.begin(); item != json.end(); ++item) {
462
5/10
✓ Branch 1 taken 5860 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5860 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5860 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5860 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 5860 times.
✗ Branch 14 not taken.
17580 out += pad + Json(item.key()).dump() + ": ";
463
2/4
✓ Branch 1 taken 5860 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5860 times.
✗ Branch 5 not taken.
5860 Print(item.value(), indent + 2, out);
464
3/4
✓ Branch 2 taken 5860 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3837 times.
✓ Branch 5 taken 2023 times.
23440 out += std::next(item) == json.end() ? "\n" : ",\n";
465 }
466
3/6
✓ Branch 1 taken 2023 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2023 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2023 times.
✗ Branch 8 not taken.
6069 out += std::string(indent, ' ') + "}";
467
4/4
✓ Branch 0 taken 814 times.
✓ Branch 1 taken 3452 times.
✓ Branch 2 taken 690 times.
✓ Branch 3 taken 124 times.
5080 } else if (json.is_array() &&
468
3/4
✓ Branch 0 taken 1461 times.
✓ Branch 1 taken 22 times.
✓ Branch 4 taken 814 times.
✗ Branch 5 not taken.
3656 std::ranges::any_of(json, [](const Json& j) { return j.is_structured(); })) {
469
1/2
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
124 out += "[\n";
470 436 for (std::size_t i = 0; i < json.size(); ++i) {
471
1/2
✓ Branch 1 taken 312 times.
✗ Branch 2 not taken.
312 out += pad;
472
2/4
✓ Branch 1 taken 312 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 312 times.
✗ Branch 5 not taken.
312 Print(json[i], indent + 2, out);
473
4/4
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 312 times.
✓ Branch 3 taken 124 times.
748 out += i + 1 == json.size() ? "\n" : ",\n";
474 }
475
3/6
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 124 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 124 times.
✗ Branch 8 not taken.
372 out += std::string(indent, ' ') + "]";
476
2/2
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 3452 times.
4142 } else if (json.is_array()) {
477
4/8
✓ Branch 1 taken 1359 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 690 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 690 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 690 times.
✗ Branch 11 not taken.
3429 out += "[" + Join(json, ", ", [](const Json& item) { return item.dump(); }) + "]";
478 } else {
479
1/2
✓ Branch 1 taken 3452 times.
✗ Branch 2 not taken.
6904 out += json.dump();
480 }
481 6289 }
482
483 /// @return The scene file's prims.
484 81 Json ParsePrims(std::string_view text) {
485 81 Json root;
486 81 try {
487
2/2
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 2 times.
83 root = Json::parse(text);
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } catch (const Json::parse_error& error) {
489
2/4
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
6 throw std::invalid_argument(std::string("Not JSON: ") + error.what());
490 2 }
491
5/8
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 78 times.
✓ Branch 4 taken 1 time.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 78 times.
79 if (!root.is_object() || !root.contains(kPrims) || !root[kPrims].is_object()) {
492
1/2
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 throw std::invalid_argument("A scene file is an object with \"prims\"");
493 }
494
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
156 return std::move(root[kPrims]);
495 81 }
496
497 } // namespace
498
499 117 std::string PrintJson(const Json& json) {
500
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 std::string out;
501
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 Print(json, 0, out);
502
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 return out + "\n";
503 117 }
504
505 115 Json SceneFile(Json prims) {
506 115 Json root = Json::object();
507
3/6
✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 115 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 115 times.
✗ Branch 8 not taken.
115 root["$schema"] = std::string(kSceneSchemaUrl);
508
1/2
✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
115 root[kPrims] = std::move(prims);
509 115 return root;
510 ✗ }
511
512 81 void LoadScene(Scene& scene, std::string_view text, std::span<const Tensor> arrays,
513 std::vector<SceneProblem>* problems) {
514 81 ERNIE_ZONE("Load a scene");
515 81 Json prims;
516
4/4
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 1 time.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 78 times.
163 if (!Attempt(problems, Path(), "", [&] { prims = ParsePrims(text); })) {
517 2 return;
518 }
519
5/8
✓ Branch 3 taken 177 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 177 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 253 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 177 times.
✓ Branch 12 taken 76 times.
253 for (const auto& [path, prim] : prims.items()) {
520
3/4
✓ Branch 1 taken 177 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 175 times.
✓ Branch 5 taken 2 times.
354 LoadPrim(scene, Path(path), prim, arrays, problems);
521 80 }
522 84 }
523
524 17 std::string SceneProblem::Message() const {
525
5/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 14 times.
✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 12 times.
31 std::string message = path.empty() ? "" : "'" + path + "'";
526
5/8
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
46 message += key.empty() ? "" : (message.empty() ? "" : " ") + key;
527
5/8
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 14 times.
✗ Branch 10 not taken.
31 return message.empty() ? what : message + ": " + what;
528 17 }
529
530 3 void LoadSceneFile(Scene& scene, const std::filesystem::path& path) {
531 3 try {
532
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 LoadScene(scene, ReadTextFile(path));
533
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } catch (const std::runtime_error& error) {
534
0/2
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ throw std::invalid_argument(error.what());
535 ✗ }
536 3 }
537
538 8 std::string SaveScene(const Scene& scene) {
539 8 ERNIE_ZONE("Save a scene");
540
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 Json prims = Json::object();
541
3/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90 times.
✓ Branch 4 taken 7 times.
97 for (const Path& path : scene.Prims()) {
542
4/6
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 1 time.
✓ Branch 4 taken 89 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 89 times.
✗ Branch 8 not taken.
90 prims[path.String()] = WritePrim(scene, path);
543 8 }
544
2/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
14 return PrintJson(SceneFile(std::move(prims)));
545 9 }
546
547 1 void SaveSceneFile(const Scene& scene, const std::filesystem::path& path) {
548 1 const std::string text = SaveScene(scene);
549 1 try {
550
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 WriteTextFile(path, text);
551
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } catch (const std::runtime_error& error) {
552
0/2
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ throw std::invalid_argument(error.what());
553 ✗ }
554 1 }
555
556 } // namespace ernie
557