Addresses #17866 following practicalswift's suggestion: #17866 (comment)
~Used ::ToString to avoid aliasing issues. Left uses in QT and test.~
Addresses #17866 following practicalswift's suggestion: #17866 (comment)
~Used ::ToString to avoid aliasing issues. Left uses in QT and test.~
~Limited to integral types to avoid inconsistencies noted in the examples here: https://en.cppreference.com/w/cpp/string/basic_string/to_string~
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--174a7506f384e20aa4161008e828411d-->
Reviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
Concept ACK: simple and robust (locale independent) is better than gotcha-filled and fragile (locale dependent).
Thanks for working on reducing the usage of locale dependent functions. Hope to see more PR's of this type from you :)
Will review.
497 | @@ -497,7 +498,7 @@ std::string RPCHelpMan::ToString() const 498 | if (i == 0) ret += "\nArguments:\n"; 499 | 500 | // Push named argument name and description 501 | - sections.m_sections.emplace_back(std::to_string(i + 1) + ". " + arg.m_name, arg.ToDescriptionString()); 502 | + sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.m_name, arg.ToDescriptionString());
I think this is the only one where ::ToString(…) . Please change the others to simply ToString(…) :)
Maybe I got it wrong but is the RPC interface locale independent anyways?
The intention is that the RPC interface should be 100% locale independent :)
Ok then never mind.
223 | @@ -224,6 +224,7 @@ BITCOIN_CORE_H = \ 224 | util/rbf.h \ 225 | util/settings.h \ 226 | util/string.h \ 227 | + util/string_stream.h \
Put this in util/string.h instead. No need to introduce a new file.
16 | +template <typename T> 17 | +typename std::enable_if<std::is_integral<T>::value, std::string>::type ToString(const T t) { 18 | + std::ostringstream oss; 19 | + oss.imbue(std::locale::classic()); 20 | + oss << t; 21 | + return oss.str();
Please run clang-format -i src/util/string_stream.h to get the correct indentation and formatting.
12 | + 13 | +/** 14 | + * Locale-independent version of std::to_string 15 | + */ 16 | +template <typename T> 17 | +typename std::enable_if<std::is_integral<T>::value, std::string>::type ToString(const T t) {
Remove the enable_if: we need to enable this for all types supported (the floating points in particular).
That ToString doesn't print a lot of trailing zeroes is a feature and not a bug. You can note the difference in the comment though :)
Since std::to_string is locale dependent there should be no assumption regarding formatting regardless, so no harm done by not printing trailing zeroes. Also all current code sites are safe.
13 | @@ -15,9 +14,6 @@ KNOWN_VIOLATIONS=( 14 | "src/qt/optionsmodel.cpp.*std::to_string" 15 | "src/qt/rpcconsole.cpp:.*atoi" 16 | "src/rest.cpp:.*strtol" 17 | - "src/rpc/net.cpp.*std::to_string" 18 | - "src/rpc/rawtransaction.cpp.*std::to_string" 19 | - "src/rpc/util.cpp.*std::to_string" 20 | "src/test/addrman_tests.cpp.*std::to_string"
Please replace all std::to_string with ToString. No need to do this partially. All call sites are safe.
Concept ACK
Concept ACK.
@Empact Are you still working on this PR? :)
I think it would be really good to have ToString(…) in our code base since std::to_string(…) usage keeps popping up in new code. Latest case in #18261 (see #18261 (review)).
Rebased and incorporated your feedback, @practicalswift
ACK 97eefd7c25f03e898071171eacc45ac5fb5ada6b
Rebased
53 | @@ -52,4 +54,16 @@ NODISCARD inline bool ValidAsCString(const std::string& str) noexcept 54 | return str.size() == strlen(str.c_str()); 55 | } 56 | 57 | +/** 58 | + * Locale-independent version of ToString
* Locale-independent version of std::to_string
53 | @@ -52,4 +54,16 @@ NODISCARD inline bool ValidAsCString(const std::string& str) noexcept 54 | return str.size() == strlen(str.c_str()); 55 | } 56 | 57 | +/** 58 | + * Locale-independent version of ToString 59 | + */ 60 | +template <typename T> 61 | +std::string ToString(const T t)
Not really necessary for the simple types in all current call sites, but for future-proofing, const T& t is better to avoid copying expensive types.
And should be inlined anyway, so the extra reference for simple types should get optimised out
Yeah did not originally due to the definition of std::to_string, but I agree it makes sense for future-proofing.
ACK 0add74b0b5e11124612e6d07b3f68266a4ace66e, minor nits
ACK 0add74b0b5e11124612e6d07b3f68266a4ace66e
Addressed nits.
ACK d056df033a1e88554f7cc39dd709a87b17cb49df
Very pleased to see the removal of no less than 16(!) instances of calls to locale dependent functions. Thanks! :)
ACK d056df033a1e88554f7cc39dd709a87b17cb49df
So for tinyformat, do we want to do this as well?
// Added for Bitcoin Core
template<typename... Args>
std::string format(const std::string &fmt, const Args&... args)
{
std::ostringstream oss;
+ oss.imbue(std::locale::classic());
format(oss, fmt.c_str(), args...);
return oss.str();
}
@laanwj Technically we don't technically that in the tfm::format case since we're already implicitly assuming that the C++ locale is always the classic locale. If that was not the case a lot of things would break as demonstrated in #18281. However I think we should make that implicit assumption explicit - PR coming up! :)