Merge branch 'fmtlib:master' into master
This commit is contained in:
commit
ea8a98ea5c
1
.github/workflows/linux.yml
vendored
1
.github/workflows/linux.yml
vendored
@ -52,6 +52,7 @@ jobs:
|
||||
- name: Create Build Environment
|
||||
run: |
|
||||
${{matrix.install}}
|
||||
sudo apt update
|
||||
sudo apt install locales-all
|
||||
cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
|
||||
17
doc/api.rst
17
doc/api.rst
@ -450,16 +450,19 @@ The format syntax is described in :ref:`chrono-specs`.
|
||||
Format string compilation
|
||||
=========================
|
||||
|
||||
``fmt/compile.h`` provides format string compilation support when using
|
||||
``FMT_COMPILE``. Format strings are parsed, checked and converted into efficient
|
||||
formatting code at compile-time. This supports arguments of built-in and string
|
||||
types as well as user-defined types with ``constexpr`` ``parse`` functions in
|
||||
their ``formatter`` specializations. Format string compilation can generate more
|
||||
binary code compared to the default API and is only recommended in places where
|
||||
formatting is a performance bottleneck.
|
||||
``fmt/compile.h`` provides format string compilation enabled via the
|
||||
``FMT_COMPILE`` macro or the ``_cf`` user-defined literal. Format strings
|
||||
marked with ``FMT_COMPILE`` or ``_cf`` are parsed, checked and converted into
|
||||
efficient formatting code at compile-time. This supports arguments of built-in
|
||||
and string types as well as user-defined types with ``constexpr`` ``parse``
|
||||
functions in their ``formatter`` specializations. Format string compilation can
|
||||
generate more binary code compared to the default API and is only recommended in
|
||||
places where formatting is a performance bottleneck.
|
||||
|
||||
.. doxygendefine:: FMT_COMPILE
|
||||
|
||||
.. doxygenfunction:: operator""_cf()
|
||||
|
||||
.. _color-api:
|
||||
|
||||
Terminal color and text style
|
||||
|
||||
@ -323,7 +323,7 @@ template <typename T, typename Char> struct is_range {
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename Context, typename Element> struct range_mapper {
|
||||
template <typename Context> struct range_mapper {
|
||||
using mapper = arg_mapper<Context>;
|
||||
|
||||
template <typename T,
|
||||
@ -340,29 +340,36 @@ template <typename Context, typename Element> struct range_mapper {
|
||||
};
|
||||
|
||||
template <typename Char, typename Element>
|
||||
using range_formatter_type =
|
||||
conditional_t<is_formattable<Element, Char>::value,
|
||||
formatter<remove_cvref_t<decltype(
|
||||
range_mapper<buffer_context<Char>, Element>{}
|
||||
.map(std::declval<Element>()))>,
|
||||
Char>,
|
||||
fallback_formatter<Element, Char>>;
|
||||
using range_formatter_type = conditional_t<
|
||||
is_formattable<Element, Char>::value,
|
||||
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
|
||||
std::declval<Element>()))>,
|
||||
Char>,
|
||||
fallback_formatter<Element, Char>>;
|
||||
|
||||
template <typename R>
|
||||
using maybe_const_range =
|
||||
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||
} // namespace detail
|
||||
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<fmt::is_range<R, Char>::value
|
||||
enable_if_t<
|
||||
fmt::is_range<R, Char>::value
|
||||
// Workaround a bug in MSVC 2019 and earlier.
|
||||
#if !FMT_MSC_VER
|
||||
&& (is_formattable<detail::uncvref_type<R>, Char>::value ||
|
||||
detail::has_fallback_formatter<detail::uncvref_type<R>,
|
||||
Char>::value)
|
||||
&&
|
||||
(is_formattable<detail::uncvref_type<detail::maybe_const_range<R>>,
|
||||
Char>::value ||
|
||||
detail::has_fallback_formatter<
|
||||
detail::uncvref_type<detail::maybe_const_range<R>>, Char>::value)
|
||||
#endif
|
||||
>> {
|
||||
>> {
|
||||
|
||||
using range_type = detail::maybe_const_range<R>;
|
||||
using formatter_type =
|
||||
detail::range_formatter_type<Char, detail::uncvref_type<R>>;
|
||||
detail::range_formatter_type<Char, detail::uncvref_type<range_type>>;
|
||||
formatter_type underlying_;
|
||||
bool custom_specs_ = false;
|
||||
|
||||
@ -381,12 +388,9 @@ struct formatter<
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <
|
||||
typename FormatContext, typename U,
|
||||
FMT_ENABLE_IF(
|
||||
std::is_same<U, conditional_t<detail::has_const_begin_end<R>::value,
|
||||
const R, R>>::value)>
|
||||
auto format(U& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
||||
Char prefix = '{';
|
||||
Char postfix = '}';
|
||||
@ -394,7 +398,7 @@ struct formatter<
|
||||
Char prefix = detail::is_set<R>::value ? '{' : '[';
|
||||
Char postfix = detail::is_set<R>::value ? '}' : ']';
|
||||
#endif
|
||||
detail::range_mapper<buffer_context<Char>, detail::uncvref_type<R>> mapper;
|
||||
detail::range_mapper<buffer_context<Char>> mapper;
|
||||
auto out = ctx.out();
|
||||
*out++ = prefix;
|
||||
int i = 0;
|
||||
|
||||
@ -364,3 +364,18 @@ TEST(ranges_test, escape_convertible_to_string_view) {
|
||||
"[\"foo\"]");
|
||||
}
|
||||
#endif // FMT_USE_STRING_VIEW
|
||||
|
||||
template <typename R> struct fmt_ref_view {
|
||||
R* r;
|
||||
|
||||
auto begin() const -> decltype(r->begin()) { return r->begin(); }
|
||||
auto end() const -> decltype(r->end()) { return r->end(); }
|
||||
};
|
||||
|
||||
TEST(ranges_test, range_of_range_of_mixed_const) {
|
||||
std::vector<std::vector<int>> v = {{1, 2, 3}, {4, 5}};
|
||||
EXPECT_EQ(fmt::format("{}", v), "[[1, 2, 3], [4, 5]]");
|
||||
|
||||
fmt_ref_view<decltype(v)> r{&v};
|
||||
EXPECT_EQ(fmt::format("{}", r), "[[1, 2, 3], [4, 5]]");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user