mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 19:24:48 +02:00
Simplify the core API
This commit is contained in:
@@ -383,24 +383,22 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char> struct arg_id_handler {
|
template <typename Char> struct arg_id_handler {
|
||||||
constexpr void on_error(const char* message) { throw format_error(message); }
|
arg_ref<Char> arg_id;
|
||||||
|
|
||||||
constexpr int on_arg_id() {
|
constexpr int operator()() {
|
||||||
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
constexpr int operator()(int id) {
|
||||||
constexpr int on_arg_id(int id) {
|
arg_id = arg_ref<Char>(id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
constexpr int operator()(basic_string_view<Char> id) {
|
||||||
arg_id = arg_ref<Char>(id);
|
arg_id = arg_ref<Char>(id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int on_arg_id(basic_string_view<Char> id) {
|
constexpr void on_error(const char* message) { throw format_error(message); }
|
||||||
arg_id = arg_ref<Char>(id);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
arg_ref<Char> arg_id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char> struct parse_arg_id_result {
|
template <typename Char> struct parse_arg_id_result {
|
||||||
@@ -411,8 +409,7 @@ template <typename Char> struct parse_arg_id_result {
|
|||||||
template <int ID, typename Char>
|
template <int ID, typename Char>
|
||||||
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
|
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
|
||||||
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
|
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
|
||||||
auto adapter = id_adapter<arg_id_handler<Char>, Char>{handler, 0};
|
auto arg_id_end = parse_arg_id(begin, end, handler);
|
||||||
auto arg_id_end = parse_arg_id(begin, end, adapter);
|
|
||||||
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
|
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -87,7 +87,7 @@
|
|||||||
// GCC doesn't allow throw in constexpr until version 6 (bug 67371).
|
// GCC doesn't allow throw in constexpr until version 6 (bug 67371).
|
||||||
#ifndef FMT_USE_CONSTEXPR
|
#ifndef FMT_USE_CONSTEXPR
|
||||||
# define FMT_USE_CONSTEXPR \
|
# define FMT_USE_CONSTEXPR \
|
||||||
(FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
|
(FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1920 || \
|
||||||
(FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
|
(FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
|
||||||
!FMT_NVCC && !FMT_ICC_VERSION
|
!FMT_NVCC && !FMT_ICC_VERSION
|
||||||
#endif
|
#endif
|
||||||
@@ -311,8 +311,6 @@ template <bool B> using bool_constant = std::integral_constant<bool, B>;
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using remove_reference_t = typename std::remove_reference<T>::type;
|
using remove_reference_t = typename std::remove_reference<T>::type;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using remove_const_t = typename std::remove_const<T>::type;
|
|
||||||
template <typename T>
|
|
||||||
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
|
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
|
||||||
template <typename T> struct type_identity { using type = T; };
|
template <typename T> struct type_identity { using type = T; };
|
||||||
template <typename T> using type_identity_t = typename type_identity<T>::type;
|
template <typename T> using type_identity_t = typename type_identity<T>::type;
|
||||||
@@ -2126,33 +2124,28 @@ FMT_CONSTEXPR FMT_INLINE const Char* parse_arg_id(const Char* begin,
|
|||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adapts SpecHandler to IDHandler API for dynamic width.
|
|
||||||
template <typename SpecHandler, typename Char> struct width_adapter {
|
|
||||||
explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
|
|
||||||
FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); }
|
|
||||||
FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
|
|
||||||
handler.on_dynamic_width(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char* message) {
|
|
||||||
handler.on_error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecHandler& handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename Handler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end,
|
FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end,
|
||||||
Handler&& handler) {
|
Handler&& handler) {
|
||||||
|
struct width_adapter {
|
||||||
|
Handler& handler;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
|
||||||
|
FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); }
|
||||||
|
FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
|
||||||
|
handler.on_dynamic_width(id);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR void on_error(const char* message) {
|
||||||
|
handler.on_error(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
FMT_ASSERT(begin != end, "");
|
FMT_ASSERT(begin != end, "");
|
||||||
if ('0' <= *begin && *begin <= '9') {
|
if ('0' <= *begin && *begin <= '9') {
|
||||||
handler.on_width(parse_nonnegative_int(begin, end, handler));
|
handler.on_width(parse_nonnegative_int(begin, end, handler));
|
||||||
} else if (*begin == '{') {
|
} else if (*begin == '{') {
|
||||||
++begin;
|
++begin;
|
||||||
if (begin != end)
|
if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler});
|
||||||
begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler));
|
|
||||||
if (begin == end || *begin != '}')
|
if (begin == end || *begin != '}')
|
||||||
return handler.on_error("invalid format string"), begin;
|
return handler.on_error("invalid format string"), begin;
|
||||||
++begin;
|
++begin;
|
||||||
@@ -2160,36 +2153,30 @@ FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end,
|
|||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adapts SpecHandler to IDHandler API for dynamic precision.
|
|
||||||
template <typename SpecHandler, typename Char> struct precision_adapter {
|
|
||||||
explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
|
|
||||||
FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); }
|
|
||||||
FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
|
|
||||||
handler.on_dynamic_precision(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char* message) {
|
|
||||||
handler.on_error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecHandler& handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename Handler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end,
|
FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end,
|
||||||
Handler&& handler) {
|
Handler&& handler) {
|
||||||
|
struct precision_adapter {
|
||||||
|
Handler& handler;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
|
||||||
|
FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); }
|
||||||
|
FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
|
||||||
|
handler.on_dynamic_precision(id);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR void on_error(const char* message) {
|
||||||
|
handler.on_error(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
++begin;
|
++begin;
|
||||||
auto c = begin != end ? *begin : Char();
|
auto c = begin != end ? *begin : Char();
|
||||||
if ('0' <= c && c <= '9') {
|
if ('0' <= c && c <= '9') {
|
||||||
handler.on_precision(parse_nonnegative_int(begin, end, handler));
|
handler.on_precision(parse_nonnegative_int(begin, end, handler));
|
||||||
} else if (c == '{') {
|
} else if (c == '{') {
|
||||||
++begin;
|
++begin;
|
||||||
if (begin != end) {
|
if (begin != end)
|
||||||
begin =
|
begin = parse_arg_id(begin, end, precision_adapter{handler});
|
||||||
parse_arg_id(begin, end, precision_adapter<Handler, Char>(handler));
|
|
||||||
}
|
|
||||||
if (begin == end || *begin++ != '}')
|
if (begin == end || *begin++ != '}')
|
||||||
return handler.on_error("invalid format string"), begin;
|
return handler.on_error("invalid format string"), begin;
|
||||||
} else {
|
} else {
|
||||||
@@ -2265,24 +2252,24 @@ FMT_CONSTEXPR FMT_INLINE const Char* parse_format_specs(const Char* begin,
|
|||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Handler, typename Char> struct id_adapter {
|
|
||||||
Handler& handler;
|
|
||||||
int arg_id;
|
|
||||||
|
|
||||||
FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); }
|
|
||||||
FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); }
|
|
||||||
FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
|
|
||||||
arg_id = handler.on_arg_id(id);
|
|
||||||
}
|
|
||||||
FMT_CONSTEXPR void on_error(const char* message) {
|
|
||||||
handler.on_error(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename Handler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
|
FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
|
||||||
const Char* end,
|
const Char* end,
|
||||||
Handler&& handler) {
|
Handler&& handler) {
|
||||||
|
struct id_adapter {
|
||||||
|
Handler& handler;
|
||||||
|
int arg_id;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); }
|
||||||
|
FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); }
|
||||||
|
FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
|
||||||
|
arg_id = handler.on_arg_id(id);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR void on_error(const char* message) {
|
||||||
|
handler.on_error(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
++begin;
|
++begin;
|
||||||
if (begin == end) return handler.on_error("invalid format string"), end;
|
if (begin == end) return handler.on_error("invalid format string"), end;
|
||||||
if (*begin == '}') {
|
if (*begin == '}') {
|
||||||
@@ -2290,7 +2277,7 @@ FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
|
|||||||
} else if (*begin == '{') {
|
} else if (*begin == '{') {
|
||||||
handler.on_text(begin, begin + 1);
|
handler.on_text(begin, begin + 1);
|
||||||
} else {
|
} else {
|
||||||
auto adapter = id_adapter<Handler, Char>{handler, 0};
|
auto adapter = id_adapter{handler, 0};
|
||||||
begin = parse_arg_id(begin, end, adapter);
|
begin = parse_arg_id(begin, end, adapter);
|
||||||
Char c = begin != end ? *begin : Char();
|
Char c = begin != end ? *begin : Char();
|
||||||
if (c == '}') {
|
if (c == '}') {
|
||||||
@@ -2390,7 +2377,7 @@ class compile_parse_context
|
|||||||
ErrorHandler eh = {})
|
ErrorHandler eh = {})
|
||||||
: base(format_str, eh), num_args_(num_args) {}
|
: base(format_str, eh), num_args_(num_args) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR int next_arg_id() {
|
FMT_CONSTEXPR auto next_arg_id() -> int {
|
||||||
int id = base::next_arg_id();
|
int id = base::next_arg_id();
|
||||||
if (id >= num_args_) this->on_error("argument not found");
|
if (id >= num_args_) this->on_error("argument not found");
|
||||||
return id;
|
return id;
|
||||||
@@ -2423,8 +2410,8 @@ FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) {
|
|||||||
|
|
||||||
// Checks char specs and returns true if the type spec is char (and not int).
|
// Checks char specs and returns true if the type spec is char (and not int).
|
||||||
template <typename Char, typename ErrorHandler = error_handler>
|
template <typename Char, typename ErrorHandler = error_handler>
|
||||||
FMT_CONSTEXPR bool check_char_specs(const basic_format_specs<Char>& specs,
|
FMT_CONSTEXPR auto check_char_specs(const basic_format_specs<Char>& specs,
|
||||||
ErrorHandler&& eh = {}) {
|
ErrorHandler&& eh = {}) -> bool {
|
||||||
if (specs.type && specs.type != 'c') {
|
if (specs.type && specs.type != 'c') {
|
||||||
check_int_type_spec(specs.type, eh);
|
check_int_type_spec(specs.type, eh);
|
||||||
return false;
|
return false;
|
||||||
@@ -2454,8 +2441,9 @@ struct float_specs {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename ErrorHandler = error_handler, typename Char>
|
template <typename ErrorHandler = error_handler, typename Char>
|
||||||
FMT_CONSTEXPR float_specs parse_float_type_spec(
|
FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
|
||||||
const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) {
|
ErrorHandler&& eh = {})
|
||||||
|
-> float_specs {
|
||||||
auto result = float_specs();
|
auto result = float_specs();
|
||||||
result.showpoint = specs.alt;
|
result.showpoint = specs.alt;
|
||||||
result.locale = specs.localized;
|
result.locale = specs.localized;
|
||||||
@@ -2497,7 +2485,8 @@ FMT_CONSTEXPR float_specs parse_float_type_spec(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename ErrorHandler = error_handler>
|
template <typename Char, typename ErrorHandler = error_handler>
|
||||||
FMT_CONSTEXPR bool check_cstring_type_spec(Char spec, ErrorHandler&& eh = {}) {
|
FMT_CONSTEXPR auto check_cstring_type_spec(Char spec, ErrorHandler&& eh = {})
|
||||||
|
-> bool {
|
||||||
if (spec == 0 || spec == 's') return true;
|
if (spec == 0 || spec == 's') return true;
|
||||||
if (spec != 'p') eh.on_error("invalid type specifier");
|
if (spec != 'p') eh.on_error("invalid type specifier");
|
||||||
return false;
|
return false;
|
||||||
@@ -2567,7 +2556,7 @@ constexpr int invalid_arg_index = -1;
|
|||||||
|
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
template <int N, typename T, typename... Args, typename Char>
|
template <int N, typename T, typename... Args, typename Char>
|
||||||
constexpr int get_arg_index_by_name(basic_string_view<Char> name) {
|
constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
||||||
if constexpr (detail::is_statically_named_arg<T>()) {
|
if constexpr (detail::is_statically_named_arg<T>()) {
|
||||||
if (name == T::name) return N;
|
if (name == T::name) return N;
|
||||||
}
|
}
|
||||||
@@ -2579,7 +2568,7 @@ constexpr int get_arg_index_by_name(basic_string_view<Char> name) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename... Args, typename Char>
|
template <typename... Args, typename Char>
|
||||||
FMT_CONSTEXPR int get_arg_index_by_name(basic_string_view<Char> name) {
|
FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
if constexpr (sizeof...(Args) > 0)
|
if constexpr (sizeof...(Args) > 0)
|
||||||
return get_arg_index_by_name<0, Args...>(name);
|
return get_arg_index_by_name<0, Args...>(name);
|
||||||
@@ -2608,9 +2597,11 @@ class format_string_checker {
|
|||||||
|
|
||||||
FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
|
FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR int on_arg_id() { return context_.next_arg_id(); }
|
FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); }
|
||||||
FMT_CONSTEXPR int on_arg_id(int id) { return context_.check_arg_id(id), id; }
|
FMT_CONSTEXPR auto on_arg_id(int id) -> int {
|
||||||
FMT_CONSTEXPR int on_arg_id(basic_string_view<Char> id) {
|
return context_.check_arg_id(id), id;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
auto index = get_arg_index_by_name<Args...>(id);
|
auto index = get_arg_index_by_name<Args...>(id);
|
||||||
if (index == invalid_arg_index) on_error("named argument is not found");
|
if (index == invalid_arg_index) on_error("named argument is not found");
|
||||||
@@ -2624,8 +2615,8 @@ class format_string_checker {
|
|||||||
|
|
||||||
FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
|
FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char* on_format_specs(int id, const Char* begin,
|
FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*)
|
||||||
const Char*) {
|
-> const Char* {
|
||||||
context_.advance_to(context_.begin() + (begin - &*context_.begin()));
|
context_.advance_to(context_.begin() + (begin - &*context_.begin()));
|
||||||
// id >= 0 check is a workaround for gcc 10 bug (#2065).
|
// id >= 0 check is a workaround for gcc 10 bug (#2065).
|
||||||
return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
|
return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
|
||||||
|
Reference in New Issue
Block a user