aboutsummaryrefslogtreecommitdiff
path: root/include/fmt/ranges.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/fmt/ranges.h')
-rw-r--r--include/fmt/ranges.h115
1 files changed, 73 insertions, 42 deletions
diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h
index 6110fdaf..632f0494 100644
--- a/include/fmt/ranges.h
+++ b/include/fmt/ranges.h
@@ -12,7 +12,9 @@
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
+#include <initializer_list>
#include <type_traits>
+
#include "format.h"
// output only up to N items from the range.
@@ -31,7 +33,7 @@ template <typename Char> struct formatting_base {
template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> {
- static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
+ static FMT_CONSTEXPR_DECL const size_t range_length_limit =
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
// range.
Char prefix;
@@ -52,7 +54,7 @@ struct formatting_tuple : formatting_base<Char> {
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
-namespace internal {
+namespace detail {
template <typename RangeT, typename OutputIterator>
OutputIterator copy(const RangeT& range, OutputIterator out) {
@@ -104,10 +106,7 @@ struct is_range_<
/// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ {
template <typename U>
- static auto check(U* p)
- -> decltype(std::tuple_size<U>::value,
- (void)std::declval<typename std::tuple_element<0, U>::type>(),
- int());
+ static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
template <typename> static void check(...);
public:
@@ -119,26 +118,24 @@ template <typename T> class is_tuple_like_ {
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
-template <std::size_t... N> using index_sequence = std::index_sequence<N...>;
-template <std::size_t N>
-using make_index_sequence = std::make_index_sequence<N>;
+template <size_t... N> using index_sequence = std::index_sequence<N...>;
+template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N> struct integer_sequence {
using value_type = T;
- static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
+ static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
};
-template <std::size_t... N>
-using index_sequence = integer_sequence<std::size_t, N...>;
+template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
-template <typename T, std::size_t N, T... Ns>
+template <typename T, size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
-template <std::size_t N>
-using make_index_sequence = make_integer_sequence<std::size_t, N>;
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
#endif
template <class Tuple, class F, size_t... Is>
@@ -160,6 +157,9 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
}
+template <typename Range>
+using value_type = remove_cvref_t<decltype(*std::declval<Range>().begin())>;
+
template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
typename std::decay<Arg>::type>::value)>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
@@ -185,12 +185,11 @@ FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
return add_space ? L" '{}'" : L"'{}'";
}
-
-} // namespace internal
+} // namespace detail
template <typename T> struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value =
- internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
+ detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
};
template <typename TupleT, typename Char>
@@ -203,17 +202,17 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
- out = internal::copy(formatting.delimiter, out);
+ out = detail::copy(formatting.delimiter, out);
}
out = format_to(out,
- internal::format_str_quoted(
+ detail::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
++i;
}
formatting_tuple<Char>& formatting;
- std::size_t& i;
+ size_t& i;
typename std::add_lvalue_reference<decltype(
std::declval<FormatContext>().out())>::type out;
};
@@ -229,14 +228,14 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
template <typename FormatContext = format_context>
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
- std::size_t i = 0;
- internal::copy(formatting.prefix, out);
+ size_t i = 0;
+ detail::copy(formatting.prefix, out);
- internal::for_each(values, format_each<FormatContext>{formatting, i, out});
+ detail::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
- internal::copy(formatting.postfix, out);
+ detail::copy(formatting.postfix, out);
return ctx.out();
}
@@ -244,15 +243,23 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
template <typename T, typename Char> struct is_range {
static FMT_CONSTEXPR_DECL const bool value =
- internal::is_range_<T>::value &&
- !internal::is_like_std_string<T>::value &&
+ detail::is_range_<T>::value && !detail::is_like_std_string<T>::value &&
!std::is_convertible<T, std::basic_string<Char>>::value &&
- !std::is_constructible<internal::std_string_view<Char>, T>::value;
+ !std::is_constructible<detail::std_string_view<Char>, T>::value;
};
-template <typename RangeT, typename Char>
-struct formatter<RangeT, Char,
- enable_if_t<fmt::is_range<RangeT, Char>::value>> {
+template <typename T, typename Char>
+struct formatter<
+ T, Char,
+ enable_if_t<fmt::is_range<T, Char>::value
+// Workaround a bug in MSVC 2017 and earlier.
+#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
+ &&
+ (has_formatter<detail::value_type<T>, format_context>::value ||
+ detail::has_fallback_formatter<detail::value_type<T>,
+ format_context>::value)
+#endif
+ >> {
formatting_range<Char> formatting;
template <typename ParseContext>
@@ -261,17 +268,18 @@ struct formatter<RangeT, Char,
}
template <typename FormatContext>
- typename FormatContext::iterator format(const RangeT& values,
- FormatContext& ctx) {
- auto out = internal::copy(formatting.prefix, ctx.out());
- std::size_t i = 0;
- for (auto it = values.begin(), end = values.end(); it != end; ++it) {
+ typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
+ auto out = detail::copy(formatting.prefix, ctx.out());
+ size_t i = 0;
+ auto it = values.begin();
+ auto end = values.end();
+ for (; it != end; ++it) {
if (i > 0) {
if (formatting.add_prepostfix_space) *out++ = ' ';
- out = internal::copy(formatting.delimiter, out);
+ out = detail::copy(formatting.delimiter, out);
}
out = format_to(out,
- internal::format_str_quoted(
+ detail::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), *it),
*it);
if (++i > formatting.range_length_limit) {
@@ -280,11 +288,11 @@ struct formatter<RangeT, Char,
}
}
if (formatting.add_prepostfix_space) *out++ = ' ';
- return internal::copy(formatting.postfix, out);
+ return detail::copy(formatting.postfix, out);
}
};
-template <typename Char, typename... T> struct tuple_arg_join : internal::view {
+template <typename Char, typename... T> struct tuple_arg_join : detail::view {
const std::tuple<T...>& tuple;
basic_string_view<Char> sep;
@@ -302,14 +310,14 @@ struct formatter<tuple_arg_join<Char, T...>, Char> {
template <typename FormatContext>
typename FormatContext::iterator format(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx) {
- return format(value, ctx, internal::make_index_sequence<sizeof...(T)>{});
+ return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{});
}
private:
template <typename FormatContext, size_t... N>
typename FormatContext::iterator format(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
- internal::index_sequence<N...>) {
+ detail::index_sequence<N...>) {
return format_args(value, ctx, std::get<N>(value.tuple)...);
}
@@ -360,6 +368,29 @@ FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
return {tuple, sep};
}
+/**
+ \rst
+ Returns an object that formats `initializer_list` with elements separated by
+ `sep`.
+
+ **Example**::
+
+ fmt::print("{}", fmt::join({1, 2, 3}, ", "));
+ // Output: "1, 2, 3"
+ \endrst
+ */
+template <typename T>
+arg_join<const T*, const T*, char> join(std::initializer_list<T> list,
+ string_view sep) {
+ return join(std::begin(list), std::end(list), sep);
+}
+
+template <typename T>
+arg_join<const T*, const T*, wchar_t> join(std::initializer_list<T> list,
+ wstring_view sep) {
+ return join(std::begin(list), std::end(list), sep);
+}
+
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_