From 75df1be94d7d9df77dab77233f33d92041d9d746 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Fri, 14 Aug 2026 16:46:09 +0300 Subject: [PATCH] Add std::format helpers for pointers, optional, variant, and support an extension mechanism using format_impl() that doesn't require manually specializing std::formatter --- libs/util/include/psemek/util/format.hpp | 118 +++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 libs/util/include/psemek/util/format.hpp diff --git a/libs/util/include/psemek/util/format.hpp b/libs/util/include/psemek/util/format.hpp new file mode 100644 index 00000000..3dfc0deb --- /dev/null +++ b/libs/util/include/psemek/util/format.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include + +namespace psemek::util +{ + + template + concept has_format_impl = requires (T x, std::format_context & format_context) + { + format_impl(x, format_context); + }; + +} + +namespace std +{ + + template + requires ::psemek::util::has_format_impl + struct formatter + { + constexpr auto parse(std::format_parse_context & ctx) const + { + return ctx.begin(); + } + + template + auto format(T const & x, FormatContext & ctx) const + { + return format_impl(x, ctx); + } + }; + + template + requires (!std::is_same_v && !std::is_same_v) + struct formatter + : formatter + { + using base = formatter; + + template + 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 + struct formatter, Char> + : formatter + { + using base = formatter; + + template + auto format(unique_ptr const & ptr, FormatContext & ctx) const + { + if (ptr) + return base::format((void *)ptr.get(), ctx); + else + return std::format_to(ctx.out(), "(null)"); + } + }; + + template + struct formatter, Char> + : formatter + { + using base = formatter; + + template + auto format(shared_ptr const & ptr, FormatContext & ctx) const + { + if (ptr) + return base::format((void *)ptr.get(), ctx); + else + return std::format_to(ctx.out(), "(null)"); + } + }; + + template + struct formatter, Char> + : formatter + { + using base = formatter; + + template + auto format(optional const & opt, FormatContext & ctx) const + { + if (opt) + return base::format(*opt, ctx); + else + return std::format_to(ctx.out(), "(none)"); + } + }; + + template + struct formatter, Char> + { + constexpr auto parse(std::format_parse_context & ctx) const + { + return ctx.begin(); + } + + template + auto format(variant const & v, FormatContext & ctx) const + { + return std::visit([&ctx](auto const & v){ return std::format_to(ctx.out(), "{}", v); }, v); + } + }; + +}