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 ::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 extraNamespace = Options::instance().extraNamespace();
if (!extraNamespace.empty() && extraNamespace != "QT_NAMESPACE")
namespacesList.push_back(extraNamespace);
for (auto &ns : utils::split(fullTypeName, "."))
namespacesList.push_back(std::move(ns));
if (!namespacesList.empty())
namespacesList.pop_back(); // Remove name
return namespacesList;
std::string output = Options::instance().extraNamespace();
std::string::size_type nameIndex = fullDescriptorName.rfind('.');
if (nameIndex == std::string::npos)
return output;
std::string namespacesStr =
utils::replace(fullDescriptorName.substr(0, nameIndex), ".", separator);
if (!output.empty() && !namespacesStr.empty())
output += separator;
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);
for (size_t i = utils::count(type->file()->package(), '.') + 1; i < namespaces.size(); ++i)
namespaces[i] += Templates::QtProtobufNestedNamespace();
return namespaces;
static const std::string nestedSuffix = Templates::QtProtobufNestedNamespace();
const std::size_t packageSize =
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)
{
return utils::join(namespacesList, separator);
}
std::string common::getScopeNamespacesString(std::string original, const std::string &scope)
/*
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++
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::getScopeNamespace(std::string_view original, std::string_view scope)
{
if (scope.empty())
return original;
return std::string(original);
if (original == scope)
return "";
if (utils::startsWith(original, scope + "::"))
return original.substr(scope.size() + 2);
return original;
std::string scopeWithSeparator;
scopeWithSeparator.reserve(scope.size() + 2);
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)
@ -60,11 +94,9 @@ std::map<std::string, std::string> common::getNestedScopeNamespace(const std::st
TypeMap common::produceQtTypeMap(const Descriptor *type, const Descriptor *scope)
{
std::vector<std::string> namespaceList = getNamespaces(type);
std::string namespaces = getNamespacesString(namespaceList, "::");
std::string scopeNamespaces =
getScopeNamespacesString(namespaces, getNamespacesString(getNamespaces(scope), "::"));
std::string qmlPackage = getNamespacesString(namespaceList, ".");
std::string namespaces = getFullNamespace(type, "::");
std::string scopeNamespaces = getScopeNamespace(namespaces, getFullNamespace(scope, "::"));
std::string qmlPackage = getFullNamespace(type, ".");
std::string name = type->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)
{
std::vector<std::string> namespaceList = getNamespaces(type);
std::vector<std::string> nestedNamespaceList =
isNested(type) ? getNestedNamespaces(type) : namespaceList;
std::string namespaces = getNamespacesString(namespaceList, "::");
std::string scopeNamespaces =
getScopeNamespacesString(getNamespacesString(nestedNamespaceList, "::"),
getNamespacesString(getNamespaces(scope), "::"));
std::string qmlPackage = getNamespacesString(namespaceList, ".");
std::string namespaces = getFullNamespace(type, "::");
std::string nestedNamespaces = isNested(type) ? getNestedNamespace(type, "::") : namespaces;
std::string scopeNamespaces = getScopeNamespace(nestedNamespaces, getFullNamespace(scope, "::"));
std::string qmlPackage = getFullNamespace(type, ".");
if (qmlPackage.empty())
qmlPackage = "QtProtobuf";
@ -136,23 +162,22 @@ TypeMap common::produceMessageTypeMap(const Descriptor *type, const Descriptor *
TypeMap common::produceEnumTypeMap(const EnumDescriptor *type, const Descriptor *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());
// qml package should consist only from proto spackage
std::string qmlPackage = getNamespacesString(namespaceList, ".");
std::string qmlPackage = getFullNamespace(type, ".");
if (qmlPackage.empty())
qmlPackage = "QtProtobuf";
// Not used:
std::string enumGadget = scope != nullptr ? utils::capitalizeAsciiName(scope->name()) : "";
if (visibility == GLOBAL_ENUM) {
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 =
getScopeNamespacesString(namespaces, getNamespacesString(getNamespaces(scope), "::"));
std::string scopeNamespaces = getScopeNamespace(namespaces, getFullNamespace(scope, "::"));
std::string fullName = namespaces.empty() ? name : (namespaces + "::" + 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)
{
auto namespaces = getNamespaces(field->message_type());
return namespaces.size() == 1 && namespaces.front() == "QtProtobuf"
return utils::startsWith(field->message_type()->full_name(), "QtProtobuf.")
&& field->file()->package() != "QtProtobuf"; // Used for qttypes library to avoid types
// conversion inside library
}

View File

@ -9,6 +9,7 @@
#include <vector>
#include <map>
#include <string>
#include <string_view>
#include <functional>
#include "utils.h"
@ -35,18 +36,6 @@ struct common {
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)
{
if (identifier.empty())
@ -54,9 +43,18 @@ struct common {
return "QPB_" + identifier + "_EXPORT";
}
static std::string getNamespacesString(const std::vector<std::string> &namespacesList,
std::string_view separator);
static std::string getScopeNamespacesString(std::string original, const std::string &scope);
static std::string getFullNamespace(std::string_view fullDescriptorName,
std::string_view separator);
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 TypeMap produceQtTypeMap(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 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);
};
} // namespace QtProtobuf::generator

View File

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

View File

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

View File

@ -130,16 +130,17 @@ bool SingleFileGenerator::GenerateMessages(const FileDescriptor *file,
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 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
printer->Print("\n");
if (hasQtNamespace)
printer->PrintRaw("QT_BEGIN_NAMESPACE\n");
if (!scope_namespaces.empty())
printer->Print({{"scope_namespaces", scope_namespaces}}, Templates::NamespaceTemplate());
if (!scopeNamespaces.empty())
printer->Print({ { "scope_namespaces", scopeNamespaces } },
Templates::NamespaceTemplate());
};
openNamespaces(headerPrinter);
openNamespaces(sourcePrinter);
@ -169,8 +170,9 @@ bool SingleFileGenerator::GenerateMessages(const FileDescriptor *file,
});
auto closeNamespaces = [&](auto printer) {
if (!scope_namespaces.empty())
printer->Print({{"scope_namespaces", scope_namespaces}}, Templates::NamespaceClosingTemplate());
if (!scopeNamespaces.empty())
printer->Print({ { "scope_namespaces", scopeNamespaces } },
Templates::NamespaceClosingTemplate());
if (hasQtNamespace)
printer->PrintRaw("QT_END_NAMESPACE\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)
{
assert(!from.empty());
if (from == to)
return std::string(where);
std::string out;
out.reserve(where.size());
std::size_t pos = 0;