#ifndef FLATBUFFERS_BFBS_GEN_H_
#define FLATBUFFERS_BFBS_GEN_H_
#include <cstdint>
#include "flatbuffers/code_generator.h"
#include "flatbuffers/reflection_generated.h"
namespace flatbuffers {
namespace {
static void ForAllEnums(
const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
std::function<void(const reflection::Enum *)> func) {
for (auto it = enums->cbegin(); it != enums->cend(); ++it) { func(*it); }
}
static void ForAllObjects(
const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects,
std::function<void(const reflection::Object *)> func) {
for (auto it = objects->cbegin(); it != objects->cend(); ++it) { func(*it); }
}
static void ForAllEnumValues(
const reflection::Enum *enum_def,
std::function<void(const reflection::EnumVal *)> func) {
for (auto it = enum_def->values()->cbegin(); it != enum_def->values()->cend();
++it) {
func(*it);
}
}
static void ForAllDocumentation(
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
*documentation,
std::function<void(const flatbuffers::String *)> func) {
if (!documentation) { return; }
for (auto it = documentation->cbegin(); it != documentation->cend(); ++it) {
func(*it);
}
}
static std::vector<uint32_t> FieldIdToIndex(const reflection::Object *object) {
std::vector<uint32_t> field_index_by_id;
field_index_by_id.resize(object->fields()->size());
for (uint32_t i = 0; i < object->fields()->size(); ++i) {
auto field = object->fields()->Get(i);
field_index_by_id[field->id()] = i;
}
return field_index_by_id;
}
static bool IsStructOrTable(const reflection::BaseType base_type) {
return base_type == reflection::Obj;
}
static bool IsFloatingPoint(const reflection::BaseType base_type) {
return base_type == reflection::Float || base_type == reflection::Double;
}
static bool IsBool(const reflection::BaseType base_type) {
return base_type == reflection::Bool;
}
static bool IsSingleByte(const reflection::BaseType base_type) {
return base_type >= reflection::UType && base_type <= reflection::UByte;
}
static bool IsVector(const reflection::BaseType base_type) {
return base_type == reflection::Vector;
}
}
class BaseBfbsGenerator : public CodeGenerator {
public:
virtual ~BaseBfbsGenerator() {}
BaseBfbsGenerator() : schema_(nullptr) {}
virtual Status GenerateFromSchema(const reflection::Schema *schema,
const CodeGenOptions &options) = 0;
virtual uint64_t SupportedAdvancedFeatures() const = 0;
Status GenerateCode(const uint8_t *buffer, int64_t length,
const CodeGenOptions &options) FLATBUFFERS_OVERRIDE {
flatbuffers::Verifier verifier(buffer, static_cast<size_t>(length));
if (!reflection::VerifySchemaBuffer(verifier)) {
return FAILED_VERIFICATION;
}
schema_ = reflection::GetSchema(buffer);
const uint64_t advance_features = schema_->advanced_features();
if (advance_features > SupportedAdvancedFeatures()) {
return FAILED_VERIFICATION;
}
Status status = GenerateFromSchema(schema_, options);
schema_ = nullptr;
return status;
}
protected:
const reflection::Object *GetObject(const reflection::Type *type,
bool element_type = false) const {
const reflection::BaseType base_type =
element_type ? type->element() : type->base_type();
if (type->index() >= 0 && IsStructOrTable(base_type)) {
return GetObjectByIndex(type->index());
}
return nullptr;
}
const reflection::Enum *GetEnum(const reflection::Type *type,
bool element_type = false) const {
const reflection::BaseType base_type =
element_type ? type->element() : type->base_type();
if (type->index() >= 0 && !IsStructOrTable(base_type)) {
return GetEnumByIndex(type->index());
}
return nullptr;
}
const reflection::Object *GetObjectByIndex(int32_t index) const {
if (!schema_ || index < 0 ||
index >= static_cast<int32_t>(schema_->objects()->size())) {
return nullptr;
}
return schema_->objects()->Get(index);
}
const reflection::Enum *GetEnumByIndex(int32_t index) const {
if (!schema_ || index < 0 ||
index >= static_cast<int32_t>(schema_->enums()->size())) {
return nullptr;
}
return schema_->enums()->Get(index);
}
void ForAllFields(const reflection::Object *object, bool reverse,
std::function<void(const reflection::Field *)> func) const {
const std::vector<uint32_t> field_to_id_map = FieldIdToIndex(object);
for (size_t i = 0; i < field_to_id_map.size(); ++i) {
func(object->fields()->Get(
field_to_id_map[reverse ? field_to_id_map.size() - (i + 1) : i]));
}
}
bool IsTable(const reflection::Type *type, bool use_element = false) const {
return !IsStruct(type, use_element);
}
bool IsStruct(const reflection::Type *type, bool use_element = false) const {
const reflection::BaseType base_type =
use_element ? type->element() : type->base_type();
return IsStructOrTable(base_type) &&
GetObjectByIndex(type->index())->is_struct();
}
const reflection::Schema *schema_;
};
}
#endif