Add formatters for container adapters
This commit is contained in:
parent
f89cd276f7
commit
61544730e6
@ -660,6 +660,50 @@ struct formatter<tuple_join_view<Char, T...>, Char> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
// Check if T has an interface like container adapter (e.g. std::stack,
|
||||||
|
// std::queue, std::priority_queue).
|
||||||
|
template <typename T> class is_container_adaptor_like {
|
||||||
|
template <typename U> static auto check(U* p) -> typename U::container_type;
|
||||||
|
template <typename> static void check(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr const bool value =
|
||||||
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
auto get_container(T& t) ->
|
||||||
|
typename std::add_const<typename T::container_type>::type& {
|
||||||
|
struct getter : T {
|
||||||
|
static auto get(const T& t) ->
|
||||||
|
typename std::add_const<typename T::container_type>::type& {
|
||||||
|
return t.*(&getter::c); // Access c through the derived class.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return getter::get(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<T, Char,
|
||||||
|
enable_if_t<detail::is_container_adaptor_like<T>::value>> {
|
||||||
|
struct formatter<decltype(detail::get_container(std::declval<T&>())), Char>
|
||||||
|
container_formatter;
|
||||||
|
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return container_formatter.parse(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const T& value, FormatContext& ctx) const ->
|
||||||
|
typename FormatContext::iterator {
|
||||||
|
return container_formatter.format(detail::get_container(value), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_MODULE_EXPORT_BEGIN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -14,6 +14,8 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
@ -406,3 +408,60 @@ TEST(ranges_test, range_of_range_of_mixed_const) {
|
|||||||
TEST(ranges_test, vector_char) {
|
TEST(ranges_test, vector_char) {
|
||||||
EXPECT_EQ(fmt::format("{}", std::vector<char>{'a', 'b'}), "['a', 'b']");
|
EXPECT_EQ(fmt::format("{}", std::vector<char>{'a', 'b'}), "['a', 'b']");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ranges_test, container_adaptor) {
|
||||||
|
{
|
||||||
|
using fmt::detail::is_container_adaptor_like;
|
||||||
|
using T = std::nullptr_t;
|
||||||
|
static_assert(is_container_adaptor_like<std::stack<T>>::value, "");
|
||||||
|
static_assert(is_container_adaptor_like<std::queue<T>>::value, "");
|
||||||
|
static_assert(is_container_adaptor_like<std::priority_queue<T>>::value, "");
|
||||||
|
static_assert(!is_container_adaptor_like<std::vector<T>>::value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::stack<int> s;
|
||||||
|
s.push(1);
|
||||||
|
s.push(2);
|
||||||
|
EXPECT_EQ(fmt::format("{}", s), "[1, 2]");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::stack<int, std::vector<int>> s;
|
||||||
|
s.push(1);
|
||||||
|
s.push(2);
|
||||||
|
EXPECT_EQ(fmt::format("{}", s), "[1, 2]");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::queue<int> q;
|
||||||
|
q.push(1);
|
||||||
|
q.push(2);
|
||||||
|
EXPECT_EQ(fmt::format("{}", q), "[1, 2]");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::priority_queue<int> q;
|
||||||
|
q.push(3);
|
||||||
|
q.push(1);
|
||||||
|
q.push(2);
|
||||||
|
q.push(4);
|
||||||
|
EXPECT_EQ(fmt::format("{}", q), "[4, 3, 2, 1]");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct my_container_adaptor {
|
||||||
|
using value_type = int;
|
||||||
|
using container_type = std::vector<value_type>;
|
||||||
|
void push(const value_type& v) { c.push_back(v); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
container_type c;
|
||||||
|
};
|
||||||
|
|
||||||
|
my_container_adaptor m;
|
||||||
|
m.push(1);
|
||||||
|
m.push(2);
|
||||||
|
EXPECT_EQ(fmt::format("{}", m), "[1, 2]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user