1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
#ifndef NEWSBOAT_STRPRINTF_H_
#define NEWSBOAT_STRPRINTF_H_
#include <cstdint>
#include <string>
#include <tuple>
#include <vector>
namespace newsboat {
namespace strprintf {
namespace detail {
template<typename T, typename... Args>
std::string fmt_impl(const std::string& format, const T& argument,
Args... args);
}
std::pair<std::string, std::string> split_format(
const std::string& printf_format);
std::string fmt(const std::string& format);
template<typename... Args>
std::string fmt(const std::string& format, const char* argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const int32_t argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const std::uint32_t argument,
Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const int64_t argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const uint64_t argument,
Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const void* argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const std::nullptr_t argument,
Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const float argument, Args... args)
{
// Variadic functions (like snprintf) do not accept `float`, so let's
// convert that.
return detail::fmt_impl(format, static_cast<double>(argument), args...);
}
template<typename... Args>
std::string fmt(const std::string& format, const double argument, Args... args)
{
return detail::fmt_impl(format, argument, args...);
}
template<typename... Args>
std::string fmt(const std::string& format,
const std::string& argument,
Args... args)
{
return fmt(format, argument.c_str(), args...);
}
template<typename... Args>
std::string fmt(const std::string& format,
const std::string* argument,
Args... args)
{
return fmt(format, argument->c_str(), args...);
}
namespace detail {
template<typename T, typename... Args>
std::string fmt_impl(const std::string& format, const T& argument, Args... args)
{
std::string local_format, remaining_format;
std::tie(local_format, remaining_format) = split_format(format);
char buffer[1024];
std::string result;
unsigned int len = 1 +
snprintf(buffer,
sizeof(buffer),
local_format.c_str(),
argument);
// snprintf returns the length of the formatted string. If it's
// longer than the buffer size, we have to enlarge the buffer in
// order to get the whole result.
//
// `<=` is correct since we've added 1 to `len`, above. We have to
// do it because `buffer` has to fit not only the string but the
// terminating null byte as well.
if (len <= sizeof(buffer)) {
result = buffer;
} else {
std::vector<char> buf(len);
snprintf(
buf.data(), len, local_format.c_str(), argument);
result = buf.data();
}
return result + fmt(remaining_format, args...);
}
}
};
} // namespace newsboat
#endif /* NEWSBOAT_STRPRINTF_H_ */
|