• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef FLATBUFFERS_BFBS_GEN_H_
18 #define FLATBUFFERS_BFBS_GEN_H_
19 
20 #include <cstdint>
21 
22 #include "flatbuffers/code_generator.h"
23 #include "flatbuffers/reflection_generated.h"
24 
25 namespace flatbuffers {
26 
27 namespace {
28 
ForAllEnums(const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> * enums,std::function<void (const reflection::Enum *)> func)29 static void ForAllEnums(
30     const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
31     std::function<void(const reflection::Enum *)> func) {
32   for (auto it = enums->cbegin(); it != enums->cend(); ++it) { func(*it); }
33 }
34 
ForAllObjects(const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> * objects,std::function<void (const reflection::Object *)> func)35 static void ForAllObjects(
36     const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects,
37     std::function<void(const reflection::Object *)> func) {
38   for (auto it = objects->cbegin(); it != objects->cend(); ++it) { func(*it); }
39 }
40 
ForAllEnumValues(const reflection::Enum * enum_def,std::function<void (const reflection::EnumVal *)> func)41 static void ForAllEnumValues(
42     const reflection::Enum *enum_def,
43     std::function<void(const reflection::EnumVal *)> func) {
44   for (auto it = enum_def->values()->cbegin(); it != enum_def->values()->cend();
45        ++it) {
46     func(*it);
47   }
48 }
49 
ForAllDocumentation(const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> * documentation,std::function<void (const flatbuffers::String *)> func)50 static void ForAllDocumentation(
51     const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
52         *documentation,
53     std::function<void(const flatbuffers::String *)> func) {
54   if (!documentation) { return; }
55   for (auto it = documentation->cbegin(); it != documentation->cend(); ++it) {
56     func(*it);
57   }
58 }
59 
60 // Maps the field index into object->fields() to the field's ID (the ith element
61 // in the return vector).
FieldIdToIndex(const reflection::Object * object)62 static std::vector<uint32_t> FieldIdToIndex(const reflection::Object *object) {
63   std::vector<uint32_t> field_index_by_id;
64   field_index_by_id.resize(object->fields()->size());
65 
66   // Create the mapping of field ID to the index into the vector.
67   for (uint32_t i = 0; i < object->fields()->size(); ++i) {
68     auto field = object->fields()->Get(i);
69     field_index_by_id[field->id()] = i;
70   }
71 
72   return field_index_by_id;
73 }
74 
IsStructOrTable(const reflection::BaseType base_type)75 static bool IsStructOrTable(const reflection::BaseType base_type) {
76   return base_type == reflection::Obj;
77 }
78 
IsFloatingPoint(const reflection::BaseType base_type)79 static bool IsFloatingPoint(const reflection::BaseType base_type) {
80   return base_type == reflection::Float || base_type == reflection::Double;
81 }
82 
IsBool(const reflection::BaseType base_type)83 static bool IsBool(const reflection::BaseType base_type) {
84   return base_type == reflection::Bool;
85 }
86 
IsSingleByte(const reflection::BaseType base_type)87 static bool IsSingleByte(const reflection::BaseType base_type) {
88   return base_type >= reflection::UType && base_type <= reflection::UByte;
89 }
90 
IsVector(const reflection::BaseType base_type)91 static bool IsVector(const reflection::BaseType base_type) {
92   return base_type == reflection::Vector;
93 }
94 
95 }  // namespace
96 
97 // A concrete base Flatbuffer Generator that specific language generators can
98 // derive from.
99 class BaseBfbsGenerator : public CodeGenerator {
100  public:
~BaseBfbsGenerator()101   virtual ~BaseBfbsGenerator() {}
BaseBfbsGenerator()102   BaseBfbsGenerator() : schema_(nullptr) {}
103 
104   virtual Status GenerateFromSchema(const reflection::Schema *schema,
105                                     const CodeGenOptions &options) = 0;
106 
107   virtual uint64_t SupportedAdvancedFeatures() const = 0;
108 
109   // Override of the Generator::GenerateCode method that does the initial
110   // deserialization and verification steps.
GenerateCode(const uint8_t * buffer,int64_t length,const CodeGenOptions & options)111   Status GenerateCode(const uint8_t *buffer, int64_t length,
112                       const CodeGenOptions &options) FLATBUFFERS_OVERRIDE {
113     flatbuffers::Verifier verifier(buffer, static_cast<size_t>(length));
114     if (!reflection::VerifySchemaBuffer(verifier)) {
115       return FAILED_VERIFICATION;
116     }
117 
118     // Store the root schema since there are cases where leaf nodes refer to
119     // things in the root schema (e.g., indexing the objects).
120     schema_ = reflection::GetSchema(buffer);
121 
122     const uint64_t advance_features = schema_->advanced_features();
123     if (advance_features > SupportedAdvancedFeatures()) {
124       return FAILED_VERIFICATION;
125     }
126 
127     Status status = GenerateFromSchema(schema_, options);
128     schema_ = nullptr;
129     return status;
130   }
131 
132  protected:
133   // GetObject returns the underlying object struct of the given type
134   // if element_type is true and GetObject is a list of objects then
135   // GetObject will correctly return the object struct of the vector's elements
136   const reflection::Object *GetObject(const reflection::Type *type,
137                                       bool element_type = false) const {
138     const reflection::BaseType base_type =
139         element_type ? type->element() : type->base_type();
140     if (type->index() >= 0 && IsStructOrTable(base_type)) {
141       return GetObjectByIndex(type->index());
142     }
143     return nullptr;
144   }
145 
146   // GetEnum returns the underlying enum struct of the given type
147   // if element_type is true and GetEnum is a list of enums then
148   // GetEnum will correctly return the enum struct of the vector's elements
149   const reflection::Enum *GetEnum(const reflection::Type *type,
150                                   bool element_type = false) const {
151     const reflection::BaseType base_type =
152         element_type ? type->element() : type->base_type();
153     // TODO(derekbailey): it would be better to have a explicit list of allowed
154     // base types, instead of negating Obj types.
155     if (type->index() >= 0 && !IsStructOrTable(base_type)) {
156       return GetEnumByIndex(type->index());
157     }
158     return nullptr;
159   }
160 
161   // Used to get a object that is reference by index. (e.g.
162   // reflection::Type::index). Returns nullptr if no object is available.
GetObjectByIndex(int32_t index)163   const reflection::Object *GetObjectByIndex(int32_t index) const {
164     if (!schema_ || index < 0 ||
165         index >= static_cast<int32_t>(schema_->objects()->size())) {
166       return nullptr;
167     }
168     return schema_->objects()->Get(index);
169   }
170 
171   // Used to get a enum that is reference by index. (e.g.
172   // reflection::Type::index). Returns nullptr if no enum is available.
GetEnumByIndex(int32_t index)173   const reflection::Enum *GetEnumByIndex(int32_t index) const {
174     if (!schema_ || index < 0 ||
175         index >= static_cast<int32_t>(schema_->enums()->size())) {
176       return nullptr;
177     }
178     return schema_->enums()->Get(index);
179   }
180 
ForAllFields(const reflection::Object * object,bool reverse,std::function<void (const reflection::Field *)> func)181   void ForAllFields(const reflection::Object *object, bool reverse,
182                     std::function<void(const reflection::Field *)> func) const {
183     const std::vector<uint32_t> field_to_id_map = FieldIdToIndex(object);
184     for (size_t i = 0; i < field_to_id_map.size(); ++i) {
185       func(object->fields()->Get(
186           field_to_id_map[reverse ? field_to_id_map.size() - (i + 1) : i]));
187     }
188   }
189 
190   bool IsTable(const reflection::Type *type, bool use_element = false) const {
191     return !IsStruct(type, use_element);
192   }
193 
194   bool IsStruct(const reflection::Type *type, bool use_element = false) const {
195     const reflection::BaseType base_type =
196         use_element ? type->element() : type->base_type();
197     return IsStructOrTable(base_type) &&
198            GetObjectByIndex(type->index())->is_struct();
199   }
200 
201   const reflection::Schema *schema_;
202 };
203 
204 }  // namespace flatbuffers
205 
206 #endif  // FLATBUFFERS_BFBS_GEN_H_
207