diff --git a/include/libimp/byte.h b/include/libimp/byte.h index aa0c405..5bf2b6c 100644 --- a/include/libimp/byte.h +++ b/include/libimp/byte.h @@ -10,10 +10,10 @@ #include #include // std::byte (since C++17) -#include "fmt/format.h" - #include "libimp/def.h" #include "libimp/detect_plat.h" +#include "libimp/span.h" +#include "libimp/fmt.h" #if defined(LIBIMP_CPP_17) && defined(__cpp_lib_byte) #define LIBIMP_CPP_LIB_BYTE_ @@ -46,7 +46,7 @@ class byte { public: constexpr byte() noexcept : byte(0) {} - + template > constexpr byte(T v) noexcept : bits_(static_cast(v)) {} @@ -155,15 +155,27 @@ U *byte_cast(byte const *p) noexcept { return reinterpret_cast(p); } -LIBIMP_NAMESPACE_END_ +/// @brief Converts a span into a view of its underlying bytes. +/// @see https://en.cppreference.com/w/cpp/container/span/as_bytes -template <> -struct fmt::formatter<::LIBIMP::byte> { - constexpr auto parse(format_parse_context& ctx) const { - return ctx.end(); - } - template - auto format(::LIBIMP::byte b, FormatContext &ctx) { - return format_to(ctx.out(), "{:#04x}", static_cast(b)); - } -}; +template ::value, byte const, byte>::type> +auto as_bytes(span s) noexcept -> span { + return {byte_cast(s.data()), s.size_bytes()}; +} + +/// @brief Custom defined fmt_to_string method for imp::fmt +namespace detail { + +inline std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), ::LIBIMP::byte b) { + return ::LIBIMP::to_string(static_cast(b), "02x"); +} + +template , ::LIBIMP::byte>::value>> +std::string tag_invoke(fmt_to_string_t, fmt_ref arg) noexcept { + return ::LIBIMP::to_string(static_cast(arg.param), arg.fstr); +} + +} // namespace detail +LIBIMP_NAMESPACE_END_ diff --git a/include/libimp/fmt.h b/include/libimp/fmt.h index 6e5dd9d..b76f715 100644 --- a/include/libimp/fmt.h +++ b/include/libimp/fmt.h @@ -14,10 +14,10 @@ #include // std::tm #include "libimp/def.h" +#include "libimp/fmt_cpo.h" #include "libimp/span.h" #include "libimp/detect_plat.h" #include "libimp/export.h" -#include "libimp/generic.h" LIBIMP_NAMESPACE_BEG_ @@ -35,19 +35,6 @@ 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; diff --git a/include/libimp/fmt_cpo.h b/include/libimp/fmt_cpo.h new file mode 100644 index 0000000..dd5bb28 --- /dev/null +++ b/include/libimp/fmt_cpo.h @@ -0,0 +1,32 @@ +/** + * @file libimp/fmt_cpo.h + * @author mutouyun (orz@orzz.org) + * @brief String formatting CPO. + * @date 2022-11-28 + */ +#pragma once + +#include + +#include "libimp/def.h" +#include "libimp/generic.h" + +LIBIMP_NAMESPACE_BEG_ + +/** + * @brief Supports custom fmt_to_string methods for imp::fmt. + */ +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 {}; + +LIBIMP_NAMESPACE_END_ diff --git a/include/libimp/result.h b/include/libimp/result.h index 8603d62..158a519 100644 --- a/include/libimp/result.h +++ b/include/libimp/result.h @@ -10,8 +10,6 @@ #include #include -#include "fmt/format.h" - #include "libimp/def.h" #include "libimp/detect_plat.h" #include "libimp/export.h" @@ -75,10 +73,6 @@ struct default_traits::value>> { static std::string format(result const &r) noexcept { return fmt(*r); } - template - static auto format(result const &r, Out &&out) noexcept { - return format_to(out, format(r)); - } }; template @@ -97,10 +91,6 @@ struct default_traits::value>> { } return fmt(static_cast(*r), ", code = ", r.code_value()); } - template - static auto format(result const &r, Out &&out) noexcept { - return format_to(out, format(r)); - } }; } // namespace detail_result @@ -168,35 +158,14 @@ public: /// @brief Custom defined fmt_to_string method for imp::fmt namespace detail { -inline std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), result_code r) noexcept { +inline std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), result_code r) { return fmt("[", (r ? "succ" : "fail"), ", value = ", *r, "]"); } template -std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), result r) noexcept { +std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), result r) { return fmt("[", (r ? "succ" : "fail"), ", value = ", result::default_traits_t::format(r), "]"); } } // namespace detail LIBIMP_NAMESPACE_END_ - -template -struct fmt::formatter<::LIBIMP::result> { - constexpr auto parse(format_parse_context& ctx) const { - return ctx.end(); - } - template - auto format(::LIBIMP::result r, FormatContext &ctx) { - return format_to(::LIBIMP::result::default_traits_t::format(r, - format_to(ctx.out(), "[{}, value = ", r ? "succ" : "fail")), "]"); - } -}; - -template <> -struct fmt::formatter<::LIBIMP::result_code> - : formatter<::LIBIMP::result<::LIBIMP::result_type>> { - template - auto format(::LIBIMP::result_code r, FormatContext &ctx) { - return format_to(ctx.out(), "[{}, value = {}]", (r ? "succ" : "fail"), *r); - } -}; diff --git a/include/libimp/span.h b/include/libimp/span.h index 1e61326..ec88c37 100644 --- a/include/libimp/span.h +++ b/include/libimp/span.h @@ -17,11 +17,9 @@ #include #include -#include "fmt/format.h" - #include "libimp/def.h" #include "libimp/detect_plat.h" -#include "libimp/byte.h" +#include "libimp/fmt_cpo.h" #if defined(LIBIMP_CPP_20) && defined(__cpp_lib_span) #include @@ -222,15 +220,6 @@ bool operator==(span a, span b) noexcept { return true; } -/// @brief Converts a span into a view of its underlying bytes. -/// @see https://en.cppreference.com/w/cpp/container/span/as_bytes - -template ::value, byte const, byte>::type> -auto as_bytes(span s) noexcept -> span { - return {byte_cast(s.data()), s.size_bytes()}; -} - /// @brief Constructs an object of type T and wraps it in a span. /// Before C++17, template argument deduction for class templates was not supported. /// @see https://en.cppreference.com/w/cpp/language/template_argument_deduction @@ -278,22 +267,20 @@ inline auto make_span(std::string const &str) noexcept -> span { return {str.data(), str.size()}; } -LIBIMP_NAMESPACE_END_ +/// @brief Custom defined fmt_to_string method for imp::fmt +namespace detail { template -struct fmt::formatter<::LIBIMP::span> { - constexpr auto parse(format_parse_context& ctx) const { - return ctx.end(); +std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), span s) { + if (s.empty()) { + return {}; } - template - auto format(::LIBIMP::span s, FormatContext &ctx) { - if (s.empty()) { - return format_to(ctx.out(), ""); - } - auto appender = format_to(ctx.out(), "{}", s[0]); - for (std::size_t i = 1; i < s.size(); ++i) { - appender = format_to(appender, " {}", s[i]); - } - return appender; + auto appender = fmt(s[0]); + for (std::size_t i = 1; i < s.size(); ++i) { + appender += fmt(' ', s[i]); } -}; + return appender; +} + +} // namespace detail +LIBIMP_NAMESPACE_END_ diff --git a/include/libimp/system.h b/include/libimp/system.h index ce207c6..69ab783 100644 --- a/include/libimp/system.h +++ b/include/libimp/system.h @@ -13,7 +13,7 @@ #include "libimp/def.h" #include "libimp/export.h" #include "libimp/result.h" -#include "libimp/fmt.h" +#include "libimp/fmt_cpo.h" LIBIMP_NAMESPACE_BEG_ namespace sys { @@ -73,12 +73,3 @@ inline std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), error r) noexce } // namespace sys LIBIMP_NAMESPACE_END_ - -template <> -struct fmt::formatter<::LIBIMP::sys::error> - : formatter { - template - auto format(::LIBIMP::sys::error r, FormatContext &ctx) { - return format_to(ctx.out(), ::LIBIMP::sys::error_msg(r.code())); - } -}; diff --git a/src/libimp/CMakeLists.txt b/src/libimp/CMakeLists.txt index f21db72..bcd46f0 100644 --- a/src/libimp/CMakeLists.txt +++ b/src/libimp/CMakeLists.txt @@ -29,8 +29,6 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${LIBIPC_PROJECT_DIR}/include PRIVATE ${LIBIPC_PROJECT_DIR}/src) -target_link_libraries(${PROJECT_NAME} PUBLIC fmt) - install( TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin diff --git a/test/imp/test_imp_byte.cpp b/test/imp/test_imp_byte.cpp index ad2fd37..b8f9e26 100644 --- a/test/imp/test_imp_byte.cpp +++ b/test/imp/test_imp_byte.cpp @@ -3,6 +3,7 @@ #include "libimp/byte.h" #include "libimp/span.h" +#include "libimp/fmt.h" TEST(byte, construct) { { @@ -38,13 +39,13 @@ TEST(byte, compare) { TEST(byte, fmt) { { imp::byte b1, b2(31); - EXPECT_EQ(fmt::format("{}", b1), "0x00"); - EXPECT_EQ(fmt::format("{}", b2), "0x1f"); + EXPECT_EQ(imp::fmt(b1), "00"); + EXPECT_EQ(imp::fmt(b2), "1f"); + EXPECT_EQ(imp::fmt(imp::spec("03X")(b2)), "01F"); } { imp::byte bs[] {31, 32, 33, 34, 35, 36, 37, 38}; - EXPECT_EQ(fmt::format("{}", imp::make_span(bs)), - "0x1f 0x20 0x21 0x22 0x23 0x24 0x25 0x26"); + EXPECT_EQ(imp::fmt(imp::make_span(bs)), "1f 20 21 22 23 24 25 26"); } } diff --git a/test/imp/test_imp_result.cpp b/test/imp/test_imp_result.cpp index e79600f..162264c 100644 --- a/test/imp/test_imp_result.cpp +++ b/test/imp/test_imp_result.cpp @@ -2,9 +2,9 @@ #include #include "gtest/gtest.h" -#include "fmt/format.h" #include "libimp/result.h" +#include "libimp/fmt.h" TEST(result, ok) { imp::result_code ret; @@ -59,23 +59,23 @@ TEST(result, compare) { TEST(result, fmt) { { imp::result_code r1; - EXPECT_EQ(fmt::format("{}", r1), "[fail, value = 0]"); + EXPECT_EQ(imp::fmt(r1), "[fail, value = 0]"); imp::result_code r2(true, 65537); - EXPECT_EQ(fmt::format("{}", r2), "[succ, value = 65537]"); + EXPECT_EQ(imp::fmt(r2), "[succ, value = 65537]"); imp::result_code r3(0); - EXPECT_EQ(fmt::format("{}", r3), "[succ, value = 0]"); + EXPECT_EQ(imp::fmt(r3), "[succ, value = 0]"); } { imp::result r1 {false, -123}; - EXPECT_EQ(fmt::format("{}", r1), fmt::format("[fail, value = {}]", -123)); + EXPECT_EQ(imp::fmt(r1), imp::fmt("[fail, value = ", -123, "]")); imp::result r2 {&r1}; - EXPECT_EQ(fmt::format("{}", r2), imp::fmt("[succ, value = ", (void *)&r1, "]")); + EXPECT_EQ(imp::fmt(r2), imp::fmt("[succ, value = ", (void *)&r1, "]")); int aaa {}; imp::result r3 {&aaa}; - EXPECT_EQ(fmt::format("{}", r3), imp::fmt("[succ, value = ", (void *)&aaa, "]")); + EXPECT_EQ(imp::fmt(r3), imp::fmt("[succ, value = ", (void *)&aaa, "]")); imp::result r4 {nullptr}; - EXPECT_EQ(fmt::format("{}", r4), imp::fmt("[fail, value = ", nullptr, ", code = 0]")); + EXPECT_EQ(imp::fmt(r4), imp::fmt("[fail, value = ", nullptr, ", code = 0]")); r4 = {nullptr, 1234}; - EXPECT_EQ(fmt::format("{}", r4), imp::fmt("[fail, value = ", nullptr, ", code = 1234]")); + EXPECT_EQ(imp::fmt(r4), imp::fmt("[fail, value = ", nullptr, ", code = 1234]")); } } \ No newline at end of file diff --git a/test/imp/test_imp_span.cpp b/test/imp/test_imp_span.cpp index f49ae25..630bca2 100644 --- a/test/imp/test_imp_span.cpp +++ b/test/imp/test_imp_span.cpp @@ -6,6 +6,8 @@ #include "libimp/span.h" #include "libimp/countof.h" +#include "libimp/byte.h" +#include "libimp/fmt.h" TEST(span, to_address) { int *a = new int; @@ -56,6 +58,6 @@ TEST(span, span) { } TEST(span, fmt) { - EXPECT_EQ(fmt::format("{}", imp::span{}), ""); - EXPECT_EQ(fmt::format("{}", imp::make_span({1, 3, 2, 4, 5, 6, 7})), "1 3 2 4 5 6 7"); + EXPECT_EQ(imp::fmt(imp::span{}), ""); + EXPECT_EQ(imp::fmt(imp::make_span({1, 3, 2, 4, 5, 6, 7})), "1 3 2 4 5 6 7"); } \ No newline at end of file diff --git a/test/imp/test_imp_system.cpp b/test/imp/test_imp_system.cpp index d4128ed..b3d46c2 100644 --- a/test/imp/test_imp_system.cpp +++ b/test/imp/test_imp_system.cpp @@ -3,11 +3,11 @@ #include #include "gtest/gtest.h" -#include "fmt/format.h" #include "libimp/system.h" #include "libimp/detect_plat.h" #include "libimp/codecvt.h" +#include "libimp/fmt.h" #if defined(LIBIMP_OS_WIN) #include @@ -25,11 +25,11 @@ TEST(system, error_code) { imp::sys::error e_obj {err}; EXPECT_EQ(err.value(), e_obj.value()); - auto e_msg = fmt::format("{}", imp::sys::error_msg(imp::sys::error_code())); + auto e_msg = imp::fmt(imp::sys::error_msg(imp::sys::error_code())); std::stringstream ss; ss << imp::sys::error{}; EXPECT_EQ(e_msg, ss.str()); - EXPECT_EQ(e_msg, fmt::format("{}", imp::sys::error())); + EXPECT_EQ(e_msg, imp::fmt(imp::sys::error())); std::cout << e_msg << "\n"; }