Skip to content

Commit

Permalink
tinyformat: Add compile-time checking for literal format strings
Browse files Browse the repository at this point in the history
Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^[email protected]>
  • Loading branch information
ryanofsky and MarcoFalke committed Oct 28, 2024
1 parent a99194e commit ecc5cb9
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 22 deletions.
30 changes: 17 additions & 13 deletions src/tinyformat.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ namespace tfm = tinyformat;
#include <iostream>
#include <sstream>
#include <stdexcept> // Added for Bitcoin Core
#include <util/string.h> // Added for Bitcoin Core

#ifndef TINYFORMAT_ASSERT
# include <cassert>
Expand Down Expand Up @@ -178,6 +179,18 @@ namespace tfm = 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
class format_error: public std::runtime_error
{
Expand Down Expand Up @@ -1056,15 +1069,15 @@ inline void vformat(std::ostream& out, const char* fmt, FormatListRef list)

/// Format list of arguments to the stream according to given format string.
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...));
}

/// Format list of arguments according to the given format string and return
/// the result as a string.
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;
format(oss, fmt, args...);
Expand All @@ -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
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...);
}

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...);
std::cout << '\n';
Expand Down Expand Up @@ -1145,15 +1158,6 @@ TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)

#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

// Added for Bitcoin Core:
Expand Down
9 changes: 0 additions & 9 deletions src/util/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#define BITCOIN_UTIL_STRING_H

#include <span.h>
#include <tinyformat.h>

#include <array>
#include <cstdint>
Expand Down Expand Up @@ -256,12 +255,4 @@ 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

0 comments on commit ecc5cb9

Please sign in to comment.