Skip to content

Commit e30326c

Browse files
Merge pull request #17 from contour-terminal/improvement/some_updates
Some small changes, more tests and readme update
2 parents d284402 + 6c5b14c commit e30326c

File tree

3 files changed

+134
-60
lines changed

3 files changed

+134
-60
lines changed

README.md

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,26 @@ int main()
4141

4242
```
4343

44+
You can create boxed types in the following way:
45+
``` c++
46+
using boxed_type = boxed::boxed<int>;
47+
48+
struct Tag{};
49+
using boxed_type_with_custom_tag = boxed::boxed<int,Tag>;
50+
```
4451

45-
When you need to get value from boxed type, you need to unbox it
52+
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`.
4653
``` c++
4754
//unbox in declared type. double in this case
48-
auto speed_value_native = unbox(speed_of_light);
55+
auto speed_value_native = unbox(speed_of_light); // identical to speed_of_light.get();
4956
//unbox into float type
50-
auto speed_value_float = unbox<float>(speed_of_light);
57+
auto speed_value_float = unbox<float>(speed_of_light); // identical to speed_of_light.as<float>();
5158
// unbox into int type
52-
auto speed_value_int = unbox<int>(speed_of_light);
59+
auto speed_value_int = unbox<int>(speed_of_light); // identical to speed_of_light.as<int>();
5360
```
5461

5562

56-
You can also evaluate expressions with boxed types without the need of unboxing them if explicitly declare the resulted type
63+
You can also evaluate expressions with boxed types without the need of unboxing them
5764
``` c++
5865
auto speed_of_light = Speed(299792458.0);
5966
auto value = speed_of_light * 2.0; // type of value is Speed
@@ -63,50 +70,90 @@ double value_d = speed_of_light * 2.0;
6370
```
6471

6572

66-
# More examples of usage
67-
You can crate functions that will automatically adjust order of parameters. Complete code see: [godbolt](https://godbolt.org/z/aqobbcGe6)
73+
# Another examples
74+
You can create functions that will automatically adjust order of parameters. [godbolt](https://godbolt.org/z/n8Ez5K6vq)
6875

6976
``` c++
7077
using rho_type = boxed::boxed<double>;
7178
using theta_type = boxed::boxed<double>;
7279
using phi_type = boxed::boxed<double>;
7380

74-
template <typename... F>
75-
struct overload: F...{ using F::operator()...;};
81+
template <typename... F> struct overload : F... {
82+
using F::operator()...;
83+
};
7684

77-
template<typename... Ts> overload(Ts...) -> overload<Ts...>;
85+
template <typename... Ts> overload(Ts...) -> overload<Ts...>;
7886

79-
template<typename... Ts>
80-
struct Wrap
81-
{
82-
overload<Ts...> func_wrap;
87+
template <typename... Ts> struct Wrap {
88+
overload<Ts...> func_wrap;
8389

84-
Wrap(Ts... funcs): func_wrap(funcs...){}
90+
Wrap(Ts... funcs) : func_wrap(funcs...) {}
8591

86-
template<typename... Args>
87-
auto operator()(Args... args)
88-
{
89-
return (func_wrap(args)*...);
90-
}
92+
template <typename... Args> auto operator()(Args... args) {
93+
return (func_wrap(args) * ...);
94+
}
9195
};
9296

93-
auto x_coord = Wrap([](rho_type rho){ return unbox(rho); },
94-
[](theta_type theta){ return sin(unbox(theta)); },
95-
[](phi_type phi){ return cos(unbox(phi)); }
96-
);
97+
auto x_coord = Wrap([](rho_type rho) { return unbox(rho); },
98+
[](theta_type theta) { return sin(unbox(theta)); },
99+
[](phi_type phi) { return cos(unbox(phi)); });
97100

98-
int main()
99-
{
100-
rho_type rho{1.0};
101-
theta_type theta{3.14 / 3.0};
102-
phi_type phi{3.14/2.0};
101+
int main() {
102+
rho_type rho{1.0};
103+
theta_type theta{3.14 / 3.0};
104+
phi_type phi{3.14 / 2.0};
103105

104-
std::cout << x_coord(rho,theta,phi) << std::endl; // 0.000689428
105-
std::cout << x_coord(phi,theta,rho) << std::endl; // 0.000689428
106-
std::cout << x_coord(rho,phi,theta) << std::endl; // 0.000689428
106+
std::cout << x_coord(rho, theta, phi) << std::endl;
107+
std::cout << x_coord(phi, theta, rho) << std::endl;
108+
std::cout << x_coord(rho, phi, theta) << std::endl;
107109
}
108110
```
109111
112+
Or using another approach: [godbolt](https://godbolt.org/z/fjhaaT5hh)
113+
114+
``` c++
115+
using rho_type = boxed::boxed<double>;
116+
using theta_type = boxed::boxed<double>;
117+
using phi_type = boxed::boxed<double>;
118+
119+
template <typename Func, typename... Tuple> struct Wrap_with_tuple {
120+
using type_order = std::tuple<Tuple...>;
121+
122+
Wrap_with_tuple(Func f, type_order s) : _func(f), _order(s) {};
123+
124+
template <typename... F> decltype(auto) operator()(F... args) {
125+
auto arg_tuple = std::make_tuple(args...);
126+
auto ints = std::make_index_sequence<sizeof...(args)>{};
127+
return make_call(arg_tuple, ints);
128+
}
129+
130+
template <typename call_tuple, typename T, T... ints>
131+
decltype(auto) make_call(call_tuple arg_tuple,
132+
std::integer_sequence<T, ints...> int_seq) {
133+
return _func(
134+
std::get<std::decay_t<decltype(std::get<ints>(_order))>>(arg_tuple)...);
135+
}
136+
137+
Func _func;
138+
type_order _order;
139+
};
140+
141+
auto x_coord = Wrap_with_tuple(
142+
[](rho_type rho, theta_type theta, phi_type phi) {
143+
return unbox(rho) * sin(unbox(theta)) * cos(unbox(phi));
144+
},
145+
std::make_tuple(rho_type{}, theta_type{}, phi_type{}));
146+
147+
int main() {
148+
rho_type rho{1.0};
149+
theta_type theta{3.14 / 3.0};
150+
phi_type phi{3.14 / 2.0};
151+
152+
std::cout << x_coord(rho, theta, phi) << std::endl;
153+
std::cout << x_coord(phi, theta, rho) << std::endl;
154+
std::cout << x_coord(rho, phi, theta) << std::endl;
155+
}
156+
```
110157

111158

112159
### License

include/boxed-cpp/boxed.hpp

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace boxed
1212
namespace detail
1313
{
1414
template <typename T, typename Tag>
15+
requires std::is_enum_v<T> || std::is_integral_v<T> || std::is_floating_point_v<T>
1516
struct boxed;
1617
}
1718

@@ -52,15 +53,9 @@ constexpr bool is_boxed = helper::is_boxed<T>::value;
5253
namespace detail
5354
{
5455
template <typename T, typename Tag>
56+
requires std::is_enum_v<T> || std::is_integral_v<T> || std::is_floating_point_v<T>
5557
struct boxed
5658
{
57-
// clang-format off
58-
static_assert(
59-
std::is_enum_v<T> || std::is_integral_v<T> || std::is_floating_point_v<T>,
60-
"Boxing is only useful on integral & floating point types."
61-
);
62-
// clang-format on
63-
6459
using inner_type = T;
6560
using element_type = T;
6661

@@ -81,10 +76,7 @@ namespace detail
8176
template <typename To>
8277
[[nodiscard]] constexpr auto as() const noexcept
8378
{
84-
if constexpr (is_boxed<To>)
85-
return To { static_cast<typename To::element_type>(value) };
86-
else
87-
return static_cast<To>(value);
79+
return static_cast<To>(value);
8880
}
8981

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

103-
template <typename T, typename U>
104-
std::ostream& operator<<(std::ostream& os, boxed<T, U> value)
105-
{
106-
os << value.value;
107-
return os;
108-
}
109-
11095
// clang-format off
11196
template <typename T, typename U> constexpr boxed<T, U>& operator++(boxed<T, U>& a) noexcept { ++a.value; return a; }
11297
template <typename T, typename U> constexpr boxed<T, U>& operator--(boxed<T, U>& a) noexcept { --a.value; return a; }
@@ -229,18 +214,12 @@ struct hash<boxed::detail::boxed<T, U>>
229214
namespace fmt
230215
{
231216

232-
template <typename A, typename B>
233-
struct formatter<boxed::detail::boxed<A, B>>
217+
template <typename Type, typename Tag>
218+
struct fmt::formatter<boxed::detail::boxed<Type, Tag>>
234219
{
235-
template <typename ParseContext>
236-
constexpr auto parse(ParseContext& ctx)
237-
{
238-
return ctx.begin();
239-
}
240-
template <typename FormatContext>
241-
auto format(boxed::detail::boxed<A, B> _value, FormatContext& ctx) const
220+
auto format(boxed::detail::boxed<Type, Tag> const& val, fmt::format_context& ctx)
242221
{
243-
return fmt::format_to(ctx.out(), "{}", _value.value);
222+
return fmt::format_to(ctx.out(), "{}", val.value);
244223
}
245224
};
246225

test-boxed-cpp.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace tags { struct Length{}; struct From{}; struct To{}; }
1414
using Length = boxed::boxed<std::size_t, tags::Length>;
1515
using From = boxed::boxed<std::size_t, tags::From>;
1616
using To = boxed::boxed<std::size_t, tags::To>;
17+
using BoxedDouble = boxed::boxed<double>;
1718
struct Range { From from; To to; };
1819
// clang-format on
1920

@@ -31,6 +32,53 @@ TEST_CASE("boxed")
3132
static_assert(l == Length { 3 });
3233
}
3334

35+
TEST_CASE("boxed cout")
36+
{
37+
auto constexpr r = Range { From { 2 }, To { 4 } };
38+
auto constexpr l = length(r);
39+
std::cout << l << std::endl;
40+
}
41+
42+
TEST_CASE("boxed comparison")
43+
{
44+
auto constexpr l1 = Length { 1 };
45+
auto constexpr l2 = Length { 2 };
46+
auto constexpr l3 = Length { 3 };
47+
REQUIRE(l3 > l1);
48+
REQUIRE(l2 < l3);
49+
REQUIRE(l2 != l1);
50+
REQUIRE(l1 == l1);
51+
}
52+
53+
TEST_CASE("boxed_as")
54+
{
55+
auto constexpr f = From { 3 };
56+
To t = f.as<To>();
57+
auto constexpr tint = f.as<int>();
58+
REQUIRE(t.as<int>() == tint);
59+
60+
auto constexpr bd = BoxedDouble { 3.14 };
61+
auto constexpr bdint = bd.as<int>();
62+
// bd.as<To>(); // muse be compile error
63+
REQUIRE(bdint == unbox<int>(bd));
64+
65+
auto constexpr t2 = To::cast_from(f);
66+
REQUIRE(t2 == t);
67+
}
68+
69+
TEST_CASE("boxed_get")
70+
{
71+
auto constexpr cbd = BoxedDouble { 3.14 };
72+
REQUIRE(cbd.get() == 3.14);
73+
74+
auto bd = BoxedDouble { 2.781 };
75+
REQUIRE(bd.get() == 2.781);
76+
77+
auto& bdp = bd.get();
78+
bdp += 1.0;
79+
REQUIRE(bd.get() == 3.781);
80+
}
81+
3482
TEST_CASE("boxed_cast")
3583
{
3684
auto constexpr f = From { 3 };

0 commit comments

Comments
 (0)