Skip to content

Commit

Permalink
Fix is_formattable for tuple-like types.
Browse files Browse the repository at this point in the history
  • Loading branch information
jehelset committed Jun 18, 2022
1 parent eaa8efb commit 0203853
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
26 changes: 25 additions & 1 deletion include/fmt/ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,24 @@ template <size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
#endif

template <typename T>
using tuple_index_sequence = make_index_sequence<std::tuple_size_v<T>>;

template <typename T, bool = is_tuple_like_<T>::value>
struct is_tuple_formattable_ {
static constexpr const bool value = false;
};
template <typename T> struct is_tuple_formattable_<T, true> {
template <std::size_t... I>
static std::integral_constant<
bool, (fmt::is_formattable<std::tuple_element_t<I, T>>::value && ...)>
check(index_sequence<I...>);

public:
static constexpr const bool value =
decltype(check(tuple_index_sequence<T>{}))::value;
};

template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
using std::get;
Expand Down Expand Up @@ -283,8 +301,14 @@ template <typename T> struct is_tuple_like {
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
};

template <typename T> struct is_tuple_formattable {
static constexpr const bool value = detail::is_tuple_formattable_<T>::value;
};

template <typename TupleT, typename Char>
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
struct formatter<TupleT, Char,
enable_if_t<fmt::is_tuple_like<TupleT>::value &&
fmt::is_tuple_formattable<TupleT>::value>> {
private:
// C++11 generic lambda for format().
template <typename FormatContext> struct format_each {
Expand Down
12 changes: 12 additions & 0 deletions test/ranges-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ TEST(ranges_test, format_tuple) {
std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i');
EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')");
EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()");

enum class noformatenum{b};
struct noformatstruct{};
EXPECT_TRUE((fmt::is_formattable<std::tuple<>>::value));
EXPECT_FALSE((fmt::is_formattable<noformatenum>::value));
EXPECT_FALSE((fmt::is_formattable<noformatstruct>::value));
EXPECT_FALSE((fmt::is_formattable<std::tuple<noformatenum>>::value));
EXPECT_FALSE((fmt::is_formattable<std::tuple<noformatstruct>>::value));
EXPECT_FALSE((fmt::is_formattable<std::tuple<noformatstruct,int>>::value));
EXPECT_FALSE((fmt::is_formattable<std::tuple<int,noformatenum>>::value));
EXPECT_FALSE((fmt::is_formattable<std::tuple<noformatstruct,noformatenum>>::value));
EXPECT_TRUE((fmt::is_formattable<std::tuple<int,float>>::value));
}

#ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
Expand Down
2 changes: 2 additions & 0 deletions test/xchar-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,12 @@ TEST(xchar_test, ostream) {
#endif
}

#ifdef FMT_XCHAR_TEST_ENABLE_FORMAT_MAP
TEST(xchar_test, format_map) {
auto m = std::map<std::wstring, int>{{L"one", 1}, {L"t\"wo", 2}};
EXPECT_EQ(fmt::format(L"{}", m), L"{\"one\": 1, \"t\\\"wo\": 2}");
}
#endif

TEST(xchar_test, escape_string) {
using vec = std::vector<std::wstring>;
Expand Down

0 comments on commit 0203853

Please sign in to comment.