aboutsummaryrefslogtreecommitdiff
path: root/src/util/strencodings.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/strencodings.h')
-rw-r--r--src/util/strencodings.h93
1 files changed, 83 insertions, 10 deletions
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index 26dc0a0ce3..08a5465de1 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -11,9 +11,12 @@
#include <attributes.h>
#include <span.h>
+#include <util/string.h>
+#include <charconv>
#include <cstdint>
#include <iterator>
+#include <optional>
#include <string>
#include <vector>
@@ -27,6 +30,23 @@ enum SafeChars
};
/**
+ * Used by ParseByteUnits()
+ * Lowercase base 1000
+ * Uppercase base 1024
+*/
+enum class ByteUnit : uint64_t {
+ NOOP = 1ULL,
+ k = 1000ULL,
+ K = 1024ULL,
+ m = 1'000'000ULL,
+ M = 1ULL << 20,
+ g = 1'000'000'000ULL,
+ G = 1ULL << 30,
+ t = 1'000'000'000'000ULL,
+ T = 1ULL << 40,
+};
+
+/**
* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email
* addresses, but avoid anything even possibly remotely dangerous like & or >
* @param[in] str The string to sanitize
@@ -47,7 +67,8 @@ bool IsHexNumber(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr);
std::string EncodeBase64(Span<const unsigned char> input);
-std::string EncodeBase64(const std::string& str);
+inline std::string EncodeBase64(Span<const std::byte> input) { return EncodeBase64(MakeUCharSpan(input)); }
+inline std::string EncodeBase64(const std::string& str) { return EncodeBase64(MakeUCharSpan(str)); }
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr);
@@ -66,8 +87,33 @@ std::string EncodeBase32(Span<const unsigned char> input, bool pad = true);
std::string EncodeBase32(const std::string& str, bool pad = true);
void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut);
-int64_t atoi64(const std::string& str);
-int atoi(const std::string& str);
+
+// LocaleIndependentAtoi is provided for backwards compatibility reasons.
+//
+// New code should use ToIntegral or the ParseInt* functions
+// which provide parse error feedback.
+//
+// The goal of LocaleIndependentAtoi is to replicate the exact defined behaviour
+// of atoi and atoi64 as they behave under the "C" locale.
+template <typename T>
+T LocaleIndependentAtoi(const std::string& str)
+{
+ static_assert(std::is_integral<T>::value);
+ T result;
+ // Emulate atoi(...) handling of white space and leading +/-.
+ std::string s = TrimString(str);
+ if (!s.empty() && s[0] == '+') {
+ if (s.length() >= 2 && s[1] == '-') {
+ return 0;
+ }
+ s = s.substr(1);
+ }
+ auto [_, error_condition] = std::from_chars(s.data(), s.data() + s.size(), result);
+ if (error_condition != std::errc{}) {
+ return 0;
+ }
+ return result;
+}
/**
* Tests if the given character is a decimal digit.
@@ -95,6 +141,26 @@ constexpr inline bool IsSpace(char c) noexcept {
}
/**
+ * Convert string to integral type T. Leading whitespace, a leading +, or any
+ * trailing character fail the parsing. The required format expressed as regex
+ * is `-?[0-9]+`. The minus sign is only permitted for signed integer types.
+ *
+ * @returns std::nullopt if the entire string could not be parsed, or if the
+ * parsed value is not in the range representable by the type T.
+ */
+template <typename T>
+std::optional<T> ToIntegral(const std::string& str)
+{
+ static_assert(std::is_integral<T>::value);
+ T result;
+ const auto [first_nonmatching, error_condition] = std::from_chars(str.data(), str.data() + str.size(), result);
+ if (first_nonmatching != str.data() + str.size() || error_condition != std::errc{}) {
+ return std::nullopt;
+ }
+ return result;
+}
+
+/**
* Convert string to signed 32-bit integer with strict parse error feedback.
* @returns true if the entire string could be parsed as valid integer,
* false if not the entire string could be parsed or when overflow or underflow occurred.
@@ -137,17 +203,11 @@ constexpr inline bool IsSpace(char c) noexcept {
[[nodiscard]] bool ParseUInt64(const std::string& str, uint64_t *out);
/**
- * Convert string to double with strict parse error feedback.
- * @returns true if the entire string could be parsed as valid double,
- * false if not the entire string could be parsed or when overflow or underflow occurred.
- */
-[[nodiscard]] bool ParseDouble(const std::string& str, double *out);
-
-/**
* Convert a span of bytes to a lower-case hexadecimal string.
*/
std::string HexStr(const Span<const uint8_t> s);
inline std::string HexStr(const Span<const char> s) { return HexStr(MakeUCharSpan(s)); }
+inline std::string HexStr(const Span<const std::byte> s) { return HexStr(MakeUCharSpan(s)); }
/**
* Format a paragraph of text to a fixed width, adding spaces for
@@ -264,4 +324,17 @@ std::string ToUpper(const std::string& str);
*/
std::string Capitalize(std::string str);
+/**
+ * Parse a string with suffix unit [k|K|m|M|g|G|t|T].
+ * Must be a whole integer, fractions not allowed (0.5t), no whitespace or +-
+ * Lowercase units are 1000 base. Uppercase units are 1024 base.
+ * Examples: 2m,27M,19g,41T
+ *
+ * @param[in] str the string to convert into bytes
+ * @param[in] default_multiplier if no unit is found in str use this unit
+ * @returns optional uint64_t bytes from str or nullopt
+ * if ToIntegral is false, str is empty, trailing whitespace or overflow
+ */
+std::optional<uint64_t> ParseByteUnits(const std::string& str, ByteUnit default_multiplier);
+
#endif // BITCOIN_UTIL_STRENCODINGS_H