-
Notifications
You must be signed in to change notification settings - Fork 37.7k
refactor: Avoid copy of bilingual_str when formatting, Fix ADL violation #27892
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approach ACK. Perhaps worth annotating both arg
parameters with LIFETIMEBOUND
?
May give it a try if I have to re-touch. |
It's a pretty trivial change? And if it doesn't work, wouldn't that indicate the change is/may be unsafe and we probably want to rethink this PR? |
It requires pulling in a new header and using the keyword in the If you want, I can change the code to make the helper private to the only statement scope that uses it: diff --git a/src/util/translation.h b/src/util/translation.h
index f66f9de63a..8703741d9e 100644
--- a/src/util/translation.h
+++ b/src/util/translation.h
@@ -49,20 +49,16 @@ inline bilingual_str Untranslated(std::string original) { return {original, orig
// Provide an overload of tinyformat::format which can take bilingual_str arguments.
namespace tinyformat {
-inline const std::string& TranslateArg(const bilingual_str& arg, bool translated)
-{
- return translated ? arg.translated : arg.original;
-}
-
-template <typename T>
-const T& TranslateArg(const T& arg, bool translated)
-{
- return arg;
-}
-
template <typename... Args>
bilingual_str format(const bilingual_str& fmt, const Args&... args)
{
+ constexpr auto TranslateArg{[](const auto& arg, bool translated) {
+ if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) {
+ return translated ? arg.translated : arg.original;
+ } else {
+ return arg;
+ }
+ }};
return bilingual_str{format(fmt.original, TranslateArg(args, false)...),
format(fmt.translated, TranslateArg(args, true)...)};
} |
fa0e607
to
faa8576
Compare
Force pushed to use the lambda approach. Also, fixed the ADL violation found by @hebasto in #27862 (comment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK faa8576
Lambda approach is elegant. I would've been okay with a simple LIFETIMEBOUND
attribute but this is probably better, thanks for reworking it.
it would have already been unsafe in master because T& is already a lifetime-bound reference.
Yes, but I think that doesn't hold for what was the untemplated TranslateArg? It doesn't really matter here because format
returns a copy anyway, but it would make new callsites of std::string TranslateArg(const bilingual_str& arg, bool translated)
potentially unsafe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK faa8576
Thanks for the fix. The code looks safe and should fix the namespace problem, but I had some questions about how it is working internally, see below. They aren't important, just asking to improve my understanding.
src/util/translation.h
Outdated
template <typename... Args> | ||
bilingual_str format(const bilingual_str& fmt, const Args&... args) | ||
{ | ||
return bilingual_str{format(fmt.original, TranslateArg(args, false)...), | ||
format(fmt.translated, TranslateArg(args, true)...)}; | ||
constexpr auto TranslateArg{[](const auto& arg, bool translated) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "refactor: Avoid copy of bilingual_str when formatting, Fix ADL violation" (faa8576)
Commit messsage says this is more efficient because TranslateArg
lambda returns a reference. But how do you know it actually does return a reference? I'm not that familiar with the rules for deduced return values, so you probably know more here, but if the default return type is -> auto
I would expect it to return by value not reference. Maybe can add -> const auto&
return type to force returning a reference or just be clear that it is supposed to be a reference?
Also, should type of lambda variable be const auto
instead of constexpr auto
? Again I could be wrong but const auto
suggests to me lambda does not have mutable state, which is true, while constexpr auto
suggests lambda will be called by compile time code, which could be true, but is not true right now because format function is not constexpr.
Also maybe would rename TranslateArg
to translate_arg
since it is a local variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. The return type is auto
, not (as I assumed decltype(auto)
). See also #20495
I guess I'll need to use -> decltype(auto)
or -> const auto&
, as you suggest.
The return type of TranslateArg is std::string, which creates a copy. Fix this by moving everything into a lambda that takes a reference and returns a reference. Also, the format function is called without specifying the namespace it lives in. Fix this by specifying the namespace. See also: https://github.com/bitcoin/bitcoin/blob/7a59865793cd710d7d6650a6106ca4e790ced5d3/doc/developer-notes.md#L117-L137.
faa8576
to
fa8ef7d
Compare
To clarify, it should be possible to add this attribute to a lambda, but I still don't think it is useful here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK fa8ef7d. Looks great! Thanks for updating
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK fa8ef7d, I have reviewed the code and it looks OK.
ACK fa8ef7d |
…tting, Fix ADL violation fa8ef7d refactor: Avoid copy of bilingual_str when formatting, Fix ADL violation (MarcoFalke) Pull request description: This refactor shouldn't change behavior, but may fix compile errors such as bitcoin#27862 (comment) ACKs for top commit: achow101: ACK fa8ef7d ryanofsky: Code review ACK fa8ef7d. Looks great! Thanks for updating hebasto: ACK fa8ef7d, I have reviewed the code and it looks OK. Tree-SHA512: 903019962f27b5432b8e3af052b472238ef68d3ee165148c9d2232bf290309075f9f17d8d06c9b5c7fddb89c1a9c3a4c09c6310af01e8561adc0244a30db0857
Summary: Previous bilingual_str tinyformat::format accepted bilingual format strings, but not bilingual arguments. Extend it to accept both. This is useful when embedding one translated string inside another translated string, for example: `strprintf(_("Error: %s"), message)` which would fail previously if `message` was a bilingual_str. This is a partial backport of [[bitcoin/bitcoin#27150 | core#27150]] bitcoin/bitcoin@3db2874 ---- refactor: Avoid copy of bilingual_str when formatting, Fix ADL violation The return type of TranslateArg is std::string, which creates a copy. Fix this by moving everything into a lambda that takes a reference and returns a reference. Also, the format function is called without specifying the namespace it lives in. Fix this by specifying the namespace. See also: https://github.com/bitcoin/bitcoin/blob/7a59865793cd710d7d6650a6106ca4e790ced5d3/doc/developer-notes.md#L117-L137. This is a backport of [[bitcoin/bitcoin#27892 | core#27892]] Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D14993
This refactor shouldn't change behavior, but may fix compile errors such as #27862 (comment)