blob: 63220e8aae0fd2c3de864bc8251c55d4db62316c [file] [log] [blame]
James Kuszmauldac091f2022-03-22 09:35:06 -07001/*
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
25namespace flatbuffers {
26
Austin Schuha1d006e2022-09-14 21:50:42 -070027namespace {
28
29static void ForAllEnums(
James Kuszmauldac091f2022-03-22 09:35:06 -070030 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
Austin Schuha1d006e2022-09-14 21:50:42 -070035static void ForAllObjects(
James Kuszmauldac091f2022-03-22 09:35:06 -070036 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
Austin Schuha1d006e2022-09-14 21:50:42 -070041static void ForAllEnumValues(const reflection::Enum *enum_def,
James Kuszmauldac091f2022-03-22 09:35:06 -070042 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
Austin Schuha1d006e2022-09-14 21:50:42 -070049static void ForAllDocumentation(
James Kuszmauldac091f2022-03-22 09:35:06 -070050 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).
61static 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
74static bool IsStructOrTable(const reflection::BaseType base_type) {
75 return base_type == reflection::BaseType::Obj;
76}
77
James Kuszmauldac091f2022-03-22 09:35:06 -070078static bool IsFloatingPoint(const reflection::BaseType base_type) {
79 return base_type == reflection::BaseType::Float || base_type == reflection::BaseType::Double;
80}
81
82static bool IsBool(const reflection::BaseType base_type) {
83 return base_type == reflection::BaseType::Bool;
84}
85
86static bool IsSingleByte(const reflection::BaseType base_type) {
87 return base_type >= reflection::BaseType::UType && base_type <= reflection::BaseType::UByte;
88}
89
90static bool IsVector(const reflection::BaseType base_type) {
91 return base_type == reflection::BaseType::Vector;
92}
93
Austin Schuha1d006e2022-09-14 21:50:42 -070094} // namespace
James Kuszmauldac091f2022-03-22 09:35:06 -070095
96// A concrete base Flatbuffer Generator that specific language generators can
97// derive from.
98class BaseBfbsGenerator : public BfbsGenerator {
99 public:
100 virtual ~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.
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 = static_cast<uint64_t>(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:
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
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.
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.
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
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_