Tune namespace related functions to make them pure string

Tune namespace related functions to make them pure string to stop
using std::vector to collect strings up, for later joining.

Change-Id: Ibc2dc3250a62dfd0f4db6135fea5f72146b8c552
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Alexey Edelev 2022-10-11 21:02:02 +02:00
parent 3a3c1413f5
commit 12d35dcdc0
6 changed files with 110 additions and 87 deletions

View File

@ -13,44 +13,78 @@ using namespace ::google::protobuf;
using namespace ::google::protobuf::io; using namespace ::google::protobuf::io;
using namespace ::QtProtobuf::generator; using namespace ::QtProtobuf::generator;
std::vector<std::string> common::getNamespaces(const std::string &fullTypeName) /*
Constructs a C++ namespace from the full protobuf descriptor name. E.g. for
the message descriptor "test.protobuf.MessageType" the function
returns "test::protobuf", if the separator is "::".
*/
std::string common::getFullNamespace(std::string_view fullDescriptorName,
std::string_view separator)
{ {
std::vector<std::string> namespacesList; std::string output = Options::instance().extraNamespace();
std::string extraNamespace = Options::instance().extraNamespace(); std::string::size_type nameIndex = fullDescriptorName.rfind('.');
if (!extraNamespace.empty() && extraNamespace != "QT_NAMESPACE") if (nameIndex == std::string::npos)
namespacesList.push_back(extraNamespace); return output;
for (auto &ns : utils::split(fullTypeName, ".")) std::string namespacesStr =
namespacesList.push_back(std::move(ns)); utils::replace(fullDescriptorName.substr(0, nameIndex), ".", separator);
if (!namespacesList.empty()) if (!output.empty() && !namespacesStr.empty())
namespacesList.pop_back(); // Remove name output += separator;
return namespacesList; output += namespacesStr;
return output;
} }
std::vector<std::string> common::getNestedNamespaces(const Descriptor *type) /*
Constructs a C++ namespace for wrapping nested message types.
E.g. for the message descriptor with name "test.protobuf.MessageType.NestedMessageType" the
function returns "test::protobuf::MessageType_QtProtobufNested", if the separator
is "::".
*/
std::string common::getNestedNamespace(const Descriptor *type, std::string_view separator)
{ {
auto namespaces = getNamespaces(type); static const std::string nestedSuffix = Templates::QtProtobufNestedNamespace();
for (size_t i = utils::count(type->file()->package(), '.') + 1; i < namespaces.size(); ++i)
namespaces[i] += Templates::QtProtobufNestedNamespace(); const std::size_t packageSize =
return namespaces; type->file()->package().size() > 0 ? type->file()->package().size() + 1 : 0;
const std::size_t nameSize = type->name().size() > 0 ? type->name().size() + 1 : 0;
const std::size_t namespaceSize = type->full_name().size() - packageSize - nameSize;
if (namespaceSize == 0)
return {};
std::string nestedNamespaces =
utils::replace(type->full_name().substr(packageSize, namespaceSize), ".",
nestedSuffix + std::string(separator));
if (!nestedNamespaces.empty())
nestedNamespaces += nestedSuffix;
std::string output = utils::replace(type->file()->package(), ".", separator);
if (!output.empty() && !nestedNamespaces.empty())
output += separator;
output += nestedNamespaces;
return output;
} }
std::string common::getNamespacesString(const std::vector<std::string> &namespacesList, /*
std::string_view separator) Cuts the prepending 'scope' namespaces from the original string to create the minimum required
{ C++ identifier that can be used inside the scope namespace. Both strings should be C++
return utils::join(namespacesList, separator); namespaces separated by double colon.
} E.g. for the original namespace "test::protobuf" with the "test" scope the function should
return "protobuf".
std::string common::getScopeNamespacesString(std::string original, const std::string &scope) */
std::string common::getScopeNamespace(std::string_view original, std::string_view scope)
{ {
if (scope.empty()) if (scope.empty())
return original; return std::string(original);
if (original == scope) if (original == scope)
return ""; return "";
if (utils::startsWith(original, scope + "::")) std::string scopeWithSeparator;
return original.substr(scope.size() + 2); scopeWithSeparator.reserve(scope.size() + 2);
return original; scopeWithSeparator += scope;
scopeWithSeparator += "::";
if (utils::startsWith(original, scopeWithSeparator))
return std::string(original.substr(scopeWithSeparator.size()));
return std::string(original);
} }
std::map<std::string, std::string> common::getNestedScopeNamespace(const std::string &className) std::map<std::string, std::string> common::getNestedScopeNamespace(const std::string &className)
@ -60,11 +94,9 @@ std::map<std::string, std::string> common::getNestedScopeNamespace(const std::st
TypeMap common::produceQtTypeMap(const Descriptor *type, const Descriptor *scope) TypeMap common::produceQtTypeMap(const Descriptor *type, const Descriptor *scope)
{ {
std::vector<std::string> namespaceList = getNamespaces(type); std::string namespaces = getFullNamespace(type, "::");
std::string namespaces = getNamespacesString(namespaceList, "::"); std::string scopeNamespaces = getScopeNamespace(namespaces, getFullNamespace(scope, "::"));
std::string scopeNamespaces = std::string qmlPackage = getFullNamespace(type, ".");
getScopeNamespacesString(namespaces, getNamespacesString(getNamespaces(scope), "::"));
std::string qmlPackage = getNamespacesString(namespaceList, ".");
std::string name = type->name(); std::string name = type->name();
std::string fullName = name; std::string fullName = name;
@ -90,16 +122,10 @@ TypeMap common::produceQtTypeMap(const Descriptor *type, const Descriptor *scope
TypeMap common::produceMessageTypeMap(const Descriptor *type, const Descriptor *scope) TypeMap common::produceMessageTypeMap(const Descriptor *type, const Descriptor *scope)
{ {
std::vector<std::string> namespaceList = getNamespaces(type); std::string namespaces = getFullNamespace(type, "::");
std::string nestedNamespaces = isNested(type) ? getNestedNamespace(type, "::") : namespaces;
std::vector<std::string> nestedNamespaceList = std::string scopeNamespaces = getScopeNamespace(nestedNamespaces, getFullNamespace(scope, "::"));
isNested(type) ? getNestedNamespaces(type) : namespaceList; std::string qmlPackage = getFullNamespace(type, ".");
std::string namespaces = getNamespacesString(namespaceList, "::");
std::string scopeNamespaces =
getScopeNamespacesString(getNamespacesString(nestedNamespaceList, "::"),
getNamespacesString(getNamespaces(scope), "::"));
std::string qmlPackage = getNamespacesString(namespaceList, ".");
if (qmlPackage.empty()) if (qmlPackage.empty())
qmlPackage = "QtProtobuf"; qmlPackage = "QtProtobuf";
@ -136,23 +162,22 @@ TypeMap common::produceMessageTypeMap(const Descriptor *type, const Descriptor *
TypeMap common::produceEnumTypeMap(const EnumDescriptor *type, const Descriptor *scope) TypeMap common::produceEnumTypeMap(const EnumDescriptor *type, const Descriptor *scope)
{ {
EnumVisibility visibility = enumVisibility(type, scope); EnumVisibility visibility = enumVisibility(type, scope);
std::vector<std::string> namespaceList = getNamespaces(type); std::string namespaces = getFullNamespace(type, "::");
std::string name = utils::capitalizeAsciiName(type->name()); std::string name = utils::capitalizeAsciiName(type->name());
// qml package should consist only from proto spackage // qml package should consist only from proto spackage
std::string qmlPackage = getNamespacesString(namespaceList, "."); std::string qmlPackage = getFullNamespace(type, ".");
if (qmlPackage.empty()) if (qmlPackage.empty())
qmlPackage = "QtProtobuf"; qmlPackage = "QtProtobuf";
// Not used: // Not used:
std::string enumGadget = scope != nullptr ? utils::capitalizeAsciiName(scope->name()) : ""; std::string enumGadget = scope != nullptr ? utils::capitalizeAsciiName(scope->name()) : "";
if (visibility == GLOBAL_ENUM) { if (visibility == GLOBAL_ENUM) {
enumGadget = name + Templates::EnumClassSuffix(); enumGadget = name + Templates::EnumClassSuffix();
namespaceList.push_back(enumGadget); // Global enums are stored in helper Gadget namespaces += "::";
namespaces += enumGadget; // Global enums are stored in helper Gadget
} }
std::string namespaces = getNamespacesString(namespaceList, "::"); std::string scopeNamespaces = getScopeNamespace(namespaces, getFullNamespace(scope, "::"));
std::string scopeNamespaces =
getScopeNamespacesString(namespaces, getNamespacesString(getNamespaces(scope), "::"));
std::string fullName = namespaces.empty() ? name : (namespaces + "::" + name); std::string fullName = namespaces.empty() ? name : (namespaces + "::" + name);
std::string scopeName = scopeNamespaces.empty() ? name : (scopeNamespaces + "::" + name); std::string scopeName = scopeNamespaces.empty() ? name : (scopeNamespaces + "::" + name);
@ -244,8 +269,7 @@ TypeMap common::produceSimpleTypeMap(FieldDescriptor::Type type)
bool common::isQtType(const FieldDescriptor *field) bool common::isQtType(const FieldDescriptor *field)
{ {
auto namespaces = getNamespaces(field->message_type()); return utils::startsWith(field->message_type()->full_name(), "QtProtobuf.")
return namespaces.size() == 1 && namespaces.front() == "QtProtobuf"
&& field->file()->package() != "QtProtobuf"; // Used for qttypes library to avoid types && field->file()->package() != "QtProtobuf"; // Used for qttypes library to avoid types
// conversion inside library // conversion inside library
} }

View File

@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <string> #include <string>
#include <string_view>
#include <functional> #include <functional>
#include "utils.h" #include "utils.h"
@ -35,18 +36,6 @@ struct common {
NEIGHBOR_ENUM NEIGHBOR_ENUM
}; };
static std::vector<std::string> getNamespaces(const std::string &fullTypeName);
template <typename T>
static std::vector<std::string> getNamespaces(const T *type)
{
if (type == nullptr)
return {};
std::string fullTypeName = type->full_name();
return getNamespaces(fullTypeName);
}
static std::vector<std::string> getNestedNamespaces(const Descriptor *type);
static std::string buildExportMacro(std::string identifier) static std::string buildExportMacro(std::string identifier)
{ {
if (identifier.empty()) if (identifier.empty())
@ -54,9 +43,18 @@ struct common {
return "QPB_" + identifier + "_EXPORT"; return "QPB_" + identifier + "_EXPORT";
} }
static std::string getNamespacesString(const std::vector<std::string> &namespacesList, static std::string getFullNamespace(std::string_view fullDescriptorName,
std::string_view separator); std::string_view separator);
static std::string getScopeNamespacesString(std::string original, const std::string &scope); template<typename T>
static std::string getFullNamespace(const T *type, std::string_view separator)
{
if (type == nullptr)
return {};
return getFullNamespace(type->full_name(), separator);
}
static std::string getNestedNamespace(const Descriptor *type, std::string_view separator);
static std::string getScopeNamespace(std::string_view original, std::string_view scope);
static std::map<std::string, std::string> getNestedScopeNamespace(const std::string &className); static std::map<std::string, std::string> getNestedScopeNamespace(const std::string &className);
static TypeMap produceQtTypeMap(const Descriptor *type, const Descriptor *scope); static TypeMap produceQtTypeMap(const Descriptor *type, const Descriptor *scope);
static TypeMap produceMessageTypeMap(const Descriptor *type, const Descriptor *scope); static TypeMap produceMessageTypeMap(const Descriptor *type, const Descriptor *scope);
@ -82,10 +80,6 @@ struct common {
static bool hasNestedMessages(const Descriptor *message); static bool hasNestedMessages(const Descriptor *message);
static bool isNested(const Descriptor *message); static bool isNested(const Descriptor *message);
static bool isNestedOf(const Descriptor *message, const Descriptor *containing)
{
return containing == message->containing_type();
}
static const Descriptor *findHighestMessage(const Descriptor *message); static const Descriptor *findHighestMessage(const Descriptor *message);
}; };
} // namespace QtProtobuf::generator } // namespace QtProtobuf::generator

View File

@ -29,13 +29,13 @@ MessageDeclarationPrinter::~MessageDeclarationPrinter() = default;
void MessageDeclarationPrinter::printClassForwardDeclarationPrivate() void MessageDeclarationPrinter::printClassForwardDeclarationPrivate()
{ {
if (common::hasNestedMessages(m_descriptor)) { if (common::hasNestedMessages(m_descriptor)) {
auto scope_namespaces = common::getNestedScopeNamespace(m_typeMap["classname"]); auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
m_printer->Print(scope_namespaces, Templates::NamespaceTemplate()); m_printer->Print(scopeNamespaces, Templates::NamespaceTemplate());
common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) { common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) {
MessageDeclarationPrinter nesterPrinter(nestedMessage, m_printer); MessageDeclarationPrinter nesterPrinter(nestedMessage, m_printer);
nesterPrinter.printClassForwardDeclarationPrivate(); nesterPrinter.printClassForwardDeclarationPrivate();
}); });
m_printer->Print(scope_namespaces, Templates::NamespaceClosingTemplate()); m_printer->Print(scopeNamespaces, Templates::NamespaceClosingTemplate());
} }
m_printer->Print(m_typeMap, Templates::ClassMessageForwardDeclarationTemplate()); m_printer->Print(m_typeMap, Templates::ClassMessageForwardDeclarationTemplate());
@ -55,13 +55,13 @@ void MessageDeclarationPrinter::printClassDeclaration()
void MessageDeclarationPrinter::printClassDeclarationPrivate() void MessageDeclarationPrinter::printClassDeclarationPrivate()
{ {
if (common::hasNestedMessages(m_descriptor)) { if (common::hasNestedMessages(m_descriptor)) {
auto scope_namespaces = common::getNestedScopeNamespace(m_typeMap["classname"]); auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
m_printer->Print(scope_namespaces, Templates::NamespaceTemplate()); m_printer->Print(scopeNamespaces, Templates::NamespaceTemplate());
common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) { common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) {
MessageDeclarationPrinter nesterPrinter(nestedMessage, m_printer); MessageDeclarationPrinter nesterPrinter(nestedMessage, m_printer);
nesterPrinter.printClassDeclarationPrivate(); nesterPrinter.printClassDeclarationPrivate();
}); });
m_printer->Print(scope_namespaces, Templates::NamespaceClosingTemplate()); m_printer->Print(scopeNamespaces, Templates::NamespaceClosingTemplate());
} }
printComments(m_descriptor); printComments(m_descriptor);
printClassDeclarationBegin(); printClassDeclarationBegin();

View File

@ -26,13 +26,13 @@ MessageDefinitionPrinter::~MessageDefinitionPrinter() = default;
void MessageDefinitionPrinter::printClassDefinitionPrivate() void MessageDefinitionPrinter::printClassDefinitionPrivate()
{ {
if (common::hasNestedMessages(m_descriptor)) { if (common::hasNestedMessages(m_descriptor)) {
auto scope_namespaces = common::getNestedScopeNamespace(m_typeMap["classname"]); auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
m_printer->Print(scope_namespaces, Templates::NamespaceTemplate()); m_printer->Print(scopeNamespaces, Templates::NamespaceTemplate());
common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) { common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) {
MessageDefinitionPrinter nestedPrinter(nestedMessage, m_printer); MessageDefinitionPrinter nestedPrinter(nestedMessage, m_printer);
nestedPrinter.printClassDefinitionPrivate(); nestedPrinter.printClassDefinitionPrivate();
}); });
m_printer->Print(scope_namespaces, Templates::NamespaceClosingTemplate()); m_printer->Print(scopeNamespaces, Templates::NamespaceClosingTemplate());
} }
printDestructor(); printDestructor();
@ -455,14 +455,14 @@ void MessageDefinitionPrinter::printDestructor()
void MessageDefinitionPrinter::printClassRegistration(Printer *printer) void MessageDefinitionPrinter::printClassRegistration(Printer *printer)
{ {
if (common::hasNestedMessages(m_descriptor)) { if (common::hasNestedMessages(m_descriptor)) {
auto scope_namespaces = common::getNestedScopeNamespace(m_typeMap["classname"]); auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
printer->Print(scope_namespaces, Templates::NamespaceTemplate()); printer->Print(scopeNamespaces, Templates::NamespaceTemplate());
common::iterateNestedMessages( common::iterateNestedMessages(
m_descriptor, [this, &printer](const Descriptor *nestedMessage) { m_descriptor, [this, &printer](const Descriptor *nestedMessage) {
MessageDefinitionPrinter nestedPrinter(nestedMessage, m_printer); MessageDefinitionPrinter nestedPrinter(nestedMessage, m_printer);
nestedPrinter.printClassRegistration(printer); nestedPrinter.printClassRegistration(printer);
}); });
printer->Print(scope_namespaces, Templates::NamespaceClosingTemplate()); printer->Print(scopeNamespaces, Templates::NamespaceClosingTemplate());
} }
printer->Print(m_typeMap, Templates::RegistrarTemplate()); printer->Print(m_typeMap, Templates::RegistrarTemplate());

View File

@ -130,16 +130,17 @@ bool SingleFileGenerator::GenerateMessages(const FileDescriptor *file,
Templates::ExportMacroTemplate()); Templates::ExportMacroTemplate());
} }
auto namespaces = file->message_type_count() > 0 ? common::getNamespaces(file->message_type(0))
: common::getNamespaces(file->enum_type(0));
const bool hasQtNamespace = (Options::instance().extraNamespace() == "QT_NAMESPACE"); const bool hasQtNamespace = (Options::instance().extraNamespace() == "QT_NAMESPACE");
const std::string scope_namespaces = common::getNamespacesString(namespaces, "::"); const std::string scopeNamespaces = file->message_type_count() > 0
? common::getFullNamespace(file->message_type(0), "::")
: common::getFullNamespace(file->enum_type(0), "::");
auto openNamespaces = [&](auto printer) { // open namespaces auto openNamespaces = [&](auto printer) { // open namespaces
printer->Print("\n"); printer->Print("\n");
if (hasQtNamespace) if (hasQtNamespace)
printer->PrintRaw("QT_BEGIN_NAMESPACE\n"); printer->PrintRaw("QT_BEGIN_NAMESPACE\n");
if (!scope_namespaces.empty()) if (!scopeNamespaces.empty())
printer->Print({{"scope_namespaces", scope_namespaces}}, Templates::NamespaceTemplate()); printer->Print({ { "scope_namespaces", scopeNamespaces } },
Templates::NamespaceTemplate());
}; };
openNamespaces(headerPrinter); openNamespaces(headerPrinter);
openNamespaces(sourcePrinter); openNamespaces(sourcePrinter);
@ -169,8 +170,9 @@ bool SingleFileGenerator::GenerateMessages(const FileDescriptor *file,
}); });
auto closeNamespaces = [&](auto printer) { auto closeNamespaces = [&](auto printer) {
if (!scope_namespaces.empty()) if (!scopeNamespaces.empty())
printer->Print({{"scope_namespaces", scope_namespaces}}, Templates::NamespaceClosingTemplate()); printer->Print({ { "scope_namespaces", scopeNamespaces } },
Templates::NamespaceClosingTemplate());
if (hasQtNamespace) if (hasQtNamespace)
printer->PrintRaw("QT_END_NAMESPACE\n"); printer->PrintRaw("QT_END_NAMESPACE\n");
printer->Print("\n"); printer->Print("\n");

View File

@ -44,6 +44,9 @@ std::vector<std::string> split(std::string_view s, std::string_view c, bool keep
std::string replace(std::string_view where, std::string_view from, std::string_view to) std::string replace(std::string_view where, std::string_view from, std::string_view to)
{ {
assert(!from.empty()); assert(!from.empty());
if (from == to)
return std::string(where);
std::string out; std::string out;
out.reserve(where.size()); out.reserve(where.size());
std::size_t pos = 0; std::size_t pos = 0;