From 31e4c4d5e465f7dc8ea0bf1d18faedcf56a41347 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 27 Nov 2022 21:45:52 +0800 Subject: [PATCH] add: [imp] tag_invoke for fmt --- include/libimp/fmt.h | 31 +++++++++++++++++++++++++++++-- include/libimp/generic.h | 23 +++++++++++++++++++++++ include/libimp/log.h | 9 +++++++++ src/libimp/fmt.cpp | 6 +++++- 4 files changed, 66 insertions(+), 3 deletions(-) diff --git a/include/libimp/fmt.h b/include/libimp/fmt.h index 9906982..c35c68f 100644 --- a/include/libimp/fmt.h +++ b/include/libimp/fmt.h @@ -17,6 +17,7 @@ #include "libimp/span.h" #include "libimp/detect_plat.h" #include "libimp/export.h" +#include "libimp/generic.h" LIBIMP_NAMESPACE_BEG_ @@ -34,17 +35,31 @@ auto spec(char const (&fstr)[N]) noexcept { }; } +namespace detail { + +struct fmt_to_string_t { + template + std::string operator()(T &&arg) const { + return ::LIBIMP::tag_invoke(fmt_to_string_t{}, std::forward(arg)); + } +}; + +} // namespace detail + +constexpr detail::fmt_to_string_t fmt_to_string {}; + template std::string fmt(A &&...args) { std::string joined; LIBIMP_UNUSED auto unfold = { - joined.append(to_string(std::forward(args)))... + joined.append(fmt_to_string(std::forward(args)))... }; return joined; } /// @brief Return the string directly. -LIBIMP_EXPORT std::string const &to_string(std::string const &a) noexcept; +LIBIMP_EXPORT std::string to_string(std::string const &a) noexcept; +LIBIMP_EXPORT std::string to_string(std::string &&a) noexcept; LIBIMP_EXPORT std::string to_string(std::string const &a, span fstr) noexcept; /// @brief Character to string conversion. @@ -92,4 +107,16 @@ LIBIMP_EXPORT std::string to_string(std::chrono::time_point con return detail::time_to_string(std::chrono::system_clock::to_time_t(a), fstr); } +/** + * @brief Predefined fmt_to_string method + */ +namespace detail { + +template +auto tag_invoke(fmt_to_string_t, T &&arg) noexcept + -> decltype(::LIBIMP::to_string(std::forward(arg))) { + return ::LIBIMP::to_string(std::forward(arg)); +} + +} // namespace detail LIBIMP_NAMESPACE_END_ diff --git a/include/libimp/generic.h b/include/libimp/generic.h index 643069a..80932ac 100644 --- a/include/libimp/generic.h +++ b/include/libimp/generic.h @@ -6,6 +6,8 @@ */ #pragma once +#include + #include "libimp/def.h" LIBIMP_NAMESPACE_BEG_ @@ -17,4 +19,25 @@ LIBIMP_NAMESPACE_BEG_ template using void_t = void; +/** + * @brief A general pattern for supporting customisable functions + * @see https://www.open-std.org/jtc1/sc22/WG21/docs/papers/2019/p1895r0.pdf +*/ +namespace detail { + +void tag_invoke(); + +struct tag_invoke_t { + template + constexpr auto operator()(T tag, A &&...args) const + noexcept(noexcept(tag_invoke(std::forward(tag), std::forward(args)...))) + -> decltype(tag_invoke(std::forward(tag), std::forward(args)...)) { + return tag_invoke(std::forward(tag), std::forward(args)...); + } +}; + +} // namespace detail + +constexpr detail::tag_invoke_t tag_invoke {}; + LIBIMP_NAMESPACE_END_ diff --git a/include/libimp/log.h b/include/libimp/log.h index dbb8555..df9b794 100644 --- a/include/libimp/log.h +++ b/include/libimp/log.h @@ -17,6 +17,7 @@ #include "libimp/detect_plat.h" #include "libimp/export.h" #include "libimp/enum_cast.h" +#include "libimp/fmt.h" LIBIMP_NAMESPACE_BEG_ namespace log { @@ -39,6 +40,14 @@ struct context { LIBIMP_EXPORT std::string to_string(context &&) noexcept; +/** + * @brief Custom defined fmt_to_string method for imp::fmt + */ +template +std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), context &&arg) noexcept { + return ::LIBIMP::log::to_string(std::move(arg)); +} + } // namespace log namespace detail_log { diff --git a/src/libimp/fmt.cpp b/src/libimp/fmt.cpp index f9da2e1..9db9e13 100644 --- a/src/libimp/fmt.cpp +++ b/src/libimp/fmt.cpp @@ -98,10 +98,14 @@ std::string sprintf(F fop, span fstr, span s, A a) noexc } // namespace -std::string const &to_string(std::string const &a) noexcept { +std::string to_string(std::string const &a) noexcept { return a; } +std::string to_string(std::string &&a) noexcept { + return std::move(a); +} + std::string to_string(std::string const &a, span fstr) noexcept { if (a.empty()) return {}; return ::LIBIMP::sprintf(fmt_of, fstr, "s", a.c_str());