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
This commit is contained in:
Alexey Ochapov
2021-01-30 18:42:58 +03:00
committed by GitHub
parent b0b56b4379
commit 2a25e2bf4d
3 changed files with 99 additions and 89 deletions

View File

@ -381,7 +381,7 @@ template <typename T> inline T* make_checked(T* p, size_t) { return p; }
#endif #endif
template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)> template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
#if FMT_CLANG_VERSION #if FMT_CLANG_VERSION >= 307
__attribute__((no_sanitize("undefined"))) __attribute__((no_sanitize("undefined")))
#endif #endif
inline checked_ptr<typename Container::value_type> 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 char reset_color[5];
static const wchar_t wreset_color[5]; static const wchar_t wreset_color[5];
static const char signs[]; static const char signs[];
static constexpr const char left_padding_shifts[] = {31, 31, 0, 1, 0}; static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1, 0};
static constexpr const char right_padding_shifts[] = {0, 31, 0, 1, 0}; static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1, 0};
// DEPRECATED! These are for ABI compatibility. // DEPRECATED! These are for ABI compatibility.
static const uint32_t zero_or_powers_of_10_32[]; static const uint32_t zero_or_powers_of_10_32[];

View File

@ -368,7 +368,7 @@ template <typename Char, typename... T> struct tuple_arg_join : detail::view {
basic_string_view<Char> sep; basic_string_view<Char> sep;
tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s) 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> template <typename Char, typename... T>

View File

@ -11,17 +11,23 @@
#include "fmt/ranges.h" #include "fmt/ranges.h"
#include <array>
#include <map>
#include <string>
#include <vector>
#include "gtest.h" #include "gtest.h"
// Check if 'if constexpr' is supported. #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 601
#if (__cplusplus > 201402L) || \ # define FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) #endif
# include <array> #if !FMT_MSC_VER || FMT_MSC_VER > 1910
# include <map> # define FMT_RANGES_TEST_ENABLE_JOIN
# include <string> # define FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
# include <vector> #endif
#ifdef FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY
TEST(RangesTest, FormatArray) { TEST(RangesTest, FormatArray) {
int32_t ia[] = {1, 2, 3, 5, 7, 11}; int32_t ia[] = {1, 2, 3, 5, 7, 11};
auto iaf = fmt::format("{}", ia); auto iaf = fmt::format("{}", ia);
@ -34,6 +40,12 @@ TEST(RangesTest, Format2dArray) {
EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", iaf); 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) { TEST(RangesTest, FormatVector) {
std::vector<int32_t> iv{1, 2, 3, 5, 7, 11}; std::vector<int32_t> iv{1, 2, 3, 5, 7, 11};
auto ivf = fmt::format("{}", iv); auto ivf = fmt::format("{}", iv);
@ -51,11 +63,6 @@ TEST(RangesTest, FormatMap) {
EXPECT_EQ("{(\"one\", 1), (\"two\", 2)}", fmt::format("{}", simap)); 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) { TEST(RangesTest, FormatPair) {
std::pair<int64_t, float> pa1{42, 1.5f}; std::pair<int64_t, float> pa1{42, 1.5f};
EXPECT_EQ("(42, 1.5)", fmt::format("{}", pa1)); EXPECT_EQ("(42, 1.5)", fmt::format("{}", pa1));
@ -68,43 +75,21 @@ TEST(RangesTest, FormatTuple) {
EXPECT_EQ("()", fmt::format("{}", std::tuple<>())); EXPECT_EQ("()", fmt::format("{}", std::tuple<>()));
} }
TEST(RangesTest, JoinTuple) { #ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
// 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 my_struct { struct my_struct {
int32_t i; int32_t i;
std::string str; // can throw std::string str; // can throw
template <size_t N> decltype(auto) get() const noexcept { template <size_t N> fmt::enable_if_t<N == 0, int32_t> get() const noexcept {
if constexpr (N == 0) return i;
return i; }
else if constexpr (N == 1) template <size_t N>
return fmt::string_view{str}; 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>(); return s.get<N>();
} }
@ -122,10 +107,11 @@ TEST(RangesTest, FormatStruct) {
my_struct mst{13, "my struct"}; my_struct mst{13, "my struct"};
EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst)); EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst));
} }
#endif // FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
TEST(RangesTest, FormatTo) { TEST(RangesTest, FormatTo) {
char buf[10]; 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'; *end = '\0';
EXPECT_STREQ(buf, "{1, 2, 3}"); EXPECT_STREQ(buf, "{1, 2, 3}");
} }
@ -141,9 +127,6 @@ TEST(RangesTest, PathLike) {
EXPECT_FALSE((fmt::is_range<path_like, char>::value)); 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 #ifdef FMT_USE_STRING_VIEW
struct string_like { struct string_like {
const char* begin(); const char* begin();
@ -157,23 +140,6 @@ TEST(RangesTest, FormatStringLike) {
} }
#endif // FMT_USE_STRING_VIEW #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 // A range that provides non-const only begin()/end() to test fmt::join handles
// that // that
// //
@ -212,27 +178,6 @@ template <typename T> class noncopyable_range {
const_iterator end() const { return vec.end(); } 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) { TEST(RangesTest, Range) {
noncopyable_range<int> w(3u, 0); noncopyable_range<int> w(3u, 0);
EXPECT_EQ("{0, 0, 0}", fmt::format("{}", w)); EXPECT_EQ("{0, 0, 0}", fmt::format("{}", w));
@ -258,3 +203,68 @@ TEST(RangesTest, UnformattableRange) {
fmt::format_context>::value)); fmt::format_context>::value));
} }
#endif #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