Commit a3d8391f authored by Frank Benkstein's avatar Frank Benkstein Committed by Wouter van Oortmerssen

don't use std::function in flatbuffers::Parser (#4995)

std::function makes code harder to debug because it requires stepping
through a separate destructor and call operator.  It's use unnecessary
in the Parser since the functions taking functors are private and are
only used within idl_parser.cpp.  Therefore the definitions can stay in
idl_parser.cpp as well.  Only care must be taken that the definitions
appear before use but that's already true and all compilers will
complain equally if it get's violated.  This change might also improve
performance since it might allow inlining where it wasn't possible
before but I haven't measured that.
parent 241e87d1
...@@ -682,35 +682,15 @@ class Parser : public ParserState { ...@@ -682,35 +682,15 @@ class Parser : public ParserState {
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn, size_t parent_fieldn,
const StructDef *parent_struct_def); const StructDef *parent_struct_def);
// clang-format off template<typename F>
#if defined(FLATBUFFERS_CPP98_STL)
typedef CheckedError (*ParseTableDelimitersBody)(
const std::string &name, size_t &fieldn, const StructDef *struct_def,
void *state);
#else
typedef std::function<CheckedError(const std::string&, size_t&,
const StructDef*, void*)>
ParseTableDelimitersBody;
#endif // defined(FLATBUFFERS_CPP98_STL)
// clang-format on
FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn, FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
const StructDef *struct_def, const StructDef *struct_def,
ParseTableDelimitersBody body, F body);
void *state);
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def, FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
std::string *value, uoffset_t *ovalue); std::string *value, uoffset_t *ovalue);
void SerializeStruct(const StructDef &struct_def, const Value &val); void SerializeStruct(const StructDef &struct_def, const Value &val);
// clang-format off template<typename F>
#if defined(FLATBUFFERS_CPP98_STL) FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(size_t &count, F body);
typedef CheckedError (*ParseVectorDelimitersBody)(size_t &count,
void *state);
#else
typedef std::function<CheckedError(size_t&, void*)>
ParseVectorDelimitersBody;
#endif // defined(FLATBUFFERS_CPP98_STL)
// clang-format on
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(
size_t &count, ParseVectorDelimitersBody body, void *state);
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue); FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field, FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field,
size_t fieldn, size_t fieldn,
...@@ -761,14 +741,7 @@ class Parser : public ParserState { ...@@ -761,14 +741,7 @@ class Parser : public ParserState {
Namespace *UniqueNamespace(Namespace *ns); Namespace *UniqueNamespace(Namespace *ns);
FLATBUFFERS_CHECKED_ERROR RecurseError(); FLATBUFFERS_CHECKED_ERROR RecurseError();
template<typename F> CheckedError Recurse(F f) { template<typename F> CheckedError Recurse(F f);
if (recurse_protection_counter >= (FLATBUFFERS_MAX_PARSING_DEPTH))
return RecurseError();
recurse_protection_counter++;
auto ce = f();
recurse_protection_counter--;
return ce;
}
public: public:
SymbolTable<Type> types_; SymbolTable<Type> types_;
......
...@@ -119,6 +119,15 @@ CheckedError Parser::RecurseError() { ...@@ -119,6 +119,15 @@ CheckedError Parser::RecurseError() {
NumToString(FLATBUFFERS_MAX_PARSING_DEPTH) + " reached"); NumToString(FLATBUFFERS_MAX_PARSING_DEPTH) + " reached");
} }
template<typename F> CheckedError Parser::Recurse(F f) {
if (recurse_protection_counter >= (FLATBUFFERS_MAX_PARSING_DEPTH))
return RecurseError();
recurse_protection_counter++;
auto ce = f();
recurse_protection_counter--;
return ce;
}
CheckedError Parser::InvalidNumber(const char *number, const std::string &msg) { CheckedError Parser::InvalidNumber(const char *number, const std::string &msg) {
return Error("invalid number: \"" + std::string(number) + "\"" + msg); return Error("invalid number: \"" + std::string(number) + "\"" + msg);
} }
...@@ -927,10 +936,10 @@ void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) { ...@@ -927,10 +936,10 @@ void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
builder_.AddStructOffset(val.offset, builder_.GetSize()); builder_.AddStructOffset(val.offset, builder_.GetSize());
} }
template <typename F>
CheckedError Parser::ParseTableDelimiters(size_t &fieldn, CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
const StructDef *struct_def, const StructDef *struct_def,
ParseTableDelimitersBody body, F body) {
void *state) {
// We allow tables both as JSON object{ .. } with field names // We allow tables both as JSON object{ .. } with field names
// or vector[..] with all fields in order // or vector[..] with all fields in order
char terminator = '}'; char terminator = '}';
...@@ -958,7 +967,7 @@ CheckedError Parser::ParseTableDelimiters(size_t &fieldn, ...@@ -958,7 +967,7 @@ CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
} }
if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':'); if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
} }
ECHECK(body(name, fieldn, struct_def, state)); ECHECK(body(name, fieldn, struct_def));
if (Is(terminator)) break; if (Is(terminator)) break;
ECHECK(ParseComma()); ECHECK(ParseComma());
} }
...@@ -974,66 +983,60 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, ...@@ -974,66 +983,60 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
size_t fieldn_outer = 0; size_t fieldn_outer = 0;
auto err = ParseTableDelimiters( auto err = ParseTableDelimiters(
fieldn_outer, &struct_def, fieldn_outer, &struct_def,
[](const std::string &name, size_t &fieldn, [&](const std::string &name, size_t &fieldn,
const StructDef *struct_def_inner, void *state) -> CheckedError { const StructDef *struct_def_inner) -> CheckedError {
auto *parser = static_cast<Parser *>(state);
if (name == "$schema") { if (name == "$schema") {
ECHECK(parser->Expect(kTokenStringConstant)); ECHECK(Expect(kTokenStringConstant));
return NoError(); return NoError();
} }
auto field = struct_def_inner->fields.Lookup(name); auto field = struct_def_inner->fields.Lookup(name);
if (!field) { if (!field) {
if (!parser->opts.skip_unexpected_fields_in_json) { if (!opts.skip_unexpected_fields_in_json) {
return parser->Error("unknown field: " + name); return Error("unknown field: " + name);
} else { } else {
ECHECK(parser->SkipAnyJsonValue()); ECHECK(SkipAnyJsonValue());
} }
} else { } else {
if (parser->IsIdent("null") && if (IsIdent("null") && !IsScalar(field->value.type.base_type)) {
!IsScalar(field->value.type.base_type)) { ECHECK(Next()); // Ignore this field.
ECHECK(parser->Next()); // Ignore this field.
} else { } else {
Value val = field->value; Value val = field->value;
if (field->flexbuffer) { if (field->flexbuffer) {
flexbuffers::Builder builder(1024, flexbuffers::Builder builder(1024,
flexbuffers::BUILDER_FLAG_SHARE_ALL); flexbuffers::BUILDER_FLAG_SHARE_ALL);
ECHECK(parser->ParseFlexBufferValue(&builder)); ECHECK(ParseFlexBufferValue(&builder));
builder.Finish(); builder.Finish();
// Force alignment for nested flexbuffer // Force alignment for nested flexbuffer
parser->builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t), builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t),
sizeof(largest_scalar_t)); sizeof(largest_scalar_t));
auto off = parser->builder_.CreateVector(builder.GetBuffer()); auto off = builder_.CreateVector(builder.GetBuffer());
val.constant = NumToString(off.o); val.constant = NumToString(off.o);
} else if (field->nested_flatbuffer) { } else if (field->nested_flatbuffer) {
ECHECK(parser->ParseNestedFlatbuffer(val, field, fieldn, ECHECK(
struct_def_inner)); ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
} else { } else {
ECHECK(parser->Recurse([&]() { ECHECK(Recurse([&]() {
return parser->ParseAnyValue(val, field, fieldn, return ParseAnyValue(val, field, fieldn, struct_def_inner);
struct_def_inner);
})); }));
} }
// Hardcoded insertion-sort with error-check. // Hardcoded insertion-sort with error-check.
// If fields are specified in order, then this loop exits // If fields are specified in order, then this loop exits
// immediately. // immediately.
auto elem = parser->field_stack_.rbegin(); auto elem = field_stack_.rbegin();
for (; elem != parser->field_stack_.rbegin() + fieldn; ++elem) { for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
auto existing_field = elem->second; auto existing_field = elem->second;
if (existing_field == field) if (existing_field == field)
return parser->Error("field set more than once: " + return Error("field set more than once: " + field->name);
field->name);
if (existing_field->value.offset < field->value.offset) break; if (existing_field->value.offset < field->value.offset) break;
} }
// Note: elem points to before the insertion point, thus .base() // Note: elem points to before the insertion point, thus .base()
// points to the correct spot. // points to the correct spot.
parser->field_stack_.insert(elem.base(), field_stack_.insert(elem.base(), std::make_pair(val, field));
std::make_pair(val, field));
fieldn++; fieldn++;
} }
} }
return NoError(); return NoError();
}, });
this);
ECHECK(err); ECHECK(err);
// Check if all required fields are parsed. // Check if all required fields are parsed.
...@@ -1130,13 +1133,12 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, ...@@ -1130,13 +1133,12 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
return NoError(); return NoError();
} }
CheckedError Parser::ParseVectorDelimiters(size_t &count, template <typename F>
ParseVectorDelimitersBody body, CheckedError Parser::ParseVectorDelimiters(size_t &count, F body) {
void *state) {
EXPECT('['); EXPECT('[');
for (;;) { for (;;) {
if ((!opts.strict_json || !count) && Is(']')) break; if ((!opts.strict_json || !count) && Is(']')) break;
ECHECK(body(count, state)); ECHECK(body(count));
count++; count++;
if (Is(']')) break; if (Is(']')) break;
ECHECK(ParseComma()); ECHECK(ParseComma());
...@@ -1147,22 +1149,13 @@ CheckedError Parser::ParseVectorDelimiters(size_t &count, ...@@ -1147,22 +1149,13 @@ CheckedError Parser::ParseVectorDelimiters(size_t &count,
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) { CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
size_t count = 0; size_t count = 0;
std::pair<Parser *, const Type &> parser_and_type_state(this, type); auto err = ParseVectorDelimiters(count, [&](size_t &) -> CheckedError {
auto err = ParseVectorDelimiters( Value val;
count, val.type = type;
[](size_t &, void *state) -> CheckedError { ECHECK(Recurse([&]() { return ParseAnyValue(val, nullptr, 0, nullptr); }));
auto *parser_and_type = field_stack_.push_back(std::make_pair(val, nullptr));
static_cast<std::pair<Parser *, const Type &> *>(state); return NoError();
auto *parser = parser_and_type->first; });
Value val;
val.type = parser_and_type->second;
ECHECK(parser->Recurse([&]() {
return parser->ParseAnyValue(val, nullptr, 0, nullptr);
}));
parser->field_stack_.push_back(std::make_pair(val, nullptr));
return NoError();
},
&parser_and_type_state);
ECHECK(err); ECHECK(err);
builder_.StartVector(count * InlineSize(type) / InlineAlignment(type), builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
...@@ -2220,28 +2213,18 @@ CheckedError Parser::SkipAnyJsonValue() { ...@@ -2220,28 +2213,18 @@ CheckedError Parser::SkipAnyJsonValue() {
size_t fieldn_outer = 0; size_t fieldn_outer = 0;
return ParseTableDelimiters( return ParseTableDelimiters(
fieldn_outer, nullptr, fieldn_outer, nullptr,
[](const std::string &, size_t &fieldn, const StructDef *, [&](const std::string &, size_t &fieldn,
void *state) -> CheckedError { const StructDef *) -> CheckedError {
auto *parser = static_cast<Parser *>(state); ECHECK(Recurse([&]() { return SkipAnyJsonValue(); }));
ECHECK(parser->Recurse([&]() {
return parser->SkipAnyJsonValue();
}));
fieldn++; fieldn++;
return NoError(); return NoError();
}, });
this);
} }
case '[': { case '[': {
size_t count = 0; size_t count = 0;
return ParseVectorDelimiters( return ParseVectorDelimiters(count, [&](size_t &) -> CheckedError {
count, return Recurse([&]() { return SkipAnyJsonValue(); });
[](size_t &, void *state) -> CheckedError { });
auto *parser = static_cast<Parser *>(state);
return parser->Recurse([&]() {
return parser->SkipAnyJsonValue();
});
},
this);
} }
case kTokenStringConstant: case kTokenStringConstant:
case kTokenIntegerConstant: case kTokenIntegerConstant:
...@@ -2258,25 +2241,17 @@ CheckedError Parser::SkipAnyJsonValue() { ...@@ -2258,25 +2241,17 @@ CheckedError Parser::SkipAnyJsonValue() {
CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
switch (token_) { switch (token_) {
case '{': { case '{': {
std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
this, builder);
auto start = builder->StartMap(); auto start = builder->StartMap();
size_t fieldn_outer = 0; size_t fieldn_outer = 0;
auto err = ParseTableDelimiters( auto err =
fieldn_outer, nullptr, ParseTableDelimiters(fieldn_outer, nullptr,
[](const std::string &name, size_t &fieldn, const StructDef *, [&](const std::string &name, size_t &fieldn,
void *state) -> CheckedError { const StructDef *) -> CheckedError {
auto *parser_and_builder = builder->Key(name);
static_cast<std::pair<Parser *, flexbuffers::Builder *> *>( ECHECK(ParseFlexBufferValue(builder));
state); fieldn++;
auto *parser = parser_and_builder->first; return NoError();
auto *current_builder = parser_and_builder->second; });
current_builder->Key(name);
ECHECK(parser->ParseFlexBufferValue(current_builder));
fieldn++;
return NoError();
},
&parser_and_builder_state);
ECHECK(err); ECHECK(err);
builder->EndMap(start); builder->EndMap(start);
break; break;
...@@ -2284,18 +2259,9 @@ CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { ...@@ -2284,18 +2259,9 @@ CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
case '[': { case '[': {
auto start = builder->StartVector(); auto start = builder->StartVector();
size_t count = 0; size_t count = 0;
std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state( ECHECK(ParseVectorDelimiters(count, [&](size_t &) -> CheckedError {
this, builder); return ParseFlexBufferValue(builder);
ECHECK(ParseVectorDelimiters( }));
count,
[](size_t &, void *state) -> CheckedError {
auto *parser_and_builder =
static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
state);
return parser_and_builder->first->ParseFlexBufferValue(
parser_and_builder->second);
},
&parser_and_builder_state));
builder->EndVector(start, false, false); builder->EndVector(start, false, false);
break; break;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment