1
1
mirror of https://github.com/mawww/kakoune.git synced 2024-09-11 13:00:41 +03:00

Extract format implementation to its own file

Split it to avoid pulling all string_utils dependencies for just
format.
This commit is contained in:
Maxime Coste 2024-08-09 18:16:51 +10:00
parent 2d9886afe7
commit 1a52006c3d
13 changed files with 272 additions and 247 deletions

View File

@ -1,7 +1,7 @@
#include "backtrace.hh"
#include "string.hh"
#include "string_utils.hh"
#include "format.hh"
#if defined(__GLIBC__) || defined(__APPLE__)
# include <execinfo.h>

View File

@ -2,7 +2,7 @@
#include "exception.hh"
#include "ranges.hh"
#include "string_utils.hh"
#include "format.hh"
#include <cstdio>

View File

@ -2,7 +2,7 @@
#include "exception.hh"
#include "ranges.hh"
#include "string_utils.hh"
#include "format.hh"
namespace Kakoune
{

180
src/format.cc Normal file
View File

@ -0,0 +1,180 @@
#include "format.hh"
#include "exception.hh"
#include "string_utils.hh"
#include <charconv>
namespace Kakoune
{
template<size_t N>
InplaceString<N> to_string_impl(auto val, auto format)
{
InplaceString<N> res;
auto [end, errc] = std::to_chars(res.m_data, res.m_data + N, val, format);
if (errc != std::errc{})
throw runtime_error("to_string error");
res.m_length = end - res.m_data;
*end = '\0';
return res;
}
template<size_t N>
InplaceString<N> to_string_impl(auto val)
{
return to_string_impl<N>(val, 10);
}
InplaceString<15> to_string(int val)
{
return to_string_impl<15>(val);
}
InplaceString<15> to_string(unsigned val)
{
return to_string_impl<15>(val);
}
InplaceString<23> to_string(long int val)
{
return to_string_impl<23>(val);
}
InplaceString<23> to_string(long long int val)
{
return to_string_impl<23>(val);
}
InplaceString<23> to_string(unsigned long val)
{
return to_string_impl<23>(val);
}
InplaceString<23> to_string(Hex val)
{
return to_string_impl<23>(val.val, 16);
}
InplaceString<23> to_string(Grouped val)
{
auto ungrouped = to_string_impl<23>(val.val);
InplaceString<23> res;
for (int pos = 0, len = ungrouped.m_length; pos != len; ++pos)
{
if (res.m_length and ((len - pos) % 3) == 0)
res.m_data[res.m_length++] = ',';
res.m_data[res.m_length++] = ungrouped.m_data[pos];
}
return res;
}
InplaceString<23> to_string(float val)
{
#if defined(__cpp_lib_to_chars)
return to_string_impl<23>(val, std::chars_format::general);
#else
InplaceString<23> res;
res.m_length = snprintf(res.m_data, 23, "%f", val);
return res;
#endif
}
InplaceString<7> to_string(Codepoint c)
{
InplaceString<7> res;
char* ptr = res.m_data;
utf8::dump(ptr, c);
res.m_length = (int)(ptr - res.m_data);
return res;
}
template<typename AppendFunc>
void format_impl(StringView fmt, ArrayView<const StringView> params, AppendFunc append)
{
int implicitIndex = 0;
for (auto it = fmt.begin(), end = fmt.end(); it != end;)
{
auto opening = std::find(it, end, '{');
if (opening == end)
{
append(StringView{it, opening});
break;
}
else if (opening != it and *(opening-1) == '\\')
{
append(StringView{it, opening-1});
append('{');
it = opening + 1;
}
else
{
append(StringView{it, opening});
auto closing = std::find(opening, end, '}');
if (closing == end)
throw runtime_error("format string error, unclosed '{'");
auto format = std::find(opening+1, closing, ':');
const int index = opening+1 == format ? implicitIndex : str_to_int({opening+1, format});
if (index >= params.size())
throw runtime_error("format string parameter index too big");
if (format != closing)
{
char padding = ' ';
if (*(++format) == '0')
{
padding = '0';
++format;
}
for (ColumnCount width = str_to_int({format, closing}), len = params[index].column_length();
width > len; --width)
append(padding);
}
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 };
}
void format_with(FunctionRef<void (StringView)> append, StringView fmt, ArrayView<const StringView> params)
{
format_impl(fmt, params, append);
}
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;
}
}

81
src/format.hh Normal file
View File

@ -0,0 +1,81 @@
#ifndef format_hh_INCLUDED
#define format_hh_INCLUDED
#include "string.hh"
#include "utils.hh"
namespace Kakoune
{
template<size_t N>
struct InplaceString
{
static_assert(N < 256, "InplaceString cannot handle sizes >= 256");
constexpr operator StringView() const { return {m_data, ByteCount{m_length}}; }
operator String() const { return {m_data, ByteCount{m_length}}; }
unsigned char m_length{};
char m_data[N];
};
struct Hex { size_t val; };
constexpr Hex hex(size_t val) { return {val}; }
struct Grouped { size_t val; };
constexpr Grouped grouped(size_t val) { return {val}; }
InplaceString<15> to_string(int val);
InplaceString<15> to_string(unsigned val);
InplaceString<23> to_string(long int val);
InplaceString<23> to_string(unsigned long val);
InplaceString<23> to_string(long long int val);
InplaceString<23> to_string(Hex val);
InplaceString<23> to_string(Grouped val);
InplaceString<23> to_string(float val);
InplaceString<7> to_string(Codepoint c);
template<typename RealType, typename ValueType>
decltype(auto) to_string(const StronglyTypedNumber<RealType, ValueType>& val)
{
return to_string((ValueType)val);
}
namespace detail
{
template<typename T> requires std::is_convertible_v<T, StringView>
StringView format_param(const T& val) { return val; }
template<typename T> requires (not std::is_convertible_v<T, StringView>)
decltype(auto) format_param(const T& val) { return to_string(val); }
}
String format(StringView fmt, ArrayView<const StringView> params);
template<typename... Types>
String format(StringView fmt, Types&&... params)
{
return format(fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(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(std::forward<Types>(params))...});
}
void format_with(FunctionRef<void (StringView)> append, StringView fmt, ArrayView<const StringView> params);
template<typename... Types>
void format_with(FunctionRef<void (StringView)> append, StringView fmt, Types&&... params)
{
return format_with(append, fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
}
}
#endif // format_hh_INCLUDED

View File

@ -1,7 +1,7 @@
#include "highlighter_group.hh"
#include "ranges.hh"
#include "string_utils.hh"
#include "format.hh"
namespace Kakoune
{

View File

@ -3,7 +3,7 @@
#include "array_view.hh"
#include "assert.hh"
#include "exception.hh"
#include "string_utils.hh"
#include "format.hh"
#include <algorithm>

View File

@ -8,7 +8,7 @@
#include "optional.hh"
#include "flags.hh"
#include "string.hh"
#include "string_utils.hh"
#include "format.hh"
#include <functional>

View File

@ -6,7 +6,7 @@
#include "unit_tests.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"
#include "string_utils.hh"
#include "format.hh"
#include "vector.hh"
#include "utils.hh"

View File

@ -3,7 +3,7 @@
#include "assert.hh"
#include "context.hh"
#include "hash_map.hh"
#include "string_utils.hh"
#include "format.hh"
namespace Kakoune
{

View File

@ -147,88 +147,6 @@ int str_to_int(StringView str)
throw runtime_error{str + " is not a number"};
}
template<size_t N>
InplaceString<N> to_string_impl(auto val, auto format)
{
InplaceString<N> res;
auto [end, errc] = std::to_chars(res.m_data, res.m_data + N, val, format);
if (errc != std::errc{})
throw runtime_error("to_string error");
res.m_length = end - res.m_data;
*end = '\0';
return res;
}
template<size_t N>
InplaceString<N> to_string_impl(auto val)
{
return to_string_impl<N>(val, 10);
}
InplaceString<15> to_string(int val)
{
return to_string_impl<15>(val);
}
InplaceString<15> to_string(unsigned val)
{
return to_string_impl<15>(val);
}
InplaceString<23> to_string(long int val)
{
return to_string_impl<23>(val);
}
InplaceString<23> to_string(long long int val)
{
return to_string_impl<23>(val);
}
InplaceString<23> to_string(unsigned long val)
{
return to_string_impl<23>(val);
}
InplaceString<23> to_string(Hex val)
{
return to_string_impl<23>(val.val, 16);
}
InplaceString<23> to_string(Grouped val)
{
auto ungrouped = to_string_impl<23>(val.val);
InplaceString<23> res;
for (int pos = 0, len = ungrouped.m_length; pos != len; ++pos)
{
if (res.m_length and ((len - pos) % 3) == 0)
res.m_data[res.m_length++] = ',';
res.m_data[res.m_length++] = ungrouped.m_data[pos];
}
return res;
}
InplaceString<23> to_string(float val)
{
#if defined(__cpp_lib_to_chars)
return to_string_impl<23>(val, std::chars_format::general);
#else
InplaceString<23> res;
res.m_length = snprintf(res.m_data, 23, "%f", val);
return res;
#endif
}
InplaceString<7> to_string(Codepoint c)
{
InplaceString<7> res;
char* ptr = res.m_data;
utf8::dump(ptr, c);
res.m_length = (int)(ptr - res.m_data);
return res;
}
bool subsequence_match(StringView str, StringView subseq)
{
auto it = str.begin();
@ -327,92 +245,6 @@ WrapView::Iterator& WrapView::Iterator::operator++()
return *this;
}
template<typename AppendFunc>
void format_impl(StringView fmt, ArrayView<const StringView> params, AppendFunc append)
{
int implicitIndex = 0;
for (auto it = fmt.begin(), end = fmt.end(); it != end;)
{
auto opening = std::find(it, end, '{');
if (opening == end)
{
append(StringView{it, opening});
break;
}
else if (opening != it and *(opening-1) == '\\')
{
append(StringView{it, opening-1});
append('{');
it = opening + 1;
}
else
{
append(StringView{it, opening});
auto closing = std::find(opening, end, '}');
if (closing == end)
throw runtime_error("format string error, unclosed '{'");
auto format = std::find(opening+1, closing, ':');
const int index = opening+1 == format ? implicitIndex : str_to_int({opening+1, format});
if (index >= params.size())
throw runtime_error("format string parameter index too big");
if (format != closing)
{
char padding = ' ';
if (*(++format) == '0')
{
padding = '0';
++format;
}
for (ColumnCount width = str_to_int({format, closing}), len = params[index].column_length();
width > len; --width)
append(padding);
}
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 };
}
void format_with(FunctionRef<void (StringView)> append, StringView fmt, ArrayView<const StringView> params)
{
format_impl(fmt, params, append);
}
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;
}
String double_up(StringView s, StringView characters)
{
String res;

View File

@ -4,9 +4,10 @@
#include "string.hh"
#include "enum.hh"
#include "vector.hh"
#include "ranges.hh"
#include "optional.hh"
#include "utils.hh"
#include "format.hh"
#include "ranges.hh"
namespace Kakoune
{
@ -107,75 +108,6 @@ inline auto wrap_at(ColumnCount max_width)
int str_to_int(StringView str); // throws on error
Optional<int> str_to_int_ifp(StringView str);
template<size_t N>
struct InplaceString
{
static_assert(N < 256, "InplaceString cannot handle sizes >= 256");
constexpr operator StringView() const { return {m_data, ByteCount{m_length}}; }
operator String() const { return {m_data, ByteCount{m_length}}; }
unsigned char m_length{};
char m_data[N];
};
struct Hex { size_t val; };
constexpr Hex hex(size_t val) { return {val}; }
struct Grouped { size_t val; };
constexpr Grouped grouped(size_t val) { return {val}; }
InplaceString<15> to_string(int val);
InplaceString<15> to_string(unsigned val);
InplaceString<23> to_string(long int val);
InplaceString<23> to_string(unsigned long val);
InplaceString<23> to_string(long long int val);
InplaceString<23> to_string(Hex val);
InplaceString<23> to_string(Grouped val);
InplaceString<23> to_string(float val);
InplaceString<7> to_string(Codepoint c);
template<typename RealType, typename ValueType>
decltype(auto) to_string(const StronglyTypedNumber<RealType, ValueType>& val)
{
return to_string((ValueType)val);
}
namespace detail
{
template<typename T> requires std::is_convertible_v<T, StringView>
StringView format_param(const T& val) { return val; }
template<typename T> requires (not std::is_convertible_v<T, StringView>)
decltype(auto) format_param(const T& val) { return to_string(val); }
}
String format(StringView fmt, ArrayView<const StringView> params);
template<typename... Types>
String format(StringView fmt, Types&&... params)
{
return format(fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(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(std::forward<Types>(params))...});
}
void format_with(FunctionRef<void (StringView)> append, StringView fmt, ArrayView<const StringView> params);
template<typename... Types>
void format_with(FunctionRef<void (StringView)> append, StringView fmt, Types&&... params)
{
return format_with(append, fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
}
String double_up(StringView s, StringView characters);
inline String quote(StringView s)

View File

@ -7,7 +7,7 @@
#include "file.hh"
#include "keys.hh"
#include "ranges.hh"
#include "string_utils.hh"
#include "format.hh"
#include "diff.hh"
#include <algorithm>