Skip to content

Commit

Permalink
Disable range formatter when user provides one
Browse files Browse the repository at this point in the history
Disable formatting type as range if user provided format_as function
exists, using that instead. Should fix issue raised in fmtlib#3839
  • Loading branch information
Arghnews committed May 15, 2024
1 parent 8e72804 commit 414401a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/fmt/ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<conjunction<
bool_constant<!detail::has_format_as<R>{}>,
bool_constant<range_format_kind<R, Char>::value !=
range_format::disabled &&
range_format_kind<R, Char>::value != range_format::map>
Expand Down
61 changes: 61 additions & 0 deletions test/ranges-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "fmt/ranges.h"

#include <algorithm>
#include <array>
#include <list>
#include <map>
Expand Down Expand Up @@ -742,3 +743,63 @@ TEST(ranges_test, movable_only_istream_iter_join) {
EXPECT_EQ("1, 2, 3, 4, 5",
fmt::format("{}", fmt::join(std::move(first), last, ", ")));
}

namespace ranges_format_as {
struct RangeLike {
std::array<char, 3> arr = {{'h', 'e', 'y'}};
const char* begin() const { return arr.begin(); }
const char* end() const { return arr.end(); }
};

struct RangeLikeWithFormatAs : RangeLike {
friend std::string format_as(const RangeLikeWithFormatAs& r) {
std::string s{r.begin(), r.end()};
s += '!';
return s;
}
};

struct RangeLikeSpecialized : RangeLike {};
} // namespace ranges_format_as

FMT_BEGIN_NAMESPACE
template <>
struct formatter<ranges_format_as::RangeLikeSpecialized>
: formatter<std::string> {
auto format(const ranges_format_as::RangeLikeSpecialized& r,
format_context& ctx) const -> format_context::iterator {
std::string s{r.begin(), r.end()};
std::reverse(s.begin(), s.end());
return formatter<std::string>::format(s, ctx);
}
};
FMT_END_NAMESPACE

TEST(ranges_test, prefer_user_formatter_to_range_like) {
using namespace ranges_format_as;
{
EXPECT_EQ(fmt::format("{}", RangeLike{}), "['h', 'e', 'y']");
using T = RangeLike;
constexpr std::array<RangeLike, 3> arr{T{}, T{}, T{}};
EXPECT_EQ(fmt::format("{}", arr),
"[['h', 'e', 'y'], ['h', 'e', 'y'], ['h', 'e', 'y']]");
EXPECT_EQ(fmt::format("{}", fmt::join(arr, " - ")),
"['h', 'e', 'y'] - ['h', 'e', 'y'] - ['h', 'e', 'y']");
}

{
EXPECT_EQ(fmt::format("{}", RangeLikeWithFormatAs{}), "hey!");
using T = RangeLikeWithFormatAs;
constexpr std::array<RangeLikeWithFormatAs, 3> arr{T{}, T{}, T{}};
EXPECT_EQ(fmt::format("{}", arr), "[\"hey!\", \"hey!\", \"hey!\"]");
EXPECT_EQ(fmt::format("{}", fmt::join(arr, " - ")), "hey! - hey! - hey!");
}

{
EXPECT_EQ(fmt::format("{}", RangeLikeSpecialized{}), "yeh");
using T = RangeLikeSpecialized;
constexpr std::array<RangeLikeSpecialized, 3> arr{T{}, T{}, T{}};
EXPECT_EQ(fmt::format("{}", arr), "[\"yeh\", \"yeh\", \"yeh\"]");
EXPECT_EQ(fmt::format("{}", fmt::join(arr, " - ")), "yeh - yeh - yeh");
}
}

0 comments on commit 414401a

Please sign in to comment.