blob: afa1cb49a198585ada074a2cf57310c8391801be [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
Austin Schuh6bdcc372024-06-27 14:49:11 -07009FlatbufferType::FlatbufferType(const flatbuffers::TypeTable *type_table) {
10 CHECK(type_table != nullptr);
11 type_table_ = type_table;
12}
13FlatbufferType::FlatbufferType(const reflection::Schema *schema) {
14 CHECK(schema != nullptr);
15 schema_ = schema;
16 DCHECK(schema->root_table() != nullptr);
17 object_ = schema->root_table();
18}
19
20FlatbufferType::FlatbufferType(const reflection::Schema *schema,
21 const reflection::Object *object) {
22 CHECK(schema != nullptr);
23 schema_ = schema;
24 DCHECK(object != nullptr);
25 object_ = object;
26}
27
28FlatbufferType::FlatbufferType(const reflection::Schema *schema,
29 const reflection::Enum *fb_enum) {
30 CHECK(schema != nullptr);
31 schema_ = schema;
32 CHECK(fb_enum != nullptr);
33 enum_ = fb_enum;
34}
35
Brian Silvermancf4fb662021-02-10 17:54:53 -080036bool FlatbufferType::IsSequence() const {
37 if (type_table_) {
38 return type_table_->st != flatbuffers::ST_ENUM;
39 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080040 if (object_) {
41 return true;
42 }
43 if (enum_) {
44 return enum_->is_union();
45 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080046 LOG(FATAL) << "Unimplemented";
47}
48
James Kuszmaul768c4682023-10-12 21:07:16 -070049bool FlatbufferType::IsTable() const {
50 if (type_table_) {
51 return type_table_->st == flatbuffers::ST_TABLE;
52 }
53 if (object_) {
54 return !object_->is_struct();
55 }
56 LOG(FATAL) << "Unimplemented";
57}
58
59bool FlatbufferType::IsStruct() const {
60 if (type_table_) {
61 return type_table_->st == flatbuffers::ST_STRUCT;
62 }
63 if (object_) {
64 return object_->is_struct();
65 }
66 LOG(FATAL) << "Unimplemented";
67}
68
Brian Silvermancf4fb662021-02-10 17:54:53 -080069bool FlatbufferType::IsEnum() const {
70 if (type_table_) {
71 return type_table_->st == flatbuffers::ST_ENUM;
72 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080073 if (object_) {
74 return false;
75 }
76 if (enum_) {
77 return !enum_->is_union();
78 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080079 LOG(FATAL) << "Unimplemented";
80}
81
82bool FlatbufferType::FieldIsSequence(int index) const {
83 DCHECK(IsSequence());
84 if (type_table_) {
85 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
86 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
87 if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
88 return false;
89 }
90 DCHECK(FieldType(index).IsSequence());
91 return true;
92 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -080093 if (object_ || enum_) {
94 const reflection::BaseType base_type = ReflectionElementBaseType(index);
95 return base_type == reflection::BaseType::Obj ||
96 base_type == reflection::BaseType::Union;
97 }
Brian Silvermancf4fb662021-02-10 17:54:53 -080098 LOG(FATAL) << "Unimplemented";
99}
100
101bool FlatbufferType::FieldIsEnum(int index) const {
102 DCHECK(IsSequence());
103 if (type_table_) {
104 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
105 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
106 if (type_code.base_type == flatbuffers::ET_SEQUENCE) {
107 return false;
108 }
109 if (type_code.sequence_ref == -1) {
110 // Not an enum.
111 return false;
112 }
113 DCHECK(FieldType(index).IsEnum());
114 return true;
115 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800116 if (object_ || enum_) {
117 const reflection::BaseType base_type = ReflectionElementBaseType(index);
118 if (base_type == reflection::BaseType::Obj ||
119 base_type == reflection::BaseType::Union) {
120 return false;
121 }
122 return ReflectionType(index)->index() >= 0;
123 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800124 LOG(FATAL) << "Unimplemented";
125}
126
127std::optional<int64_t> FlatbufferType::EnumValue(std::string_view name) const {
128 DCHECK(IsEnum());
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800129 DCHECK(!object_);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800130 if (type_table_) {
131 for (size_t i = 0; i < type_table_->num_elems; ++i) {
132 if (name == type_table_->names[i]) {
133 if (type_table_->values) {
134 return type_table_->values[i];
135 } else {
136 return i;
137 }
138 }
139 }
140 return std::nullopt;
141 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800142 if (enum_) {
143 for (size_t i = 0; i < enum_->values()->size(); ++i) {
144 const auto *const value = enum_->values()->Get(i);
145 if (name == value->name()->string_view()) {
146 return value->value();
147 }
148 }
149 return std::nullopt;
150 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800151 LOG(FATAL) << "Unimplemented";
152}
153
154bool FlatbufferType::FieldIsRepeating(int index) const {
155 DCHECK(IsSequence());
156 if (type_table_) {
157 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
158 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
159 return type_code.is_repeating;
160 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800161 if (object_ || enum_) {
162 const reflection::BaseType type = ReflectionType(index)->base_type();
163 CHECK(type != reflection::BaseType::None);
164 return type == reflection::BaseType::Vector ||
165 type == reflection::BaseType::Array;
166 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800167 LOG(FATAL) << "Unimplemented";
168}
169
170int FlatbufferType::FieldIndex(std::string_view field_name) const {
171 DCHECK(IsSequence());
172 if (type_table_) {
173 for (size_t i = 0; i < type_table_->num_elems; ++i) {
174 if (field_name == std::string_view(type_table_->names[i])) {
175 return i;
176 }
177 }
178 return -1;
179 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800180 if (object_) {
181 for (size_t i = 0; i < object_->fields()->size(); ++i) {
182 const reflection::Field *const field = object_->fields()->Get(i);
183 if (field_name == field->name()->string_view()) {
184 return field->id();
185 }
186 }
187 return -1;
188 }
189 if (enum_) {
190 for (size_t i = 0; i < enum_->values()->size(); ++i) {
191 const reflection::EnumVal *const value = enum_->values()->Get(i);
192 if (field_name == value->name()->string_view()) {
193 return value->value();
194 }
195 }
196 return -1;
197 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800198 LOG(FATAL) << "Unimplemented";
199}
200
201std::string_view FlatbufferType::FieldName(int index) const {
202 DCHECK(IsSequence());
203 if (type_table_) {
204 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
205 return type_table_->names[index];
206 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800207 if (object_) {
208 return ReflectionObjectField(index)->name()->string_view();
209 }
210 if (enum_) {
211 return ReflectionEnumValue(index)->name()->string_view();
212 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800213 LOG(FATAL) << "Unimplemented";
214}
215
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800216namespace {
217
218flatbuffers::ElementaryType ElementaryTypeFromBaseType(
219 reflection::BaseType base_type) {
220 switch (base_type) {
221 case reflection::BaseType::None:
222 LOG(FATAL) << "Invalid schema";
223 case reflection::BaseType::UType:
224 return flatbuffers::ElementaryType::ET_UTYPE;
225 case reflection::BaseType::Bool:
226 return flatbuffers::ElementaryType::ET_BOOL;
227 case reflection::BaseType::Byte:
228 return flatbuffers::ElementaryType::ET_CHAR;
229 case reflection::BaseType::UByte:
230 return flatbuffers::ElementaryType::ET_UCHAR;
231 case reflection::BaseType::Short:
232 return flatbuffers::ElementaryType::ET_SHORT;
233 case reflection::BaseType::UShort:
234 return flatbuffers::ElementaryType::ET_USHORT;
235 case reflection::BaseType::Int:
236 return flatbuffers::ElementaryType::ET_INT;
237 case reflection::BaseType::UInt:
238 return flatbuffers::ElementaryType::ET_UINT;
239 case reflection::BaseType::Long:
240 return flatbuffers::ElementaryType::ET_LONG;
241 case reflection::BaseType::ULong:
242 return flatbuffers::ElementaryType::ET_ULONG;
243 case reflection::BaseType::Float:
244 return flatbuffers::ElementaryType::ET_FLOAT;
245 case reflection::BaseType::Double:
246 return flatbuffers::ElementaryType::ET_DOUBLE;
247 case reflection::BaseType::String:
248 return flatbuffers::ElementaryType::ET_STRING;
249 case reflection::BaseType::Obj:
250 return flatbuffers::ElementaryType::ET_SEQUENCE;
251 case reflection::BaseType::Union:
252 return flatbuffers::ElementaryType::ET_SEQUENCE;
253 default:
254 LOG(FATAL) << "Unknown BaseType";
255 }
256}
257
258} // namespace
259
Brian Silvermancf4fb662021-02-10 17:54:53 -0800260flatbuffers::ElementaryType FlatbufferType::FieldElementaryType(
261 int index) const {
262 DCHECK(IsSequence());
263 if (type_table_) {
264 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
265 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
266 return static_cast<flatbuffers::ElementaryType>(type_code.base_type);
267 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800268 if (object_ || enum_) {
269 return ElementaryTypeFromBaseType(ReflectionElementBaseType(index));
270 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800271 LOG(FATAL) << "Unimplemented";
272}
273
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800274namespace {
275
276size_t BaseTypeInlineSize(reflection::BaseType base_type) {
277 switch (base_type) {
278 case reflection::BaseType::None:
279 LOG(FATAL) << "Invalid schema";
280 case reflection::BaseType::UType:
281 case reflection::BaseType::Bool:
282 case reflection::BaseType::Byte:
283 case reflection::BaseType::UByte:
284 return 1;
285 case reflection::BaseType::Short:
286 case reflection::BaseType::UShort:
287 return 2;
288 case reflection::BaseType::Int:
289 case reflection::BaseType::UInt:
290 case reflection::BaseType::Float:
291 case reflection::BaseType::String:
292 return 4;
293 case reflection::BaseType::Long:
294 case reflection::BaseType::ULong:
295 case reflection::BaseType::Double:
296 return 8;
297 case reflection::BaseType::Union:
298 return 4;
299 default:
300 LOG(FATAL) << "Unknown BaseType";
301 }
302}
303
304} // namespace
305
James Kuszmaul768c4682023-10-12 21:07:16 -0700306size_t FlatbufferType::InlineSize() const {
307 DCHECK(IsSequence());
308 if (type_table_) {
309 return flatbuffers::InlineSize(flatbuffers::ElementaryType::ET_SEQUENCE,
310 type_table_);
311 }
312 if (object_) {
313 return object_->is_struct() ? object_->bytesize() : /*offset size*/ 4u;
314 }
315 if (enum_) {
316 return BaseTypeInlineSize(enum_->underlying_type()->base_type());
317 }
318 LOG(FATAL) << "Unimplemented";
319}
320
321// Returns the required alignment for this type.
322size_t FlatbufferType::Alignment() const {
323 if (type_table_) {
324 // Attempt to derive alignment as max alignment of the members.
325 size_t alignment = 1u;
326 for (size_t field_index = 0;
327 field_index < static_cast<size_t>(NumberFields()); ++field_index) {
328 alignment = std::max(alignment, FieldInlineAlignment(field_index));
329 }
330 return alignment;
331 }
332 if (object_) {
333 return object_->minalign();
334 }
335 // We don't do a great job of supporting unions in general, and as of this
336 // writing did not try to look up what the alignment rules for unions were.
337 LOG(FATAL) << "Unimplemented";
338}
339
340size_t FlatbufferType::FieldInlineAlignment(size_t field_index) const {
341 if (FieldIsSequence(field_index) && FieldType(field_index).IsStruct()) {
342 return FieldType(field_index).Alignment();
343 }
344 return FieldInlineSize(field_index);
345}
346
347size_t FlatbufferType::StructFieldOffset(int index) const {
348 DCHECK(IsStruct());
349 if (type_table_) {
350 return type_table_->values[index];
351 }
352 if (object_) {
353 return ReflectionObjectField(index)->offset();
354 }
355 LOG(FATAL) << "Unimplemented";
356}
357
Brian Silvermancf4fb662021-02-10 17:54:53 -0800358size_t FlatbufferType::FieldInlineSize(int index) const {
359 DCHECK(IsSequence());
360 if (type_table_) {
James Kuszmaul768c4682023-10-12 21:07:16 -0700361 return flatbuffers::InlineSize(
362 FieldElementaryType(index),
363 FieldIsSequence(index) ? FieldType(index).type_table_ : nullptr);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800364 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800365 if (object_ || enum_) {
366 const reflection::Type *const type = ReflectionType(index);
367 const reflection::BaseType element_base_type =
368 ReflectionElementBaseType(index);
369 int element_size;
370 if (element_base_type == reflection::BaseType::Obj) {
371 const FlatbufferType field_type = FieldType(index);
372 if (field_type.object_ && field_type.object_->is_struct()) {
373 element_size = field_type.object_->bytesize();
374 } else {
375 element_size = 4;
376 }
377 } else {
378 element_size = BaseTypeInlineSize(element_base_type);
379 }
380 if (type->base_type() == reflection::BaseType::Array) {
381 return element_size * type->fixed_length();
382 }
383 return element_size;
384 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800385 LOG(FATAL) << "Unimplemented";
386}
387
388int FlatbufferType::NumberFields() const {
389 DCHECK(IsSequence());
390 if (type_table_) {
391 return type_table_->num_elems;
392 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800393 if (object_) {
394 return object_->fields()->size();
395 }
396 if (enum_) {
397 return enum_->values()->size();
398 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800399 LOG(FATAL) << "Unimplemented";
400}
401
402FlatbufferType FlatbufferType::FieldType(int index) const {
403 DCHECK(IsSequence());
404 if (type_table_) {
405 DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
406 const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
407 CHECK_GE(type_code.sequence_ref, 0);
408 // type_refs can be shorter than num_elems, but not longer, so this is still
409 // a valid sanity check.
410 DCHECK_LT(static_cast<size_t>(type_code.sequence_ref),
411 type_table_->num_elems);
412 const flatbuffers::TypeFunction type_function =
413 type_table_->type_refs[type_code.sequence_ref];
414 return FlatbufferType(type_function());
415 }
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800416 if (object_ || enum_) {
417 const reflection::BaseType base_type = ReflectionElementBaseType(index);
418 const int object_index = ReflectionType(index)->index();
419 CHECK(object_index >= 0) << ": Invalid schema";
420 if (base_type == reflection::BaseType::Obj ||
421 base_type == reflection::BaseType::Union) {
422 DCHECK_LT(static_cast<size_t>(object_index), schema_->objects()->size());
423 return FlatbufferType(schema_, schema_->objects()->Get(object_index));
424 } else {
425 DCHECK_LT(static_cast<size_t>(object_index), schema_->enums()->size());
426 return FlatbufferType(schema_, schema_->enums()->Get(object_index));
427 }
428 }
Brian Silvermancf4fb662021-02-10 17:54:53 -0800429 LOG(FATAL) << "Unimplemented";
430}
431
Brian Silvermanc5105ab2021-02-10 17:55:38 -0800432const reflection::Type *FlatbufferType::ReflectionType(int index) const {
433 if (object_) {
434 return ReflectionObjectField(index)->type();
435 } else {
436 return ReflectionEnumValue(index)->union_type();
437 }
438}
439
440const reflection::Field *FlatbufferType::ReflectionObjectField(
441 int index) const {
442 DCHECK(object_);
443 const auto result = std::find_if(
444 object_->fields()->begin(), object_->fields()->end(),
445 [index](const reflection::Field *field) { return field->id() == index; });
446 DCHECK(result != object_->fields()->end());
447 return *result;
448}
449
450const reflection::EnumVal *FlatbufferType::ReflectionEnumValue(
451 int index) const {
452 DCHECK(enum_);
453 const auto result =
454 std::find_if(enum_->values()->begin(), enum_->values()->end(),
455 [index](const reflection::EnumVal *value) {
456 return value->value() == index;
457 });
458 DCHECK(result != enum_->values()->end());
459 return *result;
460}
461
462reflection::BaseType FlatbufferType::ReflectionElementBaseType(
463 int index) const {
464 const reflection::Type *const type = ReflectionType(index);
465 reflection::BaseType base_type = type->base_type();
466 if (base_type == reflection::BaseType::Vector ||
467 base_type == reflection::BaseType::Array) {
468 base_type = type->element();
469 }
470 CHECK(base_type != reflection::BaseType::None);
471 return base_type;
472}
473
Brian Silvermancf4fb662021-02-10 17:54:53 -0800474} // namespace aos