Skip to content

Commit

Permalink
Some small changes, more tests and readme update
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaraslaut committed Mar 1, 2024
1 parent d284402 commit 6c5b14c
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 60 deletions.
111 changes: 79 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,26 @@ int main()

```

You can create boxed types in the following way:
``` c++
using boxed_type = boxed::boxed<int>;

struct Tag{};
using boxed_type_with_custom_tag = boxed::boxed<int,Tag>;
```

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<float>(speed_of_light);
auto speed_value_float = unbox<float>(speed_of_light); // identical to speed_of_light.as<float>();
// unbox into int type
auto speed_value_int = unbox<int>(speed_of_light);
auto speed_value_int = unbox<int>(speed_of_light); // identical to speed_of_light.as<int>();
```


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
Expand All @@ -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<double>;
using theta_type = boxed::boxed<double>;
using phi_type = boxed::boxed<double>;

template <typename... F>
struct overload: F...{ using F::operator()...;};
template <typename... F> struct overload : F... {
using F::operator()...;
};

template<typename... Ts> overload(Ts...) -> overload<Ts...>;
template <typename... Ts> overload(Ts...) -> overload<Ts...>;

template<typename... Ts>
struct Wrap
{
overload<Ts...> func_wrap;
template <typename... Ts> struct Wrap {
overload<Ts...> func_wrap;

Wrap(Ts... funcs): func_wrap(funcs...){}
Wrap(Ts... funcs) : func_wrap(funcs...) {}

template<typename... Args>
auto operator()(Args... args)
{
return (func_wrap(args)*...);
}
template <typename... Args> 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<double>;
using theta_type = boxed::boxed<double>;
using phi_type = boxed::boxed<double>;
template <typename Func, typename... Tuple> struct Wrap_with_tuple {
using type_order = std::tuple<Tuple...>;
Wrap_with_tuple(Func f, type_order s) : _func(f), _order(s) {};
template <typename... F> decltype(auto) operator()(F... args) {
auto arg_tuple = std::make_tuple(args...);
auto ints = std::make_index_sequence<sizeof...(args)>{};
return make_call(arg_tuple, ints);
}
template <typename call_tuple, typename T, T... ints>
decltype(auto) make_call(call_tuple arg_tuple,
std::integer_sequence<T, ints...> int_seq) {
return _func(
std::get<std::decay_t<decltype(std::get<ints>(_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
Expand Down
35 changes: 7 additions & 28 deletions include/boxed-cpp/boxed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace boxed
namespace detail
{
template <typename T, typename Tag>
requires std::is_enum_v<T> || std::is_integral_v<T> || std::is_floating_point_v<T>
struct boxed;
}

Expand Down Expand Up @@ -52,15 +53,9 @@ constexpr bool is_boxed = helper::is_boxed<T>::value;
namespace detail
{
template <typename T, typename Tag>
requires std::is_enum_v<T> || std::is_integral_v<T> || std::is_floating_point_v<T>
struct boxed
{
// clang-format off
static_assert(
std::is_enum_v<T> || std::is_integral_v<T> || std::is_floating_point_v<T>,
"Boxing is only useful on integral & floating point types."
);
// clang-format on

using inner_type = T;
using element_type = T;

Expand All @@ -81,10 +76,7 @@ namespace detail
template <typename To>
[[nodiscard]] constexpr auto as() const noexcept
{
if constexpr (is_boxed<To>)
return To { static_cast<typename To::element_type>(value) };
else
return static_cast<To>(value);
return static_cast<To>(value);
}

template <typename Source>
Expand All @@ -100,13 +92,6 @@ namespace detail
[[nodiscard]] constexpr auto operator<=>(boxed const& other) const noexcept = default;
};

template <typename T, typename U>
std::ostream& operator<<(std::ostream& os, boxed<T, U> value)
{
os << value.value;
return os;
}

// clang-format off
template <typename T, typename U> constexpr boxed<T, U>& operator++(boxed<T, U>& a) noexcept { ++a.value; return a; }
template <typename T, typename U> constexpr boxed<T, U>& operator--(boxed<T, U>& a) noexcept { --a.value; return a; }
Expand Down Expand Up @@ -229,18 +214,12 @@ struct hash<boxed::detail::boxed<T, U>>
namespace fmt
{

template <typename A, typename B>
struct formatter<boxed::detail::boxed<A, B>>
template <typename Type, typename Tag>
struct fmt::formatter<boxed::detail::boxed<Type, Tag>>
{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(boxed::detail::boxed<A, B> _value, FormatContext& ctx) const
auto format(boxed::detail::boxed<Type, Tag> const& val, fmt::format_context& ctx)
{
return fmt::format_to(ctx.out(), "{}", _value.value);
return fmt::format_to(ctx.out(), "{}", val.value);
}
};

Expand Down
48 changes: 48 additions & 0 deletions test-boxed-cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace tags { struct Length{}; struct From{}; struct To{}; }
using Length = boxed::boxed<std::size_t, tags::Length>;
using From = boxed::boxed<std::size_t, tags::From>;
using To = boxed::boxed<std::size_t, tags::To>;
using BoxedDouble = boxed::boxed<double>;
struct Range { From from; To to; };
// clang-format on

Expand All @@ -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<To>();
auto constexpr tint = f.as<int>();
REQUIRE(t.as<int>() == tint);

auto constexpr bd = BoxedDouble { 3.14 };
auto constexpr bdint = bd.as<int>();
// bd.as<To>(); // muse be compile error
REQUIRE(bdint == unbox<int>(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 };
Expand Down

0 comments on commit 6c5b14c

Please sign in to comment.