1 #pragma once
2 #ifndef CATA_SRC_UNITS_H
3 #define CATA_SRC_UNITS_H
4 
5 #include <cctype>
6 #include <algorithm>
7 #include <cmath>
8 #include <cstddef>
9 #include <limits>
10 #include <map>
11 #include <sstream>
12 #include <string>
13 #include <type_traits>
14 #include <utility>
15 #include <vector>
16 
17 #include "json.h"
18 #include "math_defines.h"
19 #include "translations.h"
20 #include "units_fwd.h" // IWYU pragma: export
21 
22 namespace units
23 {
24 
25 template<typename V, typename U>
26 class quantity
27 {
28     public:
29         using value_type = V;
30         using unit_type = U;
31         using this_type = quantity<value_type, unit_type>;
32 
33         /**
34          * Create an empty quantity - its @ref value_ is value initialized.
35          * It does not need an explicitly named unit, it's always 0: 0 l == 0 ml == 0 Ml.
36          */
quantity()37         constexpr quantity() : value_() {
38         }
39         /**
40          * Construct from value. This is supposed to be wrapped into a static
41          * function (e.g. `from_liter(int)` ) to provide context.
42          */
quantity(const value_type & v,unit_type)43         constexpr quantity( const value_type &v, unit_type ) : value_( v ) {
44         }
45         /**
46          * Conversion from other value type, e.g. from `quantity<int, foo>` to
47          * `quantity<float, foo>`. The unit type stays the same!
48          */
49         template<typename other_value_type>
50         // NOLINTNEXTLINE(google-explicit-constructor)
quantity(const quantity<other_value_type,unit_type> & other)51         constexpr quantity( const quantity<other_value_type, unit_type> &other ) :
52             value_( other.value() ) {
53         }
54 
55         /**
56          * Access the raw dimensionless value. Use it in a properly named wrapper function only.
57          */
value()58         constexpr const value_type &value() const {
59             return value_;
60         }
61 
62         /**
63          * The usual comparators, they compare the base value only.
64          */
65         /**@{*/
66         constexpr bool operator==( const this_type &rhs ) const {
67             return value_ == rhs.value_;
68         }
69         constexpr bool operator!=( const this_type &rhs ) const {
70             return !operator==( rhs );
71         }
72         constexpr bool operator<( const this_type &rhs ) const {
73             return value_ < rhs.value_;
74         }
75         constexpr bool operator>=( const this_type &rhs ) const {
76             return !operator<( rhs );
77         }
78         constexpr bool operator>( const this_type &rhs ) const {
79             return value_ > rhs.value_;
80         }
81         constexpr bool operator<=( const this_type &rhs ) const {
82             return !operator>( rhs );
83         }
84         /**@}*/
85 
86         /**
87          * Addition and subtraction of quantities of the same unit type. Result is
88          * a quantity with the same unit as the input.
89          * Functions are templated to allow combining quantities with different `value_type`, e.g.
90          * \code
91          *   quantity<int, foo> a = ...;
92          *   quantity<double, foo> b = ...;
93          *   auto sum = a + b;
94          *   static_assert(std::is_same<decltype(sum), quantity<double, foo>>::value);
95          * \endcode
96          *
97          * Note that `+=` and `-=` accept any type as `value_type` for the other operand, but
98          * they convert this back to the type of the right hand, like in `int a; a += 0.4;`
99          * \code
100          *   quantity<int, foo> a( 10, foo{} );
101          *   quantity<double, foo> b( 0.5, foo{} );
102          *   a += b;
103          *   cata_assert( a == quantity<int, foo>( 10 + 0.5, foo{} ) );
104          *   cata_assert( a == quantity<int, foo>( 10, foo{} ) );
105          * \endcode
106          */
107         /**@{*/
108         template<typename other_value_type>
109         constexpr quantity < decltype( std::declval<value_type>() + std::declval<other_value_type>() ),
110                   unit_type >
111         operator+( const quantity<other_value_type, unit_type> &rhs ) const {
112             return { value_ + rhs.value(), unit_type{} };
113         }
114         template<typename other_value_type>
115         constexpr quantity < decltype( std::declval<value_type>() + std::declval<other_value_type>() ),
116                   unit_type >
117         operator-( const quantity<other_value_type, unit_type> &rhs ) const {
118             return { value_ - rhs.value(), unit_type{} };
119         }
120 
121         template<typename other_value_type>
122         this_type &operator+=( const quantity<other_value_type, unit_type> &rhs ) {
123             value_ += rhs.value();
124             return *this;
125         }
126         template<typename other_value_type>
127         this_type &operator-=( const quantity<other_value_type, unit_type> &rhs ) {
128             value_ -= rhs.value();
129             return *this;
130         }
131         /**@}*/
132 
133         constexpr this_type operator-() const {
134             return this_type( -value_, unit_type{} );
135         }
136 
137         void serialize( JsonOut &jsout ) const;
138         void deserialize( JsonIn &jsin );
139 
140     private:
141         value_type value_;
142 };
143 
144 template<typename V, typename U>
fabs(quantity<V,U> q)145 inline quantity<V, U> fabs( quantity<V, U> q )
146 {
147     return quantity<V, U>( std::fabs( q.value() ), U{} );
148 }
149 
150 template<typename V, typename U>
fmod(quantity<V,U> num,quantity<V,U> den)151 inline quantity<V, U> fmod( quantity<V, U> num, quantity<V, U> den )
152 {
153     return quantity<V, U>( std::fmod( num.value(), den.value() ), U{} );
154 }
155 
156 /**
157  * Multiplication and division with scalars. Result is a quantity with the same unit
158  * as the input.
159  * Functions are templated to allow scaling with different types:
160  * \code
161  *   quantity<int, foo> a{ 10, foo{} };
162  *   auto b = a * 4.52;
163  *   static_assert(std::is_same<decltype(b), quantity<double, foo>>::value);
164  * \endcode
165  *
166  * Note that the result for `*=` and `/=` is calculated using the given types, but is
167  * implicitly converted back to `value_type` as it is stored in the operand.
168  * \code
169  *   quantity<int, foo> a{ 10, foo{} };
170  *   a *= 4.52;
171  *   cata_assert( a == quantity<int, foo>( 10 * 4.52, foo{} ) );
172  *   cata_assert( a != quantity<int, foo>( 10 * (int)4.52, foo{} ) );
173  *   cata_assert( a == quantity<int, foo>( 45, foo{} ) );
174  * \endcode
175  *
176  * Division of a quantity with a quantity of the same unit yields a dimensionless
177  * scalar value, with the same type as the division of the contained `value_type`s:
178  * \code
179  *   quantity<int, foo> a{ 10, foo{} };
180  *   quantity<double, foo> b{ 20, foo{} };
181  *   auto proportion = a / b;
182  *   static_assert(std::is_same<decltype(proportion), double>::value);
183  *   cata_assert( proportion == 10 / 20.0 );
184  * \endcode
185  *
186  */
187 /**@{*/
188 // the decltype in the result type ensures the returned type has the same scalar type
189 // as you would get when performing the operation directly:
190 // `int * double` => `double` and `char * int` => `int`
191 // st is scalar type (dimensionless)
192 // lvt is the value type (of a quantity) on the left side, rvt is the value type on the right side
193 // ut is unit type (same for left and right side)
194 // The enable_if ensures no ambiguity, the compiler may otherwise not be able to decide whether
195 // "quantity / scalar" or "quantity / other_quanity" is meant.
196 
197 // scalar * quantity<foo, unit> == quantity<decltype(foo * scalar), unit>
198 template<typename lvt, typename ut, typename st, typename = typename std::enable_if<std::is_arithmetic<st>::value>::type>
199 inline constexpr quantity<decltype( std::declval<lvt>() * std::declval<st>() ), ut>
200 operator*( const st &factor, const quantity<lvt, ut> &rhs )
201 {
202     return { factor * rhs.value(), ut{} };
203 }
204 
205 // same as above only with inverse order of operands: quantity * scalar
206 template<typename lvt, typename ut, typename st, typename = typename std::enable_if<std::is_arithmetic<st>::value>::type>
207 inline constexpr quantity<decltype( std::declval<st>() * std::declval<lvt>() ), ut>
208 operator*( const quantity<lvt, ut> &lhs, const st &factor )
209 {
210     return { lhs.value() *factor, ut{} };
211 }
212 
213 // quantity<foo, unit> * quantity<bar, unit> is not supported
214 template<typename lvt, typename ut, typename rvt, typename = typename std::enable_if<std::is_arithmetic<lvt>::value>::type>
215 inline void operator*( quantity<lvt, ut>, quantity<rvt, ut> ) = delete;
216 
217 // operator *=
218 template<typename lvt, typename ut, typename st, typename = typename std::enable_if<std::is_arithmetic<st>::value>::type>
219 inline quantity<lvt, ut> &
220 operator*=( quantity<lvt, ut> &lhs, const st &factor )
221 {
222     lhs = lhs * factor;
223     return lhs;
224 }
225 
226 // and the revers of the multiplication above:
227 // quantity<foo, unit> / scalar == quantity<decltype(foo / scalar), unit>
228 template<typename lvt, typename ut, typename rvt, typename = typename std::enable_if<std::is_arithmetic<rvt>::value>::type>
229 inline constexpr quantity<decltype( std::declval<lvt>() * std::declval<rvt>() ), ut>
230 operator/( const quantity<lvt, ut> &lhs, const rvt &divisor )
231 {
232     return { lhs.value() / divisor, ut{} };
233 }
234 
235 // scalar / quantity<foo, unit> is not supported
236 template<typename lvt, typename ut, typename rvt, typename = typename std::enable_if<std::is_arithmetic<lvt>::value>::type>
237 inline void operator/( lvt, quantity<rvt, ut> ) = delete;
238 
239 // quantity<foo, unit> / quantity<bar, unit> == decltype(foo / bar)
240 template<typename lvt, typename ut, typename rvt>
241 inline constexpr decltype( std::declval<lvt>() / std::declval<rvt>() )
242 operator/( const quantity<lvt, ut> &lhs, const quantity<rvt, ut> &rhs )
243 {
244     return lhs.value() / rhs.value();
245 }
246 
247 // operator /=
248 template<typename lvt, typename ut, typename st, typename = typename std::enable_if<std::is_arithmetic<st>::value>::type>
249 inline quantity<lvt, ut> &
250 operator/=( quantity<lvt, ut> &lhs, const st &divisor )
251 {
252     lhs = lhs / divisor;
253     return lhs;
254 }
255 
256 // remainder:
257 // quantity<foo, unit> % scalar == quantity<decltype(foo % scalar), unit>
258 template<typename lvt, typename ut, typename rvt, typename = typename std::enable_if<std::is_arithmetic<rvt>::value>::type>
259 inline constexpr quantity < decltype( std::declval<lvt>() % std::declval<rvt>() ), ut >
260 operator%( const quantity<lvt, ut> &lhs, const rvt &divisor )
261 {
262     return { lhs.value() % divisor, ut{} };
263 }
264 
265 // scalar % quantity<foo, unit> is not supported
266 template<typename lvt, typename ut, typename rvt, typename = typename std::enable_if<std::is_arithmetic<lvt>::value>::type>
267 inline void operator%( lvt, quantity<rvt, ut> ) = delete;
268 
269 // quantity<foo, unit> % quantity<bar, unit> == decltype(foo % bar)
270 template<typename lvt, typename ut, typename rvt>
271 inline constexpr quantity < decltype( std::declval<lvt>() % std::declval<rvt>() ), ut >
272 operator%( const quantity<lvt, ut> &lhs, const quantity<rvt, ut> &rhs )
273 {
274     return { lhs.value() % rhs.value(), ut{} };
275 }
276 
277 // operator %=
278 template<typename lvt, typename ut, typename st, typename = typename std::enable_if<std::is_arithmetic<st>::value>::type>
279 inline quantity<lvt, ut> &
280 operator%=( quantity<lvt, ut> &lhs, const st &divisor )
281 {
282     lhs = lhs % divisor;
283     return lhs;
284 }
285 template<typename lvt, typename ut, typename rvt>
286 inline quantity<lvt, ut> &
287 operator%=( quantity<lvt, ut> &lhs, const quantity<rvt, ut> &rhs )
288 {
289     lhs = lhs % rhs;
290     return lhs;
291 }
292 /**@}*/
293 
294 const volume volume_min = units::volume( std::numeric_limits<units::volume::value_type>::min(),
295                           units::volume::unit_type{} );
296 
297 const volume volume_max = units::volume( std::numeric_limits<units::volume::value_type>::max(),
298                           units::volume::unit_type{} );
299 
300 template<typename value_type>
from_milliliter(const value_type v)301 inline constexpr quantity<value_type, volume_in_milliliter_tag> from_milliliter(
302     const value_type v )
303 {
304     return quantity<value_type, volume_in_milliliter_tag>( v, volume_in_milliliter_tag{} );
305 }
306 
307 template<typename value_type>
from_liter(const value_type v)308 inline constexpr quantity<value_type, volume_in_milliliter_tag> from_liter( const value_type v )
309 {
310     return from_milliliter<value_type>( v * 1000 );
311 }
312 
313 template<typename value_type>
to_milliliter(const quantity<value_type,volume_in_milliliter_tag> & v)314 inline constexpr value_type to_milliliter( const quantity<value_type, volume_in_milliliter_tag> &v )
315 {
316     return v / from_milliliter<value_type>( 1 );
317 }
318 
to_liter(const volume & v)319 inline constexpr double to_liter( const volume &v )
320 {
321     return v.value() / 1000.0;
322 }
323 
324 // Legacy conversions factor for old volume values.
325 // Don't use in new code! Use one of the from_* functions instead.
326 static constexpr volume legacy_volume_factor = from_milliliter( 250 );
327 
328 const mass mass_min = units::mass( std::numeric_limits<units::mass::value_type>::min(),
329                                    units::mass::unit_type{} );
330 
331 const mass mass_max = units::mass( std::numeric_limits<units::mass::value_type>::max(),
332                                    units::mass::unit_type{} );
333 
334 template<typename value_type>
from_milligram(const value_type v)335 inline constexpr quantity<value_type, mass_in_milligram_tag> from_milligram(
336     const value_type v )
337 {
338     return quantity<value_type, mass_in_milligram_tag>( v, mass_in_milligram_tag{} );
339 }
340 
341 template<typename value_type>
from_gram(const value_type v)342 inline constexpr quantity<value_type, mass_in_milligram_tag> from_gram(
343     const value_type v )
344 {
345     return from_milligram( v * 1000 );
346 }
347 
348 template<typename value_type>
from_kilogram(const value_type v)349 inline constexpr quantity<value_type, mass_in_milligram_tag> from_kilogram(
350     const value_type v )
351 {
352     return from_gram( v * 1000 );
353 }
354 
355 template<typename value_type>
to_milligram(const quantity<value_type,mass_in_milligram_tag> & v)356 inline constexpr value_type to_milligram( const quantity<value_type, mass_in_milligram_tag> &v )
357 {
358     return v.value();
359 }
360 
361 template<typename value_type>
to_gram(const quantity<value_type,mass_in_milligram_tag> & v)362 inline constexpr value_type to_gram( const quantity<value_type, mass_in_milligram_tag> &v )
363 {
364     return v.value() / 1000.0;
365 }
366 
to_kilogram(const mass & v)367 inline constexpr double to_kilogram( const mass &v )
368 {
369     return v.value() / 1000000.0;
370 }
371 
372 const energy energy_min = units::energy( std::numeric_limits<units::energy::value_type>::min(),
373                           units::energy::unit_type{} );
374 
375 const energy energy_max = units::energy( std::numeric_limits<units::energy::value_type>::max(),
376                           units::energy::unit_type{} );
377 
378 template<typename value_type>
from_millijoule(const value_type v)379 inline constexpr quantity<value_type, energy_in_millijoule_tag> from_millijoule(
380     const value_type v )
381 {
382     return quantity<value_type, energy_in_millijoule_tag>( v, energy_in_millijoule_tag{} );
383 }
384 
385 template<typename value_type>
from_joule(const value_type v)386 inline constexpr quantity<value_type, energy_in_millijoule_tag> from_joule( const value_type v )
387 {
388     const value_type max_energy_joules = std::numeric_limits<value_type>::max() / 1000;
389     // Check for overflow - if the energy provided is greater than max energy, then it
390     // if overflow when converted to millijoules
391     const value_type energy = v > max_energy_joules ? max_energy_joules : v;
392     return from_millijoule<value_type>( energy * 1000 );
393 }
394 
395 template<typename value_type>
from_kilojoule(const value_type v)396 inline constexpr quantity<value_type, energy_in_millijoule_tag> from_kilojoule( const value_type v )
397 {
398     const value_type max_energy_joules = std::numeric_limits<value_type>::max() / 1000;
399     // This checks for value_type overflow - if the energy we are given in Joules is greater
400     // than the max energy in Joules, overflow will occur when it is converted to millijoules
401     // The value we are given is in kJ, multiply by 1000 to convert it to joules, for use in from_joule
402     value_type energy = v * 1000 > max_energy_joules ? max_energy_joules : v * 1000;
403     return from_joule<value_type>( energy );
404 }
405 
406 template<typename value_type>
to_millijoule(const quantity<value_type,energy_in_millijoule_tag> & v)407 inline constexpr value_type to_millijoule( const quantity<value_type, energy_in_millijoule_tag> &v )
408 {
409     return v / from_millijoule<value_type>( 1 );
410 }
411 
412 template<typename value_type>
to_joule(const quantity<value_type,energy_in_millijoule_tag> & v)413 inline constexpr value_type to_joule( const quantity<value_type, energy_in_millijoule_tag> &v )
414 {
415     return to_millijoule( v ) / 1000.0;
416 }
417 
418 template<typename value_type>
to_kilojoule(const quantity<value_type,energy_in_millijoule_tag> & v)419 inline constexpr value_type to_kilojoule( const quantity<value_type, energy_in_millijoule_tag> &v )
420 {
421     return to_joule( v ) / 1000.0;
422 }
423 
424 const money money_min = units::money( std::numeric_limits<units::money::value_type>::min(),
425                                       units::money::unit_type{} );
426 
427 const money money_max = units::money( std::numeric_limits<units::money::value_type>::max(),
428                                       units::money::unit_type{} );
429 
430 template<typename value_type>
from_cent(const value_type v)431 inline constexpr quantity<value_type, money_in_cent_tag> from_cent(
432     const value_type v )
433 {
434     return quantity<value_type, money_in_cent_tag>( v, money_in_cent_tag{} );
435 }
436 
437 template<typename value_type>
from_usd(const value_type v)438 inline constexpr quantity<value_type, money_in_cent_tag> from_usd( const value_type v )
439 {
440     return from_cent<value_type>( v * 100 );
441 }
442 
443 template<typename value_type>
from_kusd(const value_type v)444 inline constexpr quantity<value_type, money_in_cent_tag> from_kusd( const value_type v )
445 {
446     return from_usd<value_type>( v * 1000 );
447 }
448 
449 template<typename value_type>
to_cent(const quantity<value_type,money_in_cent_tag> & v)450 inline constexpr value_type to_cent( const quantity<value_type, money_in_cent_tag> &v )
451 {
452     return v / from_cent<value_type>( 1 );
453 }
454 
455 template<typename value_type>
to_usd(const quantity<value_type,money_in_cent_tag> & v)456 inline constexpr value_type to_usd( const quantity<value_type, money_in_cent_tag> &v )
457 {
458     return to_cent( v ) / 100.0;
459 }
460 
461 template<typename value_type>
to_kusd(const quantity<value_type,money_in_cent_tag> & v)462 inline constexpr value_type to_kusd( const quantity<value_type, money_in_cent_tag> &v )
463 {
464     return to_usd( v ) / 1000.0;
465 }
466 
467 const length length_min = units::length( std::numeric_limits<units::length::value_type>::min(),
468                           units::length::unit_type{} );
469 
470 const length length_max = units::length( std::numeric_limits<units::length::value_type>::max(),
471                           units::length::unit_type{} );
472 
473 template<typename value_type>
from_millimeter(const value_type v)474 inline constexpr quantity<value_type, length_in_millimeter_tag> from_millimeter(
475     const value_type v )
476 {
477     return quantity<value_type, length_in_millimeter_tag>( v, length_in_millimeter_tag{} );
478 }
479 
480 template<typename value_type>
from_centimeter(const value_type v)481 inline constexpr quantity<value_type, length_in_millimeter_tag> from_centimeter(
482     const value_type v )
483 {
484     return from_millimeter<value_type>( v * 10 );
485 }
486 
487 template<typename value_type>
from_meter(const value_type v)488 inline constexpr quantity<value_type, length_in_millimeter_tag> from_meter(
489     const value_type v )
490 {
491     return from_millimeter<value_type>( v * 1000 );
492 }
493 
494 template<typename value_type>
from_kilometer(const value_type v)495 inline constexpr quantity<value_type, length_in_millimeter_tag> from_kilometer(
496     const value_type v )
497 {
498     return from_millimeter<value_type>( v * 1'000'000 );
499 }
500 
501 template<typename value_type>
to_millimeter(const quantity<value_type,length_in_millimeter_tag> & v)502 inline constexpr value_type to_millimeter( const quantity<value_type, length_in_millimeter_tag> &v )
503 {
504     return v / from_millimeter<value_type>( 1 );
505 }
506 
507 template<typename value_type>
to_centimeter(const quantity<value_type,length_in_millimeter_tag> & v)508 inline constexpr value_type to_centimeter( const quantity<value_type, length_in_millimeter_tag> &v )
509 {
510     return to_millimeter( v ) / 10.0;
511 }
512 
513 template<typename value_type>
to_meter(const quantity<value_type,length_in_millimeter_tag> & v)514 inline constexpr value_type to_meter( const quantity<value_type, length_in_millimeter_tag> &v )
515 {
516     return to_millimeter( v ) / 1'000.0;
517 }
518 
519 template<typename value_type>
520 inline constexpr value_type to_kilometer( const quantity<value_type, length_in_millimeter_tag> &v )
521 {
522     return to_millimeter( v ) / 1'000'000.0;
523 }
524 
525 template<typename value_type>
526 inline constexpr quantity<value_type, angle_in_radians_tag> from_radians( const value_type v )
527 {
528     return quantity<value_type, angle_in_radians_tag>( v, angle_in_radians_tag{} );
529 }
530 
531 inline constexpr double to_radians( const units::angle v )
532 {
533     return v.value();
534 }
535 
536 template<typename value_type>
537 inline constexpr quantity<double, angle_in_radians_tag> from_degrees( const value_type v )
538 {
539     return from_radians( v * M_PI / 180 );
540 }
541 
542 inline constexpr double to_degrees( const units::angle v )
543 {
544     return to_radians( v ) * 180 / M_PI;
545 }
546 
547 template<typename value_type>
548 inline constexpr quantity<double, angle_in_radians_tag> from_arcmin( const value_type v )
549 {
550     return from_degrees( v / 60.0 );
551 }
552 
553 inline constexpr double to_arcmin( const units::angle v )
554 {
555     return to_degrees( v ) * 60;
556 }
557 
558 // converts a volume as if it were a cube to the length of one side
559 template<typename value_type>
560 inline constexpr quantity<value_type, length_in_millimeter_tag> default_length_from_volume(
561     const quantity<value_type, volume_in_milliliter_tag> &v )
562 {
563     return units::from_centimeter<int>(
564                std::round(
565                    std::cbrt( units::to_milliliter( v ) ) ) );
566 }
567 
568 // Streaming operators for debugging and tests
569 // (for UI output other functions should be used which render in the user's
570 // chosen units)
571 inline std::ostream &operator<<( std::ostream &o, mass_in_milligram_tag )
572 {
573     return o << "mg";
574 }
575 
576 inline std::ostream &operator<<( std::ostream &o, volume_in_milliliter_tag )
577 {
578     return o << "ml";
579 }
580 
581 inline std::ostream &operator<<( std::ostream &o, energy_in_millijoule_tag )
582 {
583     return o << "mJ";
584 }
585 
586 inline std::ostream &operator<<( std::ostream &o, money_in_cent_tag )
587 {
588     return o << "cent";
589 }
590 
591 inline std::ostream &operator<<( std::ostream &o, length_in_millimeter_tag )
592 {
593     return o << "mm";
594 }
595 
596 inline std::ostream &operator<<( std::ostream &o, angle_in_radians_tag )
597 {
598     return o << "rad";
599 }
600 
601 template<typename value_type, typename tag_type>
602 inline std::ostream &operator<<( std::ostream &o, const quantity<value_type, tag_type> &v )
603 {
604     return o << v.value() << tag_type{};
605 }
606 
607 template<typename value_type, typename tag_type>
608 inline std::string quantity_to_string( const quantity<value_type, tag_type> &v )
609 {
610     std::ostringstream os;
611     os << v;
612     return os.str();
613 }
614 
615 inline std::string display( const units::energy v )
616 {
617     const int kj = units::to_kilojoule( v );
618     const int j = units::to_joule( v );
619     // at least 1 kJ and there is no fraction
620     if( kj >= 1 && static_cast<float>( j ) / kj == 1000 ) {
621         return std::to_string( kj ) + ' ' + pgettext( "energy unit: kilojoule", "kJ" );
622     }
623     const int mj = units::to_millijoule( v );
624     // at least 1 J and there is no fraction
625     if( j >= 1 && static_cast<float>( mj ) / j  == 1000 ) {
626         return std::to_string( j ) + ' ' + pgettext( "energy unit: joule", "J" );
627     }
628     return std::to_string( mj ) + ' ' + pgettext( "energy unit: millijoule", "mJ" );
629 }
630 
631 } // namespace units
632 
633 // Implicitly converted to volume, which has int as value_type!
634 inline constexpr units::volume operator"" _ml( const unsigned long long v )
635 {
636     return units::from_milliliter( v );
637 }
638 
639 inline constexpr units::quantity<double, units::volume_in_milliliter_tag> operator"" _ml(
640     const long double v )
641 {
642     return units::from_milliliter( v );
643 }
644 
645 // Implicitly converted to volume, which has int as value_type!
646 inline constexpr units::volume operator"" _liter( const unsigned long long v )
647 {
648     return units::from_milliliter( v * 1000 );
649 }
650 
651 inline constexpr units::quantity<double, units::volume_in_milliliter_tag> operator"" _liter(
652     const long double v )
653 {
654     return units::from_milliliter( v * 1000 );
655 }
656 
657 // Implicitly converted to mass, which has int as value_type!
658 inline constexpr units::mass operator"" _milligram( const unsigned long long v )
659 {
660     return units::from_milligram( v );
661 }
662 inline constexpr units::mass operator"" _gram( const unsigned long long v )
663 {
664     return units::from_gram( v );
665 }
666 
667 inline constexpr units::mass operator"" _kilogram( const unsigned long long v )
668 {
669     return units::from_kilogram( v );
670 }
671 
672 inline constexpr units::quantity<double, units::mass_in_milligram_tag> operator"" _milligram(
673     const long double v )
674 {
675     return units::from_milligram( v );
676 }
677 
678 inline constexpr units::quantity<double, units::mass_in_milligram_tag> operator"" _gram(
679     const long double v )
680 {
681     return units::from_gram( v );
682 }
683 
684 inline constexpr units::quantity<double, units::mass_in_milligram_tag> operator"" _kilogram(
685     const long double v )
686 {
687     return units::from_kilogram( v );
688 }
689 
690 inline constexpr units::energy operator"" _mJ( const unsigned long long v )
691 {
692     return units::from_millijoule( v );
693 }
694 
695 inline constexpr units::quantity<double, units::energy_in_millijoule_tag> operator"" _mJ(
696     const long double v )
697 {
698     return units::from_millijoule( v );
699 }
700 
701 inline constexpr units::energy operator"" _J( const unsigned long long v )
702 {
703     return units::from_joule( v );
704 }
705 
706 inline constexpr units::quantity<double, units::energy_in_millijoule_tag> operator"" _J(
707     const long double v )
708 {
709     return units::from_joule( v );
710 }
711 
712 inline constexpr units::energy operator"" _kJ( const unsigned long long v )
713 {
714     return units::from_kilojoule( v );
715 }
716 
717 inline constexpr units::quantity<double, units::energy_in_millijoule_tag> operator"" _kJ(
718     const long double v )
719 {
720     return units::from_kilojoule( v );
721 }
722 
723 inline constexpr units::money operator"" _cent( const unsigned long long v )
724 {
725     return units::from_cent( v );
726 }
727 
728 inline constexpr units::quantity<double, units::money_in_cent_tag> operator"" _cent(
729     const long double v )
730 {
731     return units::from_cent( v );
732 }
733 
734 inline constexpr units::money operator"" _USD( const unsigned long long v )
735 {
736     return units::from_usd( v );
737 }
738 
739 inline constexpr units::quantity<double, units::money_in_cent_tag> operator"" _USD(
740     const long double v )
741 {
742     return units::from_usd( v );
743 }
744 
745 inline constexpr units::money operator"" _kUSD( const unsigned long long v )
746 {
747     return units::from_kusd( v );
748 }
749 
750 inline constexpr units::quantity<double, units::money_in_cent_tag> operator"" _kUSD(
751     const long double v )
752 {
753     return units::from_kusd( v );
754 }
755 
756 inline constexpr units::quantity<double, units::length_in_millimeter_tag> operator"" _mm(
757     const long double v )
758 {
759     return units::from_millimeter( v );
760 }
761 
762 inline constexpr units::length operator"" _mm( const unsigned long long v )
763 {
764     return units::from_millimeter( v );
765 }
766 
767 inline constexpr units::quantity<double, units::length_in_millimeter_tag> operator"" _cm(
768     const long double v )
769 {
770     return units::from_centimeter( v );
771 }
772 
773 inline constexpr units::length operator"" _cm( const unsigned long long v )
774 {
775     return units::from_centimeter( v );
776 }
777 
778 inline constexpr units::quantity<double, units::length_in_millimeter_tag> operator"" _meter(
779     const long double v )
780 {
781     return units::from_meter( v );
782 }
783 
784 inline constexpr units::length operator"" _meter( const unsigned long long v )
785 {
786     return units::from_meter( v );
787 }
788 
789 inline constexpr units::quantity<double, units::length_in_millimeter_tag> operator"" _km(
790     const long double v )
791 {
792     return units::from_kilometer( v );
793 }
794 
795 inline constexpr units::length operator"" _km( const unsigned long long v )
796 {
797     return units::from_kilometer( v );
798 }
799 
800 inline constexpr units::angle operator"" _radians( const long double v )
801 {
802     return units::from_radians( v );
803 }
804 
805 inline constexpr units::angle operator"" _radians( const unsigned long long v )
806 {
807     return units::from_radians( v );
808 }
809 
810 inline constexpr units::angle operator"" _pi_radians( const long double v )
811 {
812     return units::from_radians( v * M_PI );
813 }
814 
815 inline constexpr units::angle operator"" _pi_radians( const unsigned long long v )
816 {
817     return units::from_radians( v * M_PI );
818 }
819 
820 inline constexpr units::angle operator"" _degrees( const long double v )
821 {
822     return units::from_degrees( v );
823 }
824 
825 inline constexpr units::angle operator"" _degrees( const unsigned long long v )
826 {
827     return units::from_degrees( v );
828 }
829 
830 inline constexpr units::angle operator"" _arcmin( const long double v )
831 {
832     return units::from_arcmin( v );
833 }
834 
835 inline constexpr units::angle operator"" _arcmin( const unsigned long long v )
836 {
837     return units::from_arcmin( v );
838 }
839 
840 namespace units
841 {
842 
sin(angle a)843 inline double sin( angle a )
844 {
845     return std::sin( to_radians( a ) );
846 }
847 
cos(angle a)848 inline double cos( angle a )
849 {
850     return std::cos( to_radians( a ) );
851 }
852 
tan(angle a)853 inline double tan( angle a )
854 {
855     return std::tan( to_radians( a ) );
856 }
857 
atan2(double y,double x)858 inline units::angle atan2( double y, double x )
859 {
860     return from_radians( std::atan2( y, x ) );
861 }
862 
863 static const std::vector<std::pair<std::string, energy>> energy_units = { {
864         { "mJ", 1_mJ },
865         { "J", 1_J },
866         { "kJ", 1_kJ },
867     }
868 };
869 static const std::vector<std::pair<std::string, mass>> mass_units = { {
870         { "mg", 1_milligram },
871         { "g", 1_gram },
872         { "kg", 1_kilogram },
873     }
874 };
875 static const std::vector<std::pair<std::string, money>> money_units = { {
876         { "cent", 1_cent },
877         { "USD", 1_USD },
878         { "kUSD", 1_kUSD },
879     }
880 };
881 static const std::vector<std::pair<std::string, volume>> volume_units = { {
882         { "ml", 1_ml },
883         { "L", 1_liter }
884     }
885 };
886 static const std::vector<std::pair<std::string, length>> length_units = { {
887         { "mm", 1_mm },
888         { "cm", 1_cm },
889         { "meter", 1_meter },
890         { "km", 1_km }
891     }
892 };
893 static const std::vector<std::pair<std::string, angle>> angle_units = { {
894         { "arcmin", 1_arcmin },
895         { "°", 1_degrees },
896         { "rad", 1_radians },
897     }
898 };
899 } // namespace units
900 
901 template<typename T>
read_from_json_string(JsonIn & jsin,const std::vector<std::pair<std::string,T>> & units)902 T read_from_json_string( JsonIn &jsin, const std::vector<std::pair<std::string, T>> &units )
903 {
904     const size_t pos = jsin.tell();
905     size_t i = 0;
906     const auto error = [&]( const char *const msg ) {
907         jsin.seek( pos + i );
908         jsin.error( msg );
909     };
910 
911     const std::string s = jsin.get_string();
912     // returns whether we are at the end of the string
913     const auto skip_spaces = [&]() {
914         while( i < s.size() && s[i] == ' ' ) {
915             ++i;
916         }
917         return i >= s.size();
918     };
919     const auto get_unit = [&]() {
920         if( skip_spaces() ) {
921             error( "invalid quantity string: missing unit" );
922         }
923         for( const auto &pair : units ) {
924             const std::string &unit = pair.first;
925             if( s.size() >= unit.size() + i && s.compare( i, unit.size(), unit ) == 0 ) {
926                 i += unit.size();
927                 return pair.second;
928             }
929         }
930         error( "invalid quantity string: unknown unit" );
931         // above always throws but lambdas cannot be marked [[noreturn]]
932         throw std::string( "Exceptionally impossible" );
933     };
934 
935     if( skip_spaces() ) {
936         error( "invalid quantity string: empty string" );
937     }
938     T result{};
939     do {
940         int sign_value = +1;
941         if( s[i] == '-' ) {
942             sign_value = -1;
943             ++i;
944         } else if( s[i] == '+' ) {
945             ++i;
946         }
947         if( i >= s.size() || !isdigit( s[i] ) ) {
948             error( "invalid quantity string: number expected" );
949         }
950         int value = 0;
951         for( ; i < s.size() && isdigit( s[i] ); ++i ) {
952             value = value * 10 + ( s[i] - '0' );
953         }
954         result += sign_value * value * get_unit();
955     } while( !skip_spaces() );
956     return result;
957 }
958 
959 template<typename T>
dump_to_json_string(T t,JsonOut & jsout,const std::vector<std::pair<std::string,T>> & units)960 void dump_to_json_string( T t, JsonOut &jsout,
961                           const std::vector<std::pair<std::string, T>> &units )
962 {
963     // deduplicate unit strings and choose the shortest representations
964     std::map<T, std::string> sorted_units;
965     for( const auto &p : units ) {
966         const auto it = sorted_units.find( p.second );
967         if( it != sorted_units.end() ) {
968             if( p.first.length() < it->second.length() ) {
969                 it->second = p.first;
970             }
971         } else {
972             sorted_units.emplace( p.second, p.first );
973         }
974     }
975     std::string str;
976     bool written = false;
977     for( auto it = sorted_units.rbegin(); it != sorted_units.rend(); ++it ) {
978         const int val = static_cast<int>( t / it->first );
979         if( val != 0 ) {
980             if( written ) {
981                 str += ' ';
982             }
983             int tmp = val;
984             if( tmp < 0 ) {
985                 str += '-';
986                 tmp = -tmp;
987             }
988             const size_t val_beg = str.size();
989             while( tmp != 0 ) {
990                 str += static_cast<char>( '0' + tmp % 10 );
991                 tmp /= 10;
992             }
993             std::reverse( str.begin() + val_beg, str.end() );
994             str += ' ';
995             str += it->second;
996             written = true;
997             t -= it->first * val;
998         }
999     }
1000     if( str.empty() ) {
1001         str = "0 " + sorted_units.begin()->second;
1002     }
1003     jsout.write( str );
1004 }
1005 
1006 #endif // CATA_SRC_UNITS_H
1007