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! :)