207 lines
7.2 KiB
C++
207 lines
7.2 KiB
C++
/*
|
|
* Copyright 2021 Google Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#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);
|
|
}
|
|
}
|
|
|
|
// Maps the field index into object->fields() to the field's ID (the ith element
|
|
// in the return vector).
|
|
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());
|
|
|
|
// Create the mapping of field ID to the index into the vector.
|
|
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;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// A concrete base Flatbuffer Generator that specific language generators can
|
|
// derive from.
|
|
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;
|
|
|
|
// Override of the Generator::GenerateCode method that does the initial
|
|
// deserialization and verification steps.
|
|
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;
|
|
}
|
|
|
|
// Store the root schema since there are cases where leaf nodes refer to
|
|
// things in the root schema (e.g., indexing the objects).
|
|
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:
|
|
// GetObject returns the underlying object struct of the given type
|
|
// if element_type is true and GetObject is a list of objects then
|
|
// GetObject will correctly return the object struct of the vector's elements
|
|
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;
|
|
}
|
|
|
|
// GetEnum returns the underlying enum struct of the given type
|
|
// if element_type is true and GetEnum is a list of enums then
|
|
// GetEnum will correctly return the enum struct of the vector's elements
|
|
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();
|
|
// TODO(derekbailey): it would be better to have a explicit list of allowed
|
|
// base types, instead of negating Obj types.
|
|
if (type->index() >= 0 && !IsStructOrTable(base_type)) {
|
|
return GetEnumByIndex(type->index());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Used to get a object that is reference by index. (e.g.
|
|
// reflection::Type::index). Returns nullptr if no object is available.
|
|
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);
|
|
}
|
|
|
|
// Used to get a enum that is reference by index. (e.g.
|
|
// reflection::Type::index). Returns nullptr if no enum is available.
|
|
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_;
|
|
};
|
|
|
|
} // namespace flatbuffers
|
|
|
|
#endif // FLATBUFFERS_BFBS_GEN_H_
|