2018-08-22 12:11:19 +02:00
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
2020-09-10 11:33:58 +02:00
# include "test_tools.h"
2021-03-30 13:21:05 +02:00
# include <units/bits/dimension_op.h>
# include <units/bits/external/type_traits.h>
# include <units/exponent.h>
# include <units/generic/dimensionless.h>
# include <units/isq/si/area.h>
# include <units/isq/si/cgs/length.h>
# include <units/isq/si/fps/length.h>
# include <units/isq/si/frequency.h>
# include <units/isq/si/prefixes.h>
# include <units/isq/si/speed.h>
# include <units/isq/si/time.h>
# include <units/isq/si/volume.h>
# include <units/unit.h>
# include <limits>
# include <type_traits>
2019-12-04 17:46:19 +01:00
# include <utility>
2018-10-19 13:02:58 +02:00
2018-09-28 07:47:37 -07:00
namespace {
2019-12-04 17:46:19 +01:00
using namespace units ;
2021-03-16 12:03:25 +01:00
namespace si = isq : : si ;
2021-01-18 15:55:55 -04:00
using namespace si ;
2021-03-18 14:03:43 -04:00
using namespace references ;
2021-01-18 15:55:55 -04:00
2021-03-18 14:03:43 -04:00
constexpr auto cgs_cm = cgs : : references : : cm ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
//////////////////////////////
// quantity class invariants
//////////////////////////////
static_assert ( sizeof ( length < metre > ) = = sizeof ( double ) ) ;
static_assert ( sizeof ( length < metre , short > ) = = sizeof ( short ) ) ;
2021-03-15 21:13:21 +01:00
# if UNITS_COMP_GCC != 10 || UNITS_COMP_GCC_MINOR > 2
2020-10-06 18:17:52 +02:00
template < template < typename , typename , typename > typename Q >
concept invalid_types = requires {
requires ! requires { typename Q < dim_length , second , int > ; } ; // unit of a different dimension
requires ! requires { typename Q < dim_length , metre , length < metre > > ; } ; // quantity used as Rep
requires ! requires { typename Q < metre , dim_length , double > ; } ; // reordered arguments
requires ! requires { typename Q < metre , double , dim_length > ; } ; // reordered arguments
2020-09-05 21:41:02 -04:00
} ;
2020-10-06 18:17:52 +02:00
static_assert ( invalid_types < quantity > ) ;
# endif
static_assert ( std : : is_trivially_default_constructible_v < length < metre > > ) ;
static_assert ( std : : is_trivially_copy_constructible_v < length < metre > > ) ;
static_assert ( std : : is_trivially_move_constructible_v < length < metre > > ) ;
static_assert ( std : : is_trivially_copy_assignable_v < length < metre > > ) ;
static_assert ( std : : is_trivially_move_assignable_v < length < metre > > ) ;
static_assert ( std : : is_trivially_destructible_v < length < metre > > ) ;
static_assert ( std : : is_nothrow_default_constructible_v < length < metre > > ) ;
static_assert ( std : : is_nothrow_copy_constructible_v < length < metre > > ) ;
static_assert ( std : : is_nothrow_move_constructible_v < length < metre > > ) ;
static_assert ( std : : is_nothrow_copy_assignable_v < length < metre > > ) ;
static_assert ( std : : is_nothrow_move_assignable_v < length < metre > > ) ;
static_assert ( std : : is_nothrow_destructible_v < length < metre > > ) ;
static_assert ( std : : is_trivially_copyable_v < length < metre > > ) ;
static_assert ( std : : is_standard_layout_v < length < metre > > ) ;
static_assert ( std : : default_initializable < length < metre > > ) ;
static_assert ( std : : move_constructible < length < metre > > ) ;
static_assert ( std : : copy_constructible < length < metre > > ) ;
static_assert ( std : : equality_comparable < length < metre > > ) ;
static_assert ( std : : totally_ordered < length < metre > > ) ;
static_assert ( std : : regular < length < metre > > ) ;
static_assert ( std : : three_way_comparable < length < metre > > ) ;
2020-09-05 21:41:02 -04:00
2020-10-06 18:17:52 +02:00
//////////////////
2019-12-04 17:46:19 +01:00
// member types
2020-10-06 18:17:52 +02:00
//////////////////
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
static_assert ( is_same_v < length < metre , int > : : dimension , dim_length > ) ;
static_assert ( is_same_v < fps : : length < fps : : mile > : : dimension , fps : : dim_length > ) ;
2020-06-29 20:30:59 +02:00
static_assert ( is_same_v < length < metre , int > : : unit , metre > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( is_same_v < fps : : length < fps : : mile > : : unit , fps : : mile > ) ;
static_assert ( is_same_v < length < metre , int > : : rep , int > ) ;
static_assert ( is_same_v < fps : : length < fps : : mile > : : rep , double > ) ;
////////////////////////////
// static member functions
////////////////////////////
2021-03-19 06:47:37 +01:00
static_assert ( length < metre , int > : : zero ( ) . number ( ) = = 0 ) ;
static_assert ( length < metre , int > : : min ( ) . number ( ) = = std : : numeric_limits < int > : : lowest ( ) ) ;
static_assert ( length < metre , int > : : max ( ) . number ( ) = = std : : numeric_limits < int > : : max ( ) ) ;
static_assert ( length < metre , double > : : zero ( ) . number ( ) = = 0.0 ) ;
static_assert ( length < metre , double > : : min ( ) . number ( ) = = std : : numeric_limits < double > : : lowest ( ) ) ;
static_assert ( length < metre , double > : : max ( ) . number ( ) = = std : : numeric_limits < double > : : max ( ) ) ;
2020-10-06 18:17:52 +02:00
//////////////////////////////
// construction from a value
//////////////////////////////
// only explicit construction from a value
static_assert ( std : : constructible_from < length < metre > , double > ) ;
static_assert ( ! std : : convertible_to < double , length < metre > > ) ;
static_assert ( std : : constructible_from < length < metre > , float > ) ;
static_assert ( ! std : : convertible_to < float , length < metre > > ) ;
static_assert ( std : : constructible_from < length < metre , float > , double > ) ; // truncating implicit conversions double -> float allowed
static_assert ( ! std : : convertible_to < double , length < metre , float > > ) ;
static_assert ( std : : constructible_from < length < metre > , int > ) ;
static_assert ( ! std : : convertible_to < int , length < metre > > ) ;
static_assert ( std : : constructible_from < length < metre > , short > ) ;
static_assert ( ! std : : convertible_to < short , length < metre > > ) ;
static_assert ( std : : constructible_from < length < metre , short > , int > ) ; // truncating implicit conversions int -> short allowed
static_assert ( ! std : : convertible_to < int , length < metre , short > > ) ;
// exception, implicit construction from a value allowed for a dimensionless quantity
static_assert ( std : : constructible_from < dimensionless < one > , double > ) ;
static_assert ( std : : convertible_to < double , dimensionless < one > > ) ;
static_assert ( std : : constructible_from < dimensionless < one > , float > ) ;
static_assert ( std : : convertible_to < float , dimensionless < one > > ) ;
static_assert ( std : : constructible_from < dimensionless < one , float > , double > ) ;
static_assert ( std : : convertible_to < double , dimensionless < one , float > > ) ;
static_assert ( std : : constructible_from < dimensionless < one > , int > ) ;
static_assert ( std : : convertible_to < int , dimensionless < one > > ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
static_assert ( std : : constructible_from < dimensionless < one > , short > ) ;
static_assert ( std : : convertible_to < short , dimensionless < one > > ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
static_assert ( std : : constructible_from < dimensionless < one , short > , int > ) ;
static_assert ( std : : convertible_to < int , dimensionless < one , short > > ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
// but only if a dimensionless quantity has a ratio(1)
static_assert ( std : : constructible_from < dimensionless < percent > , double > ) ;
static_assert ( ! std : : convertible_to < double , dimensionless < percent > > ) ;
static_assert ( std : : constructible_from < dimensionless < percent > , float > ) ;
static_assert ( ! std : : convertible_to < float , dimensionless < percent > > ) ;
static_assert ( std : : constructible_from < dimensionless < percent , float > , double > ) ; // truncating implicit conversions double -> float allowed
static_assert ( ! std : : convertible_to < double , dimensionless < percent , float > > ) ;
static_assert ( std : : constructible_from < dimensionless < percent > , int > ) ;
static_assert ( ! std : : convertible_to < int , dimensionless < percent > > ) ;
static_assert ( std : : constructible_from < dimensionless < percent > , short > ) ;
static_assert ( ! std : : convertible_to < short , dimensionless < percent > > ) ;
static_assert ( std : : constructible_from < dimensionless < percent , short > , int > ) ; // truncating implicit conversions int -> short allowed
static_assert ( ! std : : convertible_to < int , dimensionless < percent , short > > ) ;
// floating-point to integral truncating conversion not allowed
static_assert ( ! std : : constructible_from < length < metre , int > , double > ) ;
static_assert ( ! std : : convertible_to < double , length < metre , int > > ) ;
static_assert ( ! std : : constructible_from < dimensionless < one , int > , double > ) ;
static_assert ( ! std : : convertible_to < double , dimensionless < one , int > > ) ;
2021-03-19 06:47:37 +01:00
static_assert ( length < metre , int > ( ) . number ( ) = = 0 ) ; // value initialization
static_assert ( length < metre , int > ( 1 ) . number ( ) = = 1 ) ;
static_assert ( length < metre , double > ( 1.0 ) . number ( ) = = 1.0 ) ;
static_assert ( length < metre , double > ( 1 ) . number ( ) = = 1.0 ) ;
static_assert ( length < metre , double > ( 3.14 ) . number ( ) = = 3.14 ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
///////////////////////////////////////
// construction from another quantity
///////////////////////////////////////
// conversion only between equivalent dimensions
static_assert ( std : : constructible_from < length < metre > , length < metre > > ) ;
static_assert ( std : : convertible_to < length < metre > , length < metre > > ) ;
static_assert ( std : : constructible_from < length < centimetre > , cgs : : length < cgs : : centimetre > > ) ;
static_assert ( std : : convertible_to < cgs : : length < cgs : : centimetre > , length < centimetre > > ) ;
static_assert ( std : : constructible_from < fps : : length < fps : : foot > , cgs : : length < cgs : : centimetre > > ) ;
static_assert ( std : : convertible_to < cgs : : length < cgs : : centimetre > , fps : : length < fps : : foot > > ) ;
// conversion between different dimensions not allowed
2021-03-16 12:03:25 +01:00
static_assert ( ! std : : constructible_from < length < metre > , isq : : si : : time < second > > ) ;
static_assert ( ! std : : convertible_to < isq : : si : : time < second > , length < metre > > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( ! std : : constructible_from < length < metre > , speed < metre_per_second > > ) ;
static_assert ( ! std : : convertible_to < speed < metre_per_second > , length < metre > > ) ;
// implicit conversion from another quantity only if non-truncating
static_assert ( std : : constructible_from < length < metre > , length < metre , int > > ) ; // int -> double OK
static_assert ( std : : convertible_to < length < metre , int > , length < metre > > ) ; // int -> double OK
static_assert ( ! std : : constructible_from < length < metre , int > , length < metre > > ) ; // truncating double -> int not allowed
static_assert ( ! std : : convertible_to < length < metre > , length < metre , int > > ) ; // truncating double -> int not allowed
static_assert ( std : : constructible_from < length < metre , int > , length < kilometre , int > > ) ; // kilometre<int> -> metre<int> OK
static_assert ( std : : convertible_to < length < kilometre , int > , length < metre , int > > ) ; // kilometre<int> -> metre<int> OK
static_assert ( ! std : : constructible_from < length < kilometre , int > , length < metre , int > > ) ; // truncating metre<int> -> kilometre<int> not allowed
static_assert ( ! std : : convertible_to < length < metre , int > , length < kilometre , int > > ) ; // truncating metre<int> -> kilometre<int> not allowed
// converting to double always OK
2021-01-04 18:36:26 -04:00
static_assert ( std : : constructible_from < length < metre > , length < kilometre , int > > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( std : : convertible_to < length < kilometre , int > , length < metre > > ) ;
static_assert ( std : : constructible_from < length < kilometre > , length < metre , int > > ) ;
static_assert ( std : : convertible_to < length < metre , int > , length < kilometre > > ) ;
2021-03-19 06:47:37 +01:00
static_assert ( length < metre , int > ( 123 _q_m ) . number ( ) = = 123 ) ;
static_assert ( length < kilometre , int > ( 2 _q_km ) . number ( ) = = 2 ) ;
static_assert ( length < metre , int > ( 2 _q_km ) . number ( ) = = 2000 ) ;
static_assert ( length < kilometre > ( 1500 _q_m ) . number ( ) = = 1.5 ) ;
2020-10-06 18:17:52 +02:00
2021-06-27 13:42:55 +02:00
///////////////////////////////////////
// derived quantities
///////////////////////////////////////
2021-08-02 22:15:54 +02:00
template < Representation Rep , Quantity Q , const basic_fixed_string additional_nttp_argument >
2021-06-27 13:42:55 +02:00
struct derived_quantity : quantity < typename Q : : dimension , typename Q : : unit , Rep > {
2021-09-09 09:26:23 +02:00
using dimension = typename Q : : dimension ;
using unit = typename Q : : unit ;
using rep = Rep ;
using R = quantity < dimension , unit , Rep > ;
derived_quantity ( ) = default ;
constexpr explicit ( ! std : : is_trivial_v < Rep > ) derived_quantity ( const R & t ) : R ( t ) { }
constexpr explicit ( ! std : : is_trivial_v < Rep > ) derived_quantity ( R & & t ) : R ( std : : move ( t ) ) { }
constexpr derived_quantity & operator = ( const R & t ) { R : : operator = ( t ) ; return * this ; }
constexpr derived_quantity & operator = ( R & & t ) { R : : operator = ( std : : move ( t ) ) ; return * this ; }
constexpr operator R & ( ) & noexcept { return * this ; }
constexpr operator const R & ( ) const & noexcept { return * this ; }
constexpr operator R & & ( ) & & noexcept { return * this ; }
constexpr operator const R & & ( ) const & & noexcept { return * this ; }
2021-06-27 13:42:55 +02:00
} ;
2021-08-02 22:15:54 +02:00
static_assert ( detail : : is_quantity < derived_quantity < double , si : : length < metre > , " NTTP type description " > > ) ;
2021-09-09 09:26:23 +02:00
constexpr isq : : Length auto get_length_derived_quantity ( ) noexcept
{
derived_quantity < double , si : : length < metre > , " NTTP type description " > a { } ;
a + = 1 _q_m ;
a = a + 1 _q_m ;
a * = 0.5 ;
return a ;
2021-08-02 22:15:54 +02:00
}
static_assert ( get_length_derived_quantity ( ) = = 1 _q_m ) ;
2020-10-06 18:17:52 +02:00
/////////
// CTAD
/////////
2021-10-20 20:18:15 +02:00
# if UNITS_COMP_GCC >= 11 || UNITS_COMP_CLANG > 13
2021-10-20 18:52:13 +02:00
static_assert ( std : : is_same_v < decltype ( units : : aliases : : isq : : si : : m ( 123 ) ) : : rep , int > ) ;
static_assert ( std : : is_same_v < decltype ( units : : aliases : : isq : : si : : m ( 123. ) ) : : rep , double > ) ;
2021-10-20 19:58:31 +02:00
# endif
2021-10-20 18:52:13 +02:00
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( quantity { length < metre , int > ( 123 ) } ) , length < metre , int > > ) ;
static_assert ( is_same_v < decltype ( quantity { speed < metre_per_second > ( 123 ) } ) , speed < metre_per_second > > ) ;
// static_assert(is_same_v<decltype(length{length<metre, int>(123)}), length<metre, int>>); // TODO gcc ICE
static_assert ( is_same_v < decltype ( quantity { 123 _q_m } ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( quantity { 1 } ) , dimensionless < one , int > > ) ;
static_assert ( is_same_v < decltype ( quantity { 1.23 } ) , dimensionless < one , double > > ) ;
2020-10-06 18:17:52 +02:00
////////////////////////
2019-12-04 17:46:19 +01:00
// assignment operator
2020-10-06 18:17:52 +02:00
////////////////////////
2019-12-04 17:46:19 +01:00
2021-03-19 06:47:37 +01:00
static_assert ( [ ] ( ) { length < metre , int > l1 ( 1 ) , l2 ( 2 ) ; return l2 = l1 ; } ( ) . number ( ) = = 1 ) ;
static_assert ( [ ] ( ) { length < metre , int > l1 ( 1 ) , l2 ( 2 ) ; return l2 = std : : move ( l1 ) ; } ( ) . number ( ) = = 1 ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
////////////////////
// unary operators
////////////////////
2021-03-19 06:47:37 +01:00
static_assert ( ( + 123 _q_m ) . number ( ) = = 123 ) ;
static_assert ( ( - 123 _q_m ) . number ( ) = = - 123 ) ;
static_assert ( ( + ( - 123 _q_m ) ) . number ( ) = = - 123 ) ;
static_assert ( ( - ( - 123 _q_m ) ) . number ( ) = = 123 ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
static_assert ( [ ] ( auto v ) { auto vv = v + + ; return std : : pair ( v , vv ) ; } ( 123 _q_m ) = = std : : pair ( 124 _q_m , 123 _q_m ) ) ;
static_assert ( [ ] ( auto v ) { auto vv = + + v ; return std : : pair ( v , vv ) ; } ( 123 _q_m ) = = std : : pair ( 124 _q_m , 124 _q_m ) ) ;
static_assert ( [ ] ( auto v ) { auto vv = v - - ; return std : : pair ( v , vv ) ; } ( 123 _q_m ) = = std : : pair ( 122 _q_m , 123 _q_m ) ) ;
static_assert ( [ ] ( auto v ) { auto vv = - - v ; return std : : pair ( v , vv ) ; } ( 123 _q_m ) = = std : : pair ( 122 _q_m , 122 _q_m ) ) ;
2019-12-04 17:46:19 +01:00
2021-05-03 19:44:50 +02:00
static_assert ( is_same_v < decltype ( ( + ( short { 0 } * m ) ) . number ( ) ) , int & & > ) ;
2021-02-06 02:20:00 -04:00
2020-10-06 18:17:52 +02:00
////////////////////////
2019-12-04 17:46:19 +01:00
// compound assignment
2020-10-06 18:17:52 +02:00
////////////////////////
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
// same type
2021-03-19 06:47:37 +01:00
static_assert ( ( 1 _q_m + = 1 _q_m ) . number ( ) = = 2 ) ;
static_assert ( ( 2 _q_m - = 1 _q_m ) . number ( ) = = 1 ) ;
static_assert ( ( 1 _q_m * = 2 ) . number ( ) = = 2 ) ;
static_assert ( ( 2 _q_m / = 2 ) . number ( ) = = 1 ) ;
static_assert ( ( 7 _q_m % = 2 ) . number ( ) = = 1 ) ;
static_assert ( ( 1 _q_m * = quantity ( 2 ) ) . number ( ) = = 2 ) ;
static_assert ( ( 2 _q_m / = quantity ( 2 ) ) . number ( ) = = 1 ) ;
static_assert ( ( 7 _q_m % = quantity ( 2 ) ) . number ( ) = = 1 ) ;
static_assert ( ( 7 _q_m % = 2 _q_m ) . number ( ) = = 1 ) ;
2018-09-28 07:47:37 -07:00
2020-10-06 18:17:52 +02:00
// different types
2021-03-19 06:47:37 +01:00
static_assert ( ( 2.5 _q_m + = 3 _q_m ) . number ( ) = = 5.5 ) ;
static_assert ( ( 123 _q_m + = 1 _q_km ) . number ( ) = = 1123 ) ;
static_assert ( ( 5.5 _q_m - = 3 _q_m ) . number ( ) = = 2.5 ) ;
static_assert ( ( 1123 _q_m - = 1 _q_km ) . number ( ) = = 123 ) ;
static_assert ( ( 2.5 _q_m * = 3 ) . number ( ) = = 7.5 ) ;
static_assert ( ( 7.5 _q_m / = 3 ) . number ( ) = = 2.5 ) ;
static_assert ( ( 2.5 _q_m * = quantity ( 3 ) ) . number ( ) = = 7.5 ) ;
static_assert ( ( 7.5 _q_m / = quantity ( 3 ) ) . number ( ) = = 2.5 ) ;
static_assert ( ( 3500 _q_m % = 1 _q_km ) . number ( ) = = 500 ) ;
static_assert ( ( std : : uint8_t ( 255 ) * m % = 256 ) . number ( ) = = [ ] { std : : uint8_t ui ( 255 ) ; return ui % = 256 ; } ( ) ) ;
static_assert ( ( std : : uint8_t ( 255 ) * m % = quantity ( 256 ) ) . number ( ) = = [ ] { std : : uint8_t ui ( 255 ) ; return ui % = 256 ; } ( ) ) ;
// static_assert((std::uint8_t(255) * m %= 256 * m).number() != [] { std::uint8_t ui(255); return ui %= 256; }()); // UB
static_assert ( ( std : : uint8_t ( 255 ) * m % = 257 ) . number ( ) = = [ ] { std : : uint8_t ui ( 255 ) ; return ui % = 257 ; } ( ) ) ;
static_assert ( ( std : : uint8_t ( 255 ) * m % = quantity ( 257 ) ) . number ( ) = = [ ] { std : : uint8_t ui ( 255 ) ; return ui % = 257 ; } ( ) ) ;
2021-02-06 02:20:00 -04:00
// TODO: Fix
2021-03-19 06:47:37 +01:00
static_assert ( ( std : : uint8_t ( 255 ) * m % = 257 * m ) . number ( ) ! = [ ] { std : : uint8_t ui ( 255 ) ; return ui % = 257 ; } ( ) ) ;
2021-02-06 02:20:00 -04:00
2021-03-15 21:13:21 +01:00
# ifndef UNITS_COMP_MSVC // TODO ICE (https://developercommunity2.visualstudio.com/t/ICE-on-a-constexpr-operator-in-mp-unit/1302907)
2021-01-06 19:06:09 +01:00
// next two lines trigger conversions warnings
2021-01-06 16:44:32 +01:00
// (warning disabled in CMake for this file)
2021-03-19 06:47:37 +01:00
static_assert ( ( 22 _q_m * = 33.33 ) . number ( ) = = 733 ) ;
static_assert ( ( 22 _q_m / = 3.33 ) . number ( ) = = 6 ) ;
static_assert ( ( 22 _q_m * = quantity ( 33.33 ) ) . number ( ) = = 733 ) ;
static_assert ( ( 22 _q_m / = quantity ( 3.33 ) ) . number ( ) = = 6 ) ;
2021-01-06 19:06:09 +01:00
# endif
2021-01-06 16:44:32 +01:00
2021-02-16 18:40:03 -04:00
template < typename Metre , typename Kilometre >
2020-10-06 18:17:52 +02:00
concept invalid_compound_assignments = requires ( ) {
// truncating not allowed
requires ! requires ( length < Metre , int > l ) { l + = 2.5 _q_m ; } ;
requires ! requires ( length < Metre , int > l ) { l - = 2.5 _q_m ; } ;
2021-02-16 18:40:03 -04:00
requires ! requires ( length < Kilometre , int > l ) { l + = length < Metre , int > ( 2 ) ; } ;
requires ! requires ( length < Kilometre , int > l ) { l - = length < Metre , int > ( 2 ) ; } ;
requires ! requires ( length < Kilometre , int > l ) { l % = length < Metre , int > ( 2 ) ; } ;
requires ! requires ( length < Kilometre , int > l ) { l % = dimensionless < percent , int > ( 2 ) ; } ;
requires ! requires ( length < Kilometre , int > l ) { l % = dimensionless < percent , double > ( 2 ) ; } ;
// TODO: accept non-truncating argument
2021-03-18 16:09:00 -04:00
requires ! requires ( length < Kilometre , int > l ) { l * = 1 * ( km / m ) ; } ;
requires ! requires ( length < Kilometre , int > l ) { l / = 1 * ( km / m ) ; } ;
requires ! requires ( length < Kilometre , int > l ) { l % = 1 * ( km / m ) ; } ;
2020-10-06 18:17:52 +02:00
// only quantities can be added or subtracted
requires ! requires ( length < Metre , int > l ) { l + = 2 ; } ;
requires ! requires ( length < Metre , int > l ) { l - = 2 ; } ;
// compound multiply/divide by another quantity not allowed
requires ! requires ( length < Metre , int > l ) { l * = 2 _q_m ; } ;
requires ! requires ( length < Metre , int > l ) { l / = 2 _q_m ; } ;
// modulo operations on a floating point representation not allowed
2020-09-23 16:38:40 +02:00
requires ! requires ( length < Metre , double > l ) { l % = 2. ; } ;
requires ! requires ( length < Metre , double > l ) { l % = 2 ; } ;
requires ! requires ( length < Metre , double > l ) { l % = 2. _q_m ; } ;
requires ! requires ( length < Metre , double > l ) { l % = 2 _q_m ; } ;
requires ! requires ( length < Metre , int > l ) { l % = 2. _q_m ; } ;
2021-03-17 15:20:07 -04:00
// no unit constants
requires ! requires ( length < Metre , int > l ) { l + = m ; } ;
requires ! requires ( length < Metre , int > l ) { l - = m ; } ;
requires ! requires ( length < Metre , int > l ) { l * = m ; } ;
requires ! requires ( length < Metre , int > l ) { l / = m ; } ;
requires ! requires ( length < Metre , int > l ) { l % = m ; } ;
2020-09-05 21:41:02 -04:00
} ;
2021-02-16 18:40:03 -04:00
static_assert ( invalid_compound_assignments < metre , kilometre > ) ;
2020-09-05 21:41:02 -04:00
2020-10-06 18:17:52 +02:00
////////////////////
// binary operators
////////////////////
template < typename Metre >
concept invalid_binary_operations = requires {
// no crossdimensional addition and subtraction
requires ! requires { 1 _q_s + length < Metre , int > ( 1 ) ; } ;
requires ! requires { 1 _q_s - length < Metre , int > ( 1 ) ; } ;
// no floating-point modulo
requires ! requires ( length < Metre , double > a ) { a % 2 _q_m ; } ;
requires ! requires ( length < Metre , double > a ) { 2 _q_m % a ; } ;
requires ! requires ( length < Metre , double > a ) { a % 2 ; } ;
requires ! requires ( length < Metre , double > a , length < Metre , double > b ) { a % b ; } ;
requires ! requires ( length < Metre , double > a , length < Metre , int > b ) { a % b ; } ;
requires ! requires ( length < Metre , double > a , length < Metre , int > b ) { b % a ; } ;
2021-03-17 15:20:07 -04:00
// unit constants
requires ! requires { length < Metre , int > ( 1 ) + m ; } ;
requires ! requires { length < Metre , int > ( 1 ) - m ; } ;
requires ! requires { length < Metre , int > ( 1 ) % m ; } ;
requires ! requires { m + length < Metre , int > ( 1 ) ; } ;
requires ! requires { m - length < Metre , int > ( 1 ) ; } ;
requires ! requires { m % length < Metre , int > ( 1 ) ; } ;
2020-10-06 18:17:52 +02:00
} ;
static_assert ( invalid_binary_operations < metre > ) ;
// same representation type
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 1 _q_m + 1 _q_m ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m - 1 _q_m ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m * 1 ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m * quantity { 1 } ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 * 1 _q_m ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( quantity { 1 } * 1 _q_m ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m / 1 ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m / quantity { 1 } ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m % 1 ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m % quantity { 1 } ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m % 1 _q_m ) , length < metre , std : : int64_t > > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( compare < decltype ( 1 _q_m * dimensionless < percent , std : : int64_t > ( 1 ) ) , length < centimetre , std : : int64_t > > ) ;
static_assert ( compare < decltype ( dimensionless < percent , std : : int64_t > ( 1 ) * 1 _q_m ) , length < centimetre , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_m / dimensionless < percent , std : : int64_t > ( 1 ) ) , length < hectometre , std : : int64_t > > ) ;
2021-05-11 15:03:04 +02:00
static_assert ( compare < decltype ( 1 _q_m % dimensionless < percent , std : : int64_t > ( 1 ) ) , length < metre , std : : int64_t > > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( compare < decltype ( 1 _q_m * 1 _q_m ) , area < square_metre , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_m / 1 _q_m ) , dimensionless < one , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 / 1 _q_s ) , frequency < hertz , std : : int64_t > > ) ;
static_assert ( compare < decltype ( quantity { 1 } / 1 _q_s ) , frequency < hertz , std : : int64_t > > ) ;
static_assert ( compare < decltype ( dimensionless < percent , std : : int64_t > ( 1 ) / 1 _q_s ) , frequency < scaled_unit < ratio ( 1 , 100 ) , hertz > , std : : int64_t > > ) ;
2021-05-03 19:44:50 +02:00
static_assert ( is_same_v < decltype ( ( std : : uint8_t ( 0 ) * m + std : : uint8_t ( 0 ) * m ) . number ( ) ) , int & & > ) ;
static_assert ( is_same_v < decltype ( ( std : : uint8_t ( 0 ) * m - std : : uint8_t ( 0 ) * m ) . number ( ) ) , int & & > ) ;
2021-03-19 06:47:37 +01:00
static_assert ( ( std : : uint8_t ( 128 ) * m + std : : uint8_t ( 128 ) * m ) . number ( ) = = std : : uint8_t ( 128 ) + std : : uint8_t ( 128 ) ) ;
static_assert ( ( std : : uint8_t ( 0 ) * m - std : : uint8_t ( 1 ) * m ) . number ( ) = = std : : uint8_t ( 0 ) - std : : uint8_t ( 1 ) ) ;
2021-02-06 02:20:00 -04:00
2021-03-19 06:47:37 +01:00
static_assert ( is_same_v < decltype ( ( ( std : : uint8_t ( 0 ) * m ) % ( std : : uint8_t ( 0 ) * m ) ) . number ( ) ) ,
2021-05-03 19:44:50 +02:00
decltype ( std : : uint8_t ( 0 ) % std : : uint8_t ( 0 ) ) & & > ) ;
2021-02-06 02:20:00 -04:00
2020-10-06 18:17:52 +02:00
// different representation types
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 1 _q_m + 1. _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m - 1. _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m * 1. L ) , length < metre , long double > > ) ; // TODO should we address fundamental types implicit truncating conversions with concepts?
static_assert ( is_same_v < decltype ( 1 * 1. _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m * quantity { 1. L } ) , length < metre , long double > > ) ; // TODO should we address fundamental types implicit truncating conversions with concepts?
static_assert ( is_same_v < decltype ( quantity { 1 } * 1. _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m / 1. L ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m / quantity { 1. L } ) , length < metre , long double > > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( compare < decltype ( 1 _q_m * dimensionless < percent , long double > ( 1 ) ) , length < centimetre , long double > > ) ;
static_assert ( compare < decltype ( dimensionless < percent , std : : int64_t > ( 1 ) * 1. _q_m ) , length < centimetre , long double > > ) ;
static_assert ( compare < decltype ( 1 _q_m * 1. _q_m ) , area < square_metre , long double > > ) ;
static_assert ( compare < decltype ( 1 _q_m / dimensionless < percent , long double > ( 1 ) ) , length < hectometre , long double > > ) ;
static_assert ( compare < decltype ( 1 _q_m / 1. _q_m ) , dimensionless < one , long double > > ) ;
static_assert ( compare < decltype ( 1 / 1. _q_s ) , frequency < hertz , long double > > ) ;
static_assert ( compare < decltype ( quantity { 1 } / 1. _q_s ) , frequency < hertz , long double > > ) ;
static_assert ( compare < decltype ( dimensionless < percent , std : : int64_t > ( 1 ) / 1. _q_s ) , frequency < scaled_unit < ratio ( 1 , 100 ) , hertz > , long double > > ) ;
static_assert ( compare < decltype ( 1 _q_m % short ( 1 ) ) , length < metre , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_m % quantity { short ( 1 ) } ) , length < metre , std : : int64_t > > ) ;
2021-05-11 15:03:04 +02:00
static_assert ( compare < decltype ( 1 _q_m % dimensionless < percent , short > ( 1 ) ) , length < metre , std : : int64_t > > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( compare < decltype ( 1 _q_m % length < metre , short > ( 1 ) ) , length < metre , std : : int64_t > > ) ;
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 1. _q_m + 1 _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m - 1 _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m * 1 ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. L * 1 _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m * quantity { 1 } ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( quantity { 1. L } * 1 _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m / 1 ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m / quantity { 1 } ) , length < metre , long double > > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( compare < decltype ( 1. _q_m * dimensionless < percent , std : : int64_t > ( 1 ) ) , length < centimetre , long double > > ) ;
static_assert ( compare < decltype ( dimensionless < percent , long double > ( 1 ) * 1 _q_m ) , length < centimetre , long double > > ) ;
static_assert ( compare < decltype ( 1. _q_m / dimensionless < percent , std : : int64_t > ( 1 ) ) , length < hectometre , long double > > ) ;
static_assert ( compare < decltype ( 1. _q_m * 1 _q_m ) , area < square_metre , long double > > ) ;
static_assert ( compare < decltype ( 1. _q_m / 1 _q_m ) , dimensionless < one , long double > > ) ;
static_assert ( compare < decltype ( 1. L / 1 _q_s ) , frequency < hertz , long double > > ) ;
static_assert ( compare < decltype ( quantity { 1. L } / 1 _q_s ) , frequency < hertz , long double > > ) ;
static_assert ( compare < decltype ( dimensionless < percent , long double > ( 1 ) / 1 _q_s ) , frequency < scaled_unit < ratio ( 1 , 100 ) , hertz > , long double > > ) ;
// different units
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 1 _q_m + 1 _q_km ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m + 1 _q_km ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m + 1. _q_km ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m + 1. _q_km ) , length < metre , long double > > ) ;
2020-10-06 18:17:52 +02:00
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 1 _q_km + 1 _q_m ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_km + 1 _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_km + 1. _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_km + 1. _q_m ) , length < metre , long double > > ) ;
2020-10-06 18:17:52 +02:00
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 1 _q_m - 1 _q_km ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m - 1 _q_km ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_m - 1. _q_km ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_m - 1. _q_km ) , length < metre , long double > > ) ;
2020-10-06 18:17:52 +02:00
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 1 _q_km - 1 _q_m ) , length < metre , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_km - 1 _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_km - 1. _q_m ) , length < metre , long double > > ) ;
static_assert ( is_same_v < decltype ( 1. _q_km - 1. _q_m ) , length < metre , long double > > ) ;
2020-10-06 18:17:52 +02:00
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 1 _q_m % 1 _q_km ) , length < metre , std : : int64_t > > ) ;
2021-05-11 15:03:04 +02:00
static_assert ( is_same_v < decltype ( 1 _q_km % 1 _q_m ) , length < kilometre , std : : int64_t > > ) ;
2020-10-06 18:17:52 +02:00
// different dimensions
static_assert ( compare < decltype ( 1 _q_m_per_s * 1 _q_s ) , length < metre , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_m_per_s * 1 _q_h ) , length < scaled_unit < ratio ( 36 , 1 , 2 ) , metre > , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_m * 1 _q_min ) , quantity < unknown_dimension < exponent < dim_length , 1 > , exponent < dim_time , 1 > > , scaled_unit < ratio ( 60 ) , unknown_coherent_unit > , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_s * 1 _q_Hz ) , dimensionless < one , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 / 1 _q_min ) , frequency < scaled_unit < ratio ( 1 , 60 ) , hertz > , std : : int64_t > > ) ;
2021-03-16 12:03:25 +01:00
static_assert ( compare < decltype ( 1 / 1 _q_Hz ) , isq : : si : : time < second , std : : int64_t > > ) ;
2020-10-06 18:17:52 +02:00
static_assert ( compare < decltype ( 1 / 1 _q_km ) , quantity < unknown_dimension < exponent < dim_length , - 1 > > , scaled_unit < ratio ( 1 , 1 , - 3 ) , unknown_coherent_unit > , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_km / 1 _q_m ) , dimensionless < scaled_unit < ratio ( 1000 ) , one > , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_m / 1 _q_s ) , speed < metre_per_second , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_m / 1 _q_min ) , speed < scaled_unit < ratio ( 1 , 60 ) , metre_per_second > , std : : int64_t > > ) ;
static_assert ( compare < decltype ( 1 _q_min / 1 _q_m ) , quantity < unknown_dimension < exponent < dim_length , - 1 > , exponent < dim_time , 1 > > , scaled_unit < ratio ( 60 ) , unknown_coherent_unit > , std : : int64_t > > ) ;
2021-03-19 06:47:37 +01:00
static_assert ( ( 1 _q_m + 1 _q_m ) . number ( ) = = 2 ) ;
static_assert ( ( 1 _q_m + 1 _q_km ) . number ( ) = = 1001 ) ;
static_assert ( ( 1 _q_km + 1 _q_m ) . number ( ) = = 1001 ) ;
static_assert ( ( 2 _q_m - 1 _q_m ) . number ( ) = = 1 ) ;
static_assert ( ( 1 _q_km - 1 _q_m ) . number ( ) = = 999 ) ;
static_assert ( ( 2 _q_m * 2 ) . number ( ) = = 4 ) ;
static_assert ( ( 2 _q_m * quantity { 2 } ) . number ( ) = = 4 ) ;
static_assert ( ( 2 _q_m * dimensionless < percent , int > ( 2 ) ) . number ( ) = = 4 ) ;
static_assert ( ( 3 * 3 _q_m ) . number ( ) = = 9 ) ;
static_assert ( ( quantity { 3 } * 3 _q_m ) . number ( ) = = 9 ) ;
static_assert ( ( dimensionless < percent , int > ( 3 ) * 3 _q_m ) . number ( ) = = 9 ) ;
static_assert ( ( 4 _q_m / 2 ) . number ( ) = = 2 ) ;
static_assert ( ( 4 _q_m / quantity { 2 } ) . number ( ) = = 2 ) ;
static_assert ( ( 4 _q_m / dimensionless < percent , int > ( 2 ) ) . number ( ) = = 2 ) ;
static_assert ( ( 4 _q_km / 2 _q_m ) . number ( ) = = 2 ) ;
static_assert ( ( 4000 _q_m / 2 _q_m ) . number ( ) = = 2000 ) ;
static_assert ( ( 1.5 _q_m + 1 _q_m ) . number ( ) = = 2.5 ) ;
static_assert ( ( 1.5 _q_m + 1 _q_km ) . number ( ) = = 1001.5 ) ;
static_assert ( ( 1.5 _q_km + 1 _q_m ) . number ( ) = = 1501 ) ;
static_assert ( ( 2.5 _q_m - 1 _q_m ) . number ( ) = = 1.5 ) ;
static_assert ( ( 1.5 _q_km - 1 _q_m ) . number ( ) = = 1499 ) ;
static_assert ( ( 2.5 _q_m * 2 ) . number ( ) = = 5 ) ;
static_assert ( ( 2.5 _q_m * quantity { 2 } ) . number ( ) = = 5 ) ;
static_assert ( ( 2.5 _q_m * dimensionless < percent , int > ( 2 ) ) . number ( ) = = 5 ) ;
static_assert ( ( 2.5 L * 2 _q_m ) . number ( ) = = 5 ) ;
static_assert ( ( quantity { 2.5 L } * 2 _q_m ) . number ( ) = = 5 ) ;
static_assert ( ( dimensionless < percent , long double > ( 2.5 L ) * 2 _q_m ) . number ( ) = = 5 ) ;
static_assert ( ( 5. _q_m / 2 ) . number ( ) = = 2.5 ) ;
static_assert ( ( 5. _q_m / quantity { 2 } ) . number ( ) = = 2.5 ) ;
static_assert ( ( 5. _q_m / dimensionless < percent , int > ( 2 ) ) . number ( ) = = 2.5 ) ;
static_assert ( ( 5. _q_km / 2 _q_m ) . number ( ) = = 2.5 ) ;
static_assert ( ( 5000. _q_m / 2 _q_m ) . number ( ) = = 2500 ) ;
static_assert ( ( 1 _q_m + 1.5 _q_m ) . number ( ) = = 2.5 ) ;
static_assert ( ( 1 _q_m + 1.5 _q_km ) . number ( ) = = 1501 ) ;
static_assert ( ( 1 _q_km + 1.5 _q_m ) . number ( ) = = 1001.5 ) ;
static_assert ( ( 2 _q_m - 1.5 _q_m ) . number ( ) = = 0.5 ) ;
static_assert ( ( 1 _q_km - 1.5 _q_m ) . number ( ) = = 998.5 ) ;
static_assert ( ( 2 _q_m * 2.5 L ) . number ( ) = = 5 ) ;
static_assert ( ( 2 _q_m * quantity { 2.5 L } ) . number ( ) = = 5 ) ;
static_assert ( ( 2 _q_m * dimensionless < percent , long double > ( 2.5 L ) ) . number ( ) = = 5 ) ;
static_assert ( ( 2 * 2.5 _q_m ) . number ( ) = = 5 ) ;
static_assert ( ( quantity { 2 } * 2.5 _q_m ) . number ( ) = = 5 ) ;
static_assert ( ( dimensionless < percent , int > ( 2 ) * 2.5 _q_m ) . number ( ) = = 5 ) ;
static_assert ( ( 5 _q_m / 2.5 L ) . number ( ) = = 2 ) ;
static_assert ( ( 5 _q_m / quantity { 2.5 L } ) . number ( ) = = 2 ) ;
static_assert ( ( 5 _q_m / dimensionless < percent , long double > ( 2.5 L ) ) . number ( ) = = 2 ) ;
static_assert ( ( 5 _q_km / 2.5 _q_m ) . number ( ) = = 2 ) ;
static_assert ( ( 5000 _q_m / 2.5 _q_m ) . number ( ) = = 2000 ) ;
static_assert ( ( 7 _q_m % 2 ) . number ( ) = = 1 ) ;
static_assert ( ( 7 _q_m % quantity { 2 } ) . number ( ) = = 1 ) ;
static_assert ( ( 7 _q_m % dimensionless < percent , int > ( 2 ) ) . number ( ) = = 1 ) ;
static_assert ( ( 7 _q_m % 2 _q_m ) . number ( ) = = 1 ) ;
2021-05-11 15:03:04 +02:00
static_assert ( ( 7 _q_km % 2000 _q_m ) . number ( ) = = 7 ) ;
2020-09-09 19:20:35 +02:00
static_assert ( ( 10 _q_km2 * 10 _q_km2 ) / 50 _q_km2 = = 2 _q_km2 ) ;
2021-03-19 06:47:37 +01:00
static_assert ( ( 10 _q_km / 5 _q_m ) . number ( ) = = 2 ) ;
static_assert ( dimensionless < one > ( 10 _q_km / 5 _q_m ) . number ( ) = = 2000 ) ;
2020-09-08 11:02:16 +02:00
2020-09-13 18:45:46 +02:00
# if UNITS_DOWNCAST_MODE == 0
2021-03-19 06:47:37 +01:00
static_assert ( quantity_cast < dim_one , one > ( 10 _q_km / 5 _q_m ) . number ( ) = = 2000 ) ;
2020-09-10 11:33:58 +02:00
# else
2021-03-19 06:47:37 +01:00
static_assert ( quantity_cast < one > ( 10 _q_km / 5 _q_m ) . number ( ) = = 2000 ) ;
2020-09-10 11:33:58 +02:00
# endif
2020-09-08 11:02:16 +02:00
2021-03-19 06:47:37 +01:00
static_assert ( ( 10 _q_s * 2 _q_kHz ) . number ( ) = = 20 ) ;
2019-12-04 17:46:19 +01:00
2021-05-11 15:03:04 +02:00
// quantity references
2021-03-18 16:09:00 -04:00
static_assert ( 2 _q_m * ( 1 * m ) = = ( 2 _q_m2 ) ) ;
static_assert ( 2 _q_m2 / ( 1 * m ) = = ( 2 _q_m ) ) ;
2021-03-17 15:20:07 -04:00
2020-05-08 21:18:16 +02:00
2020-10-06 18:17:52 +02:00
// dimensionless
2020-05-08 21:18:16 +02:00
2021-02-06 21:42:25 -04:00
static_assert ( ( quantity { 3 } * = quantity { 2 } ) = = 6 ) ;
static_assert ( ( quantity { 6 } / = quantity { 2 } ) = = 3 ) ;
2020-10-06 18:17:52 +02:00
static_assert ( quantity { 1 } + quantity { 1 } = = 2 ) ;
static_assert ( 1 + quantity { 1 } = = 2 ) ;
static_assert ( quantity { 1 } + 1 = = 2 ) ;
static_assert ( quantity { 2 } - quantity { 1 } = = 1 ) ;
static_assert ( 2 - quantity { 1 } = = 1 ) ;
static_assert ( quantity { 2 } - 1 = = 1 ) ;
static_assert ( quantity { 2 } * quantity { 2 } = = 4 ) ;
static_assert ( 2 * quantity { 2 } = = 4 ) ;
static_assert ( quantity { 2 } * 2 = = 4 ) ;
static_assert ( quantity { 4 } / quantity { 2 } = = 2 ) ;
static_assert ( 4 / quantity { 2 } = = 2 ) ;
static_assert ( quantity { 4 } / 2 = = 2 ) ;
static_assert ( quantity { 4 } % quantity { 2 } = = 0 ) ;
static_assert ( 4 % quantity { 2 } = = 0 ) ;
static_assert ( quantity { 4 } % 2 = = 0 ) ;
2021-02-06 02:20:00 -04:00
static_assert ( is_same_v < decltype ( quantity ( 0 ) + 0.0 ) , decltype ( quantity ( 0.0 ) ) > ) ;
static_assert ( is_same_v < decltype ( quantity ( 0 ) - 0.0 ) , decltype ( quantity ( 0.0 ) ) > ) ;
static_assert ( is_same_v < decltype ( 0.0 + quantity ( 0 ) ) , decltype ( quantity ( 0.0 ) ) > ) ;
static_assert ( is_same_v < decltype ( 0.0 + quantity ( 0 ) ) , decltype ( quantity ( 0.0 ) ) > ) ;
static_assert ( quantity ( 1 ) + 2.3 = = quantity ( 1 + 2.3 ) ) ;
static_assert ( quantity ( 1 ) - 2.3 = = quantity ( 1 - 2.3 ) ) ;
static_assert ( 1.2 + quantity ( 3 ) = = quantity ( 1.2 + 3 ) ) ;
static_assert ( 1.2 - quantity ( 3 ) = = quantity ( 1.2 - 3 ) ) ;
2021-05-03 19:44:50 +02:00
static_assert ( is_same_v < decltype ( ( quantity { std : : uint8_t ( 0 ) } + quantity { std : : uint8_t ( 0 ) } ) . number ( ) ) , int & & > ) ;
static_assert ( is_same_v < decltype ( ( quantity { std : : uint8_t ( 0 ) } - quantity { std : : uint8_t ( 0 ) } ) . number ( ) ) , int & & > ) ;
2021-03-19 06:47:37 +01:00
static_assert ( ( quantity { std : : uint8_t ( 128 ) } + quantity { std : : uint8_t ( 128 ) } ) . number ( ) = =
2021-02-06 02:20:00 -04:00
std : : uint8_t ( 128 ) + std : : uint8_t ( 128 ) ) ;
2021-03-19 06:47:37 +01:00
static_assert ( ( quantity { std : : uint8_t ( 0 ) } - quantity { std : : uint8_t ( 1 ) } ) . number ( ) = = std : : uint8_t ( 0 ) - std : : uint8_t ( 1 ) ) ;
2021-02-06 02:20:00 -04:00
2021-03-19 06:47:37 +01:00
static_assert ( is_same_v < decltype ( ( quantity { std : : uint8_t ( 0 ) } % quantity { std : : uint8_t ( 0 ) } ) . number ( ) ) ,
2021-05-03 19:44:50 +02:00
decltype ( std : : uint8_t ( 0 ) % std : : uint8_t ( 0 ) ) & & > ) ;
2021-02-06 02:20:00 -04:00
2021-03-18 16:09:00 -04:00
static_assert ( quantity { 2 } * ( 1 * m ) = = 2 _q_m ) ;
static_assert ( quantity { 2 } / ( 1 * m ) = = 2 / 1 _q_m ) ;
2021-03-17 15:20:07 -04:00
2020-10-06 18:17:52 +02:00
///////////////////////
// equality operators
///////////////////////
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
template < typename Metre >
concept no_crossdimensional_equality = requires {
requires ! requires { 1 _q_s = = length < Metre , int > ( 1 ) ; } ;
requires ! requires { 1 _q_s ! = length < Metre , int > ( 1 ) ; } ;
} ;
static_assert ( no_crossdimensional_equality < metre > ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
// same type
static_assert ( length < metre , int > ( 123 ) = = length < metre , int > ( 123 ) ) ;
static_assert ( length < metre , int > ( 321 ) ! = length < metre , int > ( 123 ) ) ;
static_assert ( ! ( length < metre , int > ( 123 ) = = length < metre , int > ( 321 ) ) ) ;
static_assert ( ! ( length < metre , int > ( 123 ) ! = length < metre , int > ( 123 ) ) ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
// different types
static_assert ( length < metre , double > ( 123 ) = = length < metre , int > ( 123 ) ) ;
static_assert ( length < metre , double > ( 321 ) ! = length < metre , int > ( 123 ) ) ;
static_assert ( ! ( length < metre , double > ( 123 ) = = length < metre , int > ( 321 ) ) ) ;
static_assert ( ! ( length < metre , double > ( 123 ) ! = length < metre , int > ( 123 ) ) ) ;
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
static_assert ( length < kilometre , int > ( 123 ) = = length < metre , int > ( 123000 ) ) ;
static_assert ( length < kilometre , int > ( 321 ) ! = length < metre , int > ( 123000 ) ) ;
static_assert ( ! ( length < kilometre , int > ( 123 ) = = length < metre , int > ( 321000 ) ) ) ;
static_assert ( ! ( length < kilometre , int > ( 123 ) ! = length < metre , int > ( 123000 ) ) ) ;
2020-05-28 20:19:05 +02:00
2020-10-06 18:17:52 +02:00
// dimensionless
2020-05-28 20:19:05 +02:00
2020-10-06 18:17:52 +02:00
static_assert ( quantity { 123 } = = 123 ) ;
static_assert ( quantity { 321 } ! = 123 ) ;
static_assert ( 123 = = quantity { 123 } ) ;
static_assert ( 123 ! = quantity { 321 } ) ;
2020-05-28 20:19:05 +02:00
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
///////////////////////
// ordering operators
///////////////////////
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
template < typename Metre >
concept no_crossdimensional_ordering = requires {
requires ! requires { 1 _q_s < length < Metre , int > ( 1 ) ; } ;
requires ! requires { 1 _q_s > length < Metre , int > ( 1 ) ; } ;
requires ! requires { 1 _q_s < = length < Metre , int > ( 1 ) ; } ;
requires ! requires { 1 _q_s > = length < Metre , int > ( 1 ) ; } ;
} ;
static_assert ( no_crossdimensional_ordering < metre > ) ;
// same type
static_assert ( length < metre , int > ( 123 ) < length < metre , int > ( 321 ) ) ;
static_assert ( length < metre , int > ( 123 ) < = length < metre , int > ( 123 ) ) ;
static_assert ( length < metre , int > ( 123 ) < = length < metre , int > ( 321 ) ) ;
static_assert ( length < metre , int > ( 321 ) > length < metre , int > ( 123 ) ) ;
static_assert ( length < metre , int > ( 123 ) > = length < metre , int > ( 123 ) ) ;
static_assert ( length < metre , int > ( 321 ) > = length < metre , int > ( 123 ) ) ;
static_assert ( ! ( length < metre , int > ( 321 ) < length < metre , int > ( 123 ) ) ) ;
static_assert ( ! ( length < metre , int > ( 123 ) < length < metre , int > ( 123 ) ) ) ;
static_assert ( ! ( length < metre , int > ( 321 ) < = length < metre , int > ( 123 ) ) ) ;
static_assert ( ! ( length < metre , int > ( 123 ) > length < metre , int > ( 321 ) ) ) ;
static_assert ( ! ( length < metre , int > ( 123 ) > length < metre , int > ( 123 ) ) ) ;
static_assert ( ! ( length < metre , int > ( 123 ) > = length < metre , int > ( 321 ) ) ) ;
// different types
static_assert ( length < metre , double > ( 123 ) < length < metre , int > ( 321 ) ) ;
static_assert ( length < metre , double > ( 123 ) < = length < metre , int > ( 123 ) ) ;
static_assert ( length < metre , double > ( 123 ) < = length < metre , int > ( 321 ) ) ;
static_assert ( length < metre , double > ( 321 ) > length < metre , int > ( 123 ) ) ;
static_assert ( length < metre , double > ( 123 ) > = length < metre , int > ( 123 ) ) ;
static_assert ( length < metre , double > ( 321 ) > = length < metre , int > ( 123 ) ) ;
static_assert ( ! ( length < metre , double > ( 321 ) < length < metre , int > ( 123 ) ) ) ;
static_assert ( ! ( length < metre , double > ( 123 ) < length < metre , int > ( 123 ) ) ) ;
static_assert ( ! ( length < metre , double > ( 321 ) < = length < metre , int > ( 123 ) ) ) ;
static_assert ( ! ( length < metre , double > ( 123 ) > length < metre , int > ( 321 ) ) ) ;
static_assert ( ! ( length < metre , double > ( 123 ) > length < metre , int > ( 123 ) ) ) ;
static_assert ( ! ( length < metre , double > ( 123 ) > = length < metre , int > ( 321 ) ) ) ;
static_assert ( length < kilometre , int > ( 123 ) < length < metre , int > ( 321000 ) ) ;
static_assert ( length < kilometre , int > ( 123 ) < = length < metre , int > ( 123000 ) ) ;
static_assert ( length < kilometre , int > ( 123 ) < = length < metre , int > ( 321000 ) ) ;
static_assert ( length < kilometre , int > ( 321 ) > length < metre , int > ( 123000 ) ) ;
static_assert ( length < kilometre , int > ( 123 ) > = length < metre , int > ( 123000 ) ) ;
static_assert ( length < kilometre , int > ( 321 ) > = length < metre , int > ( 123000 ) ) ;
static_assert ( ! ( length < kilometre , int > ( 321 ) < length < metre , int > ( 123000 ) ) ) ;
static_assert ( ! ( length < kilometre , int > ( 123 ) < length < metre , int > ( 123000 ) ) ) ;
static_assert ( ! ( length < kilometre , int > ( 321 ) < = length < metre , int > ( 123000 ) ) ) ;
static_assert ( ! ( length < kilometre , int > ( 123 ) > length < metre , int > ( 321000 ) ) ) ;
static_assert ( ! ( length < kilometre , int > ( 123 ) > length < metre , int > ( 123000 ) ) ) ;
static_assert ( ! ( length < kilometre , int > ( 123 ) > = length < metre , int > ( 321000 ) ) ) ;
2019-12-04 17:46:19 +01:00
2020-09-08 11:02:16 +02:00
// dimensionless
2020-10-06 18:17:52 +02:00
static_assert ( quantity { 123 } < 321 ) ;
static_assert ( quantity { 123 } < = 123 ) ;
static_assert ( quantity { 123 } < = 321 ) ;
static_assert ( quantity { 321 } > 123 ) ;
static_assert ( quantity { 123 } > = 123 ) ;
static_assert ( quantity { 321 } > = 123 ) ;
2020-09-08 11:02:16 +02:00
2020-10-06 18:17:52 +02:00
static_assert ( 123 < quantity { 321 } ) ;
static_assert ( 123 < = quantity { 123 } ) ;
static_assert ( 123 < = quantity { 321 } ) ;
static_assert ( 321 > quantity { 123 } ) ;
static_assert ( 123 > = quantity { 123 } ) ;
static_assert ( 321 > = quantity { 123 } ) ;
2020-09-08 11:02:16 +02:00
2020-10-06 18:17:52 +02:00
//////////////////
// dimensionless
//////////////////
static_assert ( std : : equality_comparable_with < dimensionless < one > , int > ) ;
static_assert ( std : : equality_comparable_with < dimensionless < one > , double > ) ;
static_assert ( std : : equality_comparable_with < dimensionless < one , int > , int > ) ;
static_assert ( ! std : : equality_comparable_with < dimensionless < one , int > , double > ) ;
2020-09-08 11:02:16 +02:00
2020-09-09 02:22:34 -04:00
template < typename Int >
2020-10-06 18:17:52 +02:00
concept invalid_dimensionless_operations = requires {
requires ! requires ( dimensionless < percent , Int > d ) { 1 + d ; } ;
requires ! requires ( dimensionless < percent , Int > d ) { d + 1 ; } ;
2020-09-08 11:02:16 +02:00
} ;
2020-09-09 02:23:49 -04:00
static_assert ( invalid_dimensionless_operations < int > ) ;
2020-09-08 11:02:16 +02:00
2020-09-10 00:35:25 +02:00
static_assert ( compare < decltype ( 10 _q_km / 5 _q_km ) , quantity < dim_one , one , std : : int64_t > > ) ;
2020-09-08 18:45:14 +02:00
2020-09-13 18:45:46 +02:00
# if UNITS_DOWNCAST_MODE == 0
2021-03-19 06:47:37 +01:00
static_assert ( quantity_cast < dim_one , percent > ( 50. _q_m / 100. _q_m ) . number ( ) = = 50 ) ;
2020-09-10 11:33:58 +02:00
# else
2021-03-19 06:47:37 +01:00
static_assert ( quantity_cast < percent > ( 50. _q_m / 100. _q_m ) . number ( ) = = 50 ) ;
2020-09-10 11:33:58 +02:00
# endif
2020-09-09 19:20:35 +02:00
static_assert ( 50. _q_m / 100. _q_m = = dimensionless < percent > ( 50 ) ) ;
2020-09-08 11:02:16 +02:00
2021-03-19 06:47:37 +01:00
static_assert ( dimensionless < one > ( dimensionless < percent > ( 50 ) ) . number ( ) = = 0.5 ) ;
2020-09-08 11:02:16 +02:00
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
////////////////
// alias units
////////////////
2020-09-05 21:41:02 -04:00
2020-10-06 18:17:52 +02:00
static_assert ( compare < decltype ( 2 _q_l + 2 _q_ml ) , volume < cubic_centimetre , std : : int64_t > > ) ;
static_assert ( 2 _q_l + 2 _q_ml = = 2002 _q_cm3 ) ;
static_assert ( 2 _q_l + 2 _q_ml = = 2002 _q_ml ) ;
static_assert ( 2 _q_l + 2 _q_cm3 = = 2002 _q_ml ) ;
static_assert ( 2 _q_dm3 + 2 _q_cm3 = = 2002 _q_ml ) ;
2020-09-05 21:41:02 -04:00
2019-12-04 17:46:19 +01:00
2020-10-06 18:17:52 +02:00
//////////////////
// quantity_cast
//////////////////
2019-12-04 17:46:19 +01:00
2021-03-19 06:47:37 +01:00
static_assert ( quantity_cast < length < metre , int > > ( 2 _q_km ) . number ( ) = = 2000 ) ;
static_assert ( quantity_cast < length < kilometre , int > > ( 2000 _q_m ) . number ( ) = = 2 ) ;
static_assert ( quantity_cast < length < metre , int > > ( 1.23 _q_m ) . number ( ) = = 1 ) ;
static_assert ( quantity_cast < metre > ( 2 _q_km ) . number ( ) = = 2000 ) ;
static_assert ( quantity_cast < kilometre > ( 2000 _q_m ) . number ( ) = = 2 ) ;
static_assert ( quantity_cast < int > ( 1.23 _q_m ) . number ( ) = = 1 ) ;
static_assert ( quantity_cast < dim_speed , kilometre_per_hour > ( 2000.0 _q_m / 3600.0 _q_s ) . number ( ) = = 2 ) ;
2019-12-04 17:46:19 +01:00
2021-01-18 15:55:55 -04:00
static_assert ( quantity_cast < dim_length > ( 1 * cgs_cm ) = = 1 * cm ) ;
2021-01-02 10:56:50 +01:00
static_assert ( is_same_v < decltype ( quantity_cast < litre > ( 2 _q_dm3 ) ) , volume < litre , std : : int64_t > > ) ;
2021-02-22 14:40:23 -04:00
static_assert ( ! is_same_v < decltype ( quantity_cast < litre > ( 2 _q_dm3 ) ) , volume < cubic_decimetre , std : : int64_t > > ) ;
2020-05-08 10:50:34 +02:00
2020-10-06 18:17:52 +02:00
////////////////
2020-05-08 10:50:34 +02:00
// downcasting
2020-10-06 18:17:52 +02:00
////////////////
2020-05-08 10:50:34 +02:00
2020-09-13 18:45:46 +02:00
# if UNITS_DOWNCAST_MODE == 0
2020-05-08 10:50:34 +02:00
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 10 _q_m / 5 _q_s ) , quantity < unknown_dimension < units : : exponent < dim_length , 1 > , units : : exponent < dim_time , - 1 > > , scaled_unit < ratio ( 1 ) , unknown_coherent_unit > , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_mm + 1 _q_km ) , length < scaled_unit < ratio ( 1 , 1 , - 3 ) , metre > , std : : int64_t > > ) ;
2020-05-08 10:50:34 +02:00
# else
2020-12-28 18:42:03 +01:00
static_assert ( is_same_v < decltype ( 10 _q_m / 5 _q_s ) , speed < metre_per_second , std : : int64_t > > ) ;
static_assert ( is_same_v < decltype ( 1 _q_mm + 1 _q_km ) , length < millimetre , std : : int64_t > > ) ;
2020-05-08 10:50:34 +02:00
# endif
2019-09-24 16:59:45 +02:00
2021-05-11 15:03:04 +02:00
// modulo arithmetics
constexpr auto quotient_remainder_theorem ( auto q1 , auto q2 )
{
auto quotient = q1 / q2 ;
auto reminder = q1 % q2 ;
auto q = quotient * q2 + reminder ;
return q ;
}
constexpr auto qr1 = quotient_remainder_theorem ( 3'000 * m , 400 * m ) ;
static_assert ( qr1 = = 3'000 * m ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr1 ) > , decltype ( 3'000 * m ) > ) ;
constexpr auto qr2 = quotient_remainder_theorem ( 3 * km , 400 * m ) ;
static_assert ( qr2 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr2 ) > , decltype ( 3 * km ) > ) ;
constexpr auto qr3 = quotient_remainder_theorem ( 3 * km , 2 * m ) ;
static_assert ( qr3 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr2 ) > , decltype ( 3 * km ) > ) ;
constexpr auto qr4 = quotient_remainder_theorem ( 3 * km , 400'000 * mm ) ;
static_assert ( qr4 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr4 ) > , decltype ( 3 * km ) > ) ;
constexpr auto qr5 = quotient_remainder_theorem ( 3 * km , 2'000 * mm ) ;
static_assert ( qr5 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr5 ) > , decltype ( 3 * km ) > ) ;
constexpr auto qr6 = quotient_remainder_theorem ( 3 * km , 400 * mm ) ;
static_assert ( qr6 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr6 ) > , decltype ( 3 * km ) > ) ;
constexpr auto qr7 = quotient_remainder_theorem ( 3 * km , 2 * mm ) ;
static_assert ( qr7 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr7 ) > , decltype ( 3 * km ) > ) ;
constexpr auto qr8 = quotient_remainder_theorem ( 3'000 * m , 400 ) ;
static_assert ( qr8 = = 3'000 * m ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr8 ) > , decltype ( 3'000 * m ) > ) ;
constexpr auto qr9 = quotient_remainder_theorem ( 3'000 * m , quantity ( 400 ) ) ;
static_assert ( qr9 = = 3'000 * m ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr9 ) > , decltype ( 3'000 * m ) > ) ;
constexpr auto qr10 = quotient_remainder_theorem ( 3 * km , quantity ( 400 ) ) ;
static_assert ( qr10 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr10 ) > , decltype ( 3 * km ) > ) ;
constexpr auto qr11 = quotient_remainder_theorem ( 3 * km , quantity ( 2 ) ) ;
static_assert ( qr11 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr11 ) > , decltype ( 3 * km ) > ) ;
constexpr auto qr12 = quotient_remainder_theorem ( 3 * km , dimensionless < scaled_unit < ratio ( 1 , 1000 ) , one > , int > ( 400 ) ) ;
static_assert ( qr12 = = 3 * km ) ;
static_assert ( is_same_v < std : : remove_cvref_t < decltype ( qr12 ) > , decltype ( 3 * km ) > ) ;
2018-09-28 07:47:37 -07:00
} // namespace