forked from OctaForge/libostd
custom formatting is now done with format_traits
Allows definition for any type, even in any foreign namespace.master
parent
e714e5f3fb
commit
bd5aa4795c
|
@ -12,9 +12,11 @@ using namespace ostd::string_literals;
|
||||||
struct Foo {
|
struct Foo {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* implementing formatting for custom objects - external function */
|
/* implementing formatting for custom objects */
|
||||||
|
template<>
|
||||||
|
struct format_traits<Foo> {
|
||||||
template<typename R>
|
template<typename R>
|
||||||
void to_format(Foo const &, R &writer, format_spec const &fs) {
|
static void to_format(Foo const &, R &writer, format_spec const &fs) {
|
||||||
switch (fs.spec()) {
|
switch (fs.spec()) {
|
||||||
case 'i':
|
case 'i':
|
||||||
range_put_all(writer, "Foo1"_sr);
|
range_put_all(writer, "Foo1"_sr);
|
||||||
|
@ -24,20 +26,6 @@ void to_format(Foo const &, R &writer, format_spec const &fs) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Bar {
|
|
||||||
/* implementing formatting for custom objects - method */
|
|
||||||
template<typename R>
|
|
||||||
void to_format(R &writer, format_spec const &fs) const {
|
|
||||||
switch (fs.spec()) {
|
|
||||||
case 'i':
|
|
||||||
range_put_all(writer, "Bar1"_sr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
range_put_all(writer, "Bar2"_sr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
@ -116,10 +104,6 @@ int main() {
|
||||||
writefln("%s", Foo{});
|
writefln("%s", Foo{});
|
||||||
writefln("%i", Foo{});
|
writefln("%i", Foo{});
|
||||||
|
|
||||||
/* again, but using a method for formatting */
|
|
||||||
writefln("%s", Bar{});
|
|
||||||
writefln("%i", Bar{});
|
|
||||||
|
|
||||||
/* formatting into a string sink (can be any output range, but
|
/* formatting into a string sink (can be any output range, but
|
||||||
* appender makes sure the capacity is unlimited so it's safe)
|
* appender makes sure the capacity is unlimited so it's safe)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -36,16 +36,9 @@ struct format_error: std::runtime_error {
|
||||||
|
|
||||||
struct format_spec;
|
struct format_spec;
|
||||||
|
|
||||||
template<
|
/* empty by default, SFINAE friendly */
|
||||||
typename T, typename R, typename = std::enable_if_t<std::is_same_v<
|
template<typename>
|
||||||
decltype(std::declval<T const &>().to_format(
|
struct format_traits {};
|
||||||
std::declval<R &>(), std::declval<format_spec const &>()
|
|
||||||
)), void
|
|
||||||
>>
|
|
||||||
>
|
|
||||||
inline void to_format(T const &v, R &writer, format_spec const &fs) {
|
|
||||||
v.to_format(writer, fs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* implementation helpers */
|
/* implementation helpers */
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
@ -174,9 +167,9 @@ namespace detail {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value;
|
constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value;
|
||||||
|
|
||||||
/* test whether to_format works */
|
/* test if format traits are available for the type */
|
||||||
template<typename T, typename R>
|
template<typename T, typename R>
|
||||||
static std::true_type test_tofmt(decltype(to_format(
|
static std::true_type test_tofmt(decltype(format_traits<T>::to_format(
|
||||||
std::declval<T const &>(), std::declval<R &>(),
|
std::declval<T const &>(), std::declval<R &>(),
|
||||||
std::declval<format_spec const &>()
|
std::declval<format_spec const &>()
|
||||||
)) *);
|
)) *);
|
||||||
|
@ -660,7 +653,7 @@ private:
|
||||||
void write_val(R &writer, bool escape, T const &val) const {
|
void write_val(R &writer, bool escape, T const &val) const {
|
||||||
/* stuff fhat can be custom-formatted goes first */
|
/* stuff fhat can be custom-formatted goes first */
|
||||||
if constexpr(detail::fmt_tofmt_test<T, noop_output_range<char>>) {
|
if constexpr(detail::fmt_tofmt_test<T, noop_output_range<char>>) {
|
||||||
to_format(val, writer, *this);
|
format_traits<T>::to_format(val, writer, *this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* second best, we can convert to string slice */
|
/* second best, we can convert to string slice */
|
||||||
|
|
Loading…
Reference in New Issue