From 7259c33c50867737da5e8446ed6f05e6e38545a5 Mon Sep 17 00:00:00 2001 From: Yaraslau Tamashevich Date: Fri, 1 Mar 2024 22:11:50 +0200 Subject: [PATCH] Some small changes, more tests and readme update --- README.md | 111 +++++++++++++++++++++++++----------- include/boxed-cpp/boxed.hpp | 35 +++--------- test-boxed-cpp.cpp | 49 ++++++++++++++++ 3 files changed, 135 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index d1c6b33..0e79d27 100644 --- a/README.md +++ b/README.md @@ -41,19 +41,26 @@ int main() ``` +You can create boxed types in the following way: +``` c++ +using boxed_type = boxed::boxed; + +struct Tag{}; +using boxed_type_with_custom_tag = boxed::boxed; +``` -When you need to get value from boxed type, you need to unbox it +When you need to get value from a boxed type, you need to `unbox` it, use `get` method, or cast it into another type with `as`. ``` c++ //unbox in declared type. double in this case -auto speed_value_native = unbox(speed_of_light); +auto speed_value_native = unbox(speed_of_light); // identical to speed_of_light.get(); //unbox into float type -auto speed_value_float = unbox(speed_of_light); +auto speed_value_float = unbox(speed_of_light); // identical to speed_of_light.as(); // unbox into int type -auto speed_value_int = unbox(speed_of_light); +auto speed_value_int = unbox(speed_of_light); // identical to speed_of_light.as(); ``` -You can also evaluate expressions with boxed types without the need of unboxing them if explicitly declare the resulted type +You can also evaluate expressions with boxed types without the need of unboxing them ``` c++ auto speed_of_light = Speed(299792458.0); auto value = speed_of_light * 2.0; // type of value is Speed @@ -63,50 +70,90 @@ double value_d = speed_of_light * 2.0; ``` -# More examples of usage -You can crate functions that will automatically adjust order of parameters. Complete code see: [godbolt](https://godbolt.org/z/aqobbcGe6) +# Another examples +You can create functions that will automatically adjust order of parameters. [godbolt](https://godbolt.org/z/n8Ez5K6vq) ``` c++ using rho_type = boxed::boxed; using theta_type = boxed::boxed; using phi_type = boxed::boxed; -template -struct overload: F...{ using F::operator()...;}; +template struct overload : F... { + using F::operator()...; +}; -template overload(Ts...) -> overload; +template overload(Ts...) -> overload; -template -struct Wrap -{ - overload func_wrap; +template struct Wrap { + overload func_wrap; - Wrap(Ts... funcs): func_wrap(funcs...){} + Wrap(Ts... funcs) : func_wrap(funcs...) {} - template - auto operator()(Args... args) - { - return (func_wrap(args)*...); - } + template auto operator()(Args... args) { + return (func_wrap(args) * ...); + } }; -auto x_coord = Wrap([](rho_type rho){ return unbox(rho); }, - [](theta_type theta){ return sin(unbox(theta)); }, - [](phi_type phi){ return cos(unbox(phi)); } - ); +auto x_coord = Wrap([](rho_type rho) { return unbox(rho); }, + [](theta_type theta) { return sin(unbox(theta)); }, + [](phi_type phi) { return cos(unbox(phi)); }); -int main() -{ - rho_type rho{1.0}; - theta_type theta{3.14 / 3.0}; - phi_type phi{3.14/2.0}; +int main() { + rho_type rho{1.0}; + theta_type theta{3.14 / 3.0}; + phi_type phi{3.14 / 2.0}; - std::cout << x_coord(rho,theta,phi) << std::endl; // 0.000689428 - std::cout << x_coord(phi,theta,rho) << std::endl; // 0.000689428 - std::cout << x_coord(rho,phi,theta) << std::endl; // 0.000689428 + std::cout << x_coord(rho, theta, phi) << std::endl; + std::cout << x_coord(phi, theta, rho) << std::endl; + std::cout << x_coord(rho, phi, theta) << std::endl; } ``` +Or using another approach: [godbolt](https://godbolt.org/z/fjhaaT5hh) + +``` c++ +using rho_type = boxed::boxed; +using theta_type = boxed::boxed; +using phi_type = boxed::boxed; + +template struct Wrap_with_tuple { + using type_order = std::tuple; + + Wrap_with_tuple(Func f, type_order s) : _func(f), _order(s) {}; + + template decltype(auto) operator()(F... args) { + auto arg_tuple = std::make_tuple(args...); + auto ints = std::make_index_sequence{}; + return make_call(arg_tuple, ints); + } + + template + decltype(auto) make_call(call_tuple arg_tuple, + std::integer_sequence int_seq) { + return _func( + std::get(_order))>>(arg_tuple)...); + } + + Func _func; + type_order _order; +}; + +auto x_coord = Wrap_with_tuple( + [](rho_type rho, theta_type theta, phi_type phi) { + return unbox(rho) * sin(unbox(theta)) * cos(unbox(phi)); + }, + std::make_tuple(rho_type{}, theta_type{}, phi_type{})); + +int main() { + rho_type rho{1.0}; + theta_type theta{3.14 / 3.0}; + phi_type phi{3.14 / 2.0}; + + std::cout << x_coord(rho, theta, phi) << std::endl; + std::cout << x_coord(phi, theta, rho) << std::endl; + std::cout << x_coord(rho, phi, theta) << std::endl; +} +``` ### License diff --git a/include/boxed-cpp/boxed.hpp b/include/boxed-cpp/boxed.hpp index 8621d2a..7b354e0 100644 --- a/include/boxed-cpp/boxed.hpp +++ b/include/boxed-cpp/boxed.hpp @@ -12,6 +12,7 @@ namespace boxed namespace detail { template + requires std::is_enum_v || std::is_integral_v || std::is_floating_point_v struct boxed; } @@ -52,15 +53,9 @@ constexpr bool is_boxed = helper::is_boxed::value; namespace detail { template + requires std::is_enum_v || std::is_integral_v || std::is_floating_point_v struct boxed { - // clang-format off - static_assert( - std::is_enum_v || std::is_integral_v || std::is_floating_point_v, - "Boxing is only useful on integral & floating point types." - ); - // clang-format on - using inner_type = T; using element_type = T; @@ -81,10 +76,7 @@ namespace detail template [[nodiscard]] constexpr auto as() const noexcept { - if constexpr (is_boxed) - return To { static_cast(value) }; - else - return static_cast(value); + return static_cast(value); } template @@ -100,13 +92,6 @@ namespace detail [[nodiscard]] constexpr auto operator<=>(boxed const& other) const noexcept = default; }; - template - std::ostream& operator<<(std::ostream& os, boxed value) - { - os << value.value; - return os; - } - // clang-format off template constexpr boxed& operator++(boxed& a) noexcept { ++a.value; return a; } template constexpr boxed& operator--(boxed& a) noexcept { --a.value; return a; } @@ -229,18 +214,12 @@ struct hash> namespace fmt { -template -struct formatter> +template +struct fmt::formatter> { - template - constexpr auto parse(ParseContext& ctx) - { - return ctx.begin(); - } - template - auto format(boxed::detail::boxed _value, FormatContext& ctx) const + auto format(boxed::detail::boxed const& val, fmt::format_context& ctx) { - return fmt::format_to(ctx.out(), "{}", _value.value); + return fmt::format_to(ctx.out(), "{}", val.value); } }; diff --git a/test-boxed-cpp.cpp b/test-boxed-cpp.cpp index f491df8..8d06819 100644 --- a/test-boxed-cpp.cpp +++ b/test-boxed-cpp.cpp @@ -14,6 +14,7 @@ namespace tags { struct Length{}; struct From{}; struct To{}; } using Length = boxed::boxed; using From = boxed::boxed; using To = boxed::boxed; +using BoxedDouble = boxed::boxed; struct Range { From from; To to; }; // clang-format on @@ -31,6 +32,53 @@ TEST_CASE("boxed") static_assert(l == Length { 3 }); } +TEST_CASE("boxed cout") +{ + auto constexpr r = Range { From { 2 }, To { 4 } }; + auto constexpr l = length(r); + std::cout << l << std::endl; +} + +TEST_CASE("boxed comparison") +{ + auto constexpr l1 = Length { 1 }; + auto constexpr l2 = Length { 2 }; + auto constexpr l3 = Length { 3 }; + REQUIRE(l3 > l1); + REQUIRE(l2 < l3); + REQUIRE(l2 != l1); + REQUIRE(l1 == l1); +} + +TEST_CASE("boxed_as") +{ + auto constexpr f = From { 3 }; + To t = f.as(); + auto constexpr tint = f.as(); + REQUIRE(t.as() == tint); + + auto constexpr bd = BoxedDouble { 3.14 }; + auto constexpr bdint = bd.as(); + //bd.as(); // muse be compile error + REQUIRE(bdint == unbox(bd)); + + auto constexpr t2 = To::cast_from(f); + REQUIRE(t2 == t); +} + +TEST_CASE("boxed_get") +{ + auto constexpr cbd = BoxedDouble { 3.14 }; + REQUIRE(cbd.get() == 3.14); + + auto bd = BoxedDouble { 2.781 }; + REQUIRE(bd.get() == 2.781); + + auto& bdp = bd.get(); + bdp += 1.0; + REQUIRE(bd.get() == 3.781); +} + TEST_CASE("boxed_cast") { auto constexpr f = From { 3 }; @@ -39,6 +87,7 @@ TEST_CASE("boxed_cast") static_assert(std::is_same_v); } + // clang-format off namespace tags { struct N {}; struct Z {}; } // clang-format on