From a62e624d71db70c5a02d42936114d0a9a5284626 Mon Sep 17 00:00:00 2001 From: Ken Matsui <26405363+ken-matsui@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:53:26 -0500 Subject: [PATCH 1/2] Format by clang-format-21 --- .github/workflows/cpp.yml | 8 +- include/mitama/maybe/factory/just_nothing.hpp | 15 +- include/mitama/maybe/maybe.hpp | 38 +++-- include/mitama/panic.hpp | 10 +- include/mitama/result/detail/result_impl.hpp | 37 +++-- include/mitama/result/factory/failure.hpp | 15 +- include/mitama/result/factory/success.hpp | 15 +- include/mitama/result/result.hpp | 140 +++++++++--------- include/mitama/thiserror/thiserror.hpp | 16 +- test/maybe_tests.cpp | 21 ++- test/result_tests.cpp | 34 +++-- test/special_member_tests.hpp | 26 +++- 12 files changed, 220 insertions(+), 155 deletions(-) diff --git a/.github/workflows/cpp.yml b/.github/workflows/cpp.yml index 7899567e..9a32c9db 100644 --- a/.github/workflows/cpp.yml +++ b/.github/workflows/cpp.yml @@ -17,12 +17,12 @@ jobs: steps: - uses: actions/checkout@v6 - - name: Install clang-format + - name: Install clang-format-21 run: | wget https://apt.llvm.org/llvm.sh chmod +x ./llvm.sh - sudo ./llvm.sh 19 - sudo apt-get install -y clang-format-19 + sudo ./llvm.sh 21 + sudo apt-get install -y clang-format-21 - name: Install Cabin run: | @@ -34,7 +34,7 @@ jobs: eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" cabin fmt --check --verbose env: - CABIN_FMT: clang-format-19 + CABIN_FMT: clang-format-21 lint: runs-on: ubuntu-24.04 diff --git a/include/mitama/maybe/factory/just_nothing.hpp b/include/mitama/maybe/factory/just_nothing.hpp index b5d3b4e5..85179a9c 100644 --- a/include/mitama/maybe/factory/just_nothing.hpp +++ b/include/mitama/maybe/factory/just_nothing.hpp @@ -117,7 +117,8 @@ class [[nodiscard]] just_t template requires not_self>::value && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr just_t(U&& u + explicit constexpr just_t( + U&& u ) noexcept(std::is_nothrow_constructible_v) : x(std::forward(u)) { @@ -126,7 +127,8 @@ class [[nodiscard]] just_t template requires(!std::is_same_v) && std::is_constructible_v && std::is_convertible_v - constexpr just_t(const just_t& t + constexpr just_t( + const just_t& t ) noexcept(std::is_nothrow_constructible_v) : x(t.get()) { @@ -135,7 +137,8 @@ class [[nodiscard]] just_t template requires(!std::is_same_v) && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr just_t(const just_t& t + explicit constexpr just_t( + const just_t& t ) noexcept(std::is_nothrow_constructible_v) : x(t.get()) { @@ -144,7 +147,8 @@ class [[nodiscard]] just_t template requires(!std::is_same_v) && std::is_constructible_v && std::is_convertible_v - constexpr just_t(just_t&& t + constexpr just_t( + just_t&& t ) noexcept(std::is_nothrow_constructible_v) : x(std::move(t.get())) { @@ -153,7 +157,8 @@ class [[nodiscard]] just_t template requires(!std::is_same_v) && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr just_t(just_t&& t + explicit constexpr just_t( + just_t&& t ) noexcept(std::is_nothrow_constructible_v) : x(std::move(t.get())) { diff --git a/include/mitama/maybe/maybe.hpp b/include/mitama/maybe/maybe.hpp index 86c00fe5..43f65cf7 100644 --- a/include/mitama/maybe/maybe.hpp +++ b/include/mitama/maybe/maybe.hpp @@ -163,8 +163,8 @@ class maybe_cloned_injector> public: constexpr maybe> cloned() const { - auto decay_copy = [](auto&& some - ) -> std::remove_const_t> + auto decay_copy = + [](auto&& some) -> std::remove_const_t> { return std::forward(some); }; const auto* self = static_cast*>(this); return self->is_just() ? maybe>{ just( @@ -471,11 +471,13 @@ class maybe : public maybe_transpose_injector>, constexpr auto map(F&& f, Args&&... args) & { using result_type = std::invoke_result_t; - return is_just() - ? maybe{ just(std::invoke( - std::forward(f), unwrap(), std::forward(args)... - )) } - : nothing; + return is_just() ? maybe{ just( + std::invoke( + std::forward(f), unwrap(), + std::forward(args)... + ) + ) } + : nothing; } template @@ -483,11 +485,13 @@ class maybe : public maybe_transpose_injector>, constexpr auto map(F&& f, Args&&... args) const& { using result_type = std::invoke_result_t; - return is_just() - ? maybe{ just(std::invoke( - std::forward(f), unwrap(), std::forward(args)... - )) } - : nothing; + return is_just() ? maybe{ just( + std::invoke( + std::forward(f), unwrap(), + std::forward(args)... + ) + ) } + : nothing; } template @@ -495,10 +499,12 @@ class maybe : public maybe_transpose_injector>, constexpr auto map(F&& f, Args&&... args) && { using result_type = std::invoke_result_t; - return is_just() ? maybe{ just(std::invoke( - std::forward(f), std::move(unwrap()), - std::forward(args)... - )) } + return is_just() ? maybe{ just( + std::invoke( + std::forward(f), std::move(unwrap()), + std::forward(args)... + ) + ) } : nothing; } diff --git a/include/mitama/panic.hpp b/include/mitama/panic.hpp index d8c2ac4c..0560c3e8 100644 --- a/include/mitama/panic.hpp +++ b/include/mitama/panic.hpp @@ -84,10 +84,12 @@ class runtime_panic : public std::runtime_error const std::source_location& loc, fmt::format_string f, Args&&... args ) noexcept - : std::runtime_error(fmt::format( - "runtime panicked at '{}', {}", - fmt::format(f, std::forward(args)...), loc - )) + : std::runtime_error( + fmt::format( + "runtime panicked at '{}', {}", + fmt::format(f, std::forward(args)...), loc + ) + ) { } }; diff --git a/include/mitama/result/detail/result_impl.hpp b/include/mitama/result/detail/result_impl.hpp index 4e20cdd3..47b26fd7 100644 --- a/include/mitama/result/detail/result_impl.hpp +++ b/include/mitama/result/detail/result_impl.hpp @@ -76,8 +76,8 @@ class transpose_friend_injector, E>> /// otherwise; if failure, returns the default value for that type. constexpr maybe> transpose() const& { - if (static_cast, E>*>(this)->is_ok( - )) + if (static_cast, E>*>(this) + ->is_ok()) { if (const auto& may = static_cast, E>*>(this) @@ -801,8 +801,8 @@ class map_err_apply_friend_injector> ))>; return static_cast*>(this)->is_ok() ? static_cast(success_t{ - static_cast*>(this)->unwrap( - ) }) + static_cast*>(this) + ->unwrap() }) : static_cast(failure_t{ std::apply( std::forward(op), std::tuple_cat( @@ -831,8 +831,10 @@ class map_err_apply_friend_injector> : static_cast(failure_t{ std::apply( std::forward(op), std::tuple_cat( - std::move(static_cast*>(this) - ->unwrap_err()), + std::move( + static_cast*>(this) + ->unwrap_err() + ), std::forward_as_tuple(std::forward(args))... ) ) }); @@ -913,10 +915,10 @@ class and_then_apply_friend_injector> std::forward_as_tuple(std::forward(args))... ) )) - : static_cast( - failure(static_cast*>(this) - ->unwrap_err()) - ); + : static_cast(failure( + static_cast*>(this) + ->unwrap_err() + )); } template @@ -943,14 +945,19 @@ class and_then_apply_friend_injector> ? static_cast(std::apply( std::forward(op), std::tuple_cat( - std::move(static_cast*>(this) - ->unwrap()), + std::move( + static_cast*>(this) + ->unwrap() + ), std::forward_as_tuple(std::forward(args)...) ) )) - : static_cast(failure(std::move( - static_cast*>(this)->unwrap_err() - ))); + : static_cast(failure( + std::move( + static_cast*>(this) + ->unwrap_err() + ) + )); } }; diff --git a/include/mitama/result/factory/failure.hpp b/include/mitama/result/factory/failure.hpp index ba0ed96d..47c36f8c 100644 --- a/include/mitama/result/factory/failure.hpp +++ b/include/mitama/result/factory/failure.hpp @@ -44,7 +44,8 @@ class [[nodiscard]] failure_t template requires not_self>::value && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr failure_t(U&& u + explicit constexpr failure_t( + U&& u ) noexcept(std::is_nothrow_constructible_v) : x(std::forward(u)) { @@ -53,7 +54,8 @@ class [[nodiscard]] failure_t template requires(!std::is_same_v) && std::is_constructible_v && std::is_convertible_v - constexpr failure_t(const failure_t& t + constexpr failure_t( + const failure_t& t ) noexcept(std::is_nothrow_constructible_v) : x(t.get()) { @@ -62,7 +64,8 @@ class [[nodiscard]] failure_t template requires(!std::is_same_v) && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr failure_t(const failure_t& t + explicit constexpr failure_t( + const failure_t& t ) noexcept(std::is_nothrow_constructible_v) : x(t.get()) { @@ -71,7 +74,8 @@ class [[nodiscard]] failure_t template requires(!std::is_same_v) && std::is_constructible_v && std::is_convertible_v - constexpr failure_t(failure_t&& t + constexpr failure_t( + failure_t&& t ) noexcept(std::is_nothrow_constructible_v) : x(std::move(t.get())) { @@ -80,7 +84,8 @@ class [[nodiscard]] failure_t template requires(!std::is_same_v) && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr failure_t(failure_t&& t + explicit constexpr failure_t( + failure_t&& t ) noexcept(std::is_nothrow_constructible_v) : x(std::move(t.get())) { diff --git a/include/mitama/result/factory/success.hpp b/include/mitama/result/factory/success.hpp index cb144956..dd8ab2ee 100644 --- a/include/mitama/result/factory/success.hpp +++ b/include/mitama/result/factory/success.hpp @@ -44,7 +44,8 @@ class [[nodiscard]] success_t template requires not_self>::value && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr success_t(U&& u + explicit constexpr success_t( + U&& u ) noexcept(std::is_nothrow_constructible_v) : x(std::forward(u)) { @@ -53,7 +54,8 @@ class [[nodiscard]] success_t template requires(!std::is_same_v) && std::is_constructible_v && std::is_convertible_v - constexpr success_t(const success_t& t + constexpr success_t( + const success_t& t ) noexcept(std::is_nothrow_constructible_v) : x(t.get()) { @@ -62,7 +64,8 @@ class [[nodiscard]] success_t template requires(!std::is_same_v) && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr success_t(const success_t& t + explicit constexpr success_t( + const success_t& t ) noexcept(std::is_nothrow_constructible_v) : x(t.get()) { @@ -71,7 +74,8 @@ class [[nodiscard]] success_t template requires(!std::is_same_v) && std::is_constructible_v && std::is_convertible_v - constexpr success_t(success_t&& t + constexpr success_t( + success_t&& t ) noexcept(std::is_nothrow_constructible_v) : x(std::move(t.get())) { @@ -80,7 +84,8 @@ class [[nodiscard]] success_t template requires(!std::is_same_v) && std::is_constructible_v && (!std::is_convertible_v) - explicit constexpr success_t(success_t&& t + explicit constexpr success_t( + success_t&& t ) noexcept(std::is_nothrow_constructible_v) : x(std::move(t.get())) { diff --git a/include/mitama/result/result.hpp b/include/mitama/result/result.hpp index d70a4581..27dc4d9a 100644 --- a/include/mitama/result/result.hpp +++ b/include/mitama/result/result.hpp @@ -259,8 +259,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// move assignment operator for convertible basic_result template requires std::is_constructible_v && std::is_constructible_v - MITAMA_VARIANT_CONSTEXPR basic_result& operator=(basic_result<_mu, U, F>&& res - ) + MITAMA_VARIANT_CONSTEXPR basic_result& + operator=(basic_result<_mu, U, F>&& res) { static_assert( is_mut_v<_mutability>, "Error: assignment to immutable result" @@ -673,8 +673,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// This function can be used to compose the results of two functions. /// result -> result template - constexpr auto - map(O&& op, Args&&... args + constexpr auto map( + O&& op, Args&&... args ) const& noexcept(std::is_nothrow_invocable_v) -> basic_result< _mutability, @@ -836,9 +836,10 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// This function can be used to unpack a successful result while handling /// an error. template - constexpr auto map_or_else( - Fallback&& _fallback, Map&& _map - ) & noexcept(std::is_nothrow_invocable_v && std::is_nothrow_invocable_v) + constexpr auto map_or_else(Fallback&& _fallback, Map&& _map) & noexcept( + std::is_nothrow_invocable_v + && std::is_nothrow_invocable_v + ) -> std::common_type_t< std::invoke_result_t, std::invoke_result_t> requires std::is_invocable_v && std::is_invocable_v @@ -875,9 +876,10 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// This function can be used to unpack a successful result while handling /// an error. template - constexpr auto map_or_else( - Fallback&& _fallback, Map&& _map - ) const& noexcept(std::is_nothrow_invocable_v && std::is_nothrow_invocable_v) + constexpr auto map_or_else(Fallback&& _fallback, Map&& _map) const& noexcept( + std::is_nothrow_invocable_v + && std::is_nothrow_invocable_v + ) -> std::common_type_t< std::invoke_result_t, std::invoke_result_t> requires std::is_invocable_v && std::is_invocable_v @@ -914,9 +916,10 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// This function can be used to unpack a successful result while handling /// an error. template - constexpr auto map_or_else( - Fallback&& _fallback, Map&& _map - ) && noexcept(std::is_nothrow_invocable_v && std::is_nothrow_invocable_v) + constexpr auto map_or_else(Fallback&& _fallback, Map&& _map) && noexcept( + std::is_nothrow_invocable_v + && std::is_nothrow_invocable_v + ) -> std::common_type_t< std::invoke_result_t, std::invoke_result_t> requires std::is_invocable_v && std::is_invocable_v @@ -950,11 +953,12 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// This function can be used to pass through a successful result while /// handling an error. result -> result template - constexpr auto map_err(O&& op, Args&&... args) - const& noexcept(std::is_nothrow_invocable_v) - -> basic_result< - _mutability, T, - void_to_monostate_t>> + constexpr auto map_err( + O&& op, Args&&... args + ) const& noexcept(std::is_nothrow_invocable_v) + -> basic_result< + _mutability, T, + void_to_monostate_t>> requires std::is_invocable_v { using result_type = basic_result< @@ -990,11 +994,12 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// This function can be used to pass through a successful result while /// handling an error. result -> result template - constexpr auto map_err(O&& op, Args&&... args) - const& noexcept(std::is_nothrow_invocable_v) - -> basic_result< - _mutability, T, - void_to_monostate_t>> + constexpr auto map_err( + O&& op, Args&&... args + ) const& noexcept(std::is_nothrow_invocable_v) + -> basic_result< + _mutability, T, + void_to_monostate_t>> requires std::is_same_v && std::is_invocable_v { @@ -1107,9 +1112,9 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// @note /// This function can be used for control flow based on result values. template - constexpr auto and_then(O&& op, Args&&... args) - const& noexcept(std::is_nothrow_invocable_v) - -> std::invoke_result_t + constexpr auto and_then(O&& op, Args&&... args) const& noexcept( + std::is_nothrow_invocable_v + ) -> std::invoke_result_t requires is_convertible_result_with_v< std::invoke_result_t, failure_t> { @@ -1134,10 +1139,9 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// @note /// This function can be used for control flow based on result values. template - constexpr auto and_then( - O&& op, Args&&... args - ) && noexcept(std::is_nothrow_invocable_v) - -> std::invoke_result_t + constexpr auto and_then(O&& op, Args&&... args) && noexcept( + std::is_nothrow_invocable_v + ) -> std::invoke_result_t requires is_convertible_result_with_v< std::invoke_result_t, failure_t> { @@ -1162,9 +1166,9 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// @note /// This function can be used for control flow based on result values. template - constexpr auto or_else(O&& op, Args&&... args) - const& noexcept(std::is_nothrow_invocable_v) - -> std::invoke_result_t + constexpr auto or_else(O&& op, Args&&... args) const& noexcept( + std::is_nothrow_invocable_v + ) -> std::invoke_result_t requires is_convertible_result_with_v< std::invoke_result_t, success_t> { @@ -1188,10 +1192,9 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// @note /// This function can be used for control flow based on result values. template - constexpr auto or_else( - O&& op, Args&&... args - ) && noexcept(std::is_nothrow_invocable_v) - -> std::invoke_result_t + constexpr auto or_else(O&& op, Args&&... args) && noexcept( + std::is_nothrow_invocable_v + ) -> std::invoke_result_t requires is_convertible_result_with_v< std::invoke_result_t, success_t> { @@ -1209,8 +1212,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// Returns `res` if the result is success_t, otherwise; returns the failure /// value of self. template - constexpr decltype(auto) conj(const basic_result<_mu, U, E>& res - ) const& noexcept + constexpr decltype(auto) + conj(const basic_result<_mu, U, E>& res) const& noexcept { using result_type = basic_result<_mutability && _mu, U, E>; return this->is_err() ? static_cast(failure_t{ @@ -1224,8 +1227,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// Returns `res` if the result is success, otherwise; returns the failure /// value of self. template - constexpr decltype(auto) operator&&(const basic_result<_mu, U, E>& res - ) const& noexcept + constexpr decltype(auto) + operator&&(const basic_result<_mu, U, E>& res) const& noexcept { return this->conj(res); } @@ -1240,8 +1243,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// it is recommended to use `or_else`, /// which is lazily evaluated. template - constexpr decltype(auto) disj(const basic_result<_mut, T, F>& res - ) const& noexcept + constexpr decltype(auto) + disj(const basic_result<_mut, T, F>& res) const& noexcept { using result_type = basic_result<_mutability, T, F>; return this->is_ok() ? static_cast(success_t{ @@ -1261,8 +1264,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// it is recommended to use `or_else`, /// which is lazily evaluated. template - constexpr decltype(auto) operator||(const basic_result<_mut, T, F>& res - ) const& noexcept + constexpr decltype(auto) + operator||(const basic_result<_mut, T, F>& res) const& noexcept { return this->disj(res); } @@ -1323,14 +1326,14 @@ class [[nodiscard]] basic_result<_mutability, T, E> /// - otherwise; static_assert. template requires std::is_invocable_r_v || std::is_invocable_r_v - constexpr T unwrap_or_else(O&& op) const - noexcept(std::disjunction_v< - std::conjunction< - std::is_invocable_r, - std::is_nothrow_invocable_r>, - std::conjunction< - std::is_invocable_r, - std::is_nothrow_invocable_r>>) + constexpr T unwrap_or_else(O&& op) const noexcept( + std::disjunction_v< + std::conjunction< + std::is_invocable_r, + std::is_nothrow_invocable_r>, + std::conjunction< + std::is_invocable_r, std::is_nothrow_invocable_r>> + ) { if constexpr (std::is_invocable_r_v) { @@ -1710,8 +1713,9 @@ class [[nodiscard]] basic_result<_mutability, T, E> } template - constexpr auto map_anything_else(F&& f - ) & noexcept(std::is_nothrow_invocable_v && std::is_nothrow_invocable_v) + constexpr auto map_anything_else(F&& f) & noexcept( + std::is_nothrow_invocable_v && std::is_nothrow_invocable_v + ) -> std::common_type_t< std::invoke_result_t, std::invoke_result_t> requires std::is_invocable_v && std::is_invocable_v @@ -1720,9 +1724,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> && std::is_convertible_v< std::invoke_result_t, std::invoke_result_t> { - auto decay_copy = - [](auto&& some - ) -> std::remove_const_t> + auto decay_copy = [](auto&& some) + -> std::remove_const_t> { return std::forward(some); }; return this->map_or_else( decay_copy(std::forward(f)), decay_copy(std::forward(f)) @@ -1730,8 +1733,10 @@ class [[nodiscard]] basic_result<_mutability, T, E> } template - constexpr auto map_anything_else(F&& f - ) const& noexcept(std::is_nothrow_invocable_v && std::is_nothrow_invocable_v) + constexpr auto map_anything_else(F&& f) const& noexcept( + std::is_nothrow_invocable_v + && std::is_nothrow_invocable_v + ) -> std::common_type_t< std::invoke_result_t, std::invoke_result_t> requires std::is_invocable_v @@ -1743,9 +1748,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> std::invoke_result_t, std::invoke_result_t> { - auto decay_copy = - [](auto&& some - ) -> std::remove_const_t> + auto decay_copy = [](auto&& some) + -> std::remove_const_t> { return std::forward(some); }; return this->map_or_else( decay_copy(std::forward(f)), decay_copy(std::forward(f)) @@ -1753,8 +1757,9 @@ class [[nodiscard]] basic_result<_mutability, T, E> } template - constexpr auto map_anything_else(F&& f - ) && noexcept(std::is_nothrow_invocable_v && std::is_nothrow_invocable_v) + constexpr auto map_anything_else(F&& f) && noexcept( + std::is_nothrow_invocable_v && std::is_nothrow_invocable_v + ) -> std::common_type_t< std::invoke_result_t, std::invoke_result_t> requires std::is_invocable_v && std::is_invocable_v @@ -1763,9 +1768,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> && std::is_convertible_v< std::invoke_result_t, std::invoke_result_t> { - auto decay_copy = - [](auto&& some - ) -> std::remove_const_t> + auto decay_copy = [](auto&& some) + -> std::remove_const_t> { return std::forward(some); }; return std::move(*this).map_or_else( decay_copy(std::forward(f)), decay_copy(std::forward(f)) diff --git a/include/mitama/thiserror/thiserror.hpp b/include/mitama/thiserror/thiserror.hpp index 5e9e27d0..29c17da0 100644 --- a/include/mitama/thiserror/thiserror.hpp +++ b/include/mitama/thiserror/thiserror.hpp @@ -60,8 +60,8 @@ struct error final : anyhow::error, ~error() override = default; - std::shared_ptr context(std::shared_ptr ctx - ) override + std::shared_ptr + context(std::shared_ptr ctx) override { return std::make_shared( std::enable_shared_from_this::shared_from_this(), std::move(ctx) @@ -107,11 +107,13 @@ struct fmt::formatter> // Check if reached the end of the range: if (it != end && *it != '}') { - throw format_error(fmt::format( - "invalid format for thiserror: (expected {{}}, found {{:{})", - std::string_view{ it, - static_cast(std::distance(it, end)) } - )); + throw format_error( + fmt::format( + "invalid format for thiserror: (expected {{}}, found {{:{})", + std::string_view{ + it, static_cast(std::distance(it, end)) } + ) + ); } // Return an iterator past the end of the parsed range: diff --git a/test/maybe_tests.cpp b/test/maybe_tests.cpp index 2fbca970..d745b5ce 100644 --- a/test/maybe_tests.cpp +++ b/test/maybe_tests.cpp @@ -57,10 +57,12 @@ TEST_CASE("unwrap()", "[maybe][unwrap]") } catch (const runtime_panic& p) { - REQUIRE(std::string_view{ p.what() }.starts_with( - "runtime panicked at 'called `maybe::unwrap()` on a " - "`nothing` value', " - )); + REQUIRE( + std::string_view{ p.what() }.starts_with( + "runtime panicked at 'called `maybe::unwrap()` on a " + "`nothing` value', " + ) + ); } } @@ -77,9 +79,11 @@ TEST_CASE("expect()", "[maybe][expect]") } catch (const runtime_panic& p) { - REQUIRE(std::string_view{ p.what() }.starts_with( - "runtime panicked at 'the world is ending', " - )); + REQUIRE( + std::string_view{ p.what() }.starts_with( + "runtime panicked at 'the world is ending', " + ) + ); } } @@ -1008,7 +1012,8 @@ TEST_CASE("format test", "[maybe][format]") using namespace std::literals; { std::stringstream ss; - ss << maybe>(just(std::map{ { "foo"s, 1 } }) + ss << maybe>( + just(std::map{ { "foo"s, 1 } }) ); REQUIRE(ss.str() == "just({\"foo\": 1})"s); } diff --git a/test/result_tests.cpp b/test/result_tests.cpp index 04e86178..d47002e0 100644 --- a/test/result_tests.cpp +++ b/test/result_tests.cpp @@ -271,14 +271,18 @@ TEST_CASE("or_else_apply() test", "[result][or_else_apply]") REQUIRE(err2.or_else_apply(fn) == failure(3u)); } -TEMPLATE_TEST_CASE("is_convertible_result_with meta test", "[is_convertible_result_with][meta]", - int, unsigned, std::string, std::vector) +TEMPLATE_TEST_CASE( + "is_convertible_result_with meta test", + "[is_convertible_result_with][meta]", int, unsigned, std::string, + std::vector +) { static_assert(is_convertible_result_with_v< mitama::result, mitama::failure_t>); - static_assert(!is_convertible_result_with_v< - result>, - mitama::failure_t>); + static_assert( + !is_convertible_result_with_v< + result>, mitama::failure_t> + ); } TEST_CASE("disj test", "[result][disj]") @@ -600,8 +604,9 @@ TEST_CASE("format test", "[result][format]") using namespace std::literals; { std::stringstream ss; - ss << result, int>(success(std::map{ - { "foo"s, 1 } })); + ss << result, int>( + success(std::map{ { "foo"s, 1 } }) + ); REQUIRE(ss.str() == "success({\"foo\": 1})"s); } } @@ -621,8 +626,9 @@ TEST_CASE("format test", "[result][format]") using namespace std::literals; { std::stringstream ss; - ss << result>, int>(success(std::vector{ - std::tuple{ 1, 1 }, std::tuple{ 1, 1 } })); + ss << result>, int>( + success(std::vector{ std::tuple{ 1, 1 }, std::tuple{ 1, 1 } }) + ); REQUIRE(ss.str() == "success([(1, 1), (1, 1)])"s); } } @@ -787,9 +793,10 @@ SCENARIO("test for dangling indirect", "[result][indirect][dangling]") ) .as_ref() .indirect(); - REQUIRE(std::is_same_v< - decltype(indirect.unwrap()), - dangling>&>); + REQUIRE( + std::is_same_v< + decltype(indirect.unwrap()), dangling>&> + ); // indirect.unwrap().transmute() // ^~~~~~~~~~~~~~~~~~~~~~~~~~ Undefined Behavior! } @@ -818,7 +825,8 @@ TEST_CASE("incomplete type reference", "[result]") { static_assert(!is_complete_type::value); [[maybe_unused]] result res = - success(get_incomplete_type() + success( + get_incomplete_type() ); // use incomplete_type& for result } diff --git a/test/special_member_tests.hpp b/test/special_member_tests.hpp index 7c45f2ca..e2bcfbab 100644 --- a/test/special_member_tests.hpp +++ b/test/special_member_tests.hpp @@ -584,11 +584,27 @@ struct ma_expected std::is_copy_assignable, std::is_copy_assignable>>; }; -#define SP_MEM_TEST(_1, _2, _3, _4, _5, _6, _7, _8) \ - static_assert(cc_expected, TestClass<_5, _6, _7, _8>>::value == std::is_copy_constructible_v, TestClass<_5, _6, _7, _8>>>); \ - static_assert(ca_expected, TestClass<_5, _6, _7, _8>>::value == std::is_copy_assignable_v, TestClass<_5, _6, _7, _8>>>); \ - static_assert(mc_expected, TestClass<_5, _6, _7, _8>>::value == std::is_move_constructible_v, TestClass<_5, _6, _7, _8>>>); \ - static_assert(ma_expected, TestClass<_5, _6, _7, _8>>::value == std::is_move_assignable_v, TestClass<_5, _6, _7, _8>>>) +#define SP_MEM_TEST(_1, _2, _3, _4, _5, _6, _7, _8) \ + static_assert( \ + cc_expected, TestClass<_5, _6, _7, _8>>::value \ + == std::is_copy_constructible_v< \ + Result, TestClass<_5, _6, _7, _8>>> \ + ); \ + static_assert( \ + ca_expected, TestClass<_5, _6, _7, _8>>::value \ + == std::is_copy_assignable_v< \ + Result, TestClass<_5, _6, _7, _8>>> \ + ); \ + static_assert( \ + mc_expected, TestClass<_5, _6, _7, _8>>::value \ + == std::is_move_constructible_v< \ + Result, TestClass<_5, _6, _7, _8>>> \ + ); \ + static_assert( \ + ma_expected, TestClass<_5, _6, _7, _8>>::value \ + == std::is_move_assignable_v< \ + Result, TestClass<_5, _6, _7, _8>>> \ + ) SP_MEM_TEST(true, true, true, true, true, true, true, true); SP_MEM_TEST(true, true, true, true, true, true, true, false); From ce839d6a84438b520779d70b7ac28716ef8d84eb Mon Sep 17 00:00:00 2001 From: Ken Matsui <26405363+ken-matsui@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:07:41 -0500 Subject: [PATCH 2/2] Migrate to C++23 and remove fmtlib --- .github/workflows/document-test.yml | 4 +- .github/workflows/full-test.yml | 45 ++---- CMakeLists.txt | 4 +- README.md | 2 +- docs/docs/README.md | 6 +- docs/docs/thiserror/thiserror.md | 2 +- docs/mkdocs.yml | 2 +- include/mitama/anyhow/error.hpp | 20 ++- include/mitama/maybe/factory/just_nothing.hpp | 13 +- include/mitama/maybe/maybe.hpp | 26 ++-- include/mitama/mitamagic/format.hpp | 133 ++++++++++++------ include/mitama/panic.hpp | 127 ++++++----------- include/mitama/result/factory/failure.hpp | 13 +- include/mitama/result/factory/success.hpp | 13 +- include/mitama/result/result.hpp | 44 +++--- include/mitama/result/result_io.hpp | 18 ++- include/mitama/thiserror/thiserror.hpp | 32 ++--- test/CMakeLists.txt | 5 +- test/result_tests.cpp | 5 +- 19 files changed, 266 insertions(+), 248 deletions(-) diff --git a/.github/workflows/document-test.yml b/.github/workflows/document-test.yml index 21c61594..8eac101f 100644 --- a/.github/workflows/document-test.yml +++ b/.github/workflows/document-test.yml @@ -19,10 +19,10 @@ jobs: compiler: - cc: clang cxx: clang++ - ver: 17 + ver: 21 - cc: gcc cxx: g++ - ver: 13 + ver: 14 env: CC: ${{ matrix.compiler.cc }}-${{ matrix.compiler.ver }} CXX: ${{ matrix.compiler.cxx }}-${{ matrix.compiler.ver }} diff --git a/.github/workflows/full-test.yml b/.github/workflows/full-test.yml index 21d76ef2..79e33dd3 100644 --- a/.github/workflows/full-test.yml +++ b/.github/workflows/full-test.yml @@ -14,35 +14,15 @@ jobs: compiler: - cc: clang cxx: clang++ - ver: 15 - os: ubuntu-22.04 - - cc: clang - cxx: clang++ - ver: 16 - os: ubuntu-22.04 - - cc: clang - cxx: clang++ - ver: 17 + ver: 19 os: ubuntu-24.04 - cc: clang cxx: clang++ - ver: 18 + ver: 20 os: ubuntu-24.04 - cc: clang cxx: clang++ - ver: 19 - os: ubuntu-24.04 - - cc: gcc - cxx: g++ - ver: 11 - os: ubuntu-22.04 - - cc: gcc - cxx: g++ - ver: 12 - os: ubuntu-24.04 - - cc: gcc - cxx: g++ - ver: 13 + ver: 21 os: ubuntu-24.04 - cc: gcc cxx: g++ @@ -61,21 +41,16 @@ jobs: sudo apt-get -qq update sudo apt-get install -y -qq pkg-config cmake - - name: Install Clang + - name: Install Clang ${{ matrix.compiler.ver }} if: startsWith(matrix.compiler.cxx, 'clang') run: | wget https://apt.llvm.org/llvm.sh chmod +x ./llvm.sh sudo ./llvm.sh ${{ matrix.compiler.ver }} - - name: Install GCC - if: matrix.compiler.cxx == 'g++' && matrix.compiler.ver == 14 - run: sudo apt update && sudo apt install -y gcc-14 - - - name: Install fmt - run: | - eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - brew install fmt + - name: Install GCC ${{ matrix.compiler.ver }} + if: matrix.compiler.cxx == 'g++' + run: sudo apt update && sudo apt install -y gcc-${{ matrix.compiler.ver }} - name: Build and test run: | @@ -90,14 +65,14 @@ jobs: strategy: fail-fast: false matrix: - osver: [13, 14, 15] + osver: [15, 26] steps: - uses: actions/checkout@v6 with: submodules: true - - name: Install CMake & fmt - run: brew install pkg-config cmake fmt + - name: Install CMake + run: brew install pkg-config cmake - name: Build and test run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 04188198..751ca750 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.20) ## Set our project name project(mitama-cpp-result VERSION 11.0.0 @@ -11,7 +11,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON) message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") add_library(${PROJECT_NAME} INTERFACE) add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) -target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20) +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23) target_include_directories(${PROJECT_NAME} INTERFACE $ $ diff --git a/README.md b/README.md index 8132af11..64e3bde8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # mitama-cpp-result -**mitama-cpp-result** is the C++20 libraries for error handling without exceptions. +**mitama-cpp-result** is the C++23 libraries for error handling without exceptions. **mitama-cpp-result** provides `result`, `maybe`, and associated monadic functions (like [Result](https://doc.rust-lang.org/std/result/enum.Result.html) diff --git a/docs/docs/README.md b/docs/docs/README.md index e26c82a0..345da5fb 100644 --- a/docs/docs/README.md +++ b/docs/docs/README.md @@ -1,6 +1,6 @@ # Introduction -`Mitama.Result` is a header only C++20 library for error handling. +`Mitama.Result` is a header only C++23 library for error handling. ## Installation @@ -8,7 +8,7 @@ ### Dependencies -* fmt: 9.0.0 or higher +* No external dependencies ### Supported OS / Compiler / Language Standard @@ -24,7 +24,7 @@ - Latest preview version of MSVC only - Language Standards - - C++20 + - C++23 - (MSVC: only support `/std:c++latest`) diff --git a/docs/docs/thiserror/thiserror.md b/docs/docs/thiserror/thiserror.md index 30ecd0fd..05d260d7 100644 --- a/docs/docs/thiserror/thiserror.md +++ b/docs/docs/thiserror/thiserror.md @@ -21,7 +21,7 @@ struct data_store_error : mitama::thiserror::derive_error { ``` The first template argument of `mitama::thiserror::error` is embedded with a format string. -The format string should be a string compliant with [**{fmt}**](https://github.com/fmtlib/fmt), check the documentation if you need it. +The format string follows the `std::format` grammar. The second template argument onwards is a list of formattable arguments. `mitama::thiserror::error` inherits from `anyhow::error`, so it can be used together with anyhow. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 97ba7f58..c6eb770e 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -1,6 +1,6 @@ site_name: Mitama.Result User Manual site_url: https://loligothick.github.io/mitama-cpp-result/ -site_description: Mitama.Result C++20 Library +site_description: Mitama.Result C++23 Library site_author: mitama # Repository diff --git a/include/mitama/anyhow/error.hpp b/include/mitama/anyhow/error.hpp index bc623a18..3bbd6fef 100644 --- a/include/mitama/anyhow/error.hpp +++ b/include/mitama/anyhow/error.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -158,11 +157,11 @@ anyhow(E&& err) -> std::shared_ptr ); } template - requires(fmt::is_formattable::value && ...) + requires(std::formattable && ...) inline auto -anyhow(fmt::format_string f, E&&... args) +anyhow(std::format_string f, E&&... args) { - return anyhow(fmt::format(f, std::forward(args)...)); + return anyhow(std::format(f, std::forward(args)...)); } inline std::ostream& @@ -184,9 +183,18 @@ failure(Args&&... args) -> mitama::failure_t> } // namespace mitama::anyhow template <> -struct fmt::formatter> - : ostream_formatter +struct std::formatter, char> + : std::formatter { + template + auto format( + const std::shared_ptr& err, FormatContext& ctx + ) const + { + return std::formatter::format( + err ? err->what() : std::string{}, ctx + ); + } }; #define MITAMA_BAIL(...) \ diff --git a/include/mitama/maybe/factory/just_nothing.hpp b/include/mitama/maybe/factory/just_nothing.hpp index 85179a9c..1f9aba0e 100644 --- a/include/mitama/maybe/factory/just_nothing.hpp +++ b/include/mitama/maybe/factory/just_nothing.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -630,7 +631,7 @@ template inline std::ostream& operator<<(std::ostream& os, const just_t& j) { - return os << fmt::format("just({})", quote_str(j.get())); + return os << std::format("just({})", quote_str(j.get())); } template @@ -685,6 +686,14 @@ class [[nodiscard]] just_t<_just_detail::forward_mode, Args...> } // namespace mitama template -struct fmt::formatter> : ostream_formatter +struct std::formatter, char> + : std::formatter { + template + auto format(const mitama::just_t& value, FormatContext& ctx) const + { + return std::formatter::format( + std::format("just({})", quote_str(value.get())), ctx + ); + } }; diff --git a/include/mitama/maybe/maybe.hpp b/include/mitama/maybe/maybe.hpp index 43f65cf7..40b06cd1 100644 --- a/include/mitama/maybe/maybe.hpp +++ b/include/mitama/maybe/maybe.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -355,7 +356,7 @@ class maybe : public maybe_transpose_injector>, unwrap(const std::source_location& loc = std::source_location::current()) & { if (is_nothing()) - PANIC("called `maybe::unwrap()` on a `nothing` value", loc); + PANIC(loc, "called `maybe::unwrap()` on a `nothing` value"); return std::get>(storage_).get(); } @@ -364,7 +365,7 @@ class maybe : public maybe_transpose_injector>, ) const& { if (is_nothing()) - PANIC("called `maybe::unwrap()` on a `nothing` value", loc); + PANIC(loc, "called `maybe::unwrap()` on a `nothing` value"); return std::get>(storage_).get(); } @@ -372,7 +373,7 @@ class maybe : public maybe_transpose_injector>, unwrap(const std::source_location& loc = std::source_location::current()) && { if (is_nothing()) - PANIC("called `maybe::unwrap()` on a `nothing` value", loc); + PANIC(loc, "called `maybe::unwrap()` on a `nothing` value"); return std::move(std::get>(storage_).get()); } @@ -620,7 +621,7 @@ class maybe : public maybe_transpose_injector>, } else { - PANIC("{}", msg, loc); + PANIC(loc, "{}", msg); } } @@ -635,7 +636,7 @@ class maybe : public maybe_transpose_injector>, } else { - PANIC("{}", msg, loc); + PANIC(loc, "{}", msg); } } @@ -650,7 +651,7 @@ class maybe : public maybe_transpose_injector>, } else { - PANIC("{}", msg, loc); + PANIC(loc, "{}", msg); } } @@ -1205,13 +1206,22 @@ template std::ostream& operator<<(std::ostream& os, const maybe& may) { - return may.is_just() ? os << fmt::format("just({})", quote_str(may.unwrap())) + return may.is_just() ? os << std::format("just({})", quote_str(may.unwrap())) : os << "nothing"; } } // namespace mitama template -struct fmt::formatter> : ostream_formatter +struct std::formatter, char> + : std::formatter { + template + auto format(const mitama::maybe& value, FormatContext& ctx) const + { + auto rendered = value.is_just() + ? std::format("just({})", quote_str(value.unwrap())) + : std::string{ "nothing" }; + return std::formatter::format(rendered, ctx); + } }; diff --git a/include/mitama/mitamagic/format.hpp b/include/mitama/mitamagic/format.hpp index 09544d96..8cd5c2b1 100644 --- a/include/mitama/mitamagic/format.hpp +++ b/include/mitama/mitamagic/format.hpp @@ -1,73 +1,124 @@ #pragma once +#include #include -#include +#include #include #include #include #include #include -inline std::ostream& -operator<<(std::ostream& os, const std::monostate&) +template + requires std::is_convertible_v, std::string_view> +std::string +quote_str(T&& val) { - return os << "()"; + return std::format("\"{}\"", std::string_view{ std::forward(val) }); } template -std::ostream& -operator<<(std::ostream& os, const std::unique_ptr& ptr) +constexpr T&& +quote_str(T&& val) noexcept +{ + return std::forward(val); +} + +namespace std { - if (ptr) +template <> +struct formatter +{ + constexpr auto parse(format_parse_context& ctx) { - return os << *ptr; + return ctx.begin(); } - else + + template + auto format(const std::monostate&, FormatContext& ctx) const { - return os << "null"; + return formatter{}.format("()", ctx); } -} +}; + template -std::ostream& -operator<<(std::ostream& os, const std::shared_ptr& ptr) +struct formatter, char> { - if (ptr) + constexpr auto parse(format_parse_context& ctx) { - return os << *ptr; + return ctx.begin(); } - else + + template + auto format(const std::unique_ptr& ptr, FormatContext& ctx) const { - return os << "null"; + if (ptr) + { + return formatter, char>{}.format(*ptr, ctx); + } + return formatter{}.format("null", ctx); } -} - -#include -#include -#include -#include - -template <> -struct fmt::formatter : ostream_formatter -{ }; + template -struct fmt::formatter> : ostream_formatter +struct formatter, char> { + constexpr auto parse(format_parse_context& ctx) + { + return ctx.begin(); + } + + template + auto format(const std::shared_ptr& ptr, FormatContext& ctx) const + { + if (ptr) + { + return formatter, char>{}.format(*ptr, ctx); + } + return formatter{}.format("null", ctx); + } }; -template -struct fmt::formatter> : ostream_formatter + +template +struct formatter { + constexpr auto parse(format_parse_context& ctx) + { + return ctx.begin(); + } + + template + auto format(const char (&value)[N], FormatContext& ctx) const + { + const auto size = N ? N - 1 : 0; + return formatter{}.format( + std::string_view{ value, size }, ctx + ); + } }; -template - requires std::is_convertible_v, std::string_view> -std::string -quote_str(T&& val) +template +struct formatter : formatter { - return fmt::format("\"{}\"", std::forward(val)); -} -template -constexpr T&& -quote_str(T&& val) noexcept +}; + +template <> +struct formatter { - return std::forward(val); -} + constexpr auto parse(format_parse_context& ctx) + { + return ctx.begin(); + } + + template + auto format(const std::source_location& loc, FormatContext& ctx) const + { + return formatter{}.format( + std::format( + "{}:{}:{}: {}", loc.file_name(), loc.line(), loc.column(), + loc.function_name() + ), + ctx + ); + } +}; +} // namespace std diff --git a/include/mitama/panic.hpp b/include/mitama/panic.hpp index 0560c3e8..136d5435 100644 --- a/include/mitama/panic.hpp +++ b/include/mitama/panic.hpp @@ -2,92 +2,36 @@ #include -#include -#include #include #include +#include #include -// FIXME: When we drop fmt < 100200 support, remove this entire block. -#if FMT_VERSION < 100200 - -/* - * The following std::source_location formatter implementation is derived from - * the {fmt} library: - * https://github.com/fmtlib/fmt - * - * Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * --- Optional exception to the license --- - * - * As an exception, if, as a result of your compiling your source code, portions - * of this Software are embedded into a machine-executable object form of such - * source code, you may redistribute such embedded portions in such object form - * without including the above copyright and permission notices. - * - * All other code in this file is separately licensed. - */ - -template <> -struct formatter -{ - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) - { - return ctx.begin(); - } - - template - auto format(const std::source_location& loc, FormatContext& ctx) const - -> decltype(ctx.out()) - { - auto out = ctx.out(); - out = detail::write(out, loc.file_name()); - out = detail::write(out, ':'); - out = detail::write(out, loc.line()); - out = detail::write(out, ':'); - out = detail::write(out, loc.column()); - out = detail::write(out, ": "); - out = detail::write(out, loc.function_name()); - return out; - } -}; -#endif - namespace mitama { class runtime_panic : public std::runtime_error { public: + [[nodiscard]] static std::string + format_location(const std::source_location& loc) + { + return std::format( + "{}:{}:{}: {}", loc.file_name(), loc.line(), loc.column(), + loc.function_name() + ); + } + template explicit runtime_panic( - const std::source_location& loc, fmt::format_string f, + const std::source_location& loc, std::format_string f, Args&&... args ) noexcept : std::runtime_error( - fmt::format( + std::format( "runtime panicked at '{}', {}", - fmt::format(f, std::forward(args)...), loc + std::format(f, std::forward(args)...), + format_location(loc) ) ) { @@ -98,26 +42,37 @@ namespace detail { template - struct runtime_panic_proxy : runtime_panic + [[noreturn]] inline void panic_dispatch( + const std::source_location& loc, std::format_string f, + Args&&... args + ) { - explicit runtime_panic_proxy( - fmt::format_string f, Args&&... args, - const std::source_location& loc = std::source_location::current() - ) noexcept - : runtime_panic(loc, f, std::forward(args)...) - { - } - }; + throw runtime_panic(loc, f, std::forward(args)...); + } + template - runtime_panic_proxy(fmt::format_string, Args&&...) - -> runtime_panic_proxy; + requires( + !std::is_same_v, std::source_location> && ... + ) + [[noreturn]] inline void + panic_dispatch(std::format_string f, Args&&... args) + { + panic_dispatch( + std::source_location::current(), f, std::forward(args)... + ); + } + + template + [[noreturn]] inline void panic_dispatch( + std::format_string f, Args&&... args, + const std::source_location& loc + ) + { + panic_dispatch(loc, f, std::forward(args)...); + } } // namespace detail } // namespace mitama -#define PANIC(...) \ - throw ::mitama::detail::runtime_panic_proxy \ - { \ - __VA_ARGS__ \ - } +#define PANIC(...) ::mitama::detail::panic_dispatch(__VA_ARGS__) diff --git a/include/mitama/result/factory/failure.hpp b/include/mitama/result/factory/failure.hpp index 47c36f8c..fb530ebd 100644 --- a/include/mitama/result/factory/failure.hpp +++ b/include/mitama/result/factory/failure.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -475,12 +476,20 @@ template inline std::ostream& operator<<(std::ostream& os, const failure_t& err) { - return os << fmt::format("failure({})", quote_str(err.get())); + return os << std::format("failure({})", quote_str(err.get())); } } // namespace mitama template -struct fmt::formatter> : ostream_formatter +struct std::formatter, char> + : std::formatter { + template + auto format(const mitama::failure_t& value, FormatContext& ctx) const + { + return std::formatter::format( + std::format("failure({})", quote_str(value.get())), ctx + ); + } }; diff --git a/include/mitama/result/factory/success.hpp b/include/mitama/result/factory/success.hpp index dd8ab2ee..da370018 100644 --- a/include/mitama/result/factory/success.hpp +++ b/include/mitama/result/factory/success.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -469,12 +470,20 @@ template inline std::ostream& operator<<(std::ostream& os, const success_t& ok) { - return os << fmt::format("success({})", quote_str(ok.get())); + return os << std::format("success({})", quote_str(ok.get())); } } // namespace mitama template -struct fmt::formatter> : ostream_formatter +struct std::formatter, char> + : std::formatter { + template + auto format(const mitama::success_t& value, FormatContext& ctx) const + { + return std::formatter::format( + std::format("success({})", quote_str(value.get())), ctx + ); + } }; diff --git a/include/mitama/result/result.hpp b/include/mitama/result/result.hpp index 27dc4d9a..8fb1a5f2 100644 --- a/include/mitama/result/result.hpp +++ b/include/mitama/result/result.hpp @@ -9,8 +9,6 @@ #include #include -#include -#include #include #include #include @@ -1367,7 +1365,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> const std::source_location& loc = std::source_location::current() ) const& { - if constexpr (fmt::is_formattable::value) + if constexpr (std::formattable) { if (is_ok()) { @@ -1376,8 +1374,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> else { PANIC( - "called `basic_result::unwrap()` on a value: `{}`", - std::get>(storage_), loc + loc, "called `basic_result::unwrap()` on a value: `{}`", + std::get>(storage_) ); } } @@ -1389,7 +1387,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> } else { - PANIC("called `basic_result::unwrap()` on a value `failure(?)`", loc); + PANIC(loc, "called `basic_result::unwrap()` on a value `failure(?)`"); } } } @@ -1403,7 +1401,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> constexpr std::conditional_t, T&, force_add_const_t&> unwrap(const std::source_location& loc = std::source_location::current()) & { - if constexpr (fmt::is_formattable::value) + if constexpr (std::formattable) { if (is_ok()) { @@ -1412,8 +1410,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> else { PANIC( - "called `basic_result::unwrap()` on a value: `{}`", - std::get>(storage_), loc + loc, "called `basic_result::unwrap()` on a value: `{}`", + std::get>(storage_) ); } } @@ -1425,7 +1423,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> } else { - PANIC("called `basic_result::unwrap()` on a value `failure_t(?)`", loc); + PANIC(loc, "called `basic_result::unwrap()` on a value `failure_t(?)`"); } } } @@ -1440,7 +1438,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> const std::source_location& loc = std::source_location::current() ) const& { - if constexpr (fmt::is_formattable::value) + if constexpr (std::formattable) { if (is_err()) { @@ -1449,8 +1447,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> else { PANIC( - "called `basic_result::unwrap_err()` on a value: `{}`", - std::get>(storage_), loc + loc, "called `basic_result::unwrap_err()` on a value: `{}`", + std::get>(storage_) ); } } @@ -1463,7 +1461,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> else { PANIC( - "called `basic_result::unwrap_err()` on a value `success_t(?)`", loc + loc, "called `basic_result::unwrap_err()` on a value `success_t(?)`" ); } } @@ -1480,7 +1478,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> const std::source_location& loc = std::source_location::current() ) & { - if constexpr (fmt::is_formattable::value) + if constexpr (std::formattable) { if (is_err()) { @@ -1489,8 +1487,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> else { PANIC( - "called `basic_result::unwrap_err()` on a value: `{}`", - std::get>(storage_), loc + loc, "called `basic_result::unwrap_err()` on a value: `{}`", + std::get>(storage_) ); } } @@ -1503,8 +1501,8 @@ class [[nodiscard]] basic_result<_mutability, T, E> else { PANIC( - "called `basic_result::unwrap_err()` on a value `success_t(?)`)", - loc + loc, + "called `basic_result::unwrap_err()` on a value `success_t(?)`)" ); } } @@ -1523,7 +1521,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> { if (is_err()) { - PANIC("{}: {}", msg, unwrap_err(), loc); + PANIC(loc, "{}: {}", msg, unwrap_err()); } else { @@ -1544,7 +1542,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> { if (is_err()) { - PANIC("{}: {}", msg, unwrap_err(), loc); + PANIC(loc, "{}: {}", msg, unwrap_err()); } else { @@ -1565,7 +1563,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> { if (is_ok()) { - PANIC("{}: {}", msg, unwrap_err(), loc); + PANIC(loc, "{}: {}", msg, unwrap_err()); } else { @@ -1586,7 +1584,7 @@ class [[nodiscard]] basic_result<_mutability, T, E> { if (is_ok()) { - PANIC("{}: {}", msg, unwrap_err(), loc); + PANIC(loc, "{}: {}", msg, unwrap_err()); } else { diff --git a/include/mitama/result/result_io.hpp b/include/mitama/result/result_io.hpp index e43d2a33..42a53ba3 100644 --- a/include/mitama/result/result_io.hpp +++ b/include/mitama/result/result_io.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace mitama { @@ -22,13 +23,24 @@ std::ostream& operator<<(std::ostream& os, const basic_result<_, T, E>& res) { return res.is_ok() - ? os << fmt::format("success({})", quote_str(res.unwrap())) - : os << fmt::format("failure({})", quote_str(res.unwrap_err())); + ? os << std::format("success({})", quote_str(res.unwrap())) + : os << std::format("failure({})", quote_str(res.unwrap_err())); } } // namespace mitama template -struct fmt::formatter> : ostream_formatter +struct std::formatter, char> + : std::formatter { + template + auto + format(const mitama::basic_result<_, T, E>& value, FormatContext& ctx) const + { + auto rendered = + value.is_ok() + ? std::format("success({})", quote_str(value.unwrap())) + : std::format("failure({})", quote_str(value.unwrap_err())); + return std::formatter::format(rendered, ctx); + } }; diff --git a/include/mitama/thiserror/thiserror.hpp b/include/mitama/thiserror/thiserror.hpp index 29c17da0..b94ec6e8 100644 --- a/include/mitama/thiserror/thiserror.hpp +++ b/include/mitama/thiserror/thiserror.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -81,7 +82,7 @@ struct error final : anyhow::error, return os << std::apply( [&](auto&&... src) { - return fmt::format(fmt, std::forward(src)...); + return std::format(fmt, std::forward(src)...); }, err.sources ); @@ -97,38 +98,21 @@ class derive_error } // namespace mitama::thiserror template -struct fmt::formatter> +struct std::formatter, char> + : std::formatter { using type = mitama::thiserror::error; - constexpr auto parse(format_parse_context& ctx) - { - auto it = ctx.begin(), end = ctx.end(); - // Check if reached the end of the range: - if (it != end && *it != '}') - { - throw format_error( - fmt::format( - "invalid format for thiserror: (expected {{}}, found {{:{})", - std::string_view{ - it, static_cast(std::distance(it, end)) } - ) - ); - } - - // Return an iterator past the end of the parsed range: - return it; - } - template auto format( const mitama::thiserror::error& err, FormatContext& ctx ) { - return std::apply( - [&ctx](const auto&... sources) - { return format_to(ctx.out(), type::fmt, sources...); }, err.sources + auto rendered = std::apply( + [](const auto&... sources) + { return std::format(type::fmt, sources...); }, err.sources ); + return std::formatter::format(rendered, ctx); } }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d7891afb..7fe8a32b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,13 +6,11 @@ set(TEST_NAMES set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11 -find_package(fmt 9.0.0 CONFIG REQUIRED) - message($CMAKE) foreach(TEST_NAME ${TEST_NAMES}) add_executable(${TEST_NAME} ${TEST_NAME}.cpp) - target_compile_features(${TEST_NAME} PRIVATE cxx_std_20) + target_compile_features(${TEST_NAME} PRIVATE cxx_std_23) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(${TEST_NAME} PRIVATE -Wall -Wextra -ftemplate-backtrace-limit=0 -fno-rtti) else() @@ -28,7 +26,6 @@ foreach(TEST_NAME ${TEST_NAMES}) PRIVATE ${CMAKE_SOURCE_DIR}/Catch2/single_include ) - target_link_libraries(${TEST_NAME} fmt::fmt-header-only) add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) endforeach () diff --git a/test/result_tests.cpp b/test/result_tests.cpp index d47002e0..fb9418d4 100644 --- a/test/result_tests.cpp +++ b/test/result_tests.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -658,9 +659,9 @@ TEST_CASE("format test", "[result][format]") { using namespace std::literals; auto res = mut_result>{ in_place_err, { 1, 2, 3 } }; - REQUIRE(fmt::format("{}", res) == "failure([1, 2, 3])"s); + REQUIRE(std::format("{}", res) == "failure([1, 2, 3])"s); res = success(1); - REQUIRE(fmt::format("{}", res) == "success(1)"s); + REQUIRE(std::format("{}", res) == "success(1)"s); } }