Simplify the core API

This commit is contained in:
Victor Zverovich
2021-05-19 08:11:08 -07:00
parent e9c1c415b8
commit 39c3c4ec22
2 changed files with 71 additions and 83 deletions

View File

@@ -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};
} }

View File

@@ -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;