From ecd28d2e56a507c735ddc086f2e1ebc9cdcadd4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Apr 2026 20:37:31 +0000 Subject: [PATCH 1/3] Optimize unnecessary object duplication: avoid regex recompilation, string copies Agent-Logs-Url: https://github.com/Cpp2Rust/cpp2rust/sessions/67031e6a-ec2f-4f6c-a534-ac63f300898d Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com> --- cpp2rust/converter/converter.cpp | 16 +++++----- cpp2rust/converter/converter_lib.cpp | 9 ++++++ cpp2rust/converter/converter_lib.h | 3 ++ cpp2rust/converter/mapper.cpp | 30 ++++++++++--------- .../converter/models/converter_refcount.cpp | 2 +- cpp2rust/converter/plugins/emplace_back.cpp | 5 +--- 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 5cad686c..9d324845 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -9,7 +9,6 @@ #include #include -#include #include "compiler.h" #include "converter/converter_lib.h" @@ -381,7 +380,7 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) { } if (decl->isFileVarDecl()) { - name = std::regex_replace(Mapper::ToString(decl), std::regex("::"), "_"); + name = ReplaceAll(Mapper::ToString(decl), "::", "_"); if ((decl->isExternallyDeclarable() && !decl->hasInit()) || !globals_.insert(name).second) { return false; @@ -2133,10 +2132,9 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { return std::format("{}::{}", GetRecordName(clang::dyn_cast( enum_constant->getDeclContext())), - enum_constant->getName().str()); + std::string_view(enum_constant->getName())); } else if (IsGlobalVar(expr)) { - return std::regex_replace(Mapper::ToString(expr->getDecl()), - std::regex("::"), "_"); + return ReplaceAll(Mapper::ToString(expr->getDecl()), "::", "_"); } return GetNamedDeclAsString(decl); @@ -2610,12 +2608,12 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) { for (auto e : decl->enumerators()) { llvm::SmallVector init; e->getInitVal().toString(init, 10); - std::string init_str(init.begin(), init.end()); if (first_enumerator) { StrCat("#[default]"); first_enumerator = false; } - StrCat(std::format("{} = {},", e->getNameAsString(), init_str)); + StrCat(std::format("{} = {},", std::string_view(e->getName()), + std::string_view(init.data(), init.size()))); } StrCat("}"); return false; @@ -2852,7 +2850,7 @@ std::string Converter::ConvertVarDefaultInit(clang::QualType qual_type) { std::string Converter::GetOverloadedFunctionName(const clang::FunctionDecl *decl) { - std::string name(decl->getNameAsString()); + auto name = decl->getNameAsString(); if (decl->getNumParams() != 0U) { name += '_'; @@ -2884,7 +2882,7 @@ std::string Converter::GetRecordName(const clang::NamedDecl *decl) const { if (auto it = inner_structs_.find(ID); it != inner_structs_.end()) { return it->second; } - return std::regex_replace(Mapper::ToString(decl), std::regex("::"), "_"); + return ReplaceAll(Mapper::ToString(decl), "::", "_"); } std::vector diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 88a4c9b1..daa72a6c 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -762,4 +762,13 @@ void Unwrap(std::string &s, std::string_view prefix, std::string_view suffix) { } } +std::string ReplaceAll(std::string str, std::string_view from, + std::string_view to) { + for (size_t pos = 0; (pos = str.find(from, pos)) != std::string::npos; + pos += to.size()) { + str.replace(pos, from.size(), to); + } + return str; +} + } // namespace cpp2rust diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index c82dbb3c..033f54d3 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -167,4 +167,7 @@ std::vector GetSwitchCaseBody(clang::CompoundStmt *body, void Unwrap(std::string &s, std::string_view prefix, std::string_view suffix); +std::string ReplaceAll(std::string str, std::string_view from, + std::string_view to); + } // namespace cpp2rust diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 9193b32f..966a9cc2 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -447,7 +447,7 @@ void addBuiltinTypes(Model model) { auto build_rust_type = [&](clang::QualType qt) { unsigned bits = ctx_->getTypeSize(qt); char sign = qt->isSignedIntegerType() ? 'i' : 'u'; - return std::string(1, sign) + std::to_string(bits); + return std::format("{}{}", sign, bits); }; // Misc @@ -547,13 +547,14 @@ std::string mapTypeStringRecursive(const std::string &cpp_type) { } std::string normalizeTranslationRule(std::string rule) { - const std::array, 2> normalization_rules{{ - // Dettach pointer from double reference. Useful for matching translation - // rules. - {std::regex(R"(\*\&\&)"), "* &&"}, - // Ignore constant template parameters, i.e. replace them with _. - {std::regex(R"(\b\d+\b)"), "_"}, - }}; + static const std::array, 2> + normalization_rules{{ + // Dettach pointer from double reference. Useful for matching + // translation rules. + {std::regex(R"(\*\&\&)"), "* &&"}, + // Ignore constant template parameters, i.e. replace them with _. + {std::regex(R"(\b\d+\b)"), "_"}, + }}; for (const auto &r : normalization_rules) { rule = std::regex_replace(rule, r.first, r.second); @@ -567,7 +568,7 @@ static std::string synthesizeAnonRecordName(const clang::RecordDecl *record) { if (auto *parent = clang::dyn_cast(record->getDeclContext())) { parent_name = parent->getIdentifier() - ? parent->getIdentifier()->getName().str() + ? std::string(parent->getIdentifier()->getName()) : synthesizeAnonRecordName(parent); parent_name += '_'; } @@ -674,7 +675,7 @@ bool ParamIsPointer(const clang::Expr *expr, unsigned index) { void AddRuleForUserDefinedType(clang::NamedDecl *decl) { auto cpp_name = ToString(decl); - auto rs_name = std::regex_replace(cpp_name, std::regex("::"), "_"); + auto rs_name = ReplaceAll(cpp_name, "::", "_"); if (types_.contains(cpp_name)) { return; @@ -863,10 +864,11 @@ std::string ToString(const clang::Expr *expr) { } if (const auto *uop = llvm::dyn_cast(expr)) { - std::string opcode = - clang::UnaryOperator::getOpcodeStr(uop->getOpcode()).str(); - return uop->isPostfix() ? ToString(uop->getSubExpr()) + std::move(opcode) - : std::move(opcode) + ToString(uop->getSubExpr()); + auto sub = ToString(uop->getSubExpr()); + std::string_view opcode = + clang::UnaryOperator::getOpcodeStr(uop->getOpcode()); + return uop->isPostfix() ? std::format("{}{}", sub, opcode) + : std::format("{}{}", opcode, sub); } return "Unhandled case in ToString"; diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index f19a7d8a..168d8556 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1754,7 +1754,7 @@ void ConverterRefCount::ConvertGenericBinaryOperator( clang::BinaryOperator *expr) { auto lhs = expr->getLHS(); auto rhs = expr->getRHS(); - auto opcode = expr->getOpcodeStr().str(); + std::string_view opcode = expr->getOpcodeStr(); auto lhs_vars = GetAllVars(lhs); auto rhs_vars = GetAllVars(rhs); diff --git a/cpp2rust/converter/plugins/emplace_back.cpp b/cpp2rust/converter/plugins/emplace_back.cpp index 26cf371f..9c156af5 100644 --- a/cpp2rust/converter/plugins/emplace_back.cpp +++ b/cpp2rust/converter/plugins/emplace_back.cpp @@ -3,8 +3,6 @@ #include -#include - #include "converter/converter_lib.h" #include "converter/mapper.h" #include "converter/models/converter_refcount.h" @@ -139,8 +137,7 @@ clang::CXXConstructExpr *buildConstructExpr(clang::CXXMemberCallExpr *call, void Converter::emplace_back_emit_push_open(clang::CXXMemberCallExpr *call) { { PushExprKind push(*this, ExprKind::LValue); - StrCat(std::regex_replace(ToString(call->getCallee()), - std::regex("emplace_back"), "push")); + StrCat(ReplaceAll(ToString(call->getCallee()), "emplace_back", "push")); } StrCat("("); } From 5a60ab6d3721a0ed5c196b03a8301fb058825d99 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Apr 2026 20:39:51 +0000 Subject: [PATCH 2/3] Fix typo 'Dettach' -> 'Detach'; restore explicit .str() for consistency Agent-Logs-Url: https://github.com/Cpp2Rust/cpp2rust/sessions/67031e6a-ec2f-4f6c-a534-ac63f300898d Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com> --- cpp2rust/converter/mapper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 966a9cc2..c9d09ce3 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -549,7 +549,7 @@ std::string mapTypeStringRecursive(const std::string &cpp_type) { std::string normalizeTranslationRule(std::string rule) { static const std::array, 2> normalization_rules{{ - // Dettach pointer from double reference. Useful for matching + // Detach pointer from double reference. Useful for matching // translation rules. {std::regex(R"(\*\&\&)"), "* &&"}, // Ignore constant template parameters, i.e. replace them with _. @@ -568,7 +568,7 @@ static std::string synthesizeAnonRecordName(const clang::RecordDecl *record) { if (auto *parent = clang::dyn_cast(record->getDeclContext())) { parent_name = parent->getIdentifier() - ? std::string(parent->getIdentifier()->getName()) + ? parent->getIdentifier()->getName().str() : synthesizeAnonRecordName(parent); parent_name += '_'; } From 5a1ad9ab68c9ef2024d4d0f7a931c1be9b3290bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Apr 2026 07:28:31 +0000 Subject: [PATCH 3/3] Optimize string operations: avoid heap allocation for short-lived strings Agent-Logs-Url: https://github.com/Cpp2Rust/cpp2rust/sessions/02bdd519-7825-4e67-90f0-8f2d0df2c427 Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com> --- cpp2rust/converter/converter.cpp | 8 ++++---- cpp2rust/converter/mapper.cpp | 11 ++++++----- cpp2rust/converter/models/converter_refcount.cpp | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 441a2524..9910cf43 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2136,7 +2136,7 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { return std::format("{}::{}", GetRecordName(clang::dyn_cast( enum_constant->getDeclContext())), - enum_constant->getName().str()); + std::string_view(enum_constant->getName())); } else if (IsGlobalVar(expr)) { return ReplaceAll(Mapper::ToString(expr->getDecl()), "::", "_"); } @@ -2612,12 +2612,12 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) { for (auto e : decl->enumerators()) { llvm::SmallVector init; e->getInitVal().toString(init, 10); - std::string init_str(init.begin(), init.end()); if (first_enumerator) { StrCat("#[default]"); first_enumerator = false; } - StrCat(std::format("{} = {},", e->getNameAsString(), init_str)); + StrCat(std::format("{} = {},", std::string_view(e->getName()), + std::string_view(init.data(), init.size()))); } StrCat("}"); return false; @@ -2854,7 +2854,7 @@ std::string Converter::ConvertVarDefaultInit(clang::QualType qual_type) { std::string Converter::GetOverloadedFunctionName(const clang::FunctionDecl *decl) { - std::string name(decl->getNameAsString()); + auto name = decl->getNameAsString(); if (decl->getNumParams() != 0U) { name += '_'; diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index e0866206..45d88bae 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -443,7 +443,7 @@ void addBuiltinTypes(Model model) { auto build_rust_type = [&](clang::QualType qt) { unsigned bits = ctx_->getTypeSize(qt); char sign = qt->isSignedIntegerType() ? 'i' : 'u'; - return std::string(1, sign) + std::to_string(bits); + return std::format("{}{}", sign, bits); }; // Misc @@ -858,10 +858,11 @@ std::string ToString(const clang::Expr *expr) { } if (const auto *uop = llvm::dyn_cast(expr)) { - std::string opcode = - clang::UnaryOperator::getOpcodeStr(uop->getOpcode()).str(); - return uop->isPostfix() ? ToString(uop->getSubExpr()) + std::move(opcode) - : std::move(opcode) + ToString(uop->getSubExpr()); + auto sub = ToString(uop->getSubExpr()); + std::string_view opcode = + clang::UnaryOperator::getOpcodeStr(uop->getOpcode()); + return uop->isPostfix() ? std::format("{}{}", sub, opcode) + : std::format("{}{}", opcode, sub); } return "Unhandled case in ToString"; diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 3cf69347..eedb1606 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1757,7 +1757,7 @@ void ConverterRefCount::ConvertGenericBinaryOperator( clang::BinaryOperator *expr) { auto lhs = expr->getLHS(); auto rhs = expr->getRHS(); - auto opcode = expr->getOpcodeStr().str(); + std::string_view opcode = expr->getOpcodeStr(); auto lhs_vars = GetAllVars(lhs); auto rhs_vars = GetAllVars(rhs);