GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
132 / 191
69.1%
Branches:
52 / 76
68.4%
Functions:
34 / 36, 1 excl
94.4%

scene/convert.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file convert.h
3 /// @brief Conversions between `Value`s and column elements.
4 #pragma once
5
6 #include "ernie/scene/storage.h"
7 #include "ernie/scene/value.h"
8 #include "ernie/util/algorithm.h"
9
10 #include <cmath>
11 #include <optional>
12 #include <type_traits>
13 #include <vector>
14
15 namespace ernie {
16
17 /// @return A number of any width, or none.
18 7234 inline std::optional<double> ToNumber(const Value& value) {
19
2/2
✓ Branch 0 taken 3023 times.
✓ Branch 1 taken 4211 times.
7234 if (const auto* d = value.Get<double>()) {
20 4211 return *d;
21 }
22
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3022 times.
3023 if (const auto* f = value.Get<float>()) {
23 1 return *f;
24 }
25
2/2
✓ Branch 0 taken 1167 times.
✓ Branch 1 taken 1855 times.
3022 if (const auto* i = value.Get<int>()) {
26 1167 return *i;
27 }
28 1855 return std::nullopt;
29 }
30
31 /// @return A vector of N doubles from one of floats, doubles or (for two) ints, or none.
32
6/6
std::optional<glm::vec<2, double, (glm::qualifier)0> > ernie::ToVector<2>(ernie::Value const&):
✓ Branch 0 taken 1825 times.
✓ Branch 1 taken 117 times.
std::optional<glm::vec<3, double, (glm::qualifier)0> > ernie::ToVector<3>(ernie::Value const&):
✓ Branch 0 taken 1813 times.
✓ Branch 1 taken 6665 times.
std::optional<glm::vec<4, double, (glm::qualifier)0> > ernie::ToVector<4>(ernie::Value const&):
✓ Branch 0 taken 1808 times.
✓ Branch 1 taken 16 times.
12244 template <glm::length_t N> std::optional<glm::vec<N, double>> ToVector(const Value& value) {
33
5/6
std::optional<glm::vec<2, double, (glm::qualifier)0> > ernie::ToVector<2>(ernie::Value const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 1825 times.
std::optional<glm::vec<3, double, (glm::qualifier)0> > ernie::ToVector<3>(ernie::Value const&):
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1810 times.
std::optional<glm::vec<4, double, (glm::qualifier)0> > ernie::ToVector<4>(ernie::Value const&):
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1807 times.
12244 if (const auto* d = value.Get<glm::vec<N, double>>()) {
34 6798 return *d;
35 }
36
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1825 times.
5446 if (const auto* f = value.Get<glm::vec<N, float>>()) {
37 4 return glm::vec<N, double>(*f);
38 }
39 if constexpr (N == 2) {
40 1825 if (const auto* i = value.Get<glm::ivec2>()) {
41 ✗ return glm::dvec2(*i);
42 }
43 }
44 5442 return std::nullopt;
45 }
46
47 /// @return The numbers of a number, or the components of a vector; none for other values.
48 3107 inline std::vector<double> ToNumbers(const Value& value) {
49
2/2
✓ Branch 0 taken 1255 times.
✓ Branch 1 taken 1852 times.
3107 if (const std::optional<double> number = ToNumber(value)) {
50 1255 return {*number};
51 }
52 45 const auto components = [](const auto& vector) {
53 45 std::vector<double> numbers(static_cast<std::size_t>(vector.length()));
54
4/6
auto ernie::ToNumbers(ernie::Value const&)::{lambda(auto:1 const&)#1}::operator()<glm::vec<2, double, (glm::qualifier)0> >(glm::vec<2, double, (glm::qualifier)0> const&) const:
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 27 times.
auto ernie::ToNumbers(ernie::Value const&)::{lambda(auto:1 const&)#1}::operator()<glm::vec<3, double, (glm::qualifier)0> >(glm::vec<3, double, (glm::qualifier)0> const&) const:
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 18 times.
auto ernie::ToNumbers(ernie::Value const&)::{lambda(auto:1 const&)#1}::operator()<glm::vec<4, double, (glm::qualifier)0> >(glm::vec<4, double, (glm::qualifier)0> const&) const:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
153 for (glm::length_t i = 0; i < vector.length(); ++i) {
55 108 numbers[static_cast<std::size_t>(i)] = vector[i];
56 }
57 45 return numbers;
58 };
59
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 1825 times.
1852 if (const auto v = ToVector<2>(value)) {
60 27 return components(*v);
61 }
62
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1807 times.
1825 if (const auto v = ToVector<3>(value)) {
63 18 return components(*v);
64 }
65
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1807 times.
1807 if (const auto v = ToVector<4>(value)) {
66 ✗ return components(*v);
67 }
68 1807 return {};
69 }
70
71 /// @return `value` as a column element, interning tokens and paths; none if it is another kind.
72
9/16
std::optional<ernie::Target> ernie::ToElement<ernie::Target>(ernie::PathTable&, ernie::Value const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 575 times.
std::optional<glm::mat<4, 4, double, (glm::qualifier)0> > ernie::ToElement<glm::mat<4, 4, double, (glm::qualifier)0> >(ernie::PathTable&, ernie::Value const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
std::optional<glm::qua<double, (glm::qualifier)0> > ernie::ToElement<glm::qua<double, (glm::qualifier)0> >(ernie::PathTable&, ernie::Value const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
std::optional<std::vector<ernie::Target, std::allocator<ernie::Target> > > ernie::ToElement<std::vector<ernie::Target, std::allocator<ernie::Target> > >(ernie::PathTable&, ernie::Value const&):
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
std::optional<std::vector<float, std::allocator<float> > > ernie::ToElement<std::vector<float, std::allocator<float> > >(ernie::PathTable&, ernie::Value const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 317 times.
std::optional<std::vector<unsigned int, std::allocator<unsigned int> > > ernie::ToElement<std::vector<unsigned int, std::allocator<unsigned int> > >(ernie::PathTable&, ernie::Value const&):
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2044 times.
std::optional<unsigned char> ernie::ToElement<unsigned char>(ernie::PathTable&, ernie::Value const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 523 times.
std::optional<unsigned int> ernie::ToElement<unsigned int>(ernie::PathTable&, ernie::Value const&):
✗ Branch 0 not taken.
✓ Branch 1 taken 3009 times.
12996 template <typename T> std::optional<T> ToElement(PathTable& paths, const Value& value) {
73 if constexpr (std::is_same_v<T, std::uint8_t>) {
74
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (const auto* b = value.Get<bool>()) {
75 523 return static_cast<std::uint8_t>(*b);
76 }
77
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (const auto* i = value.Get<int>(); i && (*i == 0 || *i == 1)) {
78 ✗ return static_cast<std::uint8_t>(*i);
79 }
80 } else if constexpr (std::is_same_v<T, std::int32_t>) {
81
2/4
✓ Branch 0 taken 1132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1132 times.
✗ Branch 3 not taken.
1132 if (const std::optional<double> n = ToNumber(value); n && std::trunc(*n) == *n) {
82 1132 return static_cast<std::int32_t>(*n);
83 }
84 } else if constexpr (std::is_same_v<T, double>) {
85 2941 return ToNumber(value);
86 } else if constexpr (std::is_same_v<T, glm::dvec2> || std::is_same_v<T, glm::dvec3> ||
87 std::is_same_v<T, glm::dvec4>) {
88 2057 return ToVector<T::length()>(value);
89 } else if constexpr (std::is_same_v<T, glm::dquat>) {
90 79 if (const auto* q = value.Get<glm::dquat>()) {
91 79 return *q;
92 }
93 } else if constexpr (std::is_same_v<T, glm::dmat4>) {
94 16 if (const auto* m = value.Get<glm::dmat4>()) {
95 16 return *m;
96 }
97 } else if constexpr (std::is_same_v<T, Token>) {
98 3009 if (const auto* text = value.Get<std::string>()) {
99 3009 return paths.Names().Intern(*text);
100 }
101 } else if constexpr (std::is_same_v<T, Target>) {
102
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 543 times.
575 if (const auto* path = value.Get<Path>()) {
103
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 543 times.
575 return Target{path->IsEmpty() ? kNoPath : paths.Intern(*path)};
104 }
105 } else if constexpr (std::is_same_v<T, std::vector<Target>>) {
106
1/2
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
301 if (const auto* path = value.Get<Path>()) {
107 ✗ return std::vector<Target>{{paths.Intern(*path)}};
108 }
109 ✗ if (const auto* list = value.Get<std::vector<Path>>()) {
110 301 return Map(*list, [&](const Path& path) { return Target{paths.Intern(path)}; });
111 }
112 } else if constexpr (std::is_same_v<T, std::vector<float>>) {
113 317 if (const auto* floats = value.Get<std::vector<float>>()) {
114 317 return *floats;
115 }
116
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (const std::optional<double> n = ToNumber(value)) {
117 ✗ return std::vector<float>{static_cast<float>(*n)};
118 }
119 } else if constexpr (std::is_same_v<T, std::vector<Token>>) {
120
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (const auto* texts = value.Get<std::vector<std::string>>()) {
121 2044 return Map(*texts, [&](const std::string& text) { return paths.Names().Intern(text); });
122 }
123 // An empty list, as Python and JSON pass one.
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
2 if (const auto* floats = value.Get<std::vector<float>>(); floats && floats->empty()) {
125 1 return std::vector<Token>{};
126 }
127 }
128 1 return std::nullopt;
129 }
130
131 /// @return A column element as a `Value`; tensors have none.
132 12342 template <typename T> Value ToValue(const PathTable& paths, const T& element) {
133 if constexpr (std::is_same_v<T, std::uint8_t>) {
134 19 return element != 0;
135 } else if constexpr (std::is_same_v<T, std::int32_t>) {
136 34 return static_cast<int>(element);
137 } else if constexpr (std::is_same_v<T, Token>) {
138 242 return std::string(paths.Names().Text(element));
139 } else if constexpr (std::is_same_v<T, Target>) {
140
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 10 times.
58 return element.path == kNoPath ? Path() : paths.ToPath(element.path);
141 } else if constexpr (std::is_same_v<T, std::vector<Target>>) {
142
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
27 return Map(element, [&](const Target& target) { return paths.ToPath(target.path); });
143 } else if constexpr (std::is_same_v<T, std::vector<Token>>) {
144 7148 return Map(element, [&](Token token) { return std::string(paths.Names().Text(token)); });
145 } else if constexpr (std::is_same_v<T, Tensor>) {
146 16 return Value();
147 } else {
148 5145 return element;
149 }
150 }
151
152 /// @return The column type an undeclared attribute's first value makes, or none.
153 190 inline std::optional<ColumnType> InferColumnType(const Value& value) {
154 190 return std::visit(
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 [](const auto& v) -> std::optional<ColumnType> {
156 using V = std::decay_t<decltype(v)>;
157 if constexpr (std::is_same_v<V, bool>) {
158 1 return ColumnType::Bool;
159 } else if constexpr (std::is_same_v<V, int>) {
160 2 return ColumnType::Int;
161 } else if constexpr (std::is_same_v<V, float> || std::is_same_v<V, double>) {
162 13 return ColumnType::Double;
163 } else if constexpr (std::is_same_v<V, glm::ivec2> || std::is_same_v<V, glm::vec2> ||
164 std::is_same_v<V, glm::dvec2>) {
165 ✗ return ColumnType::Vec2;
166 } else if constexpr (std::is_same_v<V, glm::vec3> || std::is_same_v<V, glm::dvec3>) {
167 117 return ColumnType::Vec3;
168 } else if constexpr (std::is_same_v<V, glm::vec4> || std::is_same_v<V, glm::dvec4>) {
169 1 return ColumnType::Vec4;
170 } else if constexpr (std::is_same_v<V, glm::dquat>) {
171 15 return ColumnType::Quat;
172 } else if constexpr (std::is_same_v<V, glm::dmat4>) {
173 16 return ColumnType::Matrix;
174 } else if constexpr (std::is_same_v<V, std::string>) {
175 19 return ColumnType::TokenValue;
176 } else if constexpr (std::is_same_v<V, Path>) {
177 3 return ColumnType::Relationship;
178 } else if constexpr (std::is_same_v<V, std::vector<Path>>) {
179 ✗ return ColumnType::Relationships;
180 } else if constexpr (std::is_same_v<V, std::vector<float>>) {
181 ✗ return ColumnType::FloatArray;
182 } else if constexpr (std::is_same_v<V, std::vector<std::string>>) {
183 3 return ColumnType::TokenArray;
184 } else {
185 ✗ return std::nullopt;
186 }
187 },
188 190 value.Raw());
189 }
190
191 } // namespace ernie
192