HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
units.hpp
1// Copyright Take Vos 2023.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "cast.hpp"
8#include <ratio>
9#include <concepts>
10#include <compare>
11
12namespace hi { inline namespace v1 {
13
14template<typename Tag, typename T, typename Ratio = std::ratio<1>>
15class unit {
16public:
17 using value_type = T;
18 using ratio = Ratio;
19
20 constexpr unit(unit const&) noexcept = default;
21 constexpr unit(unit&&) noexcept = default;
22 constexpr unit& operator=(unit const&) noexcept = default;
23 constexpr unit& operator=(unit&&) noexcept = default;
24
25 constexpr explicit unit(value_type value) noexcept : _value(value) {}
26
27 template<typename OtherT, typename OtherRatio>
28 constexpr explicit unit(unit<Tag, OtherT, OtherRatio> const& other) noexcept
29 requires(not std::is_same_v<unit<Tag, OtherT, OtherRatio>, unit>)
30 {
31 using conversion = std::ratio_divide<Ratio, OtherRatio>;
32
33 auto tmp = wide_cast<std::common_type_t<T, OtherT>>(other.count());
34 tmp *= conversion::den;
35 tmp /= conversion::num;
36 _value = narrow_cast<T>(tmp);
37 }
38
39 template<typename OtherT, typename OtherRatio>
40 constexpr unit& operator=(unit<Tag, OtherT, OtherRatio> const& other) noexcept
41 requires(not std::is_same_v<unit<Tag, OtherT, OtherRatio>, unit>)
42 {
43 using conversion = std::ratio_divide<Ratio, OtherRatio>;
44
45 auto tmp = wide_cast<std::common_type_t<T, OtherT>>(other.count());
46 tmp *= conversion::den;
47 tmp /= conversion::num;
48 _value = narrow_cast<T>(tmp);
49 return *this;
50 }
51
52 [[nodiscard]] constexpr value_type count() const noexcept
53 {
54 return _value;
55 }
56
57 [[nodiscard]] constexpr unit operator*(value_type const& rhs) const noexcept
58 {
59 return unit{count() * rhs};
60 }
61
62 [[nodiscard]] constexpr unit operator/(value_type const& rhs) const noexcept
63 {
64 return unit{count() / rhs};
65 }
66
67 [[nodiscard]] constexpr unit& operator+=(unit const& rhs) noexcept
68 {
69 _value += rhs.count();
70 return *this;
71 }
72
73 [[nodiscard]] constexpr unit& operator-=(unit const& rhs) noexcept
74 {
75 _value -= rhs.count();
76 return *this;
77 }
78
79 [[nodiscard]] constexpr unit& operator*=(value_type const& rhs) noexcept
80 {
81 _value *= rhs;
82 return *this;
83 }
84
85 [[nodiscard]] constexpr unit& operator/=(value_type const& rhs) noexcept
86 {
87 _value /= rhs;
88 return *this;
89 }
90
91private:
92 value_type _value;
93};
94
95}} // namespace hi::v1
96
97template<typename Tag, typename T1, typename Ratio1, typename T2, typename Ratio2>
98struct std::common_type<hi::unit<Tag, T1, Ratio1>, hi::unit<Tag, T2, Ratio2>> {
99 // clang-format off
100 using type = hi::unit<
101 Tag,
102 std::common_type_t<T1, T2>,
103 std::conditional_t<std::ratio_less_v<Ratio1, Ratio2>, Ratio1, Ratio2>>;
104 // clang-format on
105};
106
107namespace hi { inline namespace v1 {
108
109template<typename Tag, typename T1, typename Ratio1, typename T2, typename Ratio2>
110[[nodiscard]] constexpr bool operator==(unit<Tag, T1, Ratio1> const& lhs, unit<Tag, T2, Ratio2> const& rhs) noexcept
111{
112 using common_type = std::common_type_t<unit<Tag, T1, Ratio1>, unit<Tag, T2, Ratio2>>;
113
114 hilet lhs_ = common_type{lhs};
115 hilet rhs_ = common_type{rhs};
116
117 return lhs_.count() == rhs_.count();
118}
119
120template<typename Tag, typename T1, typename Ratio1, typename T2, typename Ratio2>
121[[nodiscard]] constexpr auto operator<=>(unit<Tag, T1, Ratio1> const& lhs, unit<Tag, T2, Ratio2> const& rhs) noexcept
122{
123 using common_type = std::common_type_t<unit<Tag, T1, Ratio1>, unit<Tag, T2, Ratio2>>;
124
125 hilet lhs_ = common_type{lhs};
126 hilet rhs_ = common_type{rhs};
127
128 return lhs_.count() <=> rhs_.count();
129}
130
131template<typename Tag, typename T1, typename Ratio1, typename T2, typename Ratio2>
132[[nodiscard]] constexpr auto operator+(unit<Tag, T1, Ratio1> const& lhs, unit<Tag, T2, Ratio2> const& rhs) noexcept
133{
134 using common_type = std::common_type_t<unit<Tag, T1, Ratio1>, unit<Tag, T2, Ratio2>>;
135
136 hilet lhs_ = common_type{lhs};
137 hilet rhs_ = common_type{rhs};
138
139 return common_type{lhs_.count() + rhs_.count()};
140}
141
142template<typename Tag, typename T1, typename Ratio1, typename T2, typename Ratio2>
143[[nodiscard]] constexpr auto operator-(unit<Tag, T1, Ratio1> const& lhs, unit<Tag, T2, Ratio2> const& rhs) noexcept
144{
145 using common_type = std::common_type_t<unit<Tag, T1, Ratio1>, unit<Tag, T2, Ratio2>>;
146
147 hilet lhs_ = common_type{lhs};
148 hilet rhs_ = common_type{rhs};
149
150 return common_type{lhs_.count() - rhs_.count()};
151}
152
153template<typename Tag, typename T1, typename Ratio1, typename T2, typename Ratio2>
154[[nodiscard]] constexpr auto operator/(unit<Tag, T1, Ratio1> const& lhs, unit<Tag, T2, Ratio2> const& rhs) noexcept
155{
156 using common_type = std::common_type_t<unit<Tag, T1, Ratio1>, unit<Tag, T2, Ratio2>>;
157
158 hilet lhs_ = common_type{lhs};
159 hilet rhs_ = common_type{rhs};
160
161 return lhs_.count() / rhs_.count();
162}
163
164
168
174
177using points = unit<si_length_tag, double, std::ratio<254, 720'000>::type>;
178
181using inches = unit<si_length_tag, double, std::ratio<254, 10'000>::type>;
182using feet = unit<si_length_tag, double, std::ratio<3'048, 10'000>::type>;
183using yards = unit<si_length_tag, double, std::ratio<9'144, 10'000>::type>;
184using miles = unit<si_length_tag, double, std::ratio<16'093'440, 10'000>::type>;
185
188using dips = unit<si_length_tag, double, std::ratio<254, 960'000>::type>;
189
193
197
198}} // namespace hi::v1
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
Definition units.hpp:15
Definition units.hpp:165
Definition units.hpp:166
Definition units.hpp:167