aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/CMakeLists.txt1
-rw-r--r--src/util/asmap.cpp6
-rw-r--r--src/util/check.cpp2
-rw-r--r--src/util/check.h2
-rw-r--r--src/util/feefrac.h8
-rw-r--r--src/util/fs_helpers.cpp4
-rw-r--r--src/util/strencodings.h77
-rw-r--r--src/util/string.h72
-rw-r--r--src/util/syserror.cpp2
-rw-r--r--src/util/threadnames.cpp2
-rw-r--r--src/util/tokenpipe.cpp2
-rw-r--r--src/util/trace.h2
12 files changed, 164 insertions, 16 deletions
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 26c6271f9b..4999dbf13f 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -42,4 +42,5 @@ target_link_libraries(bitcoin_util
bitcoin_clientversion
bitcoin_crypto
$<$<PLATFORM_ID:Windows>:ws2_32>
+ $<$<PLATFORM_ID:Windows>:iphlpapi>
)
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp
index f50cd8a28c..04b0673c49 100644
--- a/src/util/asmap.cpp
+++ b/src/util/asmap.cpp
@@ -203,10 +203,10 @@ std::vector<bool> DecodeAsmap(fs::path path)
LogPrintf("Failed to open asmap file from disk\n");
return bits;
}
- fseek(filestr, 0, SEEK_END);
- int length = ftell(filestr);
+ file.seek(0, SEEK_END);
+ int length = file.tell();
LogPrintf("Opened asmap file %s (%d bytes) from disk\n", fs::quoted(fs::PathToString(path)), length);
- fseek(filestr, 0, SEEK_SET);
+ file.seek(0, SEEK_SET);
uint8_t cur_byte;
for (int i = 0; i < length; ++i) {
file >> cur_byte;
diff --git a/src/util/check.cpp b/src/util/check.cpp
index eb3885832b..e1956042c3 100644
--- a/src/util/check.cpp
+++ b/src/util/check.cpp
@@ -4,7 +4,7 @@
#include <util/check.h>
-#include <config/bitcoin-config.h> // IWYU pragma: keep
+#include <bitcoin-build-config.h> // IWYU pragma: keep
#include <clientversion.h>
#include <tinyformat.h>
diff --git a/src/util/check.h b/src/util/check.h
index a02a1de8dc..8f28f5dc94 100644
--- a/src/util/check.h
+++ b/src/util/check.h
@@ -40,7 +40,7 @@ void assertion_fail(std::string_view file, int line, std::string_view func, std:
/** Helper for Assert()/Assume() */
template <bool IS_ASSERT, typename T>
-T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion)
+constexpr T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] const char* file, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* assertion)
{
if constexpr (IS_ASSERT
#ifdef ABORT_ON_FAILED_ASSUME
diff --git a/src/util/feefrac.h b/src/util/feefrac.h
index 9772162010..161322b50a 100644
--- a/src/util/feefrac.h
+++ b/src/util/feefrac.h
@@ -64,13 +64,13 @@ struct FeeFrac
int32_t size;
/** Construct an IsEmpty() FeeFrac. */
- inline FeeFrac() noexcept : fee{0}, size{0} {}
+ constexpr inline FeeFrac() noexcept : fee{0}, size{0} {}
/** Construct a FeeFrac with specified fee and size. */
- inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}
+ constexpr inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}
- inline FeeFrac(const FeeFrac&) noexcept = default;
- inline FeeFrac& operator=(const FeeFrac&) noexcept = default;
+ constexpr inline FeeFrac(const FeeFrac&) noexcept = default;
+ constexpr inline FeeFrac& operator=(const FeeFrac&) noexcept = default;
/** Check if this is empty (size and fee are 0). */
bool inline IsEmpty() const noexcept {
diff --git a/src/util/fs_helpers.cpp b/src/util/fs_helpers.cpp
index 41c8fe3b8f..7ac7b829d8 100644
--- a/src/util/fs_helpers.cpp
+++ b/src/util/fs_helpers.cpp
@@ -5,7 +5,7 @@
#include <util/fs_helpers.h>
-#include <config/bitcoin-config.h> // IWYU pragma: keep
+#include <bitcoin-build-config.h> // IWYU pragma: keep
#include <logging.h>
#include <sync.h>
@@ -22,7 +22,7 @@
#include <utility>
#ifndef WIN32
-// for posix_fallocate, in configure.ac we check if it is present after this
+// for posix_fallocate, in cmake/introspection.cmake we check if it is present after this
#ifdef __linux__
#ifdef _POSIX_C_SOURCE
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index 91ac35b132..1543de03ab 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -13,6 +13,8 @@
#include <span.h>
#include <util/string.h>
+#include <array>
+#include <bit>
#include <charconv>
#include <cstddef>
#include <cstdint>
@@ -365,4 +367,79 @@ std::string Capitalize(std::string str);
*/
std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier);
+namespace util {
+/** consteval version of HexDigit() without the lookup table. */
+consteval uint8_t ConstevalHexDigit(const char c)
+{
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'a' && c <= 'f') return c - 'a' + 0xa;
+
+ throw "Only lowercase hex digits are allowed, for consistency";
+}
+
+/**
+ * ""_hex is a compile-time user-defined literal returning a
+ * `std::array<std::byte>`, equivalent to ParseHex(). Variants provided:
+ *
+ * - ""_hex_v: Returns `std::vector<std::byte>`, useful for heap allocation or
+ * variable-length serialization.
+ *
+ * - ""_hex_u8: Returns `std::array<uint8_t>`, for cases where `std::byte` is
+ * incompatible.
+ *
+ * - ""_hex_v_u8: Returns `std::vector<uint8_t>`, combining heap allocation with
+ * `uint8_t`.
+ *
+ * @warning It could be necessary to use vector instead of array variants when
+ * serializing, or vice versa, because vectors are assumed to be variable-
+ * length and serialized with a size prefix, while arrays are considered fixed
+ * length and serialized with no prefix.
+ *
+ * @warning It may be preferable to use vector variants to save stack space when
+ * declaring local variables if hex strings are large. Alternatively variables
+ * could be declared constexpr to avoid using stack space.
+ *
+ * @warning Avoid `uint8_t` variants when not necessary, as the codebase
+ * migrates to use `std::byte` instead of `unsigned char` and `uint8_t`.
+ *
+ * @note One reason ""_hex uses `std::array` instead of `std::vector` like
+ * ParseHex() does is because heap-based containers cannot cross the compile-
+ * time/runtime barrier.
+ */
+inline namespace hex_literals {
+namespace detail {
+
+template <size_t N>
+struct Hex {
+ std::array<std::byte, N / 2> bytes{};
+ consteval Hex(const char (&hex_str)[N])
+ // 2 hex digits required per byte + implicit null terminator
+ requires(N % 2 == 1)
+ {
+ if (hex_str[N - 1]) throw "null terminator required";
+ for (std::size_t i = 0; i < bytes.size(); ++i) {
+ bytes[i] = static_cast<std::byte>(
+ (ConstevalHexDigit(hex_str[2 * i]) << 4) |
+ ConstevalHexDigit(hex_str[2 * i + 1]));
+ }
+ }
+};
+
+} // namespace detail
+
+template <util::detail::Hex str>
+constexpr auto operator""_hex() { return str.bytes; }
+
+template <util::detail::Hex str>
+constexpr auto operator""_hex_u8() { return std::bit_cast<std::array<uint8_t, str.bytes.size()>>(str.bytes); }
+
+template <util::detail::Hex str>
+constexpr auto operator""_hex_v() { return std::vector<std::byte>{str.bytes.begin(), str.bytes.end()}; }
+
+template <util::detail::Hex str>
+inline auto operator""_hex_v_u8() { return std::vector<uint8_t>{UCharCast(str.bytes.data()), UCharCast(str.bytes.data() + str.bytes.size())}; }
+
+} // inline namespace hex_literals
+} // namespace util
+
#endif // BITCOIN_UTIL_STRENCODINGS_H
diff --git a/src/util/string.h b/src/util/string.h
index 30c0a0d6c1..c5183d6c80 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2022 The Bitcoin Core developers
+// Copyright (c) 2019-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,7 @@
#define BITCOIN_UTIL_STRING_H
#include <span.h>
+#include <tinyformat.h>
#include <array>
#include <cstdint>
@@ -17,6 +18,67 @@
#include <vector>
namespace util {
+/**
+ * @brief A wrapper for a compile-time partially validated format string
+ *
+ * This struct can be used to enforce partial compile-time validation of format
+ * strings, to reduce the likelihood of tinyformat throwing exceptions at
+ * run-time. Validation is partial to try and prevent the most common errors
+ * while avoiding re-implementing the entire parsing logic.
+ *
+ * @note Counting of `*` dynamic width and precision fields (such as `%*c`,
+ * `%2$*3$d`, `%.*f`) is not implemented to minimize code complexity as long as
+ * they are not used in the codebase. Usage of these fields is not counted and
+ * can lead to run-time exceptions. Code wanting to use the `*` specifier can
+ * side-step this struct and call tinyformat directly.
+ */
+template <unsigned num_params>
+struct ConstevalFormatString {
+ const char* const fmt;
+ consteval ConstevalFormatString(const char* str) : fmt{str} { Detail_CheckNumFormatSpecifiers(fmt); }
+ constexpr static void Detail_CheckNumFormatSpecifiers(std::string_view str)
+ {
+ unsigned count_normal{0}; // Number of "normal" specifiers, like %s
+ unsigned count_pos{0}; // Max number in positional specifier, like %8$s
+ for (auto it{str.begin()}; it < str.end();) {
+ if (*it != '%') {
+ ++it;
+ continue;
+ }
+
+ if (++it >= str.end()) throw "Format specifier incorrectly terminated by end of string";
+ if (*it == '%') {
+ // Percent escape: %%
+ ++it;
+ continue;
+ }
+
+ unsigned maybe_num{0};
+ while ('0' <= *it && *it <= '9') {
+ maybe_num *= 10;
+ maybe_num += *it - '0';
+ ++it;
+ };
+
+ if (*it == '$') {
+ // Positional specifier, like %8$s
+ if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
+ count_pos = std::max(count_pos, maybe_num);
+ if (++it >= str.end()) throw "Format specifier incorrectly terminated by end of string";
+ } else {
+ // Non-positional specifier, like %s
+ ++count_normal;
+ ++it;
+ }
+ // The remainder "[flags][width][.precision][length]type" of the
+ // specifier is not checked. Parsing continues with the next '%'.
+ }
+ if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
+ unsigned count{count_normal | count_pos};
+ if (num_params != count) throw "Format specifier count must match the argument count!";
+ }
+};
+
void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute);
/** Split a string on any char found in separators, returning a vector.
@@ -173,4 +235,12 @@ template <typename T1, size_t PREFIX_LEN>
}
} // namespace util
+namespace tinyformat {
+template <typename... Args>
+std::string format(util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
+{
+ return format(fmt.fmt, args...);
+}
+} // namespace tinyformat
+
#endif // BITCOIN_UTIL_STRING_H
diff --git a/src/util/syserror.cpp b/src/util/syserror.cpp
index 6f3a724483..a902826f8e 100644
--- a/src/util/syserror.cpp
+++ b/src/util/syserror.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <config/bitcoin-config.h> // IWYU pragma: keep
+#include <bitcoin-build-config.h> // IWYU pragma: keep
#include <tinyformat.h>
#include <util/syserror.h>
diff --git a/src/util/threadnames.cpp b/src/util/threadnames.cpp
index 0249de37e3..37c5b8f617 100644
--- a/src/util/threadnames.cpp
+++ b/src/util/threadnames.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <config/bitcoin-config.h> // IWYU pragma: keep
+#include <bitcoin-build-config.h> // IWYU pragma: keep
#include <cstring>
#include <string>
diff --git a/src/util/tokenpipe.cpp b/src/util/tokenpipe.cpp
index 16fbb664ea..9425c62ebf 100644
--- a/src/util/tokenpipe.cpp
+++ b/src/util/tokenpipe.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <util/tokenpipe.h>
-#include <config/bitcoin-config.h> // IWYU pragma: keep
+#include <bitcoin-build-config.h> // IWYU pragma: keep
#ifndef WIN32
diff --git a/src/util/trace.h b/src/util/trace.h
index d9ed65e3aa..72a486d562 100644
--- a/src/util/trace.h
+++ b/src/util/trace.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_UTIL_TRACE_H
#define BITCOIN_UTIL_TRACE_H
-#include <config/bitcoin-config.h> // IWYU pragma: keep
+#include <bitcoin-build-config.h> // IWYU pragma: keep
#ifdef ENABLE_TRACING