diff options
| author | Maxime Coste <mawww@kakoune.org> | 2024-08-09 18:16:51 +1000 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2024-08-12 20:02:11 +1000 |
| commit | 1a52006c3d215196997a2cd12450795d4ae4a1ca (patch) | |
| tree | 9cae5c08d6fa0a0ec4017b6a0156e64924eeb898 /src | |
| parent | 2d9886afe76adde9f33fc0c0454146176857a6f2 (diff) | |
Extract format implementation to its own file
Split it to avoid pulling all string_utils dependencies for just
format.
Diffstat (limited to 'src')
| -rw-r--r-- | src/backtrace.cc | 2 | ||||
| -rw-r--r-- | src/color.cc | 2 | ||||
| -rw-r--r-- | src/face_registry.cc | 2 | ||||
| -rw-r--r-- | src/format.cc | 180 | ||||
| -rw-r--r-- | src/format.hh | 81 | ||||
| -rw-r--r-- | src/highlighter_group.cc | 2 | ||||
| -rw-r--r-- | src/keymap_manager.cc | 2 | ||||
| -rw-r--r-- | src/parameters_parser.hh | 2 | ||||
| -rw-r--r-- | src/regex_impl.cc | 2 | ||||
| -rw-r--r-- | src/register_manager.cc | 2 | ||||
| -rw-r--r-- | src/string_utils.cc | 168 | ||||
| -rw-r--r-- | src/string_utils.hh | 72 | ||||
| -rw-r--r-- | src/terminal_ui.cc | 2 |
13 files changed, 272 insertions, 247 deletions
diff --git a/src/backtrace.cc b/src/backtrace.cc index 1b3c6d09..04b772ad 100644 --- a/src/backtrace.cc +++ b/src/backtrace.cc @@ -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> diff --git a/src/color.cc b/src/color.cc index 145a5381..71ef46b6 100644 --- a/src/color.cc +++ b/src/color.cc @@ -2,7 +2,7 @@ #include "exception.hh" #include "ranges.hh" -#include "string_utils.hh" +#include "format.hh" #include <cstdio> diff --git a/src/face_registry.cc b/src/face_registry.cc index d6c5cd53..e4a0cf86 100644 --- a/src/face_registry.cc +++ b/src/face_registry.cc @@ -2,7 +2,7 @@ #include "exception.hh" #include "ranges.hh" -#include "string_utils.hh" +#include "format.hh" namespace Kakoune { diff --git a/src/format.cc b/src/format.cc new file mode 100644 index 00000000..685fa651 --- /dev/null +++ b/src/format.cc @@ -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; +} + +} diff --git a/src/format.hh b/src/format.hh new file mode 100644 index 00000000..652bc477 --- /dev/null +++ b/src/format.hh @@ -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 diff --git a/src/highlighter_group.cc b/src/highlighter_group.cc index 813262c0..7802df94 100644 --- a/src/highlighter_group.cc +++ b/src/highlighter_group.cc @@ -1,7 +1,7 @@ #include "highlighter_group.hh" #include "ranges.hh" -#include "string_utils.hh" +#include "format.hh" namespace Kakoune { diff --git a/src/keymap_manager.cc b/src/keymap_manager.cc index 582a271d..583fb2e7 100644 --- a/src/keymap_manager.cc +++ b/src/keymap_manager.cc @@ -3,7 +3,7 @@ #include "array_view.hh" #include "assert.hh" #include "exception.hh" -#include "string_utils.hh" +#include "format.hh" #include <algorithm> diff --git a/src/parameters_parser.hh b/src/parameters_parser.hh index c11dc501..7d26c3bb 100644 --- a/src/parameters_parser.hh +++ b/src/parameters_parser.hh @@ -8,7 +8,7 @@ #include "optional.hh" #include "flags.hh" #include "string.hh" -#include "string_utils.hh" +#include "format.hh" #include <functional> diff --git a/src/regex_impl.cc b/src/regex_impl.cc index c32917eb..2cebf964 100644 --- a/src/regex_impl.cc +++ b/src/regex_impl.cc @@ -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" diff --git a/src/register_manager.cc b/src/register_manager.cc index a189c5b6..bb198dc6 100644 --- a/src/register_manager.cc +++ b/src/register_manager.cc @@ -3,7 +3,7 @@ #include "assert.hh" #include "context.hh" #include "hash_map.hh" -#include "string_utils.hh" +#include "format.hh" namespace Kakoune { diff --git a/src/string_utils.cc b/src/string_utils.cc index c614d485..42b299f9 100644 --- a/src/string_utils.cc +++ b/src/string_utils.cc @@ -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; diff --git a/src/string_utils.hh b/src/string_utils.hh index 3034dfd5..24da0111 100644 --- a/src/string_utils.hh +++ b/src/string_utils.hh @@ -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) diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index 33574e90..991cdecf 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -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> |
