Add format_to allowing formating to an existing buffer

This commit is contained in:
Maxime Coste 2015-04-22 13:19:46 +01:00
parent 8ff63198bc
commit f6c7948c12
4 changed files with 58 additions and 16 deletions

View File

@ -231,10 +231,13 @@ void write_buffer_to_backup_file(Buffer& buffer)
StringView dir, file;
std::tie(dir,file) = split_path(path);
String pattern = dir.empty() ? format(".{}.kak.XXXXXX", file)
: format("{}/.{}.kak.XXXXXX", dir, file);
char pattern[PATH_MAX];
if (dir.empty())
format_to(pattern, ".{}.kak.XXXXXX", file);
else
format_to(pattern, "{}/.{}.kak.XXXXXX", dir, file);
int fd = mkstemp(&pattern[0]);
int fd = mkstemp(pattern);
if (fd >= 0)
{
write_buffer_to_fd(buffer, fd);

View File

@ -214,29 +214,28 @@ Vector<StringView> wrap_lines(StringView text, CharCount max_width)
return lines;
}
String format(StringView fmt, ArrayView<const StringView> params)
template<typename AppendFunc>
void format_impl(StringView fmt, ArrayView<const StringView> params, AppendFunc append)
{
ByteCount size = fmt.length();
for (auto& s : params) size += s.length();
String res;
res.reserve(size);
int implicitIndex = 0;
for (auto it = fmt.begin(), end = fmt.end(); it != end;)
{
auto opening = std::find(it, end, '{');
res += StringView{it, opening};
if (opening == end)
break;
if (opening != it && *(opening-1) == '\\')
{
res.back() = '{';
append(StringView{it, opening});
break;
}
else if (opening != it and *(opening-1) == '\\')
{
append(StringView{it, opening-1});
append('{');
it = opening + 1;
}
else
{
auto closing = std::find(it, end, '}');
append(StringView{it, opening});
auto closing = std::find(opening, end, '}');
if (closing == end)
throw runtime_error("Format string error, unclosed '{'");
int index;
@ -248,11 +247,40 @@ String format(StringView fmt, ArrayView<const StringView> params)
if (index >= params.size())
throw runtime_error("Format string parameter index too big");
res += params[index];
append(params[index]);
implicitIndex = index+1;
it = closing+1;
}
}
}
StringView format_to(ArrayView<char> buffer, StringView fmt, ArrayView<const StringView> params)
{
char* ptr = buffer.begin();
const char* end = buffer.end();
format_impl(fmt, params, [&](StringView s) mutable {
for (auto c : s)
{
if (ptr == end)
throw runtime_error("buffer is too small");
*ptr++ = c;
}
});
if (ptr == end)
throw runtime_error("buffer is too small");
*ptr = 0;
return { buffer.begin(), ptr };
}
String format(StringView fmt, ArrayView<const StringView> params)
{
ByteCount size = fmt.length();
for (auto& s : params) size += s.length();
String res;
res.reserve(size);
format_impl(fmt, params, [&](StringView s) { res += s; });
return res;
}

View File

@ -311,6 +311,14 @@ String format(StringView fmt, Types... params)
return format(fmt, ArrayView<const StringView>{detail::format_param(params)...});
}
StringView format_to(ArrayView<char> buffer, StringView fmt, ArrayView<const StringView> params);
template<typename... Types>
StringView format_to(ArrayView<char> buffer, StringView fmt, Types... params)
{
return format_to(buffer, fmt, ArrayView<const StringView>{detail::format_param(params)...});
}
}
#endif // string_hh_INCLUDED

View File

@ -140,6 +140,9 @@ void test_string()
kak_assert(format("Youhou {1} {} {0} \\{}", 10, "hehe", 5) == "Youhou hehe 5 10 {}");
char buffer[20];
kak_assert(format_to(buffer, "Hey {}", 15) == "Hey 15");
kak_assert(str_to_int("5") == 5);
kak_assert(str_to_int(to_string(INT_MAX)) == INT_MAX);
kak_assert(str_to_int(to_string(INT_MIN)) == INT_MIN);