tinyformat: Add compile-time checking for literal format strings

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
This commit is contained in:
Ryan Ofsky 2024-10-28 19:13:46 -04:00
parent 184f34f2d0
commit fe39acf88f
2 changed files with 17 additions and 22 deletions

View File

@ -145,6 +145,7 @@ namespace tfm = tinyformat;
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <stdexcept> // Added for Bitcoin Core #include <stdexcept> // Added for Bitcoin Core
#include <util/string.h> // Added for Bitcoin Core
#ifndef TINYFORMAT_ASSERT #ifndef TINYFORMAT_ASSERT
# include <cassert> # include <cassert>
@ -178,6 +179,18 @@ namespace tfm = tinyformat;
namespace tinyformat { namespace tinyformat {
// Added for Bitcoin Core. Wrapper for checking format strings at compile time.
// Unlike ConstevalFormatString this supports std::string for runtime string
// formatting without compile time checks.
template <unsigned num_params>
struct FormatStringCheck {
consteval FormatStringCheck(const char* str) : fmt{util::ConstevalFormatString<num_params>{str}.fmt} {}
FormatStringCheck(const std::string& str) : fmt{str.c_str()} {}
FormatStringCheck(util::ConstevalFormatString<num_params> str) : fmt{str.fmt} {}
operator const char*() { return fmt; }
const char* fmt;
};
// Added for Bitcoin Core // Added for Bitcoin Core
class format_error: public std::runtime_error class format_error: public std::runtime_error
{ {
@ -1056,7 +1069,7 @@ inline void vformat(std::ostream& out, const char* fmt, FormatListRef list)
/// Format list of arguments to the stream according to given format string. /// Format list of arguments to the stream according to given format string.
template<typename... Args> template<typename... Args>
void format(std::ostream& out, const char* fmt, const Args&... args) void format(std::ostream& out, FormatStringCheck<sizeof...(Args)> fmt, const Args&... args)
{ {
vformat(out, fmt, makeFormatList(args...)); vformat(out, fmt, makeFormatList(args...));
} }
@ -1064,7 +1077,7 @@ void format(std::ostream& out, const char* fmt, const Args&... args)
/// Format list of arguments according to the given format string and return /// Format list of arguments according to the given format string and return
/// the result as a string. /// the result as a string.
template<typename... Args> template<typename... Args>
std::string format(const char* fmt, const Args&... args) std::string format(FormatStringCheck<sizeof...(Args)> fmt, const Args&... args)
{ {
std::ostringstream oss; std::ostringstream oss;
format(oss, fmt, args...); format(oss, fmt, args...);
@ -1073,13 +1086,13 @@ std::string format(const char* fmt, const Args&... args)
/// Format list of arguments to std::cout, according to the given format string /// Format list of arguments to std::cout, according to the given format string
template<typename... Args> template<typename... Args>
void printf(const char* fmt, const Args&... args) void printf(FormatStringCheck<sizeof...(Args)> fmt, const Args&... args)
{ {
format(std::cout, fmt, args...); format(std::cout, fmt, args...);
} }
template<typename... Args> template<typename... Args>
void printfln(const char* fmt, const Args&... args) void printfln(FormatStringCheck<sizeof...(Args)> fmt, const Args&... args)
{ {
format(std::cout, fmt, args...); format(std::cout, fmt, args...);
std::cout << '\n'; std::cout << '\n';
@ -1145,15 +1158,6 @@ TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)
#endif #endif
// Added for Bitcoin Core
template<typename... Args>
std::string format(const std::string &fmt, const Args&... args)
{
std::ostringstream oss;
format(oss, fmt.c_str(), args...);
return oss.str();
}
} // namespace tinyformat } // namespace tinyformat
// Added for Bitcoin Core: // Added for Bitcoin Core:

View File

@ -6,7 +6,6 @@
#define BITCOIN_UTIL_STRING_H #define BITCOIN_UTIL_STRING_H
#include <span.h> #include <span.h>
#include <tinyformat.h>
#include <array> #include <array>
#include <cstdint> #include <cstdint>
@ -247,12 +246,4 @@ template <typename T1, size_t PREFIX_LEN>
} }
} // namespace util } // 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 #endif // BITCOIN_UTIL_STRING_H