xref: /aosp_15_r20/external/flatbuffers/src/bfbs_gen.h (revision 890232f25432b36107d06881e0a25aaa6b473652)
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/bfbs_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(const reflection::Enum *enum_def,
42                       std::function<void(const reflection::EnumVal *)> func) {
43   for (auto it = enum_def->values()->cbegin(); it != enum_def->values()->cend();
44        ++it) {
45     func(*it);
46   }
47 }
48 
ForAllDocumentation(const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> * documentation,std::function<void (const flatbuffers::String *)> func)49 static void ForAllDocumentation(
50     const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
51         *documentation,
52     std::function<void(const flatbuffers::String *)> func) {
53   if (!documentation) { return; }
54   for (auto it = documentation->cbegin(); it != documentation->cend(); ++it) {
55     func(*it);
56   }
57 }
58 
59 // Maps the field index into object->fields() to the field's ID (the ith element
60 // in the return vector).
FieldIdToIndex(const reflection::Object * object)61 static std::vector<uint32_t> FieldIdToIndex(const reflection::Object *object) {
62   std::vector<uint32_t> field_index_by_id;
63   field_index_by_id.resize(object->fields()->size());
64 
65   // Create the mapping of field ID to the index into the vector.
66   for (uint32_t i = 0; i < object->fields()->size(); ++i) {
67     auto field = object->fields()->Get(i);
68     field_index_by_id[field->id()] = i;
69   }
70 
71   return field_index_by_id;
72 }
73 
IsStructOrTable(const reflection::BaseType base_type)74 static bool IsStructOrTable(const reflection::BaseType base_type) {
75   return base_type == reflection::Obj;
76 }
77 
IsFloatingPoint(const reflection::BaseType base_type)78 static bool IsFloatingPoint(const reflection::BaseType base_type) {
79   return base_type == reflection::Float || base_type == reflection::Double;
80 }
81 
IsBool(const reflection::BaseType base_type)82 static bool IsBool(const reflection::BaseType base_type) {
83   return base_type == reflection::Bool;
84 }
85 
IsSingleByte(const reflection::BaseType base_type)86 static bool IsSingleByte(const reflection::BaseType base_type) {
87   return base_type >= reflection::UType && base_type <= reflection::UByte;
88 }
89 
IsVector(const reflection::BaseType base_type)90 static bool IsVector(const reflection::BaseType base_type) {
91   return base_type == reflection::Vector;
92 }
93 
94 } // namespace
95 
96 // A concrete base Flatbuffer Generator that specific language generators can
97 // derive from.
98 class BaseBfbsGenerator : public BfbsGenerator {
99  public:
~BaseBfbsGenerator()100   virtual ~BaseBfbsGenerator() {}
BaseBfbsGenerator()101   BaseBfbsGenerator() : schema_(nullptr) {}
102 
103   virtual GeneratorStatus GenerateFromSchema(
104       const reflection::Schema *schema) = 0;
105 
106   //
107   virtual uint64_t SupportedAdvancedFeatures() const = 0;
108 
109   // Override of the Generator::generate method that does the initial
110   // deserialization and verification steps.
Generate(const uint8_t * buffer,int64_t length)111   GeneratorStatus Generate(const uint8_t *buffer,
112                            int64_t length) 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     GeneratorStatus status = GenerateFromSchema(schema_);
128     schema_ = nullptr;
129     return status;
130   }
131 
132  protected:
GetObject(const reflection::Type * type)133   const reflection::Object *GetObject(const reflection::Type *type) const {
134     if (type->index() >= 0 && IsStructOrTable(type->base_type())) {
135       return GetObjectByIndex(type->index());
136     }
137     return nullptr;
138   }
139 
GetEnum(const reflection::Type * type)140   const reflection::Enum *GetEnum(const reflection::Type *type) const {
141     // TODO(derekbailey): it would be better to have a explicit list of allowed
142     // base types, instead of negating Obj types.
143     if (type->index() >= 0 && !IsStructOrTable(type->base_type())) {
144       return GetEnumByIndex(type->index());
145     }
146     return nullptr;
147   }
148 
149   // Used to get a object that is reference by index. (e.g.
150   // reflection::Type::index). Returns nullptr if no object is available.
GetObjectByIndex(int32_t index)151   const reflection::Object *GetObjectByIndex(int32_t index) const {
152     if (!schema_ || index < 0 ||
153         index >= static_cast<int32_t>(schema_->objects()->size())) {
154       return nullptr;
155     }
156     return schema_->objects()->Get(index);
157   }
158 
159   // Used to get a enum that is reference by index. (e.g.
160   // reflection::Type::index). Returns nullptr if no enum is available.
GetEnumByIndex(int32_t index)161   const reflection::Enum *GetEnumByIndex(int32_t index) const {
162     if (!schema_ || index < 0 ||
163         index >= static_cast<int32_t>(schema_->enums()->size())) {
164       return nullptr;
165     }
166     return schema_->enums()->Get(index);
167   }
168 
ForAllFields(const reflection::Object * object,bool reverse,std::function<void (const reflection::Field *)> func)169   void ForAllFields(const reflection::Object *object, bool reverse,
170                     std::function<void(const reflection::Field *)> func) const {
171     const std::vector<uint32_t> field_to_id_map = FieldIdToIndex(object);
172     for (size_t i = 0; i < field_to_id_map.size(); ++i) {
173       func(object->fields()->Get(
174           field_to_id_map[reverse ? field_to_id_map.size() - (i + 1) : i]));
175     }
176   }
177 
178   bool IsTable(const reflection::Type *type, bool use_element = false) const {
179     return !IsStruct(type, use_element);
180   }
181 
182   bool IsStruct(const reflection::Type *type, bool use_element = false) const {
183     const reflection::BaseType base_type =
184         use_element ? type->element() : type->base_type();
185     return IsStructOrTable(base_type) &&
186            GetObjectByIndex(type->index())->is_struct();
187   }
188 
189   const reflection::Schema *schema_;
190 };
191 
192 }  // namespace flatbuffers
193 
194 #endif  // FLATBUFFERS_BFBS_GEN_H_
195