Add std::format helpers for pointers, optional, variant, and support an extension mechanism using format_impl() that doesn't require manually specializing std::formatter
This commit is contained in:
parent
17be2f3aaa
commit
75df1be94d
1 changed files with 118 additions and 0 deletions
118
libs/util/include/psemek/util/format.hpp
Normal file
118
libs/util/include/psemek/util/format.hpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
namespace psemek::util
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
concept has_format_impl = requires (T x, std::format_context & format_context)
|
||||
{
|
||||
format_impl(x, format_context);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <typename T, typename Char>
|
||||
requires ::psemek::util::has_format_impl<T>
|
||||
struct formatter<T, Char>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context & ctx) const
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(T const & x, FormatContext & ctx) const
|
||||
{
|
||||
return format_impl(x, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
requires (!std::is_same_v<T, void> && !std::is_same_v<T, Char>)
|
||||
struct formatter<T *, Char>
|
||||
: formatter<void *>
|
||||
{
|
||||
using base = formatter<void *, Char>;
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(T const * ptr, FormatContext & ctx) const
|
||||
{
|
||||
if (ptr)
|
||||
return base::format((void *)ptr, ctx);
|
||||
else
|
||||
return std::format_to(ctx.out(), "(null)");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<unique_ptr<T>, Char>
|
||||
: formatter<void *>
|
||||
{
|
||||
using base = formatter<void *, Char>;
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(unique_ptr<T> const & ptr, FormatContext & ctx) const
|
||||
{
|
||||
if (ptr)
|
||||
return base::format((void *)ptr.get(), ctx);
|
||||
else
|
||||
return std::format_to(ctx.out(), "(null)");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<shared_ptr<T>, Char>
|
||||
: formatter<void *>
|
||||
{
|
||||
using base = formatter<void *, Char>;
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(shared_ptr<T> const & ptr, FormatContext & ctx) const
|
||||
{
|
||||
if (ptr)
|
||||
return base::format((void *)ptr.get(), ctx);
|
||||
else
|
||||
return std::format_to(ctx.out(), "(null)");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<optional<T>, Char>
|
||||
: formatter<T>
|
||||
{
|
||||
using base = formatter<T, Char>;
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(optional<T> const & opt, FormatContext & ctx) const
|
||||
{
|
||||
if (opt)
|
||||
return base::format(*opt, ctx);
|
||||
else
|
||||
return std::format_to(ctx.out(), "(none)");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ... Args, typename Char>
|
||||
struct formatter<variant<Args...>, Char>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context & ctx) const
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(variant<Args...> const & v, FormatContext & ctx) const
|
||||
{
|
||||
return std::visit([&ctx](auto const & v){ return std::format_to(ctx.out(), "{}", v); }, v);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue