blob: 5abe6762c04578c785018665093b634eec78c47d [file] [log] [blame]
Austin Schuh43c6a352019-09-30 22:22:10 -07001#include "aos/flatbuffer_utils.h"
Brian Silvermancf4fb662021-02-10 17:54:53 -08002
3#include "flatbuffers/minireflect.h"
Brian Silvermanc5105ab2021-02-10 17:55:38 -08004#include "flatbuffers/reflection_generated.h"
Brian Silvermancf4fb662021-02-10 17:54:53 -08005#include "glog/logging.h"
6
7namespace aos {
8
9bool FlatbufferType::IsSequence() const {
10 if (type_table_) {
11 return type_table_->st != flatbuffers::ST_ENUM;
12 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080013 if (object_) {
14 return true;
15 }
16 if (enum_) {
17 return enum_->is_union();
18 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080019 LOG(FATAL) << "Unimplemented";
20}
21
James Kuszmaul768c4682023-10-12 21:07:16 -070022bool FlatbufferType::IsTable() const {
23 if (type_table_) {
24 return type_table_->st == flatbuffers::ST_TABLE;
25 }
26 if (object_) {
27 return !object_->is_struct();
28 }
29 LOG(FATAL) << "Unimplemented";
30}
31
32bool FlatbufferType::IsStruct() const {
33 if (type_table_) {
34 return type_table_->st == flatbuffers::ST_STRUCT;
35 }
36 if (object_) {
37 return object_->is_struct();
38 }
39 LOG(FATAL) << "Unimplemented";
40}
41
Brian Silvermancf4fb662021-02-10 17:54:53 -080042bool FlatbufferType::IsEnum() const {
43 if (type_table_) {
44 return type_table_->st == flatbuffers::ST_ENUM;
45 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080046 if (object_) {
47 return false;
48 }
49 if (enum_) {
50 return !enum_->is_union();
51 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080052 LOG(FATAL) << "Unimplemented";
53}
54
55bool FlatbufferType::FieldIsSequence(int index) const {
56 DCHECK(IsSequence());
57 if (type_table_) {
58 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
59 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
60 if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
61 return false;
62 }
63 DCHECK(FieldType(index).IsSequence());
64 return true;
65 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080066 if (object_ || enum_) {
67 const reflection::BaseType base_type = ReflectionElementBaseType(index);
68 return base_type == reflection::BaseType::Obj ||
69 base_type == reflection::BaseType::Union;
70 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080071 LOG(FATAL) << "Unimplemented";
72}
73
74bool FlatbufferType::FieldIsEnum(int index) const {
75 DCHECK(IsSequence());
76 if (type_table_) {
77 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
78 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
79 if (type_code.base_type == flatbuffers::ET_SEQUENCE) {
80 return false;
81 }
82 if (type_code.sequence_ref == -1) {
83 // Not an enum.
84 return false;
85 }
86 DCHECK(FieldType(index).IsEnum());
87 return true;
88 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080089 if (object_ || enum_) {
90 const reflection::BaseType base_type = ReflectionElementBaseType(index);
91 if (base_type == reflection::BaseType::Obj ||
92 base_type == reflection::BaseType::Union) {
93 return false;
94 }
95 return ReflectionType(index)->index() >= 0;
96 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080097 LOG(FATAL) << "Unimplemented";
98}
99
100std::optional<int64_t> FlatbufferType::EnumValue(std::string_view name) const {
101 DCHECK(IsEnum());
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800102 DCHECK(!object_);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800103 if (type_table_) {
104 for (size_t i = 0; i < type_table_->num_elems; ++i) {
105 if (name == type_table_->names[i]) {
106 if (type_table_->values) {
107 return type_table_->values[i];
108 } else {
109 return i;
110 }
111 }
112 }
113 return std::nullopt;
114 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800115 if (enum_) {
116 for (size_t i = 0; i < enum_->values()->size(); ++i) {
117 const auto *const value = enum_->values()->Get(i);
118 if (name == value->name()->string_view()) {
119 return value->value();
120 }
121 }
122 return std::nullopt;
123 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800124 LOG(FATAL) << "Unimplemented";
125}
126
127bool FlatbufferType::FieldIsRepeating(int index) const {
128 DCHECK(IsSequence());
129 if (type_table_) {
130 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
131 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
132 return type_code.is_repeating;
133 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800134 if (object_ || enum_) {
135 const reflection::BaseType type = ReflectionType(index)->base_type();
136 CHECK(type != reflection::BaseType::None);
137 return type == reflection::BaseType::Vector ||
138 type == reflection::BaseType::Array;
139 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800140 LOG(FATAL) << "Unimplemented";
141}
142
143int FlatbufferType::FieldIndex(std::string_view field_name) const {
144 DCHECK(IsSequence());
145 if (type_table_) {
146 for (size_t i = 0; i < type_table_->num_elems; ++i) {
147 if (field_name == std::string_view(type_table_->names[i])) {
148 return i;
149 }
150 }
151 return -1;
152 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800153 if (object_) {
154 for (size_t i = 0; i < object_->fields()->size(); ++i) {
155 const reflection::Field *const field = object_->fields()->Get(i);
156 if (field_name == field->name()->string_view()) {
157 return field->id();
158 }
159 }
160 return -1;
161 }
162 if (enum_) {
163 for (size_t i = 0; i < enum_->values()->size(); ++i) {
164 const reflection::EnumVal *const value = enum_->values()->Get(i);
165 if (field_name == value->name()->string_view()) {
166 return value->value();
167 }
168 }
169 return -1;
170 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800171 LOG(FATAL) << "Unimplemented";
172}
173
174std::string_view FlatbufferType::FieldName(int index) const {
175 DCHECK(IsSequence());
176 if (type_table_) {
177 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
178 return type_table_->names[index];
179 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800180 if (object_) {
181 return ReflectionObjectField(index)->name()->string_view();
182 }
183 if (enum_) {
184 return ReflectionEnumValue(index)->name()->string_view();
185 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800186 LOG(FATAL) << "Unimplemented";
187}
188
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800189namespace {
190
191flatbuffers::ElementaryType ElementaryTypeFromBaseType(
192 reflection::BaseType base_type) {
193 switch (base_type) {
194 case reflection::BaseType::None:
195 LOG(FATAL) << "Invalid schema";
196 case reflection::BaseType::UType:
197 return flatbuffers::ElementaryType::ET_UTYPE;
198 case reflection::BaseType::Bool:
199 return flatbuffers::ElementaryType::ET_BOOL;
200 case reflection::BaseType::Byte:
201 return flatbuffers::ElementaryType::ET_CHAR;
202 case reflection::BaseType::UByte:
203 return flatbuffers::ElementaryType::ET_UCHAR;
204 case reflection::BaseType::Short:
205 return flatbuffers::ElementaryType::ET_SHORT;
206 case reflection::BaseType::UShort:
207 return flatbuffers::ElementaryType::ET_USHORT;
208 case reflection::BaseType::Int:
209 return flatbuffers::ElementaryType::ET_INT;
210 case reflection::BaseType::UInt:
211 return flatbuffers::ElementaryType::ET_UINT;
212 case reflection::BaseType::Long:
213 return flatbuffers::ElementaryType::ET_LONG;
214 case reflection::BaseType::ULong:
215 return flatbuffers::ElementaryType::ET_ULONG;
216 case reflection::BaseType::Float:
217 return flatbuffers::ElementaryType::ET_FLOAT;
218 case reflection::BaseType::Double:
219 return flatbuffers::ElementaryType::ET_DOUBLE;
220 case reflection::BaseType::String:
221 return flatbuffers::ElementaryType::ET_STRING;
222 case reflection::BaseType::Obj:
223 return flatbuffers::ElementaryType::ET_SEQUENCE;
224 case reflection::BaseType::Union:
225 return flatbuffers::ElementaryType::ET_SEQUENCE;
226 default:
227 LOG(FATAL) << "Unknown BaseType";
228 }
229}
230
231} // namespace
232
Brian Silvermancf4fb662021-02-10 17:54:53 -0800233flatbuffers::ElementaryType FlatbufferType::FieldElementaryType(
234 int index) const {
235 DCHECK(IsSequence());
236 if (type_table_) {
237 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
238 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
239 return static_cast<flatbuffers::ElementaryType>(type_code.base_type);
240 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800241 if (object_ || enum_) {
242 return ElementaryTypeFromBaseType(ReflectionElementBaseType(index));
243 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800244 LOG(FATAL) << "Unimplemented";
245}
246
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800247namespace {
248
249size_t BaseTypeInlineSize(reflection::BaseType base_type) {
250 switch (base_type) {
251 case reflection::BaseType::None:
252 LOG(FATAL) << "Invalid schema";
253 case reflection::BaseType::UType:
254 case reflection::BaseType::Bool:
255 case reflection::BaseType::Byte:
256 case reflection::BaseType::UByte:
257 return 1;
258 case reflection::BaseType::Short:
259 case reflection::BaseType::UShort:
260 return 2;
261 case reflection::BaseType::Int:
262 case reflection::BaseType::UInt:
263 case reflection::BaseType::Float:
264 case reflection::BaseType::String:
265 return 4;
266 case reflection::BaseType::Long:
267 case reflection::BaseType::ULong:
268 case reflection::BaseType::Double:
269 return 8;
270 case reflection::BaseType::Union:
271 return 4;
272 default:
273 LOG(FATAL) << "Unknown BaseType";
274 }
275}
276
277} // namespace
278
James Kuszmaul768c4682023-10-12 21:07:16 -0700279size_t FlatbufferType::InlineSize() const {
280 DCHECK(IsSequence());
281 if (type_table_) {
282 return flatbuffers::InlineSize(flatbuffers::ElementaryType::ET_SEQUENCE,
283 type_table_);
284 }
285 if (object_) {
286 return object_->is_struct() ? object_->bytesize() : /*offset size*/ 4u;
287 }
288 if (enum_) {
289 return BaseTypeInlineSize(enum_->underlying_type()->base_type());
290 }
291 LOG(FATAL) << "Unimplemented";
292}
293
294// Returns the required alignment for this type.
295size_t FlatbufferType::Alignment() const {
296 if (type_table_) {
297 // Attempt to derive alignment as max alignment of the members.
298 size_t alignment = 1u;
299 for (size_t field_index = 0;
300 field_index < static_cast<size_t>(NumberFields()); ++field_index) {
301 alignment = std::max(alignment, FieldInlineAlignment(field_index));
302 }
303 return alignment;
304 }
305 if (object_) {
306 return object_->minalign();
307 }
308 // We don't do a great job of supporting unions in general, and as of this
309 // writing did not try to look up what the alignment rules for unions were.
310 LOG(FATAL) << "Unimplemented";
311}
312
313size_t FlatbufferType::FieldInlineAlignment(size_t field_index) const {
314 if (FieldIsSequence(field_index) && FieldType(field_index).IsStruct()) {
315 return FieldType(field_index).Alignment();
316 }
317 return FieldInlineSize(field_index);
318}
319
320size_t FlatbufferType::StructFieldOffset(int index) const {
321 DCHECK(IsStruct());
322 if (type_table_) {
323 return type_table_->values[index];
324 }
325 if (object_) {
326 return ReflectionObjectField(index)->offset();
327 }
328 LOG(FATAL) << "Unimplemented";
329}
330
Brian Silvermancf4fb662021-02-10 17:54:53 -0800331size_t FlatbufferType::FieldInlineSize(int index) const {
332 DCHECK(IsSequence());
333 if (type_table_) {
James Kuszmaul768c4682023-10-12 21:07:16 -0700334 return flatbuffers::InlineSize(
335 FieldElementaryType(index),
336 FieldIsSequence(index) ? FieldType(index).type_table_ : nullptr);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800337 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800338 if (object_ || enum_) {
339 const reflection::Type *const type = ReflectionType(index);
340 const reflection::BaseType element_base_type =
341 ReflectionElementBaseType(index);
342 int element_size;
343 if (element_base_type == reflection::BaseType::Obj) {
344 const FlatbufferType field_type = FieldType(index);
345 if (field_type.object_ && field_type.object_->is_struct()) {
346 element_size = field_type.object_->bytesize();
347 } else {
348 element_size = 4;
349 }
350 } else {
351 element_size = BaseTypeInlineSize(element_base_type);
352 }
353 if (type->base_type() == reflection::BaseType::Array) {
354 return element_size * type->fixed_length();
355 }
356 return element_size;
357 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800358 LOG(FATAL) << "Unimplemented";
359}
360
361int FlatbufferType::NumberFields() const {
362 DCHECK(IsSequence());
363 if (type_table_) {
364 return type_table_->num_elems;
365 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800366 if (object_) {
367 return object_->fields()->size();
368 }
369 if (enum_) {
370 return enum_->values()->size();
371 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800372 LOG(FATAL) << "Unimplemented";
373}
374
375FlatbufferType FlatbufferType::FieldType(int index) const {
376 DCHECK(IsSequence());
377 if (type_table_) {
378 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
379 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
380 CHECK_GE(type_code.sequence_ref, 0);
381 // type_refs can be shorter than num_elems, but not longer, so this is still
382 // a valid sanity check.
383 DCHECK_LT(static_cast<size_t>(type_code.sequence_ref),
384 type_table_->num_elems);
385 const flatbuffers::TypeFunction type_function =
386 type_table_->type_refs[type_code.sequence_ref];
387 return FlatbufferType(type_function());
388 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800389 if (object_ || enum_) {
390 const reflection::BaseType base_type = ReflectionElementBaseType(index);
391 const int object_index = ReflectionType(index)->index();
392 CHECK(object_index >= 0) << ": Invalid schema";
393 if (base_type == reflection::BaseType::Obj ||
394 base_type == reflection::BaseType::Union) {
395 DCHECK_LT(static_cast<size_t>(object_index), schema_->objects()->size());
396 return FlatbufferType(schema_, schema_->objects()->Get(object_index));
397 } else {
398 DCHECK_LT(static_cast<size_t>(object_index), schema_->enums()->size());
399 return FlatbufferType(schema_, schema_->enums()->Get(object_index));
400 }
401 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800402 LOG(FATAL) << "Unimplemented";
403}
404
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800405const reflection::Type *FlatbufferType::ReflectionType(int index) const {
406 if (object_) {
407 return ReflectionObjectField(index)->type();
408 } else {
409 return ReflectionEnumValue(index)->union_type();
410 }
411}
412
413const reflection::Field *FlatbufferType::ReflectionObjectField(
414 int index) const {
415 DCHECK(object_);
416 const auto result = std::find_if(
417 object_->fields()->begin(), object_->fields()->end(),
418 [index](const reflection::Field *field) { return field->id() == index; });
419 DCHECK(result != object_->fields()->end());
420 return *result;
421}
422
423const reflection::EnumVal *FlatbufferType::ReflectionEnumValue(
424 int index) const {
425 DCHECK(enum_);
426 const auto result =
427 std::find_if(enum_->values()->begin(), enum_->values()->end(),
428 [index](const reflection::EnumVal *value) {
429 return value->value() == index;
430 });
431 DCHECK(result != enum_->values()->end());
432 return *result;
433}
434
435reflection::BaseType FlatbufferType::ReflectionElementBaseType(
436 int index) const {
437 const reflection::Type *const type = ReflectionType(index);
438 reflection::BaseType base_type = type->base_type();
439 if (base_type == reflection::BaseType::Vector ||
440 base_type == reflection::BaseType::Array) {
441 base_type = type->element();
442 }
443 CHECK(base_type != reflection::BaseType::None);
444 return base_type;
445}
446
Brian Silvermancf4fb662021-02-10 17:54:53 -0800447} // namespace aos