9 #ifndef EAGINE_UNITS_DETAIL_HPP
10 #define EAGINE_UNITS_DETAIL_HPP
12 #include "../mp_arithmetic.hpp"
13 #include "../type_identity.hpp"
18 namespace eagine::units::bits {
22 struct collapse_tail : type_identity<X> {};
25 using collapse_tail_t =
typename collapse_tail<X>::type;
28 template <
typename Dim,
int Pow>
31 using pow = int_constant<Pow>;
35 template <
typename Head,
typename Tail>
40 using dimless = dims<nothing_t, nothing_t>;
43 struct collapse_tail<dims<nothing_t, nothing_t>> : nothing_t {};
46 template <
typename D,
typename Dims>
49 template <
typename D,
typename Dims>
50 constexpr
int pow_of_dim_v = pow_of_dim<D, Dims>::value;
58 template <
typename D,
int P,
typename T>
59 struct pow_of_dim<D, dims<dim_pow<D, P>, T>> :
int_constant<P> {};
61 template <
typename D1,
typename D2,
int P,
typename T>
62 struct pow_of_dim<D1, dims<dim_pow<D2, P>, T>> : pow_of_dim<D1, T> {};
65 template <
typename D,
typename H,
typename T>
66 static constexpr
auto get_pow_of_dim(base::dimension<D>, dims<H, T>) noexcept
68 return pow_of_dim_v<D, dims<H, T>>;
72 template <
typename Dims1,
typename Dims2>
75 template <
typename Dims1,
typename Dims2>
76 using dim_add_t =
typename dim_add<Dims1, Dims2>::type;
79 struct dim_add<nothing_t, nothing_t> : nothing_t {};
81 template <
typename H,
typename T>
82 struct dim_add<nothing_t, dims<H, T>> : dims<H, T> {};
84 template <
typename H,
typename T>
85 struct dim_add<dims<H, T>, nothing_t> : dims<H, T> {};
88 struct dim_add<dimless, dimless> : dimless {};
90 template <
typename H,
typename T>
91 struct dim_add<dims<H, T>, dimless> : dims<H, T> {};
93 template <
typename H,
typename T>
94 struct dim_add<dimless, dims<H, T>> : dims<H, T> {};
96 template <
typename Dim,
int Pow1,
typename Tail1,
int Pow2,
typename Tail2>
97 struct dim_add<dims<dim_pow<Dim, Pow1>, Tail1>, dims<dim_pow<Dim, Pow2>, Tail2>>
100 dim_add_t<Tail1, Tail2>,
101 dims<dim_pow<Dim, Pow1 + Pow2>, collapse_tail_t<dim_add_t<Tail1, Tail2>>>> {
111 struct dim_add<dims<dim_pow<Dim1, Pow1>, Tail1>, dims<dim_pow<Dim2, Pow2>, Tail2>>
112 : std::conditional_t<
113 (base::dim_num_v<Dim1> < base::dim_num_v<Dim2>),
116 collapse_tail_t<dim_add_t<Tail1, dims<dim_pow<Dim2, Pow2>, Tail2>>>>,
119 collapse_tail_t<dim_add_t<dims<dim_pow<Dim1, Pow1>, Tail1>, Tail2>>>> {
123 template <typename Dims1, typename Dims2>
126 template <typename Dims1, typename Dims2>
127 using dim_sub_t = typename dim_sub<Dims1, Dims2>::type;
130 struct dim_sub<nothing_t, nothing_t> : dimless {};
133 struct dim_sub<nothing_t, dimless> : dimless {};
135 template <typename H, typename T>
136 struct dim_sub<dims<H, T>, nothing_t> : dims<H, T> {};
138 template <typename D, int P, typename T>
139 struct dim_sub<nothing_t, dims<dim_pow<D, P>, T>>
140 : dims<dim_pow<D, -P>, collapse_tail_t<dim_sub_t<nothing_t, T>>> {};
143 struct dim_sub<dimless, dimless> : dimless {};
145 template <typename H, typename T>
146 struct dim_sub<dims<H, T>, dimless> : dims<H, T> {};
148 template <typename D, int P, typename T>
149 struct dim_sub<dimless, dims<dim_pow<D, P>, T>>
150 : dims<dim_pow<D, -P>, collapse_tail_t<dim_sub_t<nothing_t, T>>> {};
152 template <typename Dim, int Pow1, typename Tail1, int Pow2, typename Tail2>
153 struct dim_sub<dims<dim_pow<Dim, Pow1>, Tail1>, dims<dim_pow<Dim, Pow2>, Tail2>>
154 : std::conditional_t<
156 dim_sub_t<Tail1, Tail2>,
157 dims<dim_pow<Dim, Pow1 - Pow2>, collapse_tail_t<dim_sub_t<Tail1, Tail2>>>> {
167 struct dim_sub<dims<dim_pow<Dim1, Pow1>, Tail1>, dims<dim_pow<Dim2, Pow2>, Tail2>>
168 : std::conditional_t<
169 (base::dim_num_v<Dim1> < base::dim_num_v<Dim2>),
172 collapse_tail_t<dim_sub_t<Tail1, dims<dim_pow<Dim2, Pow2>, Tail2>>>>,
174 dim_pow<Dim2, -Pow2>,
175 collapse_tail_t<dim_sub_t<dims<dim_pow<Dim1, Pow1>, Tail1>, Tail2>>>> {
179 template <typename Dims, typename Dim>
183 template <typename Dim>
184 struct get_pow<nothing_t, Dim> : int_constant<0> {};
187 template <typename Dim>
188 struct get_pow<dimless, Dim> : int_constant<0> {};
191 template <typename H, typename T, typename Dim>
192 struct get_pow<dims<H, T>, Dim> : get_pow<T, Dim> {};
195 template <typename Dim, int Pow, typename T>
196 struct get_pow<dims<dim_pow<Dim, Pow>, T>, Dim> : int_constant<Pow> {};
199 template <typename Unit, typename Scale>
202 template <typename Head, typename Tail>
204 using type = unit_scales;
208 struct collapse_tail<unit_scales<nothing_t, nothing_t>> : nothing_t {};
211 template <typename UnitScales, typename Unit, typename Scale>
214 template <typename UnitScales, typename Unit, typename Scale>
215 using insert_t = typename insert<UnitScales, Unit, Scale>::type;
217 template <typename U, typename S>
218 struct insert<nothing_t, U, S> : unit_scales<uni_sca<U, S>, nothing_t> {};
220 template <typename U, typename S>
221 struct insert<unit_scales<nothing_t, nothing_t>, U, S>
222 : unit_scales<uni_sca<U, S>, nothing_t> {};
224 template <typename U, typename SO, typename SN, typename T>
225 struct insert<unit_scales<uni_sca<U, SO>, T>, U, SN>
226 : unit_scales<uni_sca<U, SN>, T> {};
228 template <typename H, typename T, typename U, typename S>
229 struct insert<unit_scales<H, T>, U, S> : unit_scales<H, insert_t<T, U, S>> {};
232 template <typename UnitScales, typename Unit, typename Fallback>
235 template <typename UnitScales, typename Unit, typename Fallback>
236 using get_scale_t = typename get_scale<UnitScales, Unit, Fallback>::type;
238 template <typename U, typename Fallback>
239 struct get_scale<nothing_t, U, Fallback> : Fallback {};
241 template <typename U, typename Fallback>
242 struct get_scale<unit_scales<nothing_t, nothing_t>, U, Fallback> : Fallback {};
244 template <typename U, typename Scale, typename T, typename F>
245 struct get_scale<unit_scales<uni_sca<U, Scale>, T>, U, F> : Scale {};
247 template <typename U, typename S1, typename S2, typename T, typename F>
248 struct get_scale<unit_scales<uni_sca<U, S1>, T>, base::scaled_unit<S2, U>, F>
249 : scales::divided<S1, S2> {};
251 template <typename H, typename T, typename U, typename F>
252 struct get_scale<unit_scales<H, T>, U, F> : get_scale<T, U, F> {};
255 template <typename UnitScales, typename BaseDim, typename Fallback>
258 template <typename BD, typename Fallback>
259 struct get_dim_unit<nothing_t, BD, Fallback> : Fallback {};
261 template <typename BD, typename Fallback>
262 struct get_dim_unit<unit_scales<nothing_t, nothing_t>, BD, Fallback>
265 template <typename U, typename S, typename T, typename BD, typename F>
266 struct get_dim_unit<unit_scales<uni_sca<U, S>, T>, BD, F>
267 : std::conditional_t<
268 std::is_same_v<dimension_of_t<U>, BD>,
269 base::scaled_unit<S, U>,
270 typename get_dim_unit<T, BD, F>::type> {};
273 template <typename UnitConv1, typename UnitConv2>
276 template <typename UnitConv1, typename UnitConv2>
277 using merge_t = typename merge<UnitConv1, UnitConv2>::type;
280 struct merge<nothing_t, nothing_t> : unit_scales<nothing_t, nothing_t> {};
283 struct merge<unit_scales<nothing_t, nothing_t>, unit_scales<nothing_t, nothing_t>>
284 : unit_scales<nothing_t, nothing_t> {};
286 template <typename H, typename T>
287 struct merge<unit_scales<H, T>, nothing_t> : unit_scales<H, T> {};
289 template <typename H, typename T>
290 struct merge<nothing_t, unit_scales<H, T>> : unit_scales<H, T> {};
292 template <typename H, typename T>
293 struct merge<unit_scales<H, T>, unit_scales<nothing_t, nothing_t>>
294 : unit_scales<H, T> {};
296 template <typename H, typename T>
297 struct merge<unit_scales<nothing_t, nothing_t>, unit_scales<H, T>>
298 : unit_scales<H, T> {};
300 template <typename U, typename S1, typename S2, typename T1, typename T2>
301 struct merge<unit_scales<uni_sca<U, S1>, T1>, unit_scales<uni_sca<U, S2>, T2>>
302 : unit_scales<uni_sca<U, S1>, collapse_tail_t<merge_t<T1, T2>>> {};
311 struct merge<unit_scales<uni_sca<U1, S1>, T1>, unit_scales<uni_sca<U2, S2>, T2>>
312 : std::conditional_t<
313 (base::dim_num_v<dimension_of_t<U1>> <
314 base::dim_num_v<dimension_of_t<U2>>),
317 collapse_tail_t<merge_t<T1, unit_scales<uni_sca<U2, S2>, T2>>>>,
320 collapse_tail_t<merge_t<unit_scales<uni_sca<U1, S1>, T1>, T2>>>> {};
323 template <typename Scales, typename System>
324 struct _sc_unit_sc_hlp {
326 template <typename T, typename SV>
327 static constexpr auto _pow(T v, SV, int_constant<0>) {
331 template <typename T, typename S, int E>
332 static constexpr auto _pow(T v, S s, int_constant<E>) {
334 (E > 0) ? S::to_base(v) : S::from_base(v),
336 int_constant<E + ((E > 0) ? -1 : 1)>());
339 template <typename Dir, typename T>
340 static constexpr auto _hlp(Dir, T v) noexcept -> T {
344 template <
typename Dir,
typename T>
345 static constexpr
auto _hlp(Dir d, T v, nothing_t) noexcept -> T {
349 template <
typename Dir,
typename T>
350 static constexpr
auto _hlp(Dir d, T v, dimless) noexcept -> T {
354 template <
typename Dir,
typename T,
typename D,
int E>
355 static constexpr
auto _hlp2(Dir, T v, dim_pow<D, E>) noexcept {
356 using SBU =
typename System ::template base_unit<D>::type;
357 using BS = scales::scale_of_t<SBU>;
361 get_scale_t<Scales, SBU, BS>(),
365 template <
typename Dir,
typename T,
typename D,
int P,
typename Dims>
366 static constexpr
auto
367 _hlp(Dir dir, T v, dims<dim_pow<D, P>, Dims>) noexcept {
368 return _hlp(dir, _hlp2(dir, v, dim_pow<D, P>()), Dims());
374 #endif // EAGINE_UNITS_DETAIL_HPP