From 2a25e2bf4ddd2030255279e8382ca4e8722b1825 Mon Sep 17 00:00:00 2001 From: Alexey Ochapov <alexez@alexez.com> Date: Sat, 30 Jan 2021 18:42:58 +0300 Subject: [PATCH] Make ranges-test available with C++11 (#2114) * make ranges-test available with C++11, fix problem with some gcc versions * potentially fix build for MSVC 19.10, a bit reorganizing in test --- include/fmt/format.h | 6 +- include/fmt/ranges.h | 2 +- test/ranges-test.cc | 180 +++++++++++++++++++++++-------------------- 3 files changed, 99 insertions(+), 89 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index df53308169e1..06c2f63f4fd7 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -381,7 +381,7 @@ template <typename T> inline T* make_checked(T* p, size_t) { return p; } #endif template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)> -#if FMT_CLANG_VERSION +#if FMT_CLANG_VERSION >= 307 __attribute__((no_sanitize("undefined"))) #endif inline checked_ptr<typename Container::value_type> @@ -941,8 +941,8 @@ template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data { static const char reset_color[5]; static const wchar_t wreset_color[5]; static const char signs[]; - static constexpr const char left_padding_shifts[] = {31, 31, 0, 1, 0}; - static constexpr const char right_padding_shifts[] = {0, 31, 0, 1, 0}; + static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1, 0}; + static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1, 0}; // DEPRECATED! These are for ABI compatibility. static const uint32_t zero_or_powers_of_10_32[]; diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 7b58f4e1b1a4..0ebf96526442 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -368,7 +368,7 @@ template <typename Char, typename... T> struct tuple_arg_join : detail::view { basic_string_view<Char> sep; tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s) - : tuple{t}, sep{s} {} + : tuple(t), sep{s} {} }; template <typename Char, typename... T> diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 802f4ab201f7..30ed97f21233 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -11,17 +11,23 @@ #include "fmt/ranges.h" +#include <array> +#include <map> +#include <string> +#include <vector> + #include "gtest.h" -// Check if 'if constexpr' is supported. -#if (__cplusplus > 201402L) || \ - (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 601 +# define FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY +#endif -# include <array> -# include <map> -# include <string> -# include <vector> +#if !FMT_MSC_VER || FMT_MSC_VER > 1910 +# define FMT_RANGES_TEST_ENABLE_JOIN +# define FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT +#endif +#ifdef FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY TEST(RangesTest, FormatArray) { int32_t ia[] = {1, 2, 3, 5, 7, 11}; auto iaf = fmt::format("{}", ia); @@ -34,6 +40,12 @@ TEST(RangesTest, Format2dArray) { EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", iaf); } +TEST(RangesTest, FormatArrayOfLiterals) { + const char* aol[] = {"1234", "abcd"}; + EXPECT_EQ("{\"1234\", \"abcd\"}", fmt::format("{}", aol)); +} +#endif // FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY + TEST(RangesTest, FormatVector) { std::vector<int32_t> iv{1, 2, 3, 5, 7, 11}; auto ivf = fmt::format("{}", iv); @@ -51,11 +63,6 @@ TEST(RangesTest, FormatMap) { EXPECT_EQ("{(\"one\", 1), (\"two\", 2)}", fmt::format("{}", simap)); } -TEST(RangesTest, FormatArrayOfLiterals) { - const char* aol[] = {"1234", "abcd"}; - EXPECT_EQ("{\"1234\", \"abcd\"}", fmt::format("{}", aol)); -} - TEST(RangesTest, FormatPair) { std::pair<int64_t, float> pa1{42, 1.5f}; EXPECT_EQ("(42, 1.5)", fmt::format("{}", pa1)); @@ -68,43 +75,21 @@ TEST(RangesTest, FormatTuple) { EXPECT_EQ("()", fmt::format("{}", std::tuple<>())); } -TEST(RangesTest, JoinTuple) { - // Value tuple args - std::tuple<char, int, float> t1 = std::make_tuple('a', 1, 2.0f); - EXPECT_EQ("(a, 1, 2)", fmt::format("({})", fmt::join(t1, ", "))); - - // Testing lvalue tuple args - int x = 4; - std::tuple<char, int&> t2{'b', x}; - EXPECT_EQ("b + 4", fmt::format("{}", fmt::join(t2, " + "))); - - // Empty tuple - std::tuple<> t3; - EXPECT_EQ("", fmt::format("{}", fmt::join(t3, "|"))); - - // Single element tuple - std::tuple<float> t4{4.0f}; - EXPECT_EQ("4", fmt::format("{}", fmt::join(t4, "/"))); -} - -TEST(RangesTest, JoinInitializerList) { - EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join({1, 2, 3}, ", "))); - EXPECT_EQ("fmt rocks !", - fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " "))); -} - +#ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT struct my_struct { int32_t i; std::string str; // can throw - template <size_t N> decltype(auto) get() const noexcept { - if constexpr (N == 0) - return i; - else if constexpr (N == 1) - return fmt::string_view{str}; + template <size_t N> fmt::enable_if_t<N == 0, int32_t> get() const noexcept { + return i; + } + template <size_t N> + fmt::enable_if_t<N == 1, fmt::string_view> get() const noexcept { + return {str}; } }; -template <size_t N> decltype(auto) get(const my_struct& s) noexcept { +template <size_t N> +auto get(const my_struct& s) noexcept -> decltype(s.get<N>()) { return s.get<N>(); } @@ -122,10 +107,11 @@ TEST(RangesTest, FormatStruct) { my_struct mst{13, "my struct"}; EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst)); } +#endif // FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT TEST(RangesTest, FormatTo) { char buf[10]; - auto end = fmt::format_to(buf, "{}", std::vector{1, 2, 3}); + auto end = fmt::format_to(buf, "{}", std::vector<int>{1, 2, 3}); *end = '\0'; EXPECT_STREQ(buf, "{1, 2, 3}"); } @@ -141,9 +127,6 @@ TEST(RangesTest, PathLike) { EXPECT_FALSE((fmt::is_range<path_like, char>::value)); } -#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > - // 201402L && _MSC_VER >= 1910) - #ifdef FMT_USE_STRING_VIEW struct string_like { const char* begin(); @@ -157,23 +140,6 @@ TEST(RangesTest, FormatStringLike) { } #endif // FMT_USE_STRING_VIEW -struct zstring_sentinel {}; - -bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; } -bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; } - -struct zstring { - const char* p; - const char* begin() const { return p; } - zstring_sentinel end() const { return {}; } -}; - -TEST(RangesTest, JoinSentinel) { - zstring hello{"hello"}; - EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello)); - EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(hello, "_"))); -} - // A range that provides non-const only begin()/end() to test fmt::join handles // that // @@ -212,27 +178,6 @@ template <typename T> class noncopyable_range { const_iterator end() const { return vec.end(); } }; -TEST(RangesTest, JoinRange) { - noncopyable_range<int> w(3u, 0); - EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(w, ","))); - EXPECT_EQ("0,0,0", - fmt::format("{}", fmt::join(noncopyable_range<int>(3u, 0), ","))); - - non_const_only_range<int> x(3u, 0); - EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(x, ","))); - EXPECT_EQ( - "0,0,0", - fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ","))); - - std::vector<int> y(3u, 0); - EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ","))); - EXPECT_EQ("0,0,0", - fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ","))); - - const std::vector<int> z(3u, 0); - EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ","))); -} - TEST(RangesTest, Range) { noncopyable_range<int> w(3u, 0); EXPECT_EQ("{0, 0, 0}", fmt::format("{}", w)); @@ -258,3 +203,68 @@ TEST(RangesTest, UnformattableRange) { fmt::format_context>::value)); } #endif + +#ifdef FMT_RANGES_TEST_ENABLE_JOIN +TEST(RangesTest, JoinTuple) { + // Value tuple args + std::tuple<char, int, float> t1 = std::make_tuple('a', 1, 2.0f); + EXPECT_EQ("(a, 1, 2)", fmt::format("({})", fmt::join(t1, ", "))); + + // Testing lvalue tuple args + int x = 4; + std::tuple<char, int&> t2{'b', x}; + EXPECT_EQ("b + 4", fmt::format("{}", fmt::join(t2, " + "))); + + // Empty tuple + std::tuple<> t3; + EXPECT_EQ("", fmt::format("{}", fmt::join(t3, "|"))); + + // Single element tuple + std::tuple<float> t4{4.0f}; + EXPECT_EQ("4", fmt::format("{}", fmt::join(t4, "/"))); +} + +TEST(RangesTest, JoinInitializerList) { + EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join({1, 2, 3}, ", "))); + EXPECT_EQ("fmt rocks !", + fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " "))); +} + +struct zstring_sentinel {}; + +bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; } +bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; } + +struct zstring { + const char* p; + const char* begin() const { return p; } + zstring_sentinel end() const { return {}; } +}; + +TEST(RangesTest, JoinSentinel) { + zstring hello{"hello"}; + EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello)); + EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(hello, "_"))); +} + +TEST(RangesTest, JoinRange) { + noncopyable_range<int> w(3u, 0); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(w, ","))); + EXPECT_EQ("0,0,0", + fmt::format("{}", fmt::join(noncopyable_range<int>(3u, 0), ","))); + + non_const_only_range<int> x(3u, 0); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(x, ","))); + EXPECT_EQ( + "0,0,0", + fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ","))); + + std::vector<int> y(3u, 0); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ","))); + EXPECT_EQ("0,0,0", + fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ","))); + + const std::vector<int> z(3u, 0); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ","))); +} +#endif // FMT_RANGES_TEST_ENABLE_JOIN \ No newline at end of file