mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-30 06:30:01 +00:00
[idl_parser] Improve symbols lookup thru parent namespaces (#6407)
Added the new method LookupTableByName for searching symbols in parent namespaces. This method speedup (x50 or greater) symbol resolution (enum or struct) in parent namespaces. The speedup was measured without `table.empty()` guard condition. This method should suppress fuzzer timeout issue without artificial limits for nested namespaces (https://oss-fuzz.com/testcase-detail/6244168439169024). Additionally, this commit speedup (x5) the GetFullyQualifiedName method by removing unnecessary temporary std::string object.
This commit is contained in:
@@ -856,6 +856,7 @@ class Parser : public ParserState {
|
|||||||
flexbuffers::Builder *builder);
|
flexbuffers::Builder *builder);
|
||||||
|
|
||||||
StructDef *LookupStruct(const std::string &id) const;
|
StructDef *LookupStruct(const std::string &id) const;
|
||||||
|
StructDef *LookupStructThruParentNamespaces(const std::string &id) const;
|
||||||
|
|
||||||
std::string UnqualifiedName(const std::string &fullQualifiedName);
|
std::string UnqualifiedName(const std::string &fullQualifiedName);
|
||||||
|
|
||||||
|
|||||||
@@ -227,9 +227,10 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
|
|||||||
if (components.empty() || !max_components) { return name; }
|
if (components.empty() || !max_components) { return name; }
|
||||||
std::string stream_str;
|
std::string stream_str;
|
||||||
for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
|
for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
|
||||||
if (i) { stream_str += '.'; }
|
stream_str += components[i];
|
||||||
stream_str += std::string(components[i]);
|
stream_str += '.';
|
||||||
}
|
}
|
||||||
|
if (!stream_str.empty()) stream_str.pop_back();
|
||||||
if (name.length()) {
|
if (name.length()) {
|
||||||
stream_str += '.';
|
stream_str += '.';
|
||||||
stream_str += name;
|
stream_str += name;
|
||||||
@@ -237,6 +238,29 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
|
|||||||
return stream_str;
|
return stream_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T *LookupTableByName(const SymbolTable<T> &table, const std::string &name,
|
||||||
|
const Namespace ¤t_namespace, size_t skip_top) {
|
||||||
|
const auto &components = current_namespace.components;
|
||||||
|
if (table.dict.empty()) return nullptr;
|
||||||
|
if (components.size() < skip_top) return nullptr;
|
||||||
|
const auto N = components.size() - skip_top;
|
||||||
|
std::string full_name;
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
full_name += components[i];
|
||||||
|
full_name += '.';
|
||||||
|
}
|
||||||
|
for (size_t i = N; i > 0; i--) {
|
||||||
|
full_name += name;
|
||||||
|
auto obj = table.Lookup(full_name);
|
||||||
|
if (obj) return obj;
|
||||||
|
auto len = full_name.size() - components[i - 1].size() - 1 - name.size();
|
||||||
|
full_name.resize(len);
|
||||||
|
}
|
||||||
|
FLATBUFFERS_ASSERT(full_name.empty());
|
||||||
|
return table.Lookup(name); // lookup in global namespace
|
||||||
|
}
|
||||||
|
|
||||||
// Declare tokens we'll use. Single character tokens are represented by their
|
// Declare tokens we'll use. Single character tokens are represented by their
|
||||||
// ascii character code (e.g. '{'), others above 256.
|
// ascii character code (e.g. '{'), others above 256.
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@@ -576,13 +600,7 @@ CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
|
|||||||
|
|
||||||
EnumDef *Parser::LookupEnum(const std::string &id) {
|
EnumDef *Parser::LookupEnum(const std::string &id) {
|
||||||
// Search thru parent namespaces.
|
// Search thru parent namespaces.
|
||||||
for (int components = static_cast<int>(current_namespace_->components.size());
|
return LookupTableByName(enums_, id, *current_namespace_, 0);
|
||||||
components >= 0; components--) {
|
|
||||||
auto ed = enums_.Lookup(
|
|
||||||
current_namespace_->GetFullyQualifiedName(id, components));
|
|
||||||
if (ed) return ed;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StructDef *Parser::LookupStruct(const std::string &id) const {
|
StructDef *Parser::LookupStruct(const std::string &id) const {
|
||||||
@@ -591,6 +609,13 @@ StructDef *Parser::LookupStruct(const std::string &id) const {
|
|||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StructDef *Parser::LookupStructThruParentNamespaces(
|
||||||
|
const std::string &id) const {
|
||||||
|
auto sd = LookupTableByName(structs_, id, *current_namespace_, 1);
|
||||||
|
if (sd) sd->refcount++;
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
CheckedError Parser::ParseTypeIdent(Type &type) {
|
CheckedError Parser::ParseTypeIdent(Type &type) {
|
||||||
std::string id = attribute_;
|
std::string id = attribute_;
|
||||||
EXPECT(kTokenIdentifier);
|
EXPECT(kTokenIdentifier);
|
||||||
@@ -1980,13 +2005,8 @@ StructDef *Parser::LookupCreateStruct(const std::string &name,
|
|||||||
}
|
}
|
||||||
return struct_def;
|
return struct_def;
|
||||||
}
|
}
|
||||||
if (!definition) {
|
if (!definition && !struct_def) {
|
||||||
// Search thru parent namespaces.
|
struct_def = LookupStructThruParentNamespaces(name);
|
||||||
for (size_t components = current_namespace_->components.size();
|
|
||||||
components && !struct_def; components--) {
|
|
||||||
struct_def = LookupStruct(
|
|
||||||
current_namespace_->GetFullyQualifiedName(name, components - 1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!struct_def && create_if_new) {
|
if (!struct_def && create_if_new) {
|
||||||
struct_def = new StructDef();
|
struct_def = new StructDef();
|
||||||
|
|||||||
Reference in New Issue
Block a user