mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-09 14:46:26 +00:00
rebased fork
This commit is contained in:
@@ -90,7 +90,9 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
|
||||
" --defaults-json Output fields whose value is the default when\n"
|
||||
" writing JSON\n"
|
||||
" --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
|
||||
" --gen-includes (deprecated), instead use:\n"
|
||||
" --gen-includes (deprecated), this is the default behavior.\n"
|
||||
" If the original behavior is required (no include\n"
|
||||
" statements) use --no-includes.\n"
|
||||
" --no-includes Don\'t generate include statements for included\n"
|
||||
" schemas the generated file depends on (C++).\n"
|
||||
" --gen-mutable Generate accessors that can mutate buffers in-place.\n"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -202,6 +203,10 @@ static std::string GenTypeBasic(const LanguageParameters &lang,
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
|
||||
if(lang.language == GeneratorOptions::kCSharp && type.base_type == BASE_TYPE_STRUCT) {
|
||||
return "Offset<" + type.struct_def->name + ">";
|
||||
}
|
||||
|
||||
return gtypename[type.base_type * GeneratorOptions::kMAX + lang.language];
|
||||
}
|
||||
|
||||
@@ -258,6 +263,32 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type,
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenOffsetType(const LanguageParameters &lang, const StructDef &struct_def) {
|
||||
if(lang.language == GeneratorOptions::kCSharp) {
|
||||
return "Offset<" + struct_def.name + ">";
|
||||
} else {
|
||||
return "int";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenOffsetConstruct(const LanguageParameters &lang,
|
||||
const StructDef &struct_def,
|
||||
const std::string &variable_name)
|
||||
{
|
||||
if(lang.language == GeneratorOptions::kCSharp) {
|
||||
return "new Offset<" + struct_def.name + ">(" + variable_name + ")";
|
||||
}
|
||||
return variable_name;
|
||||
}
|
||||
|
||||
static std::string GenVectorOffsetType(const LanguageParameters &lang) {
|
||||
if(lang.language == GeneratorOptions::kCSharp) {
|
||||
return "VectorOffset";
|
||||
} else {
|
||||
return "int";
|
||||
}
|
||||
}
|
||||
|
||||
// Generate destination type name
|
||||
static std::string GenTypeNameDest(const LanguageParameters &lang, const Type &type)
|
||||
{
|
||||
@@ -353,7 +384,20 @@ static std::string SourceCast(const LanguageParameters &lang,
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string GenDefaultValue(const Value &value) {
|
||||
static std::string GenDefaultValue(const LanguageParameters &lang, const Value &value, bool for_buffer) {
|
||||
if(lang.language == GeneratorOptions::kCSharp && !for_buffer) {
|
||||
switch(value.type.base_type) {
|
||||
case BASE_TYPE_STRING:
|
||||
return "default(StringOffset)";
|
||||
case BASE_TYPE_STRUCT:
|
||||
return "default(Offset<" + value.type.struct_def->name + ">)";
|
||||
case BASE_TYPE_VECTOR:
|
||||
return "default(VectorOffset)";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value.type.base_type == BASE_TYPE_BOOL
|
||||
? (value.constant == "0" ? "false" : "true")
|
||||
: value.constant;
|
||||
@@ -658,7 +702,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
} else {
|
||||
code += offset_prefix + getter;
|
||||
code += "(o + bb_pos)" + dest_mask + " : " + default_cast;
|
||||
code += GenDefaultValue(field.value);
|
||||
code += GenDefaultValue(lang, field.value, false);
|
||||
}
|
||||
} else {
|
||||
switch (field.value.type.base_type) {
|
||||
@@ -765,13 +809,14 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += "\n";
|
||||
if (struct_def.fixed) {
|
||||
// create a struct constructor function
|
||||
code += " public static int " + FunctionStart(lang, 'C') + "reate";
|
||||
code += " public static " + GenOffsetType(lang, struct_def) + " ";
|
||||
code += FunctionStart(lang, 'C') + "reate";
|
||||
code += struct_def.name + "(FlatBufferBuilder builder";
|
||||
GenStructArgs(lang, struct_def, code_ptr, "");
|
||||
code += ") {\n";
|
||||
GenStructBody(lang, struct_def, code_ptr, "");
|
||||
code += " return builder.";
|
||||
code += lang.get_fbb_offset;
|
||||
code += " return ";
|
||||
code += GenOffsetConstruct(lang, struct_def, "builder." + std::string(lang.get_fbb_offset));
|
||||
code += ";\n }\n";
|
||||
} else {
|
||||
// Generate a method that creates a table in one go. This is only possible
|
||||
@@ -791,9 +836,9 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
}
|
||||
if (has_no_struct_fields && num_fields) {
|
||||
// Generate a table constructor of the form:
|
||||
// public static void createName(FlatBufferBuilder builder, args...)
|
||||
code += " public static int " + FunctionStart(lang, 'C') + "reate";
|
||||
code += struct_def.name;
|
||||
// public static int createName(FlatBufferBuilder builder, args...)
|
||||
code += " public static " + GenOffsetType(lang, struct_def) + " ";
|
||||
code += FunctionStart(lang, 'C') + "reate" + struct_def.name;
|
||||
code += "(FlatBufferBuilder builder";
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
@@ -807,7 +852,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
// Java doesn't have defaults, which means this method must always
|
||||
// supply all arguments, and thus won't compile when fields are added.
|
||||
if (lang.language != GeneratorOptions::kJava) {
|
||||
code += " = " + GenDefaultValue(field.value);
|
||||
code += " = " + GenDefaultValue(lang, field.value, false);
|
||||
}
|
||||
}
|
||||
code += ") {\n builder.";
|
||||
@@ -857,7 +902,10 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += GenMethod(lang, field.value.type) + "(";
|
||||
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
|
||||
code += DestinationValue(lang, argname, field.value.type);
|
||||
code += ", " + GenDefaultValue(field.value);
|
||||
if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang.language == GeneratorOptions::kCSharp) {
|
||||
code += ".Value";
|
||||
}
|
||||
code += ", " + GenDefaultValue(lang, field.value, true);
|
||||
code += "); }\n";
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
auto vector_type = field.value.type.VectorType();
|
||||
@@ -865,7 +913,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
auto elem_size = InlineSize(vector_type);
|
||||
if (!IsStruct(vector_type)) {
|
||||
// Generate a method to create a vector from a Java array.
|
||||
code += " public static int " + FunctionStart(lang, 'C') + "reate";
|
||||
code += " public static " + GenVectorOffsetType(lang) + " " + FunctionStart(lang, 'C') + "reate";
|
||||
code += MakeCamel(field.name);
|
||||
code += "Vector(FlatBufferBuilder builder, ";
|
||||
code += GenTypeBasic(lang, vector_type) + "[] data) ";
|
||||
@@ -877,8 +925,12 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += FunctionStart(lang, 'L') + "ength - 1; i >= 0; i--) builder.";
|
||||
code += FunctionStart(lang, 'A') + "dd";
|
||||
code += GenMethod(lang, vector_type);
|
||||
code += "(data[i]); return builder.";
|
||||
code += FunctionStart(lang, 'E') + "ndVector(); }\n";
|
||||
code += "(data[i]";
|
||||
if(lang.language == GeneratorOptions::kCSharp &&
|
||||
(vector_type.base_type == BASE_TYPE_STRUCT || vector_type.base_type == BASE_TYPE_STRING))
|
||||
code += ".Value";
|
||||
code += "); return ";
|
||||
code += "builder." + FunctionStart(lang, 'E') + "ndVector(); }\n";
|
||||
}
|
||||
// Generate a method to start a vector, data to be added manually after.
|
||||
code += " public static void " + FunctionStart(lang, 'S') + "tart";
|
||||
@@ -890,7 +942,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += "); }\n";
|
||||
}
|
||||
}
|
||||
code += " public static int ";
|
||||
code += " public static " + GenOffsetType(lang, struct_def) + " ";
|
||||
code += FunctionStart(lang, 'E') + "nd" + struct_def.name;
|
||||
code += "(FlatBufferBuilder builder) {\n int o = builder.";
|
||||
code += FunctionStart(lang, 'E') + "ndObject();\n";
|
||||
@@ -904,12 +956,16 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += "); // " + field.name + "\n";
|
||||
}
|
||||
}
|
||||
code += " return o;\n }\n";
|
||||
code += " return " + GenOffsetConstruct(lang, struct_def, "o") + ";\n }\n";
|
||||
if (parser.root_struct_def_ == &struct_def) {
|
||||
code += " public static void ";
|
||||
code += FunctionStart(lang, 'F') + "inish" + struct_def.name;
|
||||
code += "Buffer(FlatBufferBuilder builder, int offset) { ";
|
||||
code += "builder." + FunctionStart(lang, 'F') + "inish(offset";
|
||||
code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(lang, struct_def) + " offset) {";
|
||||
code += " builder." + FunctionStart(lang, 'F') + "inish(offset";
|
||||
if (lang.language == GeneratorOptions::kCSharp) {
|
||||
code += ".Value";
|
||||
}
|
||||
|
||||
if (parser.file_identifier_.length())
|
||||
code += ", \"" + parser.file_identifier_ + "\"";
|
||||
code += "); }\n";
|
||||
|
||||
@@ -918,10 +918,10 @@ void Parser::ParseDecl() {
|
||||
auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
|
||||
if (force_align->type.base_type != BASE_TYPE_INT ||
|
||||
align < struct_def.minalign ||
|
||||
align > 256 ||
|
||||
align > 16 ||
|
||||
align & (align - 1))
|
||||
Error("force_align must be a power of two integer ranging from the"
|
||||
"struct\'s natural alignment to 256");
|
||||
"struct\'s natural alignment to 16");
|
||||
struct_def.minalign = align;
|
||||
}
|
||||
struct_def.PadLastField(struct_def.minalign);
|
||||
|
||||
471
src/reflection.cpp
Normal file
471
src/reflection.cpp
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright 2015 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.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/reflection.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
// Helper functionality for reflection.
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
|
||||
# define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
|
||||
switch (type) {
|
||||
case reflection::UType:
|
||||
case reflection::Bool:
|
||||
case reflection::UByte: return FLATBUFFERS_GET(uint8_t);
|
||||
case reflection::Byte: return FLATBUFFERS_GET(int8_t);
|
||||
case reflection::Short: return FLATBUFFERS_GET(int16_t);
|
||||
case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
|
||||
case reflection::Int: return FLATBUFFERS_GET(int32_t);
|
||||
case reflection::UInt: return FLATBUFFERS_GET(uint32_t);
|
||||
case reflection::Long: return FLATBUFFERS_GET(int64_t);
|
||||
case reflection::ULong: return FLATBUFFERS_GET(uint64_t);
|
||||
case reflection::Float: return FLATBUFFERS_GET(float);
|
||||
case reflection::Double: return FLATBUFFERS_GET(double);
|
||||
case reflection::String: {
|
||||
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
|
||||
data);
|
||||
return s ? StringToInt(s->c_str()) : 0;
|
||||
}
|
||||
default: return 0; // Tables & vectors do not make sense.
|
||||
}
|
||||
# undef FLATBUFFERS_GET
|
||||
}
|
||||
|
||||
double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
|
||||
switch (type) {
|
||||
case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
|
||||
case reflection::Double: return ReadScalar<double>(data);
|
||||
case reflection::String: {
|
||||
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
|
||||
data);
|
||||
return s ? strtod(s->c_str(), nullptr) : 0.0;
|
||||
}
|
||||
default: return static_cast<double>(GetAnyValueI(type, data));
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
|
||||
const reflection::Schema *schema, int type_index) {
|
||||
switch (type) {
|
||||
case reflection::Float:
|
||||
case reflection::Double: return NumToString(GetAnyValueF(type, data));
|
||||
case reflection::String: {
|
||||
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
|
||||
data);
|
||||
return s ? s->c_str() : "";
|
||||
}
|
||||
case reflection::Obj:
|
||||
if (schema) {
|
||||
// Convert the table to a string. This is mostly for debugging purposes,
|
||||
// and does NOT promise to be JSON compliant.
|
||||
// Also prefixes the type.
|
||||
auto &objectdef = *schema->objects()->Get(type_index);
|
||||
auto s = objectdef.name()->str();
|
||||
if (objectdef.is_struct()) {
|
||||
s += "(struct)"; // TODO: implement this as well.
|
||||
} else {
|
||||
auto table_field = reinterpret_cast<const Table *>(
|
||||
ReadScalar<uoffset_t>(data) + data);
|
||||
s += " { ";
|
||||
auto fielddefs = objectdef.fields();
|
||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||
auto &fielddef = **it;
|
||||
if (!table_field->CheckField(fielddef.offset())) continue;
|
||||
auto val = GetAnyFieldS(*table_field, fielddef, schema);
|
||||
if (fielddef.type()->base_type() == reflection::String)
|
||||
val = "\"" + val + "\""; // Doesn't deal with escape codes etc.
|
||||
s += fielddef.name()->str();
|
||||
s += ": ";
|
||||
s += val;
|
||||
s += ", ";
|
||||
}
|
||||
s += "}";
|
||||
}
|
||||
return s;
|
||||
} else {
|
||||
return "(table)";
|
||||
}
|
||||
case reflection::Vector:
|
||||
return "[(elements)]"; // TODO: implement this as well.
|
||||
case reflection::Union:
|
||||
return "(union)"; // TODO: implement this as well.
|
||||
default: return NumToString(GetAnyValueI(type, data));
|
||||
}
|
||||
}
|
||||
|
||||
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
|
||||
# define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
|
||||
switch (type) {
|
||||
case reflection::UType:
|
||||
case reflection::Bool:
|
||||
case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break;
|
||||
case reflection::Byte: FLATBUFFERS_SET(int8_t ); break;
|
||||
case reflection::Short: FLATBUFFERS_SET(int16_t ); break;
|
||||
case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
|
||||
case reflection::Int: FLATBUFFERS_SET(int32_t ); break;
|
||||
case reflection::UInt: FLATBUFFERS_SET(uint32_t); break;
|
||||
case reflection::Long: FLATBUFFERS_SET(int64_t ); break;
|
||||
case reflection::ULong: FLATBUFFERS_SET(uint64_t); break;
|
||||
case reflection::Float: FLATBUFFERS_SET(float ); break;
|
||||
case reflection::Double: FLATBUFFERS_SET(double ); break;
|
||||
// TODO: support strings
|
||||
default: break;
|
||||
}
|
||||
# undef FLATBUFFERS_SET
|
||||
}
|
||||
|
||||
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
|
||||
switch (type) {
|
||||
case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
|
||||
case reflection::Double: WriteScalar(data, val); break;
|
||||
// TODO: support strings.
|
||||
default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
|
||||
switch (type) {
|
||||
case reflection::Float:
|
||||
case reflection::Double:
|
||||
SetAnyValueF(type, data, strtod(val, nullptr));
|
||||
break;
|
||||
// TODO: support strings.
|
||||
default: SetAnyValueI(type, data, StringToInt(val)); break;
|
||||
}
|
||||
}
|
||||
|
||||
// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
|
||||
// and adjusting them by "delta" if they straddle the start offset.
|
||||
// Once that is done, bytes can now be inserted/deleted safely.
|
||||
// "delta" may be negative (shrinking).
|
||||
// Unless "delta" is a multiple of the largest alignment, you'll create a small
|
||||
// amount of garbage space in the buffer (usually 0..7 bytes).
|
||||
// If your FlatBuffer's root table is not the schema's root table, you should
|
||||
// pass in your root_table type as well.
|
||||
class ResizeContext {
|
||||
public:
|
||||
ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
|
||||
std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table = nullptr)
|
||||
: schema_(schema), startptr_(flatbuf->data() + start),
|
||||
delta_(delta), buf_(*flatbuf),
|
||||
dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
|
||||
auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
|
||||
delta_ = (delta_ + mask) & ~mask;
|
||||
if (!delta_) return; // We can't shrink by less than largest_scalar_t.
|
||||
// Now change all the offsets by delta_.
|
||||
auto root = GetAnyRoot(buf_.data());
|
||||
Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
|
||||
ResizeTable(root_table ? *root_table : *schema.root_table(), root);
|
||||
// We can now add or remove bytes at start.
|
||||
if (delta_ > 0) buf_.insert(buf_.begin() + start, delta_, 0);
|
||||
else buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
|
||||
}
|
||||
|
||||
// Check if the range between first (lower address) and second straddles
|
||||
// the insertion point. If it does, change the offset at offsetloc (of
|
||||
// type T, with direction D).
|
||||
template<typename T, int D> void Straddle(void *first, void *second,
|
||||
void *offsetloc) {
|
||||
if (first <= startptr_ && second >= startptr_) {
|
||||
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
|
||||
DagCheck(offsetloc) = true;
|
||||
}
|
||||
}
|
||||
|
||||
// This returns a boolean that records if the corresponding offset location
|
||||
// has been modified already. If so, we can't even read the corresponding
|
||||
// offset, since it is pointing to a location that is illegal until the
|
||||
// resize actually happens.
|
||||
// This must be checked for every offset, since we can't know which offsets
|
||||
// will straddle and which won't.
|
||||
uint8_t &DagCheck(void *offsetloc) {
|
||||
auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
|
||||
reinterpret_cast<uoffset_t *>(buf_.data());
|
||||
return dag_check_[dag_idx];
|
||||
}
|
||||
|
||||
void ResizeTable(const reflection::Object &objectdef, Table *table) {
|
||||
if (DagCheck(table))
|
||||
return; // Table already visited.
|
||||
auto vtable = table->GetVTable();
|
||||
// Check if the vtable offset points beyond the insertion point.
|
||||
Straddle<soffset_t, -1>(table, vtable, table);
|
||||
// This direction shouldn't happen because vtables that sit before tables
|
||||
// are always directly adjacent, but check just in case we ever change the
|
||||
// way flatbuffers are built.
|
||||
Straddle<soffset_t, -1>(vtable, table, table);
|
||||
// Early out: since all fields inside the table must point forwards in
|
||||
// memory, if the insertion point is before the table we can stop here.
|
||||
auto tableloc = reinterpret_cast<uint8_t *>(table);
|
||||
if (startptr_ <= tableloc) return;
|
||||
// Check each field.
|
||||
auto fielddefs = objectdef.fields();
|
||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||
auto &fielddef = **it;
|
||||
auto base_type = fielddef.type()->base_type();
|
||||
// Ignore scalars.
|
||||
if (base_type <= reflection::Double) continue;
|
||||
// Ignore fields that are not stored.
|
||||
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
|
||||
if (!offset) continue;
|
||||
// Ignore structs.
|
||||
auto subobjectdef = base_type == reflection::Obj ?
|
||||
schema_.objects()->Get(fielddef.type()->index()) : nullptr;
|
||||
if (subobjectdef && subobjectdef->is_struct()) continue;
|
||||
// Get this fields' offset, and read it if safe.
|
||||
auto offsetloc = tableloc + offset;
|
||||
if (DagCheck(offsetloc))
|
||||
continue; // This offset already visited.
|
||||
auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
|
||||
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
|
||||
// Recurse.
|
||||
switch (base_type) {
|
||||
case reflection::Obj: {
|
||||
ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
|
||||
break;
|
||||
}
|
||||
case reflection::Vector: {
|
||||
auto elem_type = fielddef.type()->element();
|
||||
if (elem_type != reflection::Obj && elem_type != reflection::String)
|
||||
break;
|
||||
auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
|
||||
auto elemobjectdef = elem_type == reflection::Obj
|
||||
? schema_.objects()->Get(fielddef.type()->index())
|
||||
: nullptr;
|
||||
if (elemobjectdef && elemobjectdef->is_struct()) break;
|
||||
for (uoffset_t i = 0; i < vec->size(); i++) {
|
||||
auto loc = vec->Data() + i * sizeof(uoffset_t);
|
||||
if (DagCheck(loc))
|
||||
continue; // This offset already visited.
|
||||
auto dest = loc + vec->Get(i);
|
||||
Straddle<uoffset_t, 1>(loc, dest ,loc);
|
||||
if (elemobjectdef)
|
||||
ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case reflection::Union: {
|
||||
ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
|
||||
reinterpret_cast<Table *>(ref));
|
||||
break;
|
||||
}
|
||||
case reflection::String:
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(const ResizeContext &rc);
|
||||
|
||||
private:
|
||||
const reflection::Schema &schema_;
|
||||
uint8_t *startptr_;
|
||||
int delta_;
|
||||
std::vector<uint8_t> &buf_;
|
||||
std::vector<uint8_t> dag_check_;
|
||||
};
|
||||
|
||||
void SetString(const reflection::Schema &schema, const std::string &val,
|
||||
const String *str, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table) {
|
||||
auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
|
||||
auto start = static_cast<uoffset_t>(reinterpret_cast<const uint8_t *>(str) -
|
||||
flatbuf->data() +
|
||||
sizeof(uoffset_t));
|
||||
if (delta) {
|
||||
// Clear the old string, since we don't want parts of it remaining.
|
||||
memset(flatbuf->data() + start, 0, str->Length());
|
||||
// Different size, we must expand (or contract).
|
||||
ResizeContext(schema, start, delta, flatbuf, root_table);
|
||||
}
|
||||
// Copy new data. Safe because we created the right amount of space.
|
||||
memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
|
||||
}
|
||||
|
||||
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
|
||||
const VectorOfAny *vec, uoffset_t num_elems,
|
||||
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table) {
|
||||
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
|
||||
auto delta_bytes = delta_elem * static_cast<int>(elem_size);
|
||||
auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
|
||||
auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
|
||||
elem_size * num_elems);
|
||||
if (delta_bytes) {
|
||||
if (delta_elem < 0) {
|
||||
// Clear elements we're throwing away, since some might remain in the
|
||||
// buffer.
|
||||
auto size_clear = -delta_elem * elem_size;
|
||||
memset(flatbuf->data() + start - size_clear, 0, size_clear);
|
||||
}
|
||||
ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
|
||||
WriteScalar(flatbuf->data() + vec_start, newsize); // Length field.
|
||||
// Set new elements to 0.. this can be overwritten by the caller.
|
||||
if (delta_elem > 0) {
|
||||
memset(flatbuf->data() + start, 0, delta_elem * elem_size);
|
||||
}
|
||||
}
|
||||
return flatbuf->data() + start;
|
||||
}
|
||||
|
||||
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
|
||||
const uint8_t *newbuf, size_t newlen) {
|
||||
// Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
|
||||
// going to chop off the root offset.
|
||||
while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
|
||||
!(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
|
||||
flatbuf.push_back(0);
|
||||
}
|
||||
auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
|
||||
// Insert the entire FlatBuffer minus the root pointer.
|
||||
flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
|
||||
auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
|
||||
return flatbuf.data() + insertion_point + root_offset;
|
||||
}
|
||||
|
||||
void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
|
||||
const Table &table, size_t align, size_t size) {
|
||||
fbb.Align(align);
|
||||
fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
|
||||
fbb.TrackField(fielddef.offset(), fbb.GetSize());
|
||||
}
|
||||
|
||||
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
const reflection::Schema &schema,
|
||||
const reflection::Object &objectdef,
|
||||
const Table &table) {
|
||||
// Before we can construct the table, we have to first generate any
|
||||
// subobjects, and collect their offsets.
|
||||
std::vector<uoffset_t> offsets;
|
||||
auto fielddefs = objectdef.fields();
|
||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||
auto &fielddef = **it;
|
||||
// Skip if field is not present in the source.
|
||||
if (!table.CheckField(fielddef.offset())) continue;
|
||||
uoffset_t offset = 0;
|
||||
switch (fielddef.type()->base_type()) {
|
||||
case reflection::String: {
|
||||
offset = fbb.CreateString(GetFieldS(table, fielddef)).o;
|
||||
break;
|
||||
}
|
||||
case reflection::Obj: {
|
||||
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
|
||||
if (!subobjectdef.is_struct()) {
|
||||
offset = CopyTable(fbb, schema, subobjectdef,
|
||||
*GetFieldT(table, fielddef)).o;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case reflection::Union: {
|
||||
auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
|
||||
offset = CopyTable(fbb, schema, subobjectdef,
|
||||
*GetFieldT(table, fielddef)).o;
|
||||
break;
|
||||
}
|
||||
case reflection::Vector: {
|
||||
auto vec = table.GetPointer<const Vector<Offset<Table>> *>(
|
||||
fielddef.offset());
|
||||
auto element_base_type = fielddef.type()->element();
|
||||
auto elemobjectdef = element_base_type == reflection::Obj
|
||||
? schema.objects()->Get(fielddef.type()->index())
|
||||
: nullptr;
|
||||
switch (element_base_type) {
|
||||
case reflection::String: {
|
||||
std::vector<Offset<const String *>> elements(vec->size());
|
||||
auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
|
||||
for (uoffset_t i = 0; i < vec_s->size(); i++) {
|
||||
elements[i] = fbb.CreateString(vec_s->Get(i)).o;
|
||||
}
|
||||
offset = fbb.CreateVector(elements).o;
|
||||
break;
|
||||
}
|
||||
case reflection::Obj: {
|
||||
if (!elemobjectdef->is_struct()) {
|
||||
std::vector<Offset<const Table *>> elements(vec->size());
|
||||
for (uoffset_t i = 0; i < vec->size(); i++) {
|
||||
elements[i] =
|
||||
CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
|
||||
}
|
||||
offset = fbb.CreateVector(elements).o;
|
||||
break;
|
||||
}
|
||||
// FALL-THRU:
|
||||
}
|
||||
default: { // Scalars and structs.
|
||||
auto element_size = GetTypeSize(element_base_type);
|
||||
if (elemobjectdef && elemobjectdef->is_struct())
|
||||
element_size = elemobjectdef->bytesize();
|
||||
fbb.StartVector(element_size, vec->size());
|
||||
fbb.PushBytes(vec->Data(), element_size * vec->size());
|
||||
offset = fbb.EndVector(vec->size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: // Scalars.
|
||||
break;
|
||||
}
|
||||
if (offset) {
|
||||
offsets.push_back(offset);
|
||||
}
|
||||
}
|
||||
// Now we can build the actual table from either offsets or scalar data.
|
||||
auto start = objectdef.is_struct()
|
||||
? fbb.StartStruct(objectdef.minalign())
|
||||
: fbb.StartTable();
|
||||
size_t offset_idx = 0;
|
||||
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
|
||||
auto &fielddef = **it;
|
||||
if (!table.CheckField(fielddef.offset())) continue;
|
||||
auto base_type = fielddef.type()->base_type();
|
||||
switch (base_type) {
|
||||
case reflection::Obj: {
|
||||
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
|
||||
if (subobjectdef.is_struct()) {
|
||||
CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
|
||||
subobjectdef.bytesize());
|
||||
break;
|
||||
}
|
||||
// else: FALL-THRU:
|
||||
}
|
||||
case reflection::Union:
|
||||
case reflection::String:
|
||||
case reflection::Vector:
|
||||
fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
|
||||
break;
|
||||
default: { // Scalars.
|
||||
auto size = GetTypeSize(base_type);
|
||||
CopyInline(fbb, fielddef, table, size, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(offset_idx == offsets.size());
|
||||
if (objectdef.is_struct()) {
|
||||
fbb.ClearOffsets();
|
||||
return fbb.EndStruct();
|
||||
} else {
|
||||
return fbb.EndTable(start, static_cast<voffset_t>(fielddefs->size()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
Reference in New Issue
Block a user