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:
parent
2d9886afe7
commit
1a52006c3d
@ -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>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "exception.hh"
|
||||
#include "ranges.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
@ -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
180
src/format.cc
Normal 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
81
src/format.hh
Normal 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
|
@ -1,7 +1,7 @@
|
||||
#include "highlighter_group.hh"
|
||||
|
||||
#include "ranges.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "array_view.hh"
|
||||
#include "assert.hh"
|
||||
#include "exception.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "optional.hh"
|
||||
#include "flags.hh"
|
||||
#include "string.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "assert.hh"
|
||||
#include "context.hh"
|
||||
#include "hash_map.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user