blob: 3429fe4883098adf4885a7d4e709f38e8bfb7b8d [file] [log] [blame]
#include "aos/flatbuffer_utils.h"
#include "flatbuffers/minireflect.h"
#include "flatbuffers/reflection_generated.h"
#include "glog/logging.h"
namespace aos {
bool FlatbufferType::IsSequence() const {
if (type_table_) {
return type_table_->st != flatbuffers::ST_ENUM;
}
if (object_) {
return true;
}
if (enum_) {
return enum_->is_union();
}
LOG(FATAL) << "Unimplemented";
}
bool FlatbufferType::IsEnum() const {
if (type_table_) {
return type_table_->st == flatbuffers::ST_ENUM;
}
if (object_) {
return false;
}
if (enum_) {
return !enum_->is_union();
}
LOG(FATAL) << "Unimplemented";
}
bool FlatbufferType::FieldIsSequence(int index) const {
DCHECK(IsSequence());
if (type_table_) {
DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
return false;
}
DCHECK(FieldType(index).IsSequence());
return true;
}
if (object_ || enum_) {
const reflection::BaseType base_type = ReflectionElementBaseType(index);
return base_type == reflection::BaseType::Obj ||
base_type == reflection::BaseType::Union;
}
LOG(FATAL) << "Unimplemented";
}
bool FlatbufferType::FieldIsEnum(int index) const {
DCHECK(IsSequence());
if (type_table_) {
DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
if (type_code.base_type == flatbuffers::ET_SEQUENCE) {
return false;
}
if (type_code.sequence_ref == -1) {
// Not an enum.
return false;
}
DCHECK(FieldType(index).IsEnum());
return true;
}
if (object_ || enum_) {
const reflection::BaseType base_type = ReflectionElementBaseType(index);
if (base_type == reflection::BaseType::Obj ||
base_type == reflection::BaseType::Union) {
return false;
}
return ReflectionType(index)->index() >= 0;
}
LOG(FATAL) << "Unimplemented";
}
std::optional<int64_t> FlatbufferType::EnumValue(std::string_view name) const {
DCHECK(IsEnum());
DCHECK(!object_);
if (type_table_) {
for (size_t i = 0; i < type_table_->num_elems; ++i) {
if (name == type_table_->names[i]) {
if (type_table_->values) {
return type_table_->values[i];
} else {
return i;
}
}
}
return std::nullopt;
}
if (enum_) {
for (size_t i = 0; i < enum_->values()->size(); ++i) {
const auto *const value = enum_->values()->Get(i);
if (name == value->name()->string_view()) {
return value->value();
}
}
return std::nullopt;
}
LOG(FATAL) << "Unimplemented";
}
bool FlatbufferType::FieldIsRepeating(int index) const {
DCHECK(IsSequence());
if (type_table_) {
DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
return type_code.is_repeating;
}
if (object_ || enum_) {
const reflection::BaseType type = ReflectionType(index)->base_type();
CHECK(type != reflection::BaseType::None);
return type == reflection::BaseType::Vector ||
type == reflection::BaseType::Array;
}
LOG(FATAL) << "Unimplemented";
}
int FlatbufferType::FieldIndex(std::string_view field_name) const {
DCHECK(IsSequence());
if (type_table_) {
for (size_t i = 0; i < type_table_->num_elems; ++i) {
if (field_name == std::string_view(type_table_->names[i])) {
return i;
}
}
return -1;
}
if (object_) {
for (size_t i = 0; i < object_->fields()->size(); ++i) {
const reflection::Field *const field = object_->fields()->Get(i);
if (field_name == field->name()->string_view()) {
return field->id();
}
}
return -1;
}
if (enum_) {
for (size_t i = 0; i < enum_->values()->size(); ++i) {
const reflection::EnumVal *const value = enum_->values()->Get(i);
if (field_name == value->name()->string_view()) {
return value->value();
}
}
return -1;
}
LOG(FATAL) << "Unimplemented";
}
std::string_view FlatbufferType::FieldName(int index) const {
DCHECK(IsSequence());
if (type_table_) {
DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
return type_table_->names[index];
}
if (object_) {
return ReflectionObjectField(index)->name()->string_view();
}
if (enum_) {
return ReflectionEnumValue(index)->name()->string_view();
}
LOG(FATAL) << "Unimplemented";
}
namespace {
flatbuffers::ElementaryType ElementaryTypeFromBaseType(
reflection::BaseType base_type) {
switch (base_type) {
case reflection::BaseType::None:
LOG(FATAL) << "Invalid schema";
case reflection::BaseType::UType:
return flatbuffers::ElementaryType::ET_UTYPE;
case reflection::BaseType::Bool:
return flatbuffers::ElementaryType::ET_BOOL;
case reflection::BaseType::Byte:
return flatbuffers::ElementaryType::ET_CHAR;
case reflection::BaseType::UByte:
return flatbuffers::ElementaryType::ET_UCHAR;
case reflection::BaseType::Short:
return flatbuffers::ElementaryType::ET_SHORT;
case reflection::BaseType::UShort:
return flatbuffers::ElementaryType::ET_USHORT;
case reflection::BaseType::Int:
return flatbuffers::ElementaryType::ET_INT;
case reflection::BaseType::UInt:
return flatbuffers::ElementaryType::ET_UINT;
case reflection::BaseType::Long:
return flatbuffers::ElementaryType::ET_LONG;
case reflection::BaseType::ULong:
return flatbuffers::ElementaryType::ET_ULONG;
case reflection::BaseType::Float:
return flatbuffers::ElementaryType::ET_FLOAT;
case reflection::BaseType::Double:
return flatbuffers::ElementaryType::ET_DOUBLE;
case reflection::BaseType::String:
return flatbuffers::ElementaryType::ET_STRING;
case reflection::BaseType::Obj:
return flatbuffers::ElementaryType::ET_SEQUENCE;
case reflection::BaseType::Union:
return flatbuffers::ElementaryType::ET_SEQUENCE;
default:
LOG(FATAL) << "Unknown BaseType";
}
}
} // namespace
flatbuffers::ElementaryType FlatbufferType::FieldElementaryType(
int index) const {
DCHECK(IsSequence());
if (type_table_) {
DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
return static_cast<flatbuffers::ElementaryType>(type_code.base_type);
}
if (object_ || enum_) {
return ElementaryTypeFromBaseType(ReflectionElementBaseType(index));
}
LOG(FATAL) << "Unimplemented";
}
namespace {
size_t BaseTypeInlineSize(reflection::BaseType base_type) {
switch (base_type) {
case reflection::BaseType::None:
LOG(FATAL) << "Invalid schema";
case reflection::BaseType::UType:
case reflection::BaseType::Bool:
case reflection::BaseType::Byte:
case reflection::BaseType::UByte:
return 1;
case reflection::BaseType::Short:
case reflection::BaseType::UShort:
return 2;
case reflection::BaseType::Int:
case reflection::BaseType::UInt:
case reflection::BaseType::Float:
case reflection::BaseType::String:
return 4;
case reflection::BaseType::Long:
case reflection::BaseType::ULong:
case reflection::BaseType::Double:
return 8;
case reflection::BaseType::Union:
return 4;
default:
LOG(FATAL) << "Unknown BaseType";
}
}
} // namespace
size_t FlatbufferType::FieldInlineSize(int index) const {
DCHECK(IsSequence());
if (type_table_) {
return flatbuffers::InlineSize(FieldElementaryType(index), type_table_);
}
if (object_ || enum_) {
const reflection::Type *const type = ReflectionType(index);
const reflection::BaseType element_base_type =
ReflectionElementBaseType(index);
int element_size;
if (element_base_type == reflection::BaseType::Obj) {
const FlatbufferType field_type = FieldType(index);
if (field_type.object_ && field_type.object_->is_struct()) {
element_size = field_type.object_->bytesize();
} else {
element_size = 4;
}
} else {
element_size = BaseTypeInlineSize(element_base_type);
}
if (type->base_type() == reflection::BaseType::Array) {
return element_size * type->fixed_length();
}
return element_size;
}
LOG(FATAL) << "Unimplemented";
}
int FlatbufferType::NumberFields() const {
DCHECK(IsSequence());
if (type_table_) {
return type_table_->num_elems;
}
if (object_) {
return object_->fields()->size();
}
if (enum_) {
return enum_->values()->size();
}
LOG(FATAL) << "Unimplemented";
}
FlatbufferType FlatbufferType::FieldType(int index) const {
DCHECK(IsSequence());
if (type_table_) {
DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
CHECK_GE(type_code.sequence_ref, 0);
// type_refs can be shorter than num_elems, but not longer, so this is still
// a valid sanity check.
DCHECK_LT(static_cast<size_t>(type_code.sequence_ref),
type_table_->num_elems);
const flatbuffers::TypeFunction type_function =
type_table_->type_refs[type_code.sequence_ref];
return FlatbufferType(type_function());
}
if (object_ || enum_) {
const reflection::BaseType base_type = ReflectionElementBaseType(index);
const int object_index = ReflectionType(index)->index();
CHECK(object_index >= 0) << ": Invalid schema";
if (base_type == reflection::BaseType::Obj ||
base_type == reflection::BaseType::Union) {
DCHECK_LT(static_cast<size_t>(object_index), schema_->objects()->size());
return FlatbufferType(schema_, schema_->objects()->Get(object_index));
} else {
DCHECK_LT(static_cast<size_t>(object_index), schema_->enums()->size());
return FlatbufferType(schema_, schema_->enums()->Get(object_index));
}
}
LOG(FATAL) << "Unimplemented";
}
const reflection::Type *FlatbufferType::ReflectionType(int index) const {
if (object_) {
return ReflectionObjectField(index)->type();
} else {
return ReflectionEnumValue(index)->union_type();
}
}
const reflection::Field *FlatbufferType::ReflectionObjectField(
int index) const {
DCHECK(object_);
const auto result = std::find_if(
object_->fields()->begin(), object_->fields()->end(),
[index](const reflection::Field *field) { return field->id() == index; });
DCHECK(result != object_->fields()->end());
return *result;
}
const reflection::EnumVal *FlatbufferType::ReflectionEnumValue(
int index) const {
DCHECK(enum_);
const auto result =
std::find_if(enum_->values()->begin(), enum_->values()->end(),
[index](const reflection::EnumVal *value) {
return value->value() == index;
});
DCHECK(result != enum_->values()->end());
return *result;
}
reflection::BaseType FlatbufferType::ReflectionElementBaseType(
int index) const {
const reflection::Type *const type = ReflectionType(index);
reflection::BaseType base_type = type->base_type();
if (base_type == reflection::BaseType::Vector ||
base_type == reflection::BaseType::Array) {
base_type = type->element();
}
CHECK(base_type != reflection::BaseType::None);
return base_type;
}
} // namespace aos