Drop range limit and cleanup tests

This commit is contained in:
Victor Zverovich 2021-05-04 20:53:56 -07:00
parent c738c3431f
commit 38bcc04a11
2 changed files with 88 additions and 118 deletions

View File

@ -17,11 +17,6 @@
#include "format.h" #include "format.h"
// output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
template <typename Char> struct formatting_base { template <typename Char> struct formatting_base {
@ -33,9 +28,6 @@ template <typename Char> struct formatting_base {
template <typename Char, typename Enable = void> template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> { struct formatting_range : formatting_base<Char> {
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 = '{'; Char prefix = '{';
Char postfix = '}'; Char postfix = '}';
}; };
@ -360,10 +352,7 @@ struct formatter<
for (; it != end; ++it) { for (; it != end; ++it) {
if (i > 0) out = detail::write_delimiter(out); if (i > 0) out = detail::write_delimiter(out);
out = detail::write_range_entry<Char>(out, *it); out = detail::write_range_entry<Char>(out, *it);
if (++i > formatting.range_length_limit) { ++i;
out = format_to(out, FMT_STRING("{}"), " ... <other elements>");
break;
}
} }
return detail::copy(formatting.postfix, out); return detail::copy(formatting.postfix, out);
} }

View File

@ -44,69 +44,65 @@ TEST(ranges_test, format_array_of_literals) {
#endif // FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY #endif // FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY
TEST(ranges_test, format_vector) { TEST(ranges_test, format_vector) {
std::vector<int32_t> iv{1, 2, 3, 5, 7, 11}; auto v = std::vector<int>{1, 2, 3, 5, 7, 11};
auto ivf = fmt::format("{}", iv); EXPECT_EQ(fmt::format("{}", v), "{1, 2, 3, 5, 7, 11}");
EXPECT_EQ("{1, 2, 3, 5, 7, 11}", ivf);
} }
TEST(ranges_test, format_vector2) { TEST(ranges_test, format_vector2) {
std::vector<std::vector<int32_t>> ivv{{1, 2}, {3, 5}, {7, 11}}; auto v = std::vector<std::vector<int>>{{1, 2}, {3, 5}, {7, 11}};
auto ivf = fmt::format("{}", ivv); EXPECT_EQ(fmt::format("{}", v), "{{1, 2}, {3, 5}, {7, 11}}");
EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf);
} }
TEST(ranges_test, FormatMap) { TEST(ranges_test, format_map) {
std::map<std::string, int32_t> simap{{"one", 1}, {"two", 2}}; auto m = std::map<std::string, int>{{"one", 1}, {"two", 2}};
EXPECT_EQ("{(\"one\", 1), (\"two\", 2)}", fmt::format("{}", simap)); EXPECT_EQ(fmt::format("{}", m), "{(\"one\", 1), (\"two\", 2)}");
} }
TEST(ranges_test, FormatPair) { TEST(ranges_test, format_pair) {
std::pair<int64_t, float> pa1{42, 1.5f}; auto p = std::pair<int, float>(42, 1.5f);
EXPECT_EQ("(42, 1.5)", fmt::format("{}", pa1)); EXPECT_EQ(fmt::format("{}", p), "(42, 1.5)");
} }
TEST(ranges_test, FormatTuple) { TEST(ranges_test, format_tuple) {
std::tuple<int64_t, float, std::string, char> t{42, 1.5f, "this is tuple", auto t =
'i'}; std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i');
EXPECT_EQ("(42, 1.5, \"this is tuple\", 'i')", fmt::format("{}", t)); EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')");
EXPECT_EQ("()", fmt::format("{}", std::tuple<>())); EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()");
} }
#ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT #ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
struct my_struct { struct tuple_like {
int32_t i; int i;
std::string str; // can throw std::string str;
template <size_t N> fmt::enable_if_t<N == 0, int32_t> get() const noexcept {
template <size_t N> fmt::enable_if_t<N == 0, int> get() const noexcept {
return i; return i;
} }
template <size_t N> template <size_t N>
fmt::enable_if_t<N == 1, fmt::string_view> get() const noexcept { fmt::enable_if_t<N == 1, fmt::string_view> get() const noexcept {
return {str}; return str;
} }
}; };
template <size_t N> template <size_t N>
auto get(const my_struct& s) noexcept -> decltype(s.get<N>()) { auto get(const tuple_like& t) noexcept -> decltype(t.get<N>()) {
return s.get<N>(); return t.get<N>();
} }
namespace std { template <>
struct std::tuple_size<tuple_like> : std::integral_constant<size_t, 2> {};
template <> struct tuple_size<my_struct> : std::integral_constant<size_t, 2> {}; template <size_t N> struct std::tuple_element<N, tuple_like> {
using type = decltype(std::declval<tuple_like>().get<N>());
template <size_t N> struct tuple_element<N, my_struct> {
using type = decltype(std::declval<my_struct>().get<N>());
}; };
} // namespace std TEST(ranges_test, format_struct) {
auto t = tuple_like{42, "foo"};
TEST(ranges_test, FormatStruct) { EXPECT_EQ(fmt::format("{}", t), "(42, \"foo\")");
my_struct mst{13, "my struct"};
EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst));
} }
#endif // FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT #endif // FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
TEST(ranges_test, FormatTo) { TEST(ranges_test, format_to) {
char buf[10]; char buf[10];
auto end = fmt::format_to(buf, "{}", std::vector<int>{1, 2, 3}); auto end = fmt::format_to(buf, "{}", std::vector<int>{1, 2, 3});
*end = '\0'; *end = '\0';
@ -120,7 +116,7 @@ struct path_like {
operator std::string() const; operator std::string() const;
}; };
TEST(ranges_test, PathLike) { TEST(ranges_test, path_like) {
EXPECT_FALSE((fmt::is_range<path_like, char>::value)); EXPECT_FALSE((fmt::is_range<path_like, char>::value));
} }
@ -132,15 +128,15 @@ struct string_like {
explicit operator std::string_view() const { return "foo"; } explicit operator std::string_view() const { return "foo"; }
}; };
TEST(ranges_test, FormatStringLike) { TEST(ranges_test, format_string_like) {
EXPECT_EQ("foo", fmt::format("{}", string_like())); EXPECT_EQ(fmt::format("{}", string_like()), "foo");
} }
#endif // FMT_USE_STRING_VIEW #endif // FMT_USE_STRING_VIEW
// A range that provides non-const only begin()/end() to test fmt::join handles // A range that provides non-const only begin()/end() to test fmt::join handles
// that // that.
// //
// Some ranges (eg those produced by range-v3's views::filter()) can cache // Some ranges (e.g. those produced by range-v3's views::filter()) can cache
// information during iteration so they only provide non-const begin()/end(). // information during iteration so they only provide non-const begin()/end().
template <typename T> class non_const_only_range { template <typename T> class non_const_only_range {
private: private:
@ -151,7 +147,7 @@ template <typename T> class non_const_only_range {
template <typename... Args> template <typename... Args>
explicit non_const_only_range(Args&&... args) explicit non_const_only_range(Args&&... args)
: vec(::std::forward<Args>(args)...) {} : vec(std::forward<Args>(args)...) {}
const_iterator begin() { return vec.begin(); } const_iterator begin() { return vec.begin(); }
const_iterator end() { return vec.end(); } const_iterator end() { return vec.end(); }
@ -166,7 +162,7 @@ template <typename T> class noncopyable_range {
template <typename... Args> template <typename... Args>
explicit noncopyable_range(Args&&... args) explicit noncopyable_range(Args&&... args)
: vec(::std::forward<Args>(args)...) {} : vec(std::forward<Args>(args)...) {}
noncopyable_range(noncopyable_range const&) = delete; noncopyable_range(noncopyable_range const&) = delete;
noncopyable_range(noncopyable_range&) = delete; noncopyable_range(noncopyable_range&) = delete;
@ -175,75 +171,61 @@ template <typename T> class noncopyable_range {
const_iterator end() const { return vec.end(); } const_iterator end() const { return vec.end(); }
}; };
TEST(ranges_test, Range) { TEST(ranges_test, range) {
noncopyable_range<int> w(3u, 0); noncopyable_range<int> w(3u, 0);
EXPECT_EQ("{0, 0, 0}", fmt::format("{}", w)); EXPECT_EQ(fmt::format("{}", w), "{0, 0, 0}");
EXPECT_EQ("{0, 0, 0}", fmt::format("{}", noncopyable_range<int>(3u, 0))); EXPECT_EQ(fmt::format("{}", noncopyable_range<int>(3u, 0)), "{0, 0, 0}");
non_const_only_range<int> x(3u, 0); non_const_only_range<int> x(3u, 0);
EXPECT_EQ("{0, 0, 0}", fmt::format("{}", x)); EXPECT_EQ(fmt::format("{}", x), "{0, 0, 0}");
EXPECT_EQ("{0, 0, 0}", fmt::format("{}", non_const_only_range<int>(3u, 0))); EXPECT_EQ(fmt::format("{}", non_const_only_range<int>(3u, 0)), "{0, 0, 0}");
std::vector<int> y(3u, 0); auto y = std::vector<int>(3u, 0);
EXPECT_EQ("{0, 0, 0}", fmt::format("{}", y)); EXPECT_EQ(fmt::format("{}", y), "{0, 0, 0}");
EXPECT_EQ("{0, 0, 0}", fmt::format("{}", std::vector<int>(3u, 0))); EXPECT_EQ(fmt::format("{}", std::vector<int>(3u, 0)), "{0, 0, 0}");
const std::vector<int> z(3u, 0); const auto z = std::vector<int>(3u, 0);
EXPECT_EQ("{0, 0, 0}", fmt::format("{}", z)); EXPECT_EQ(fmt::format("{}", z), "{0, 0, 0}");
} }
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927 #if !FMT_MSC_VER || FMT_MSC_VER >= 1927
struct unformattable {}; struct unformattable {};
TEST(ranges_test, UnformattableRange) { TEST(ranges_test, unformattable_range) {
EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>, EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>,
fmt::format_context>::value)); fmt::format_context>::value));
} }
#endif #endif
#ifdef FMT_RANGES_TEST_ENABLE_JOIN #ifdef FMT_RANGES_TEST_ENABLE_JOIN
TEST(ranges_test, JoinTuple) { TEST(ranges_test, join_tuple) {
// Value tuple args // Value tuple args.
std::tuple<char, int, float> t1 = std::make_tuple('a', 1, 2.0f); auto t1 = std::tuple<char, int, float>('a', 1, 2.0f);
EXPECT_EQ("(a, 1, 2)", fmt::format("({})", fmt::join(t1, ", "))); EXPECT_EQ(fmt::format("({})", fmt::join(t1, ", ")), "(a, 1, 2)");
// Testing lvalue tuple args // Testing lvalue tuple args.
int x = 4; int x = 4;
std::tuple<char, int&> t2{'b', x}; auto t2 = std::tuple<char, int&>('b', x);
EXPECT_EQ("b + 4", fmt::format("{}", fmt::join(t2, " + "))); EXPECT_EQ(fmt::format("{}", fmt::join(t2, " + ")), "b + 4");
// Empty tuple // Empty tuple.
std::tuple<> t3; auto t3 = std::tuple<>();
EXPECT_EQ("", fmt::format("{}", fmt::join(t3, "|"))); EXPECT_EQ(fmt::format("{}", fmt::join(t3, "|")), "");
// Single element tuple // Single element tuple.
std::tuple<float> t4{4.0f}; auto t4 = std::tuple<float>(4.0f);
EXPECT_EQ("4", fmt::format("{}", fmt::join(t4, "/"))); EXPECT_EQ(fmt::format("{}", fmt::join(t4, "/")), "4");
} }
TEST(ranges_test, WideStringJoinTuple) { TEST(ranges_test, wide_string_join_tuple) {
// Value tuple args auto t = std::tuple<wchar_t, int, float>('a', 1, 2.0f);
std::tuple<wchar_t, int, float> t1 = std::make_tuple('a', 1, 2.0f); EXPECT_EQ(fmt::format(L"({})", fmt::join(t, L", ")), L"(a, 1, 2)");
EXPECT_EQ(L"(a, 1, 2)", fmt::format(L"({})", fmt::join(t1, L", ")));
// Testing lvalue tuple args
int x = 4;
std::tuple<wchar_t, int&> t2{'b', x};
EXPECT_EQ(L"b + 4", fmt::format(L"{}", fmt::join(t2, L" + ")));
// Empty tuple
std::tuple<> t3;
EXPECT_EQ(L"", fmt::format(L"{}", fmt::join(t3, L"|")));
// Single element tuple
std::tuple<float> t4{4.0f};
EXPECT_EQ(L"4", fmt::format(L"{}", fmt::join(t4, L"/")));
} }
TEST(ranges_test, JoinInitializerList) { TEST(ranges_test, join_initializer_list) {
EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join({1, 2, 3}, ", "))); EXPECT_EQ(fmt::format("{}", fmt::join({1, 2, 3}, ", ")), "1, 2, 3");
EXPECT_EQ("fmt rocks !", EXPECT_EQ(fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " ")),
fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " "))); "fmt rocks !");
} }
struct zstring_sentinel {}; struct zstring_sentinel {};
@ -257,30 +239,29 @@ struct zstring {
zstring_sentinel end() const { return {}; } zstring_sentinel end() const { return {}; }
}; };
TEST(ranges_test, JoinSentinel) { TEST(ranges_test, join_sentinel) {
zstring hello{"hello"}; auto hello = zstring{"hello"};
EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello)); EXPECT_EQ(fmt::format("{}", hello), "{'h', 'e', 'l', 'l', 'o'}");
EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(hello, "_"))); EXPECT_EQ(fmt::format("{}", fmt::join(hello, "_")), "h_e_l_l_o");
} }
TEST(ranges_test, JoinRange) { TEST(ranges_test, join_range) {
noncopyable_range<int> w(3u, 0); noncopyable_range<int> w(3u, 0);
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(w, ","))); EXPECT_EQ(fmt::format("{}", fmt::join(w, ",")), "0,0,0");
EXPECT_EQ("0,0,0", EXPECT_EQ(fmt::format("{}", fmt::join(noncopyable_range<int>(3u, 0), ",")),
fmt::format("{}", fmt::join(noncopyable_range<int>(3u, 0), ","))); "0,0,0");
non_const_only_range<int> x(3u, 0); non_const_only_range<int> x(3u, 0);
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(x, ","))); EXPECT_EQ(fmt::format("{}", fmt::join(x, ",")), "0,0,0");
EXPECT_EQ( EXPECT_EQ(fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ",")),
"0,0,0", "0,0,0");
fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ",")));
std::vector<int> y(3u, 0); auto y = std::vector<int>(3u, 0);
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ","))); EXPECT_EQ(fmt::format("{}", fmt::join(y, ",")), "0,0,0");
EXPECT_EQ("0,0,0", EXPECT_EQ(fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ",")),
fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ","))); "0,0,0");
const std::vector<int> z(3u, 0); const auto z = std::vector<int>(3u, 0);
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ","))); EXPECT_EQ(fmt::format("{}", fmt::join(z, ",")), "0,0,0");
} }
#endif // FMT_RANGES_TEST_ENABLE_JOIN #endif // FMT_RANGES_TEST_ENABLE_JOIN