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.~
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
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());
::ToString(…)
. Please change the others to simply ToString(…)
:)
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 \
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();
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"
std::to_string
with ToString
. No need to do this partially. All call sites are safe.
@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)).
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
0 * 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)
const T& t
is better to avoid copying expensive types.
std::to_string
, but I agree it makes sense for future-proofing.
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?
0 // Added for Bitcoin Core
1 template<typename... Args>
2 std::string format(const std::string &fmt, const Args&... args)
3 {
4 std::ostringstream oss;
5+ oss.imbue(std::locale::classic());
6 format(oss, fmt.c_str(), args...);
7 return oss.str();
8 }
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! :)