66 lines
1.2 KiB
C++
66 lines
1.2 KiB
C++
|
#include <cstring>
|
||
|
|
||
|
struct String_Buffer
|
||
|
{
|
||
|
char* str;
|
||
|
int cap;
|
||
|
int len = 0;
|
||
|
};
|
||
|
|
||
|
namespace fmt
|
||
|
{
|
||
|
|
||
|
void write(String_Buffer& buf, const char* str, int len)
|
||
|
{
|
||
|
int remaining_cap = buf.cap - buf.len - 1; // leave one byte for NUL
|
||
|
int write_len = len > remaining_cap ? remaining_cap : len;
|
||
|
if (write_len > 0)
|
||
|
memcpy(buf.str + buf.len, str, write_len);
|
||
|
buf.len += len;
|
||
|
}
|
||
|
|
||
|
void write_value(String_Buffer& buf, const char* value)
|
||
|
{
|
||
|
write(buf, value, strlen(value));
|
||
|
}
|
||
|
|
||
|
bool next_hole(String_Buffer& buf, const char*& fstr)
|
||
|
{
|
||
|
const char* prefix = fstr;
|
||
|
while (*fstr != 0) {
|
||
|
if (*fstr == '{') {
|
||
|
int len = fstr - prefix;
|
||
|
++fstr;
|
||
|
if (*fstr == '}') {
|
||
|
++fstr;
|
||
|
write(buf, prefix, len);
|
||
|
return true;
|
||
|
}
|
||
|
if (*fstr == '{') {
|
||
|
write(buf, prefix, len);
|
||
|
prefix = fstr;
|
||
|
++fstr;
|
||
|
}
|
||
|
}
|
||
|
++fstr;
|
||
|
}
|
||
|
write(buf, prefix, fstr - prefix);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
template<typename T>
|
||
|
void format_value(String_Buffer& buf, const char*& fstr, const T& value)
|
||
|
{
|
||
|
if (next_hole(buf, fstr))
|
||
|
write_value(buf, value);
|
||
|
}
|
||
|
|
||
|
template<typename... Args>
|
||
|
void format(String_Buffer& buf, const char* fstr, const Args&... args)
|
||
|
{
|
||
|
(format_value(buf, fstr, args), ...);
|
||
|
while (next_hole(buf, fstr)) {}
|
||
|
}
|
||
|
|
||
|
}
|