mirror of
https://github.com/mpusz/mp-units.git
synced 2025-06-25 01:01:33 +02:00
fix: add quantity_point::origin, like std::chrono::time_point::clock
This commit is contained in:
committed by
Mateusz Pusz
parent
7ed29807a6
commit
80eefec97c
@ -63,7 +63,7 @@ CommentPragmas: '^ NOLINT'
|
||||
# CompactNamespaces: false
|
||||
# ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
# ConstructorInitializerIndentWidth: 4
|
||||
# ContinuationIndentWidth: 4
|
||||
ContinuationIndentWidth: 2
|
||||
# Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: false
|
||||
DerivePointerAlignment: false
|
||||
@ -109,7 +109,7 @@ IndentRequires: true
|
||||
# KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
# MacroBlockBegin: ''
|
||||
# MacroBlockEnd: ''
|
||||
# MaxEmptyLinesToKeep: 1
|
||||
MaxEmptyLinesToKeep: 2
|
||||
# NamespaceIndentation: None
|
||||
# ObjCBinPackProtocolList: Never
|
||||
# ObjCBlockIndentWidth: 2
|
||||
|
BIN
docs/_static/img/concepts.png
vendored
BIN
docs/_static/img/concepts.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 134 KiB |
@ -23,7 +23,7 @@ The most important concepts in the library are `Unit`, `Dimension`,
|
||||
]
|
||||
|
||||
[<abstract>QuantityPoint|
|
||||
[quantity_point<Dimension, Unit, Rep>]
|
||||
[quantity_point<PointOrigin, Unit, Rep>]
|
||||
]
|
||||
|
||||
[<abstract>QuantityKind|
|
||||
@ -39,6 +39,10 @@ The most important concepts in the library are `Unit`, `Dimension`,
|
||||
[Unit]<-[Quantity]
|
||||
[Quantity]<-[QuantityPoint]
|
||||
|
||||
[<abstract>PointOrigin]<-[QuantityPoint]
|
||||
[Dimension]<-[PointOrigin]
|
||||
[PointOrigin]<-[PointKind]
|
||||
|
||||
[<abstract>Kind]<-[QuantityKind]
|
||||
[Dimension]<-[Kind]
|
||||
[Quantity]<-[QuantityKind]
|
||||
@ -60,7 +64,7 @@ derived dimensions. Examples: ``si::dim_time``, ``si::dim_length``, ``si::dim_sp
|
||||
specific representation. Examples: ``quantity<si::dim_time, si::second, int>``,
|
||||
``si::length<si::metre, int>``, ``si::speed<si::kilometre_per_hour>``.
|
||||
|
||||
`QuantityPoint` is an absolute `Quantity` with respect to some origin.
|
||||
`QuantityPoint` is an absolute `Quantity` with respect to an origin.
|
||||
Examples: timestamp (as opposed to duration), absolute temperature
|
||||
(as opposed to temperature difference).
|
||||
|
||||
@ -68,6 +72,6 @@ Examples: timestamp (as opposed to duration), absolute temperature
|
||||
distance (``horizonal_kind``) and height (``vertical_kind``) are different kinds
|
||||
of a length quantity.
|
||||
|
||||
`QuantityPointKind` is an absolute `QuantityKind` with respect to some origin.
|
||||
`QuantityPointKind` is an absolute `QuantityKind` with respect to an origin.
|
||||
Examples: altitude is a quantity point of ``vertical_kind`` (as opposed to
|
||||
height).
|
||||
|
@ -106,8 +106,9 @@ Quantity Points
|
||||
+++++++++++++++
|
||||
|
||||
Quantity points have a more restricted set of operations.
|
||||
Quantity can be added to or subtracted from a quantity point.
|
||||
The result will always be a quantity point of the same dimension:
|
||||
Quantity can be added to or subtracted
|
||||
from a quantity point of the same origin.
|
||||
The result will always be a quantity point of the same origin:
|
||||
|
||||
.. code-block::
|
||||
:emphasize-lines: 3-5
|
||||
@ -132,9 +133,10 @@ The result is a relative quantity of the same dimension:
|
||||
|
||||
It is not allowed to:
|
||||
|
||||
- add quantity points
|
||||
- subtract a quantity point from a quantity:
|
||||
- multiply nor divide quantity points with anything else.
|
||||
- add quantity points,
|
||||
- subtract a quantity point from a quantity,
|
||||
- multiply nor divide quantity points with anything else, and
|
||||
- mix quantity points with different origins:
|
||||
|
||||
.. code-block::
|
||||
:emphasize-lines: 3-5
|
||||
@ -144,6 +146,8 @@ The result is a relative quantity of the same dimension:
|
||||
auto res1 = quantity_point{dist1} + quantity_point{dist2}; // ERROR
|
||||
auto res2 = dist1 - quantity_point{dist2}; // ERROR
|
||||
auto res3 = quantity_point{dist1} / (2 * s); // ERROR
|
||||
auto res4 = quantity_point{std::chrono::utc_second{1s}} +
|
||||
quantity_point{std::chrono::sys_second{1s}}; // ERROR
|
||||
|
||||
Quantity Point Kinds
|
||||
++++++++++++++++++++
|
||||
|
@ -3,9 +3,20 @@
|
||||
Quantity Points
|
||||
===============
|
||||
|
||||
A quantity point is an absolute quantity with respect to zero
|
||||
(which represents some origin) and is represented in the library with a
|
||||
`quantity_point` class template.
|
||||
A quantity point is an absolute quantity with respect to an origin
|
||||
and is represented in the library with a `quantity_point` class template.
|
||||
|
||||
Point Origins
|
||||
-------------
|
||||
|
||||
We need a `point_origin` to represent the origin of a quantity point::
|
||||
|
||||
struct mean_sea_level : point_origin<si::dim_length> {};
|
||||
|
||||
Quantities points with this origin represent a point from the mean sea level.
|
||||
|
||||
The library offers a `dynamic_origin<Dimension>`
|
||||
for quantity points whose origin is not specified in the type system.
|
||||
|
||||
|
||||
Construction
|
||||
@ -14,7 +25,7 @@ Construction
|
||||
To create the quantity point object from a `quantity` we just have to pass
|
||||
the value to the `quantity_point` class template explicit constructor::
|
||||
|
||||
quantity_point<si::dim_length, si::kilometre, double> d(123 * km);
|
||||
quantity_point<dynamic_origin<si::dim_length>, si::kilometre, double> d(123 * km);
|
||||
|
||||
.. note::
|
||||
|
||||
@ -25,7 +36,7 @@ the value to the `quantity_point` class template explicit constructor::
|
||||
`copy initialization <https://en.cppreference.com/w/cpp/language/copy_initialization>`_
|
||||
**does not compile**::
|
||||
|
||||
quantity_point<si::dim_length, si::kilometre, double> d = 123 * km; // ERROR
|
||||
quantity_point<dynamic_origin<si::dim_length>, si::kilometre, double> d = 123 * km; // ERROR
|
||||
|
||||
|
||||
Differences To Quantity
|
||||
|
@ -56,11 +56,12 @@ such an explicit conversion::
|
||||
|
||||
For external quantity point-like types, `quantity_point_like_traits` is also provided.
|
||||
It works just like `quantity_like_traits`, except that
|
||||
``number(T)`` is replaced with ``relative(T)`` that returns the `QuantityLike` value.
|
||||
``number(T)`` is replaced with ``relative(T)`` that returns the `QuantityLike` value
|
||||
and ``dimension`` is replaced with ``origin``.
|
||||
|
||||
Similar to `quantity` and `quantity_kind`, `quantity_point` and `quantity_kind_point`
|
||||
provide a deduction guide from `QuantityPointLike`::
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static_assert(quantity_point{std::chrono::sys_seconds{1s}} + 1 * s == quantity_point{2s});
|
||||
static_assert((quantity_point{std::chrono::sys_seconds{1s}} + 1 * s).relative() == 2s);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <units/quantity_point_kind.h>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <units/chrono.h>
|
||||
#include <units/format.h>
|
||||
#include <units/math.h> // IWYU pragma: keep
|
||||
#include <algorithm>
|
||||
@ -88,7 +89,7 @@ using altitude = units::quantity_point_kind<vertical_point_kind, units::isq::si:
|
||||
|
||||
// time
|
||||
using duration = units::isq::si::time<units::isq::si::second>;
|
||||
using timestamp = units::quantity_point<units::isq::si::dim_time, units::isq::si::second>;
|
||||
using timestamp = units::quantity_point<units::clock_origin<std::chrono::system_clock>, units::isq::si::second>;
|
||||
|
||||
// speed
|
||||
using velocity = units::quantity_kind<velocity_kind, units::isq::si::kilometre_per_hour>;
|
||||
|
@ -205,6 +205,52 @@ concept UnitOf =
|
||||
Dimension<D> &&
|
||||
std::same_as<typename U::reference, typename dimension_unit<D>::reference>;
|
||||
|
||||
// PointOrigin
|
||||
|
||||
template<Dimension D>
|
||||
struct point_origin;
|
||||
|
||||
/**
|
||||
* @brief A concept matching a point origin
|
||||
*
|
||||
* Satisfied by types derived from an specialization of @c point_origin.
|
||||
*/
|
||||
template<typename T>
|
||||
concept PointOrigin = is_derived_from_specialization_of<T, point_origin> &&
|
||||
requires {
|
||||
typename T::dimension;
|
||||
requires Dimension<typename T::dimension>;
|
||||
typename T::point_origin;
|
||||
requires std::same_as<typename T::point_origin, point_origin<typename T::dimension>>;
|
||||
requires !std::same_as<T, point_origin<typename T::dimension>>;
|
||||
};
|
||||
|
||||
// RebindablePointOriginFor
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename O, typename D>
|
||||
struct rebind_point_origin_dimension_impl {
|
||||
using type = typename O::template rebind<D>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<PointOrigin O, Dimension D>
|
||||
using rebind_point_origin_dimension = typename conditional<is_same_v<typename O::dimension, D>, std::type_identity<O>,
|
||||
detail::rebind_point_origin_dimension_impl<O, D>>::type;
|
||||
|
||||
/**
|
||||
* @brief A concept predicating the possibility of changing an origin's dimension
|
||||
*
|
||||
* Satisfied by point origins whose dimension can be made to be `D`.
|
||||
*/
|
||||
template<typename T, typename D>
|
||||
concept RebindablePointOriginFor =
|
||||
requires { typename rebind_point_origin_dimension<T, D>; } &&
|
||||
PointOrigin<rebind_point_origin_dimension<T, D>> &&
|
||||
std::same_as<D, typename rebind_point_origin_dimension<T, D>::dimension>;
|
||||
|
||||
// Kind
|
||||
namespace detail {
|
||||
|
||||
@ -216,7 +262,7 @@ struct _kind_base;
|
||||
template<typename T, template<typename...> typename Base>
|
||||
concept kind_impl_ =
|
||||
is_derived_from_specialization_of<T, Base> &&
|
||||
requires(T* t) {
|
||||
requires {
|
||||
typename T::base_kind;
|
||||
typename T::dimension;
|
||||
requires Dimension<typename T::dimension>;
|
||||
@ -236,7 +282,7 @@ concept Kind =
|
||||
// PointKind
|
||||
namespace detail {
|
||||
|
||||
template<Kind>
|
||||
template<Kind, PointOrigin>
|
||||
struct _point_kind_base;
|
||||
|
||||
} // namespace detail
|
||||
@ -247,7 +293,12 @@ struct _point_kind_base;
|
||||
* Satisfied by all point kind types derived from an specialization of @c point_kind.
|
||||
*/
|
||||
template<typename T>
|
||||
concept PointKind = kind_impl_<T, detail::_point_kind_base>;
|
||||
concept PointKind =
|
||||
kind_impl_<T, detail::_point_kind_base> &&
|
||||
requires { typename T::origin; } &&
|
||||
PointOrigin<typename T::origin> &&
|
||||
std::same_as<typename T::dimension, typename T::base_kind::dimension> &&
|
||||
std::same_as<typename T::dimension, typename T::origin::dimension>;
|
||||
|
||||
// Reference
|
||||
namespace detail {
|
||||
|
@ -31,7 +31,7 @@ namespace units {
|
||||
template<Dimension D, UnitOf<D> U, Representation Rep>
|
||||
class quantity;
|
||||
|
||||
template<Dimension D, UnitOf<D> U, Representation Rep>
|
||||
template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep>
|
||||
class quantity_point;
|
||||
|
||||
template<Kind K, UnitOf<typename K::dimension> U, Representation Rep>
|
||||
@ -99,7 +99,8 @@ template<units::QuantityPoint QP1, units::QuantityPointEquivalentTo<QP1> QP2>
|
||||
requires requires { typename common_type_t<typename QP1::rep, typename QP2::rep>; }
|
||||
struct common_type<QP1, QP2> {
|
||||
using type = units::quantity_point<
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::dimension,
|
||||
units::rebind_point_origin_dimension<typename QP1::origin,
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::dimension>,
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::unit,
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::rep>;
|
||||
};
|
||||
|
@ -81,29 +81,48 @@ template<Unit U1, Dimension D1, Unit U2, Dimension D2>
|
||||
struct equivalent_unit : std::disjunction<equivalent_impl<U1, U2>,
|
||||
std::bool_constant<U1::ratio / dimension_unit<D1>::ratio == U2::ratio / dimension_unit<D2>::ratio>> {};
|
||||
|
||||
// point origins
|
||||
|
||||
template<PointOrigin T, PointOrigin U>
|
||||
struct equivalent_impl<T, U> : std::bool_constant<requires { // TODO: Simplify when Clang catches up.
|
||||
requires RebindablePointOriginFor<T, typename U::dimension> && RebindablePointOriginFor<U, typename T::dimension> &&
|
||||
std::same_as<T, rebind_point_origin_dimension<U, typename T::dimension>> &&
|
||||
std::same_as<U, rebind_point_origin_dimension<T, typename U::dimension>>;
|
||||
} && equivalent_impl<typename T::dimension, typename U::dimension>::value> {};
|
||||
|
||||
|
||||
// (point) kinds
|
||||
|
||||
template<typename T, typename U>
|
||||
requires (Kind<T> && Kind<U>) || (PointKind<T> && PointKind<U>)
|
||||
template<Kind T, Kind U>
|
||||
struct equivalent_impl<T, U> :
|
||||
std::conjunction<std::is_same<typename T::base_kind, typename U::base_kind>,
|
||||
equivalent_impl<typename T::dimension, typename U::dimension>> {};
|
||||
|
||||
template<PointKind T, PointKind U>
|
||||
struct equivalent_impl<T, U> :
|
||||
std::conjunction<equivalent_impl<typename T::base_kind, typename U::base_kind>,
|
||||
equivalent_impl<typename T::origin, typename U::origin>> {};
|
||||
|
||||
|
||||
// quantities, quantity points, quantity (point) kinds
|
||||
|
||||
template<typename Q1, typename Q2>
|
||||
requires (Quantity<Q1> && Quantity<Q2>) || (QuantityPoint<Q1> && QuantityPoint<Q2>)
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
struct equivalent_impl<Q1, Q2> : std::conjunction<equivalent_impl<typename Q1::dimension, typename Q2::dimension>,
|
||||
equivalent_unit<typename Q1::unit, typename Q1::dimension,
|
||||
typename Q2::unit, typename Q2::dimension>> {};
|
||||
|
||||
template<typename QK1, typename QK2>
|
||||
requires (QuantityKind<QK1> && QuantityKind<QK2>) || (QuantityPointKind<QK1> && QuantityPointKind<QK2>)
|
||||
template<QuantityPoint QP1, QuantityPoint QP2>
|
||||
struct equivalent_impl<QP1, QP2> : std::conjunction<equivalent_impl<typename QP1::quantity_type, typename QP2::quantity_type>,
|
||||
equivalent_impl<typename QP1::origin, typename QP2::origin>> {};
|
||||
|
||||
template<QuantityKind QK1, QuantityKind QK2>
|
||||
struct equivalent_impl<QK1, QK2> : std::conjunction<equivalent_impl<typename QK1::kind_type, typename QK2::kind_type>,
|
||||
equivalent_impl<typename QK1::quantity_type, typename QK2::quantity_type>> {};
|
||||
|
||||
template<QuantityPointKind QPK1, QuantityPointKind QPK2>
|
||||
struct equivalent_impl<QPK1, QPK2> : std::conjunction<equivalent_impl<typename QPK1::quantity_kind_type, typename QPK2::quantity_kind_type>,
|
||||
equivalent_impl<typename QPK1::origin, typename QPK2::origin>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename U>
|
||||
|
@ -85,21 +85,20 @@ template<typename Q1, typename Q2>
|
||||
concept QuantityEquivalentTo = Quantity<Q1> && QuantityOf<Q2, typename Q1::dimension>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantity points with provided dimension
|
||||
* @brief A concept matching all quantity points of the provided origin
|
||||
*
|
||||
* Satisfied by all quantity points with a dimension being the instantiation derived from
|
||||
* the provided dimension type.
|
||||
* Satisfied by all quantity points with an origin equivalent to the provided one.
|
||||
*/
|
||||
template<typename QP, typename Dim>
|
||||
concept QuantityPointOf = QuantityPoint<QP> && Dimension<Dim> && equivalent<typename QP::dimension, Dim>;
|
||||
template<typename QP, typename Orig>
|
||||
concept QuantityPointOf = QuantityPoint<QP> && PointOrigin<Orig> && equivalent<typename QP::origin, Orig>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching two equivalent quantity points
|
||||
*
|
||||
* Satisfied by quantity points having equivalent dimensions.
|
||||
* Satisfied by quantity points having equivalent origins.
|
||||
*/
|
||||
template<typename QP1, typename QP2>
|
||||
concept QuantityPointEquivalentTo = QuantityPoint<QP1> && QuantityPointOf<QP2, typename QP1::dimension>;
|
||||
concept QuantityPointEquivalentTo = QuantityPoint<QP1> && QuantityPointOf<QP2, typename QP1::origin>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching only quantity kinds of a specific kind.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <units/customization_points.h>
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/isq/si/time.h>
|
||||
#include <units/point_origin.h>
|
||||
#include <chrono>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
@ -38,10 +39,13 @@ struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
|
||||
[[nodiscard]] static constexpr rep number(const std::chrono::duration<Rep, Period>& q) { return q.count(); }
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
struct clock_origin : point_origin<isq::si::dim_time> { };
|
||||
|
||||
template<typename C, typename Rep, typename Period>
|
||||
struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> {
|
||||
using dimension = isq::si::dim_time;
|
||||
using unit = downcast_unit<dimension, ratio(Period::num, Period::den)>;
|
||||
using origin = clock_origin<C>;
|
||||
using unit = downcast_unit<typename origin::dimension, ratio(Period::num, Period::den)>;
|
||||
using rep = Rep;
|
||||
[[nodiscard]] static constexpr auto relative(
|
||||
const std::chrono::time_point<C, std::chrono::duration<Rep, Period>>& qp) {
|
||||
@ -49,4 +53,11 @@ struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::durati
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename C, typename Rep, typename Period>
|
||||
inline constexpr bool is_quantity_point_like<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace units
|
||||
|
@ -88,7 +88,7 @@ struct quantity_like_traits;
|
||||
/**
|
||||
* @brief Provides support for external quantity point-like types
|
||||
*
|
||||
* The type trait should provide the following nested type aliases: @c dimension, @c unit, @c rep,
|
||||
* The type trait should provide the following nested type aliases: @c origin, @c unit, @c rep,
|
||||
* and a static member function @c relative(T) that will return the quantity-like value of the quantity point.
|
||||
*
|
||||
* Usage example can be found in @c units/chrono.h header file.
|
||||
|
@ -27,6 +27,9 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
template<Dimension D>
|
||||
struct dynamic_origin;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename K, Dimension D>
|
||||
@ -35,10 +38,11 @@ struct _kind_base : downcast_base<_kind_base<K, D>> {
|
||||
using dimension = D;
|
||||
};
|
||||
|
||||
template<Kind K>
|
||||
struct _point_kind_base : downcast_base<_point_kind_base<K>> {
|
||||
template<Kind K, PointOrigin O>
|
||||
struct _point_kind_base : downcast_base<_point_kind_base<K, O>> {
|
||||
using base_kind = K;
|
||||
using dimension = typename K::dimension;
|
||||
using origin = O;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@ -47,9 +51,9 @@ template<Kind K, Dimension D>
|
||||
requires Kind<downcast<detail::_kind_base<typename K::base_kind, D>>>
|
||||
using downcast_kind = downcast<detail::_kind_base<typename K::base_kind, D>>;
|
||||
|
||||
template<Kind K>
|
||||
requires PointKind<downcast<detail::_point_kind_base<K>>>
|
||||
using downcast_point_kind = downcast<detail::_point_kind_base<K>>;
|
||||
template<Kind K, PointOrigin O = dynamic_origin<typename K::dimension>>
|
||||
requires PointKind<downcast<detail::_point_kind_base<K, O>>>
|
||||
using downcast_point_kind = downcast<detail::_point_kind_base<K, O>>;
|
||||
|
||||
template<typename K, Dimension D>
|
||||
struct kind : downcast_dispatch<K, detail::_kind_base<K, D>> {};
|
||||
@ -58,7 +62,7 @@ template<typename DK, Dimension D, Kind BK>
|
||||
requires std::same_as<BK, typename BK::base_kind>
|
||||
struct derived_kind : downcast_dispatch<DK, detail::_kind_base<BK, D>> {};
|
||||
|
||||
template<typename DPK, Kind BK>
|
||||
struct point_kind : downcast_dispatch<DPK, detail::_point_kind_base<BK>> {};
|
||||
template<typename DPK, Kind BK, PointOrigin O = dynamic_origin<typename BK::dimension>>
|
||||
struct point_kind : downcast_dispatch<DPK, detail::_point_kind_base<BK, O>> {};
|
||||
|
||||
} // namespace units
|
||||
|
34
src/core/include/units/point_origin.h
Normal file
34
src/core/include/units/point_origin.h
Normal file
@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/basic_concepts.h>
|
||||
|
||||
namespace units {
|
||||
|
||||
template<Dimension D>
|
||||
struct point_origin {
|
||||
using dimension = D;
|
||||
};
|
||||
|
||||
} // namespace units
|
@ -39,7 +39,7 @@ namespace units {
|
||||
template<Dimension D, UnitOf<D> U, Representation Rep>
|
||||
class quantity;
|
||||
|
||||
template<Dimension D, UnitOf<D> U, Representation Rep>
|
||||
template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep>
|
||||
class quantity_point;
|
||||
|
||||
template<Kind K, UnitOf<typename K::dimension> U, Representation Rep>
|
||||
@ -234,10 +234,12 @@ template<Representation ToRep, typename D, typename U, scalable_with_<ToRep> Rep
|
||||
*
|
||||
* @tparam CastSpec a target quantity point type to cast to or anything that works for quantity_cast
|
||||
*/
|
||||
template<typename CastSpec, typename D, typename U, typename Rep>
|
||||
requires is_specialization_of<CastSpec, quantity_point> ||
|
||||
requires(quantity<D, U, Rep> q) { quantity_cast<CastSpec>(q); }
|
||||
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<D, U, Rep>& qp)
|
||||
template<typename CastSpec, typename O, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<O, U, Rep>& qp)
|
||||
requires requires { requires is_specialization_of<CastSpec, quantity_point>;
|
||||
requires requires { quantity_cast<typename CastSpec::quantity_type>(qp.relative()); };
|
||||
requires equivalent<O, typename CastSpec::origin>; } || // TODO: Simplify when Clang catches up.
|
||||
requires { quantity_cast<CastSpec>(qp.relative()); }
|
||||
{
|
||||
if constexpr (is_specialization_of<CastSpec, quantity_point>)
|
||||
return quantity_point(quantity_cast<typename CastSpec::quantity_type>(qp.relative()));
|
||||
@ -261,11 +263,11 @@ template<typename CastSpec, typename D, typename U, typename Rep>
|
||||
* @tparam ToD a dimension type to use for a target quantity
|
||||
* @tparam ToU a unit type to use for a target quantity
|
||||
*/
|
||||
template<Dimension ToD, Unit ToU, typename D, typename U, typename Rep>
|
||||
requires equivalent<ToD, D> && UnitOf<ToU, ToD>
|
||||
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<D, U, Rep>& q)
|
||||
template<Dimension ToD, Unit ToU, typename O, typename U, typename Rep>
|
||||
requires equivalent<ToD, typename O::dimension> && UnitOf<ToU, ToD> && RebindablePointOriginFor<O, ToD>
|
||||
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<O, U, Rep>& q)
|
||||
{
|
||||
return quantity_point_cast<quantity_point<ToD, ToU, Rep>>(q);
|
||||
return quantity_point_cast<quantity_point<rebind_point_origin_dimension<O, ToD>, ToU, Rep>>(q);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -347,7 +349,8 @@ template<Kind ToK, Unit ToU, typename K, typename U, typename Rep>
|
||||
template<typename CastSpec, typename PK, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr QuantityPointKind auto quantity_point_kind_cast(const quantity_point_kind<PK, U, Rep>& qpk)
|
||||
requires requires { requires is_specialization_of<CastSpec, quantity_point_kind>;
|
||||
requires requires { quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()); }; } ||
|
||||
requires requires { quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()); };
|
||||
requires equivalent<typename PK::origin, typename CastSpec::point_kind_type::origin>; } ||
|
||||
requires { requires PointKind<CastSpec> && UnitOf<U, typename CastSpec::dimension>; } ||
|
||||
requires { quantity_kind_cast<CastSpec>(qpk.relative()); } // TODO: Simplify when Clang catches up.
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
#pragma once
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/point_origin.h>
|
||||
#include <units/quantity.h>
|
||||
#include <compare>
|
||||
// IWYU pragma: end_exports
|
||||
@ -34,18 +35,32 @@
|
||||
namespace units {
|
||||
|
||||
/**
|
||||
* @brief A quantity point
|
||||
* @brief A statically unspecified quantity point origin
|
||||
*
|
||||
* An absolute quantity with respect to zero (which represents some origin).
|
||||
* An origin, unspecified in the type system, from which an absolute quantity is measured from.
|
||||
*
|
||||
* @tparam D a dimension of the quantity point (can be either a BaseDimension or a DerivedDimension)
|
||||
*/
|
||||
template<Dimension D>
|
||||
struct dynamic_origin : point_origin<D> {
|
||||
template<Dimension D2>
|
||||
using rebind = dynamic_origin<D2>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A quantity point
|
||||
*
|
||||
* An absolute quantity measured from an origin.
|
||||
*
|
||||
* @tparam O a type that represents the origin from which the quantity point is measured from
|
||||
* @tparam U a measurement unit of the quantity point
|
||||
* @tparam Rep a type to be used to represent values of a quantity point
|
||||
*/
|
||||
template<Dimension D, UnitOf<D> U, Representation Rep = double>
|
||||
template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep = double>
|
||||
class quantity_point {
|
||||
public:
|
||||
using quantity_type = quantity<D, U, Rep>;
|
||||
using origin = O;
|
||||
using quantity_type = quantity<typename origin::dimension, U, Rep>;
|
||||
using dimension = typename quantity_type::dimension;
|
||||
using unit = typename quantity_type::unit;
|
||||
using rep = typename quantity_type::rep;
|
||||
@ -63,13 +78,14 @@ public:
|
||||
requires std::constructible_from<quantity_type, T>
|
||||
constexpr explicit quantity_point(T&& t) : q_(std::forward<T>(t)) {}
|
||||
|
||||
template<QuantityPoint QP2>
|
||||
template<QuantityPointOf<origin> QP2>
|
||||
requires std::convertible_to<typename QP2::quantity_type, quantity_type>
|
||||
constexpr explicit(false) quantity_point(const QP2& qp) : q_(qp.relative()) {}
|
||||
|
||||
template<QuantityPointLike QP>
|
||||
constexpr explicit quantity_point(const QP& qp)
|
||||
requires std::is_constructible_v<quantity_type, decltype(quantity_point_like_traits<QP>::relative(qp))>
|
||||
requires std::is_constructible_v<quantity_type, decltype(quantity_point_like_traits<QP>::relative(qp))> &&
|
||||
equivalent<origin, typename quantity_point_like_traits<QP>::origin>
|
||||
: q_(quantity_point_like_traits<QP>::relative(qp)) {}
|
||||
|
||||
quantity_point& operator=(const quantity_point&) = default;
|
||||
@ -141,7 +157,8 @@ public:
|
||||
{
|
||||
const auto q = lhs.relative() + rhs;
|
||||
using q_type = decltype(q);
|
||||
return quantity_point<typename q_type::dimension, typename q_type::unit, typename q_type::rep>(q);
|
||||
return quantity_point<rebind_point_origin_dimension<origin, typename q_type::dimension>, typename q_type::unit,
|
||||
typename q_type::rep>(q);
|
||||
}
|
||||
|
||||
template<Quantity Q>
|
||||
@ -157,24 +174,25 @@ public:
|
||||
{
|
||||
const auto q = lhs.relative() - rhs;
|
||||
using q_type = decltype(q);
|
||||
return quantity_point<typename q_type::dimension, typename q_type::unit, typename q_type::rep>(q);
|
||||
return quantity_point<rebind_point_origin_dimension<origin, typename q_type::dimension>, typename q_type::unit,
|
||||
typename q_type::rep>(q);
|
||||
}
|
||||
|
||||
template<QuantityPoint QP>
|
||||
template<QuantityPointOf<origin> QP>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& lhs, const QP& rhs)
|
||||
requires requires(quantity_type q) { q - rhs.relative(); }
|
||||
{
|
||||
return lhs.relative() - rhs.relative();
|
||||
}
|
||||
|
||||
template<QuantityPoint QP>
|
||||
template<QuantityPointOf<origin> QP>
|
||||
requires std::three_way_comparable_with<quantity_type, typename QP::quantity_type>
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const quantity_point& lhs, const QP& rhs)
|
||||
{
|
||||
return lhs.relative() <=> rhs.relative();
|
||||
}
|
||||
|
||||
template<QuantityPoint QP>
|
||||
template<QuantityPointOf<origin> QP>
|
||||
requires std::equality_comparable_with<quantity_type, typename QP::quantity_type>
|
||||
[[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs)
|
||||
{
|
||||
@ -183,24 +201,24 @@ public:
|
||||
};
|
||||
|
||||
template<Representation Rep>
|
||||
explicit quantity_point(Rep) -> quantity_point<dim_one, one, Rep>;
|
||||
explicit quantity_point(Rep) -> quantity_point<dynamic_origin<dim_one>, one, Rep>;
|
||||
|
||||
template<Quantity Q>
|
||||
explicit quantity_point(Q) -> quantity_point<typename Q::dimension, typename Q::unit, typename Q::rep>;
|
||||
explicit quantity_point(Q) -> quantity_point<dynamic_origin<typename Q::dimension>, typename Q::unit, typename Q::rep>;
|
||||
|
||||
template<QuantityLike Q>
|
||||
explicit quantity_point(Q) -> quantity_point<typename quantity_like_traits<Q>::dimension,
|
||||
explicit quantity_point(Q) -> quantity_point<dynamic_origin<typename quantity_like_traits<Q>::dimension>,
|
||||
typename quantity_like_traits<Q>::unit, typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
template<QuantityPointLike QP>
|
||||
explicit quantity_point(QP) -> quantity_point<typename quantity_point_like_traits<QP>::dimension,
|
||||
explicit quantity_point(QP) -> quantity_point<typename quantity_point_like_traits<QP>::origin,
|
||||
typename quantity_point_like_traits<QP>::unit,
|
||||
typename quantity_point_like_traits<QP>::rep>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
inline constexpr bool is_quantity_point<quantity_point<D, U, Rep>> = true;
|
||||
template<typename O, typename U, typename Rep>
|
||||
inline constexpr bool is_quantity_point<quantity_point<O, U, Rep>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace units {
|
||||
/**
|
||||
* @brief A quantity point kind
|
||||
*
|
||||
* An absolute quantity kind with respect to zero (which represents some origin).
|
||||
* An absolute quantity kind measured from an origin.
|
||||
*
|
||||
* @tparam PK the point kind of quantity point
|
||||
* @tparam U the measurement unit of the quantity point kind
|
||||
@ -45,6 +45,7 @@ class quantity_point_kind {
|
||||
public:
|
||||
using point_kind_type = PK;
|
||||
using kind_type = typename PK::base_kind;
|
||||
using origin = typename point_kind_type::origin;
|
||||
using quantity_kind_type = quantity_kind<kind_type, U, Rep>;
|
||||
using quantity_type = typename quantity_kind_type::quantity_type;
|
||||
using dimension = typename quantity_type::dimension;
|
||||
@ -64,14 +65,14 @@ public:
|
||||
requires std::constructible_from<quantity_kind_type, T>
|
||||
constexpr explicit quantity_point_kind(T&& t) : qk_(std::forward<T>(t)) {}
|
||||
|
||||
constexpr explicit quantity_point_kind(const quantity_point<dimension, U, Rep>& qp) : qk_(qp.relative()) {}
|
||||
constexpr explicit quantity_point_kind(quantity_point<dimension, U, Rep>&& qp) : qk_(std::move(qp).relative()) {}
|
||||
constexpr explicit quantity_point_kind(const quantity_point<origin, U, Rep>& qp) : qk_(qp.relative()) {}
|
||||
constexpr explicit quantity_point_kind(quantity_point<origin, U, Rep>&& qp) : qk_(std::move(qp).relative()) {}
|
||||
|
||||
template<QuantityPointLike QP>
|
||||
requires std::constructible_from<quantity_point<dimension, U, Rep>, QP>
|
||||
requires std::constructible_from<quantity_point<origin, U, Rep>, QP>
|
||||
constexpr explicit quantity_point_kind(const QP& qp) : qk_(quantity_point_like_traits<QP>::relative(qp)) {}
|
||||
|
||||
template<QuantityPointKindEquivalentTo<quantity_point_kind> QPK2>
|
||||
template<QuantityPointKindOf<point_kind_type> QPK2>
|
||||
requires std::convertible_to<typename QPK2::quantity_kind_type, quantity_kind_type>
|
||||
constexpr explicit(false) quantity_point_kind(const QPK2& qpk) : qk_(qpk.relative()) {}
|
||||
|
||||
@ -159,20 +160,21 @@ public:
|
||||
return units::quantity_point_kind(lhs.relative() - rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr QuantityKind auto operator-(const quantity_point_kind& lhs, const quantity_point_kind& rhs)
|
||||
template<QuantityPointKindOf<point_kind_type> QPK>
|
||||
[[nodiscard]] friend constexpr QuantityKind auto operator-(const quantity_point_kind& lhs, const QPK& rhs)
|
||||
requires requires(quantity_kind_type qk) { qk - qk; }
|
||||
{
|
||||
return lhs.relative() - rhs.relative();
|
||||
}
|
||||
|
||||
template<QuantityPointKind QPK>
|
||||
template<QuantityPointKindOf<point_kind_type> QPK>
|
||||
requires std::three_way_comparable_with<quantity_kind_type, typename QPK::quantity_kind_type>
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const quantity_point_kind& lhs, const QPK& rhs)
|
||||
{
|
||||
return lhs.relative() <=> rhs.relative();
|
||||
}
|
||||
|
||||
template<QuantityPointKind QPK>
|
||||
template<QuantityPointKindOf<point_kind_type> QPK>
|
||||
requires std::equality_comparable_with<quantity_kind_type, typename QPK::quantity_kind_type>
|
||||
[[nodiscard]] friend constexpr bool operator==(const quantity_point_kind& lhs, const QPK& rhs)
|
||||
{
|
||||
|
@ -51,6 +51,7 @@ add_library(unit_tests_static
|
||||
iec80000_test.cpp
|
||||
kind_test.cpp
|
||||
math_test.cpp
|
||||
point_origin_test.cpp
|
||||
ratio_test.cpp
|
||||
references_test.cpp
|
||||
si_test.cpp
|
||||
|
@ -36,7 +36,7 @@ using namespace std::chrono_literals;
|
||||
using sys_seconds = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
||||
using sys_days = std::chrono::time_point<std::chrono::system_clock,
|
||||
std::chrono::duration<long, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>>;
|
||||
template<typename U, typename Rep = double> using time_point = quantity_point<si::dim_time, U, Rep>;
|
||||
template<typename C, typename U, typename Rep = double> using time_point = quantity_point<clock_origin<C>, U, Rep>;
|
||||
|
||||
static_assert(QuantityLike<std::chrono::seconds>);
|
||||
static_assert(QuantityPointLike<sys_seconds>);
|
||||
@ -50,14 +50,17 @@ static_assert(std::constructible_from<si::time<si::second, std::chrono::hours::r
|
||||
static_assert(!std::convertible_to<std::chrono::hours, si::time<si::second, std::chrono::hours::rep>>);
|
||||
static_assert(!std::constructible_from<si::time<si::hour, std::chrono::seconds::rep>, std::chrono::seconds>);
|
||||
static_assert(!std::convertible_to<std::chrono::seconds, si::time<si::hour, std::chrono::seconds::rep>>);
|
||||
static_assert(std::constructible_from<time_point<si::second, sys_seconds::rep>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<si::second, sys_seconds::rep>>);
|
||||
static_assert(std::constructible_from<time_point<si::day, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<si::day, sys_days::rep>>);
|
||||
static_assert(std::constructible_from<time_point<si::second, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<si::second, sys_days::rep>>);
|
||||
static_assert(!std::constructible_from<time_point<si::day, sys_seconds::rep>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<si::day, sys_seconds::rep>>);
|
||||
static_assert(std::constructible_from<time_point<std::chrono::system_clock, si::second, sys_seconds::rep>, sys_seconds>);
|
||||
static_assert(!std::constructible_from<time_point<std::chrono::steady_clock, si::second, sys_seconds::rep>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<std::chrono::system_clock, si::second, sys_seconds::rep>>);
|
||||
static_assert(std::constructible_from<time_point<std::chrono::system_clock, si::day, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::constructible_from<time_point<std::chrono::steady_clock, si::day, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<std::chrono::system_clock, si::day, sys_days::rep>>);
|
||||
static_assert(std::constructible_from<time_point<std::chrono::system_clock, si::second, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::constructible_from<time_point<std::chrono::steady_clock, si::second, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<std::chrono::system_clock, si::second, sys_days::rep>>);
|
||||
static_assert(!std::constructible_from<time_point<std::chrono::system_clock, si::day, sys_seconds::rep>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<std::chrono::system_clock, si::day, sys_seconds::rep>>);
|
||||
|
||||
// construction - different rep type (integral to a floating-point)
|
||||
static_assert(std::constructible_from<si::time<si::second>, std::chrono::seconds>);
|
||||
@ -66,25 +69,25 @@ static_assert(std::constructible_from<si::time<si::second>, std::chrono::hours>)
|
||||
static_assert(!std::convertible_to<std::chrono::hours, si::time<si::second>>);
|
||||
static_assert(std::constructible_from<si::time<si::hour>, std::chrono::seconds>);
|
||||
static_assert(!std::convertible_to<std::chrono::seconds, si::time<si::hour>>);
|
||||
static_assert(std::constructible_from<time_point<si::second>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<si::second>>);
|
||||
static_assert(std::constructible_from<time_point<si::second>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<si::second>>);
|
||||
static_assert(std::constructible_from<time_point<si::day>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<si::day>>);
|
||||
static_assert(std::constructible_from<time_point<std::chrono::system_clock, si::second>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<std::chrono::system_clock, si::second>>);
|
||||
static_assert(std::constructible_from<time_point<std::chrono::system_clock, si::second>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<std::chrono::system_clock, si::second>>);
|
||||
static_assert(std::constructible_from<time_point<std::chrono::system_clock, si::day>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<std::chrono::system_clock, si::day>>);
|
||||
|
||||
|
||||
// CTAD
|
||||
static_assert(is_same_v<decltype(quantity{1s}), si::time<si::second, std::chrono::seconds::rep>>);
|
||||
static_assert(is_same_v<decltype(quantity{1h}), si::time<si::hour, std::chrono::hours::rep>>);
|
||||
static_assert(is_same_v<decltype(quantity_point{sys_seconds{1s}}), time_point<si::second, sys_seconds::rep>>);
|
||||
static_assert(is_same_v<decltype(quantity_point{sys_days{sys_days::duration{1}}}), time_point<si::day, sys_days::rep>>);
|
||||
static_assert(is_same_v<decltype(quantity_point{sys_seconds{1s}}), time_point<std::chrono::system_clock, si::second, sys_seconds::rep>>);
|
||||
static_assert(is_same_v<decltype(quantity_point{sys_days{sys_days::duration{1}}}), time_point<std::chrono::system_clock, si::day, sys_days::rep>>);
|
||||
|
||||
// operators
|
||||
static_assert(quantity{1s} + 1_q_s == 2_q_s);
|
||||
static_assert(quantity{1s} + 1_q_min == 61_q_s);
|
||||
static_assert(10_q_m / quantity{2s} == 5_q_m_per_s);
|
||||
static_assert(quantity_point{sys_seconds{1s}} + 1_q_s == quantity_point{2_q_s});
|
||||
static_assert(quantity_point{sys_seconds{1s}} + 1_q_min == quantity_point{61_q_s});
|
||||
static_assert(quantity_point{sys_seconds{1s}} + 1_q_s == time_point<std::chrono::system_clock, si::second>{2_q_s});
|
||||
static_assert(quantity_point{sys_seconds{1s}} + 1_q_min == time_point<std::chrono::system_clock, si::second>{61_q_s});
|
||||
|
||||
} // namespace
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <units/isq/si/length.h> // IWYU pragma: keep
|
||||
#include <units/isq/si/prefixes.h>
|
||||
#include <units/isq/si/speed.h>
|
||||
#include <units/quantity_point.h>
|
||||
#include <units/quantity_point_kind.h>
|
||||
#include <units/chrono.h>
|
||||
#include <chrono>
|
||||
#include <complex>
|
||||
@ -112,11 +112,11 @@ static_assert(!Representation<std::string>);
|
||||
|
||||
static_assert(Quantity<si::length<si::metre>>);
|
||||
static_assert(!Quantity<std::chrono::seconds>);
|
||||
static_assert(!Quantity<quantity_point<si::dim_length, si::metre>>);
|
||||
static_assert(!Quantity<quantity_point<dynamic_origin<si::dim_length>, si::metre>>);
|
||||
|
||||
// QuantityPoint
|
||||
|
||||
static_assert(QuantityPoint<quantity_point<si::dim_length, si::metre>>);
|
||||
static_assert(QuantityPoint<quantity_point<dynamic_origin<si::dim_length>, si::metre>>);
|
||||
static_assert(!QuantityPoint<si::length<si::metre>>);
|
||||
static_assert(!QuantityPoint<std::chrono::seconds>);
|
||||
|
||||
@ -141,4 +141,9 @@ static_assert(QuantityOf<si::cgs::length<si::metre>, si::dim_length>);
|
||||
static_assert(QuantityOf<si::cgs::length<si::cgs::centimetre>, si::fps::dim_length>);
|
||||
static_assert(!QuantityOf<si::cgs::length<si::cgs::centimetre>, si::dim_time>);
|
||||
|
||||
static_assert(QuantityPointOf<quantity_point<dynamic_origin<si::dim_time>, si::second, int>, dynamic_origin<si::dim_time>>);
|
||||
static_assert(QuantityPointOf<quantity_point<clock_origin<std::chrono::system_clock>, si::second, int>, clock_origin<std::chrono::system_clock>>);
|
||||
static_assert(!QuantityPointOf<quantity_point<dynamic_origin<si::dim_time>, si::second, int>, clock_origin<std::chrono::system_clock>>);
|
||||
static_assert(!QuantityPointOf<quantity_point<clock_origin<std::chrono::system_clock>, si::second, int>, dynamic_origin<si::dim_time>>);
|
||||
|
||||
} // namespace
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <units/isq/si/length.h>
|
||||
#include <units/isq/si/speed.h>
|
||||
#include <units/kind.h>
|
||||
#include <units/quantity_point.h>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace units;
|
||||
@ -97,7 +98,6 @@ static_assert(PointKind<radial_point>);
|
||||
|
||||
static_assert(is_same_v<radial_point::base_kind, radius>);
|
||||
static_assert(is_same_v<radial_point::dimension, dim_length>);
|
||||
static_assert(is_same_v<radial_point, detail::_point_kind_base<radius>>);
|
||||
static_assert(is_same_v<radial_point, downcast_point_kind<radius>>);
|
||||
|
||||
static_assert(equivalent<radial_point, radial_point>);
|
||||
@ -137,7 +137,6 @@ static_assert(PointKind<horizontal_velocity>);
|
||||
|
||||
static_assert(is_same_v<horizontal_velocity::base_kind, horizontal_speed>);
|
||||
static_assert(is_same_v<horizontal_velocity::dimension, dim_speed>);
|
||||
static_assert(is_same_v<horizontal_velocity, detail::_point_kind_base<horizontal_speed>>);
|
||||
static_assert(is_same_v<horizontal_velocity, downcast_point_kind<horizontal_speed>>);
|
||||
|
||||
static_assert(equivalent<horizontal_velocity, horizontal_velocity>);
|
||||
|
73
test/unit_test/static/point_origin_test.cpp
Normal file
73
test/unit_test/static/point_origin_test.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
// 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.
|
||||
|
||||
#include <units/bits/equivalent.h>
|
||||
#include <units/chrono.h>
|
||||
#include <units/kind.h>
|
||||
#include <units/quantity_point.h>
|
||||
#include <units/isq/si/length.h>
|
||||
#include <units/isq/si/cgs/length.h>
|
||||
|
||||
using namespace units;
|
||||
namespace si = isq::si;
|
||||
|
||||
namespace {
|
||||
|
||||
struct width : kind<width, si::dim_length> {};
|
||||
|
||||
struct ones_viewpoint1 : point_origin<si::dim_length> {
|
||||
template<typename D>
|
||||
using rebind = ones_viewpoint1;
|
||||
};
|
||||
|
||||
struct ones_viewpoint2 : point_origin<si::cgs::dim_length> {
|
||||
template<typename D>
|
||||
using rebind = ones_viewpoint1;
|
||||
};
|
||||
|
||||
static_assert(PointOrigin<dynamic_origin<si::dim_length>>);
|
||||
static_assert(!PointOrigin<point_origin<si::dim_length>>);
|
||||
static_assert(!PointOrigin<width>);
|
||||
static_assert(!PointOrigin<point_kind<struct abscissa, width>>);
|
||||
|
||||
static_assert(RebindablePointOriginFor<dynamic_origin<si::dim_length>, si::dim_length>);
|
||||
static_assert(is_same_v<rebind_point_origin_dimension<dynamic_origin<si::dim_length>, si::dim_length>,
|
||||
dynamic_origin<si::dim_length>>);
|
||||
static_assert(RebindablePointOriginFor<dynamic_origin<si::dim_length>, si::dim_time>);
|
||||
static_assert(is_same_v<rebind_point_origin_dimension<dynamic_origin<si::dim_length>, si::dim_time>,
|
||||
dynamic_origin<si::dim_time>>);
|
||||
static_assert(RebindablePointOriginFor<ones_viewpoint1, si::dim_length>);
|
||||
static_assert(is_same_v<rebind_point_origin_dimension<ones_viewpoint1, si::dim_length>, ones_viewpoint1>);
|
||||
static_assert(RebindablePointOriginFor<ones_viewpoint2, si::dim_length>);
|
||||
static_assert(is_same_v<rebind_point_origin_dimension<ones_viewpoint2, si::dim_length>, ones_viewpoint1>);
|
||||
static_assert(RebindablePointOriginFor<ones_viewpoint2, si::cgs::dim_length>);
|
||||
static_assert(is_same_v<rebind_point_origin_dimension<ones_viewpoint2, si::cgs::dim_length>, ones_viewpoint2>);
|
||||
static_assert(!RebindablePointOriginFor<ones_viewpoint1, si::cgs::dim_length>);
|
||||
|
||||
static_assert(equivalent<dynamic_origin<si::dim_time>, dynamic_origin<si::dim_time>>);
|
||||
static_assert(equivalent<dynamic_origin<si::dim_length>, dynamic_origin<si::cgs::dim_length>>);
|
||||
static_assert(!equivalent<dynamic_origin<si::dim_time>, clock_origin<std::chrono::system_clock>>);
|
||||
static_assert(!equivalent<clock_origin<std::chrono::steady_clock>, clock_origin<std::chrono::system_clock>>);
|
||||
static_assert(!equivalent<dynamic_origin<si::dim_time>, dynamic_origin<si::dim_length>>);
|
||||
static_assert(!equivalent<ones_viewpoint1, ones_viewpoint2>);
|
||||
|
||||
} // namespace
|
@ -82,16 +82,16 @@ static_assert(QuantityKind<width<metre>>);
|
||||
static_assert(QuantityKind<rate_of_climb<metre_per_second>>);
|
||||
static_assert(!QuantityKind<double>);
|
||||
static_assert(!QuantityKind<length<metre>>);
|
||||
static_assert(!QuantityKind<quantity_point<dim_length, metre>>);
|
||||
static_assert(!QuantityKind<quantity_point<dynamic_origin<dim_length>, metre>>);
|
||||
|
||||
static_assert(QuantityKindOf<width<metre>, width_kind>);
|
||||
static_assert(!QuantityKindOf<width<metre>, height_kind>);
|
||||
static_assert(!QuantityKindOf<width<metre>, metre>);
|
||||
static_assert(!QuantityKindOf<length<metre>, width_kind>);
|
||||
static_assert(!QuantityKindOf<length<metre>, metre>);
|
||||
static_assert(!QuantityKindOf<quantity_point<dim_length, metre>, width_kind>);
|
||||
static_assert(!QuantityKindOf<quantity_point<dim_length, metre>, dim_length>);
|
||||
static_assert(!QuantityKindOf<quantity_point<dim_length, metre>, metre>);
|
||||
static_assert(!QuantityKindOf<quantity_point<dynamic_origin<dim_length>, metre>, width_kind>);
|
||||
static_assert(!QuantityKindOf<quantity_point<dynamic_origin<dim_length>, metre>, dim_length>);
|
||||
static_assert(!QuantityKindOf<quantity_point<dynamic_origin<dim_length>, metre>, metre>);
|
||||
|
||||
|
||||
///////////////
|
||||
@ -105,7 +105,7 @@ template<typename Width>
|
||||
concept invalid_types = requires {
|
||||
requires !requires { typename quantity_kind<Width, second, int>; }; // unit of a different dimension
|
||||
requires !requires { typename quantity_kind<Width, metre, length<metre>>; }; // quantity used as Rep
|
||||
requires !requires { typename quantity_kind<Width, metre, quantity_point<dim_length, metre>>; }; // quantity point used as Rep
|
||||
requires !requires { typename quantity_kind<Width, metre, quantity_point<dynamic_origin<dim_length>, metre>>; }; // quantity point used as Rep
|
||||
requires !requires { typename quantity_kind<Width, metre, width<metre>>; }; // quantity kind used as Rep
|
||||
requires !requires { typename quantity_kind<metre, Width, double>; }; // reordered arguments
|
||||
requires !requires { typename quantity_kind<metre, double, Width>; }; // reordered arguments
|
||||
@ -454,7 +454,7 @@ concept invalid_compound_assignments = requires(quantity_kind<Width, metre, int>
|
||||
requires invalid_compound_assignments_<Width, metre, length<metre, int>>;
|
||||
requires invalid_compound_assignments_<Width, metre, height<metre, int>>;
|
||||
requires invalid_compound_assignments_<Width, metre, horizontal_area<square_metre, int>>;
|
||||
requires invalid_compound_assignments_<Width, metre, quantity_point<dim_length, metre, int>>;
|
||||
requires invalid_compound_assignments_<Width, metre, quantity_point<dynamic_origin<dim_length>, metre, int>>;
|
||||
requires invalid_compound_assignments_<Width, metre, std::chrono::seconds>;
|
||||
};
|
||||
static_assert(invalid_compound_assignments<width_kind>);
|
||||
@ -485,12 +485,12 @@ static_assert((width<metre, std::uint8_t>(0 * m) - width<metre, std::uint8_t>(1
|
||||
|
||||
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, double>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, length<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, quantity_point<dim_length, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, quantity_point<dynamic_origin<dim_length>, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, width<metre>, reference<dim_length, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, double>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, length<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, quantity_point<dim_length, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, quantity_point<dynamic_origin<dim_length>, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, reference<dim_length, metre>>);
|
||||
|
||||
@ -650,17 +650,17 @@ static_assert(is_same_v<
|
||||
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, reference<dim_length, metre>, width<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, width<metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, height<metre>, quantity_point<dim_length, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_point<dim_length, metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, height<metre>, quantity_point<dynamic_origin<dim_length>, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_point<dynamic_origin<dim_length>, metre>, height<metre>>);
|
||||
|
||||
static_assert(!std::is_invocable_v<std::divides<>, reference<dim_length, metre>, width<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, width<metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, height<metre>, quantity_point<dim_length, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_point<dim_length, metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, height<metre>, quantity_point<dynamic_origin<dim_length>, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_point<dynamic_origin<dim_length>, metre>, height<metre>>);
|
||||
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, reference<dim_length, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, length<metre, int>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, quantity_point<dim_length, metre, int>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, quantity_point<dynamic_origin<dim_length>, metre, int>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, double>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, width<metre, double>>);
|
||||
|
||||
@ -801,8 +801,8 @@ concept invalid_cast = requires {
|
||||
requires !requires { quantity_kind_cast<dimensionless<one>>(quantity_kind<Width, metre, int>(1 * m)); };
|
||||
requires !requires { quantity_kind_cast<square_metre>(quantity_kind<Width, metre, int>(1 * m)); };
|
||||
requires !requires { quantity_kind_cast<second>(quantity_kind<Width, metre, int>(1 * m)); };
|
||||
requires !requires { quantity_kind_cast<quantity_point<dim_length, metre, int>>(quantity_kind<Width, metre, int>(1 * m)); };
|
||||
requires !requires { quantity_kind_cast<quantity_point<dim_one, one, int>>(quantity_kind<Width, metre, int>(1 * m)); };
|
||||
requires !requires { quantity_kind_cast<quantity_point<dynamic_origin<dim_length>, metre, int>>(quantity_kind<Width, metre, int>(1 * m)); };
|
||||
requires !requires { quantity_kind_cast<quantity_point<dynamic_origin<dim_one>, one, int>>(quantity_kind<Width, metre, int>(1 * m)); };
|
||||
};
|
||||
static_assert(invalid_cast<width_kind>);
|
||||
|
||||
|
@ -57,6 +57,18 @@ struct cgs_height_kind : kind<cgs_height_kind, cgs::dim_length> {};
|
||||
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, dim_speed, height_kind> {};
|
||||
struct altitude_kind : point_kind<altitude_kind, cgs_height_kind> {};
|
||||
|
||||
struct sea_level_origin : point_origin<dim_length> {};
|
||||
struct sea_level_altitude_kind : point_kind<sea_level_altitude_kind, height_kind, sea_level_origin> {};
|
||||
|
||||
template<Dimension D>
|
||||
struct screen_origin : point_origin<D> {
|
||||
template<Dimension D2>
|
||||
using rebind = screen_origin<D2>;
|
||||
};
|
||||
struct screen_si_width_kind : point_kind<screen_si_width_kind, width_kind, screen_origin<dim_length>> {};
|
||||
struct screen_si_cgs_width_kind :
|
||||
point_kind<screen_si_cgs_width_kind, cgs_width_kind, screen_origin<cgs::dim_length>> {};
|
||||
|
||||
struct apple : kind<apple, dim_one> {};
|
||||
struct orange : kind<orange, dim_one> {};
|
||||
struct nth_apple_kind : point_kind<nth_apple_kind, apple> {};
|
||||
@ -65,6 +77,8 @@ struct nth_orange_kind : point_kind<nth_orange_kind, orange> {};
|
||||
struct time_kind : kind<time_kind, dim_time> {};
|
||||
struct time_point_kind : point_kind<time_point_kind, time_kind> {};
|
||||
|
||||
struct sys_time_point_kind : point_kind<time_point_kind, time_kind, clock_origin<std::chrono::system_clock>> {};
|
||||
|
||||
template <Unit U, Representation Rep = double> using width = quantity_kind<width_kind, U, Rep>;
|
||||
template <Unit U, Representation Rep = double> using height = quantity_kind<height_kind, U, Rep>;
|
||||
template <Unit U, Representation Rep = double> using abscissa = quantity_point_kind<abscissa_kind, U, Rep>;
|
||||
@ -76,6 +90,13 @@ template <Unit U, Representation Rep = double> using cgs_height = quantity_kind<
|
||||
template <Unit U, Representation Rep = double> using rate_of_climb = quantity_kind<rate_of_climb_kind, U, Rep>;
|
||||
template <Unit U, Representation Rep = double> using altitude = quantity_point_kind<altitude_kind, U, Rep>;
|
||||
|
||||
template<Unit U, Representation Rep = double>
|
||||
using sea_level_altitude = quantity_point_kind<sea_level_altitude_kind, U, Rep>;
|
||||
template<Unit U, Representation Rep = double>
|
||||
using screen_si_width = quantity_point_kind<screen_si_width_kind, U, Rep>;
|
||||
template<Unit U, Representation Rep = double>
|
||||
using screen_si_cgs_width = quantity_point_kind<screen_si_cgs_width_kind, U, Rep>;
|
||||
|
||||
template <Unit U = one, Representation Rep = double> using apples = quantity_kind<apple, U, Rep>;
|
||||
template <Unit U = one, Representation Rep = double> using oranges = quantity_kind<orange, U, Rep>;
|
||||
template <Unit U = one, Representation Rep = double> using nth_apple = quantity_point_kind<nth_apple_kind, U, Rep>;
|
||||
@ -89,7 +110,7 @@ static_assert(QuantityPointKind<abscissa<metre>>);
|
||||
static_assert(QuantityPointKind<nth_apple<one>>);
|
||||
static_assert(!QuantityPointKind<double>);
|
||||
static_assert(!QuantityPointKind<length<metre>>);
|
||||
static_assert(!QuantityPointKind<quantity_point<dim_length, metre>>);
|
||||
static_assert(!QuantityPointKind<quantity_point<dynamic_origin<dim_length>, metre>>);
|
||||
static_assert(!QuantityPointKind<width<metre>>);
|
||||
|
||||
static_assert(QuantityPointKindOf<abscissa<metre>, abscissa_kind>);
|
||||
@ -100,9 +121,12 @@ static_assert(!QuantityPointKindOf<length<metre>, metre>);
|
||||
static_assert(!QuantityPointKindOf<width<metre>, abscissa_kind>);
|
||||
static_assert(!QuantityPointKindOf<width<metre>, width_kind>);
|
||||
static_assert(!QuantityPointKindOf<width<metre>, metre>);
|
||||
static_assert(!QuantityPointKindOf<quantity_point<dim_length, metre>, width_kind>);
|
||||
static_assert(!QuantityPointKindOf<quantity_point<dim_length, metre>, dim_length>);
|
||||
static_assert(!QuantityPointKindOf<quantity_point<dim_length, metre>, metre>);
|
||||
static_assert(!QuantityPointKindOf<abscissa<metre>, sea_level_altitude_kind>);
|
||||
static_assert(!QuantityPointKindOf<altitude<metre>, sea_level_altitude_kind>);
|
||||
static_assert(!QuantityPointKindOf<quantity_point<dynamic_origin<dim_length>, metre>, width_kind>);
|
||||
static_assert(!QuantityPointKindOf<quantity_point<dynamic_origin<dim_length>, metre>, dim_length>);
|
||||
static_assert(!QuantityPointKindOf<quantity_point<dynamic_origin<dim_length>, metre>, dynamic_origin<dim_length>>);
|
||||
static_assert(!QuantityPointKindOf<quantity_point<dynamic_origin<dim_length>, metre>, metre>);
|
||||
|
||||
|
||||
///////////////
|
||||
@ -117,7 +141,7 @@ concept invalid_types = requires {
|
||||
requires !requires { typename quantity_point_kind<Width, metre, int>; }; // width_kind is not a point kind
|
||||
requires !requires { typename quantity_point_kind<Abscissa, second, int>; }; // unit of a different dimension
|
||||
requires !requires { typename quantity_point_kind<Abscissa, metre, length<metre>>; }; // quantity used as Rep
|
||||
requires !requires { typename quantity_point_kind<Abscissa, metre, quantity_point<dim_length, metre>>; }; // quantity point used as Rep
|
||||
requires !requires { typename quantity_point_kind<Abscissa, metre, quantity_point<dynamic_origin<dim_length>, metre>>; }; // quantity point used as Rep
|
||||
requires !requires { typename quantity_point_kind<Abscissa, metre, width<metre>>; }; // quantity kind used as Rep
|
||||
requires !requires { typename quantity_point_kind<Abscissa, metre, abscissa<metre>>; }; // quantity point kind used as Rep
|
||||
requires !requires { typename quantity_point_kind<metre, Abscissa, double>; }; // reordered arguments
|
||||
@ -160,6 +184,7 @@ static_assert(!std::is_aggregate_v<abscissa<metre>>);
|
||||
|
||||
static_assert(is_same_v<abscissa<metre>::point_kind_type, abscissa_kind>);
|
||||
static_assert(is_same_v<abscissa<metre>::kind_type, width_kind>);
|
||||
static_assert(is_same_v<abscissa<metre>::origin, dynamic_origin<dim_length>>);
|
||||
static_assert(is_same_v<abscissa<metre>::quantity_kind_type, width<metre>>);
|
||||
static_assert(is_same_v<abscissa<metre>::quantity_type, length<metre>>);
|
||||
static_assert(is_same_v<abscissa<metre>::dimension, dim_length>);
|
||||
@ -287,6 +312,14 @@ static_assert(!constructible_or_convertible_from<abscissa<metre, int>>(quantity_
|
||||
static_assert(!constructible_or_convertible_from<abscissa<metre, double>>(quantity_point(1.0 * (m * m))));
|
||||
static_assert(!constructible_or_convertible_from<abscissa<metre, double>>(quantity_point(1.0 * s)));
|
||||
|
||||
static_assert(construct_from_only<screen_si_width<metre>>(quantity_point<screen_origin<dim_length>, metre>(1 * m))
|
||||
.relative()
|
||||
.common() == 1 * m);
|
||||
static_assert(construct_from_only<screen_si_width<metre>>(quantity_point<screen_origin<cgs::dim_length>, metre>(1 * m))
|
||||
.relative()
|
||||
.common() == 1 * m);
|
||||
static_assert(!constructible_or_convertible_from<sea_level_altitude<metre, double>>(quantity_point(1.0 * m)));
|
||||
|
||||
// clang-format off
|
||||
static_assert(construct_from_only<nth_apple<one, short>>(quantity_point(1)).relative().common() == 1);
|
||||
static_assert(construct_from_only<nth_apple<one, int>>(quantity_point(1)).relative().common() == 1);
|
||||
@ -303,8 +336,12 @@ static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(quantity_p
|
||||
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(quantity_point(dimensionless<percent, double>(1))));
|
||||
static_assert(!constructible_or_convertible_from<nth_apple<one, double>>(quantity_point(1.0 * s)));
|
||||
|
||||
static_assert(construct_from_only<quantity_point_kind<time_point_kind, second, int>>(sys_seconds{42s}).relative().common() == 42 * s);
|
||||
// clang-format on
|
||||
static_assert(
|
||||
construct_from_only<quantity_point_kind<sys_time_point_kind, second, int>>(sys_seconds{42s}).relative().common() ==
|
||||
42 * s);
|
||||
static_assert(!constructible_or_convertible_from<quantity_point_kind<time_point_kind, second, int>>(sys_seconds{42s}),
|
||||
"no implicit conversion to/from dynamic_origin");
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
@ -365,6 +402,15 @@ static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(nth_orange
|
||||
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(abscissa<metre, int>(1 * m)));
|
||||
// clang-format on
|
||||
|
||||
static_assert(!constructible_or_convertible_from<quantity_point_kind<sys_time_point_kind, second, int>>(
|
||||
quantity_point_kind<time_point_kind, second, int>{}),
|
||||
"no implicit conversion to/from dynamic_origin");
|
||||
static_assert(!constructible_or_convertible_from<quantity_point_kind<time_point_kind, second, int>>(
|
||||
quantity_point_kind<sys_time_point_kind, second, int>{}),
|
||||
"no implicit conversion to/from dynamic_origin");
|
||||
static_assert(!constructible_or_convertible_from<screen_si_width<metre>>(screen_si_cgs_width<metre>(1 * m)),
|
||||
"base kinds are not the same (required by equivalent<Kind, Kind>)");
|
||||
|
||||
|
||||
//////////////////////
|
||||
// other conversions
|
||||
@ -375,7 +421,7 @@ static_assert(!std::is_convertible_v<abscissa<metre, int>, dimensionless<one, in
|
||||
static_assert(!std::is_convertible_v<abscissa<metre, int>, length<metre, int>>);
|
||||
static_assert(!std::is_convertible_v<abscissa<metre, int>, width<metre, int>>);
|
||||
static_assert(!std::is_convertible_v<abscissa<metre, int>, height<metre, int>>);
|
||||
static_assert(!std::is_convertible_v<abscissa<metre, int>, quantity_point<dim_length, metre, int>>);
|
||||
static_assert(!std::is_convertible_v<abscissa<metre, int>, quantity_point<dynamic_origin<dim_length>, metre, int>>);
|
||||
|
||||
|
||||
////////////////////////
|
||||
@ -420,7 +466,7 @@ concept invalid_compound_assignments = requires(quantity_point_kind<Abscissa, me
|
||||
requires invalid_compound_assignments_<Abscissa, metre, length<metre, int>>;
|
||||
requires invalid_compound_assignments_<Abscissa, metre, height<metre, int>>;
|
||||
requires invalid_compound_assignments_<Abscissa, metre, rate_of_climb<metre_per_second, int>>;
|
||||
requires invalid_compound_assignments_<Abscissa, metre, quantity_point<dim_length, metre, int>>;
|
||||
requires invalid_compound_assignments_<Abscissa, metre, quantity_point<dynamic_origin<dim_length>, metre, int>>;
|
||||
requires invalid_compound_assignments_<Abscissa, metre, std::chrono::seconds>;
|
||||
};
|
||||
static_assert(invalid_compound_assignments<abscissa_kind>);
|
||||
@ -447,13 +493,13 @@ static_assert(same(width<kilometre, int>(2 * km) + abscissa<metre, double>(3e3 *
|
||||
static_assert(same(width<metre, double>(2e3 * m) + abscissa<kilometre, int>(3 * km), abscissa<metre, double>(5e3 * m)));
|
||||
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, double>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, length<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, quantity_point<dim_length, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, quantity_point<dynamic_origin<dim_length>, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, abscissa<metre>, abscissa<kilometre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, abscissa<kilometre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, height<metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_point<dim_length, metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_point<dynamic_origin<dim_length>, metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, length<metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, double, abscissa<metre>>);
|
||||
|
||||
@ -469,14 +515,15 @@ static_assert(same(abscissa<kilometre, int>(2 * km) - abscissa<metre, double>(3e
|
||||
static_assert(same(abscissa<metre, double>(2e3 * m) - abscissa<kilometre, int>(3 * km), width<metre, double>(-1e3 * m)));
|
||||
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, double>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, length<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, quantity_point<dim_length, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, quantity_point<dynamic_origin<dim_length>, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, abscissa<metre>, ordinate<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, ordinate<metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, height<metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_point<dim_length, metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_point<dynamic_origin<dim_length>, metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, length<metre>, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, double, abscissa<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, screen_si_width<metre>, screen_si_cgs_width<metre>>);
|
||||
// clang-format on
|
||||
|
||||
|
||||
@ -496,8 +543,8 @@ static_assert(std::equality_comparable_with<abscissa<nanometre, int>, abscissa<k
|
||||
static_assert(std::equality_comparable_with<abscissa<cgs::centimetre, int>, abscissa<millimetre, double>>);
|
||||
static_assert(std::equality_comparable_with<abscissa<metre>, abscissa<cgs::centimetre>>);
|
||||
// clang-format on
|
||||
template<typename Abscissa>
|
||||
concept invalid_equality = requires(quantity_point_kind<Abscissa, metre, int> x) {
|
||||
template<typename Int>
|
||||
concept invalid_equality = requires(quantity_point_kind<abscissa_kind, metre, Int> x, Int i) {
|
||||
requires !requires { x == 1; };
|
||||
requires !requires { x != 1.0; };
|
||||
requires !requires { x == 1 * m; };
|
||||
@ -516,8 +563,9 @@ concept invalid_equality = requires(quantity_point_kind<Abscissa, metre, int> x)
|
||||
requires !requires { x == quantity_point(dimensionless<percent>(1.0)); };
|
||||
requires !requires { x != quantity_point_kind(cgs_width<metre, int>(1 * m)); };
|
||||
requires !requires { x == ordinate<metre, int>(1 * m); };
|
||||
requires !requires { screen_si_width<metre, Int>{} != screen_si_cgs_width<metre, Int>{}; };
|
||||
};
|
||||
static_assert(invalid_equality<abscissa_kind>);
|
||||
static_assert(invalid_equality<int>);
|
||||
|
||||
// clang-format off
|
||||
static_assert(abscissa<metre, int>(1 * m) < abscissa<metre, int>(2 * m));
|
||||
@ -531,8 +579,8 @@ static_assert(std::three_way_comparable_with<abscissa<nanometre, int>, abscissa<
|
||||
static_assert(std::three_way_comparable_with<abscissa<cgs::centimetre, int>, abscissa<millimetre, double>>);
|
||||
static_assert(std::three_way_comparable_with<abscissa<metre>, abscissa<cgs::centimetre>>);
|
||||
// clang-format on
|
||||
template<typename Abscissa>
|
||||
concept invalid_relational = requires(quantity_point_kind<Abscissa, metre, int> x) {
|
||||
template<typename Int>
|
||||
concept invalid_relational = requires(quantity_point_kind<abscissa_kind, metre, Int> x, Int i) {
|
||||
requires !requires { x < 1; };
|
||||
requires !requires { x <= 1.0; };
|
||||
requires !requires { x >= 1 * m; };
|
||||
@ -551,8 +599,9 @@ concept invalid_relational = requires(quantity_point_kind<Abscissa, metre, int>
|
||||
requires !requires { x < quantity_point(dimensionless<percent>(1.0)); };
|
||||
requires !requires { x <= quantity_point_kind(cgs_width<metre, int>(1 * m)); };
|
||||
requires !requires { x >= ordinate<metre, int>(1 * m); };
|
||||
requires !requires { screen_si_width<metre, Int>{} > screen_si_cgs_width<metre, Int>{}; };
|
||||
};
|
||||
static_assert(invalid_relational<abscissa_kind>);
|
||||
static_assert(invalid_relational<int>);
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
@ -600,6 +649,7 @@ static_assert(same(quantity_point_kind_cast<length<kilometre, int>>(abscissa<met
|
||||
static_assert(same(quantity_point_kind_cast<length<centimetre, int>>(abscissa<metre, int>(1 * m)), abscissa<centimetre, int>(100 * cm)));
|
||||
static_assert(same(quantity_point_kind_cast<length<centimetre, int>>(abscissa<metre, double>(0.01 * m)), abscissa<centimetre, int>(1 * cm)));
|
||||
static_assert(same(quantity_point_kind_cast<length<centimetre, int>>(abscissa<cgs::centimetre, int>(1 * cgs_cm)), abscissa<cgs::centimetre, int>(1 * cgs_cm)));
|
||||
static_assert(same(quantity_point_kind_cast<screen_si_cgs_width<metre, int>>(screen_si_width<metre, int>(1 * m)), screen_si_cgs_width<metre, int>(1 * m)));
|
||||
// clang-format on
|
||||
template<typename Int>
|
||||
concept invalid_cast = requires(Int i) {
|
||||
@ -617,8 +667,9 @@ concept invalid_cast = requires(Int i) {
|
||||
requires !requires { quantity_point_kind_cast<dimensionless<one>>(abscissa<metre, Int>(i * m)); };
|
||||
requires !requires { quantity_point_kind_cast<square_metre>(abscissa<metre, Int>(i * m)); };
|
||||
requires !requires { quantity_point_kind_cast<second>(abscissa<metre, Int>(i * m)); };
|
||||
requires !requires { quantity_point_kind_cast<quantity_point<dim_length, metre, Int>>(abscissa<metre, Int>(i * m)); };
|
||||
requires !requires { quantity_point_kind_cast<quantity_point<dim_one, one, Int>>(abscissa<metre, Int>(i * m)); };
|
||||
requires !requires { quantity_point_kind_cast<quantity_point<dynamic_origin<dim_length>, metre, Int>>(abscissa<metre, Int>(i * m)); };
|
||||
requires !requires { quantity_point_kind_cast<quantity_point<dynamic_origin<dim_one>, one, Int>>(abscissa<metre, Int>(i * m)); };
|
||||
requires !requires { quantity_point_kind_cast<quantity_point<dynamic_origin<dim_length>, metre, Int>>(screen_si_width<metre, Int>(i * m)); };
|
||||
};
|
||||
static_assert(invalid_cast<int>);
|
||||
|
||||
|
@ -41,72 +41,89 @@ using namespace references;
|
||||
using namespace std::chrono_literals;
|
||||
using sys_seconds = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
||||
|
||||
struct sea_level_origin : point_origin<dim_length> {};
|
||||
|
||||
// class invariants
|
||||
|
||||
template<typename DimLength>
|
||||
concept invalid_types = requires
|
||||
{
|
||||
requires !requires { typename quantity_point<DimLength, second, int>; }; // unit of a different dimension
|
||||
requires !requires { typename quantity_point<DimLength, metre, quantity<DimLength, metre, int>>; }; // quantity used as Rep
|
||||
// quantity point used as Rep
|
||||
requires !requires { typename quantity_point<DimLength, metre, quantity_point<DimLength, metre, int>>; };
|
||||
requires !requires { typename quantity<metre, DimLength, double>; }; // reordered arguments
|
||||
// unit of a different dimension:
|
||||
requires !requires { typename quantity_point<dynamic_origin<DimLength>, second, int>; };
|
||||
// quantity used as Rep:
|
||||
requires !requires { typename quantity_point<dynamic_origin<DimLength>, metre, quantity<DimLength, metre, int>>; };
|
||||
// quantity point used as Rep:
|
||||
requires !requires { typename quantity_point<dynamic_origin<DimLength>, metre,
|
||||
quantity_point<dynamic_origin<DimLength>, metre, int>>; };
|
||||
// reordered arguments:
|
||||
requires !requires { typename quantity_point<metre, dynamic_origin<DimLength>, double>; };
|
||||
// dimension used as origin:
|
||||
requires !requires { typename quantity_point<DimLength, second, int>; };
|
||||
};
|
||||
|
||||
static_assert(invalid_types<dim_length>);
|
||||
|
||||
// member types
|
||||
|
||||
static_assert(is_same_v<quantity_point<dim_length, metre, int>::rep, int>);
|
||||
static_assert(is_same_v<quantity_point<dim_length, metre, double>::rep, double>);
|
||||
static_assert(is_same_v<quantity_point<dim_length, metre, int>::unit, metre>);
|
||||
static_assert(is_same_v<quantity_point<dim_length, kilometre, int>::unit, kilometre>);
|
||||
static_assert(is_same_v<quantity_point<dim_length, metre, int>::dimension, dim_length>);
|
||||
static_assert(is_same_v<quantity_point<dim_length, metre, int>::quantity_type, quantity<dim_length, metre, int>>);
|
||||
static_assert(is_same_v<quantity_point<dynamic_origin<dim_length>, metre, int>::rep, int>);
|
||||
static_assert(is_same_v<quantity_point<dynamic_origin<dim_length>, metre, double>::rep, double>);
|
||||
static_assert(is_same_v<quantity_point<dynamic_origin<dim_length>, metre, int>::unit, metre>);
|
||||
static_assert(is_same_v<quantity_point<dynamic_origin<dim_length>, kilometre, int>::unit, kilometre>);
|
||||
static_assert(is_same_v<quantity_point<dynamic_origin<dim_length>, metre, int>::dimension, dim_length>);
|
||||
static_assert(is_same_v<quantity_point<dynamic_origin<dim_length>, metre, int>::origin, dynamic_origin<dim_length>>);
|
||||
static_assert(is_same_v<quantity_point<dynamic_origin<dim_length>, metre, int>::quantity_type, quantity<dim_length, metre, int>>);
|
||||
|
||||
// constructors
|
||||
|
||||
static_assert(quantity_point(1).relative() == quantity(1));
|
||||
static_assert(!std::is_convertible_v<int, quantity_point<dim_one, one, int>>);
|
||||
static_assert(!std::is_convertible_v<int, quantity_point<dynamic_origin<dim_one>, one, int>>);
|
||||
|
||||
static_assert(quantity_point(42s).relative() == 42 * s);
|
||||
static_assert(quantity_point(sys_seconds{42s}).relative() == 42 * s);
|
||||
static_assert(!std::is_convertible_v<std::chrono::seconds, quantity_point<dim_time, second, std::chrono::seconds::rep>>);
|
||||
static_assert(!std::is_convertible_v<sys_seconds, quantity_point<dim_time, second, sys_seconds::rep>>);
|
||||
static_assert(!std::is_convertible_v<std::chrono::seconds, quantity_point<dynamic_origin<dim_time>, second, std::chrono::seconds::rep>>);
|
||||
static_assert(!std::is_convertible_v<std::chrono::seconds, quantity_point<clock_origin<std::chrono::system_clock>, second, std::chrono::seconds::rep>>);
|
||||
static_assert(!std::is_convertible_v<sys_seconds, quantity_point<dynamic_origin<dim_time>, second, sys_seconds::rep>>);
|
||||
static_assert(!std::is_convertible_v<sys_seconds, quantity_point<clock_origin<std::chrono::system_clock>, second, sys_seconds::rep>>);
|
||||
|
||||
static_assert(quantity_point<dim_length, metre, int>().relative() == 0_q_m);
|
||||
constexpr quantity_point<dim_length, metre, int> km{1000_q_m};
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, int>().relative() == 0_q_m);
|
||||
constexpr quantity_point<dynamic_origin<dim_length>, metre, int> km{1000_q_m};
|
||||
static_assert(km.relative() == 1000_q_m);
|
||||
static_assert(quantity_point<dim_length, metre, int>(km).relative() == km.relative());
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, int>(km).relative() == km.relative());
|
||||
|
||||
static_assert(quantity_point<dim_length, metre, int>(1_q_m).relative() == 1_q_m);
|
||||
static_assert(!std::is_constructible_v<quantity_point<dim_length, metre, int>, double>); // truncating conversion
|
||||
static_assert(quantity_point<dim_length, metre, double>(1.0_q_m).relative() == 1.0_q_m);
|
||||
static_assert(quantity_point<dim_length, metre, double>(1_q_m).relative() == 1_q_m);
|
||||
static_assert(quantity_point<dim_length, metre, long double>(3.14_q_m).relative() == 3.14_q_m);
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, int>(1_q_m).relative() == 1_q_m);
|
||||
static_assert(!std::is_constructible_v<quantity_point<dynamic_origin<dim_length>, metre, int>, double>); // truncating conversion
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, double>(1.0_q_m).relative() == 1.0_q_m);
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, double>(1_q_m).relative() == 1_q_m);
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, long double>(3.14_q_m).relative() == 3.14_q_m);
|
||||
|
||||
static_assert(quantity_point<dim_length, metre, int>(km).relative() == 1000_q_m);
|
||||
static_assert(!std::is_constructible_v<quantity_point<dim_length, metre, int>,
|
||||
quantity_point<dim_length, metre, double>>); // truncating conversion
|
||||
static_assert(quantity_point<dim_length, metre, double>(quantity_point(1000.0_q_m)).relative() == 1000.0_q_m);
|
||||
static_assert(quantity_point<dim_length, metre, double>(km).relative() == 1000.0_q_m);
|
||||
static_assert(quantity_point<dim_length, metre, int>(quantity_point(1_q_km)).relative() == 1000_q_m);
|
||||
static_assert(!std::is_constructible_v<quantity_point<dim_length, metre, int>,
|
||||
quantity_point<dim_time, second, int>>); // different dimensions
|
||||
static_assert(!std::is_constructible_v<quantity_point<dim_length, kilometre, int>,
|
||||
quantity_point<dim_length, metre, int>>); // truncating conversion
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, int>(km).relative() == 1000_q_m);
|
||||
static_assert(!std::is_constructible_v<quantity_point<dynamic_origin<dim_length>, metre, int>,
|
||||
quantity_point<dynamic_origin<dim_length>, metre, double>>); // truncating conversion
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, double>(quantity_point(1000.0_q_m)).relative() == 1000.0_q_m);
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, double>(km).relative() == 1000.0_q_m);
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, int>(quantity_point(1_q_km)).relative() == 1000_q_m);
|
||||
static_assert(!std::is_constructible_v<quantity_point<dynamic_origin<dim_length>, metre, int>,
|
||||
quantity_point<dynamic_origin<dim_time>, second, int>>); // different dimensions
|
||||
static_assert(!std::is_constructible_v<quantity_point<dynamic_origin<dim_length>, kilometre, int>,
|
||||
quantity_point<dynamic_origin<dim_length>, metre, int>>); // truncating conversion
|
||||
|
||||
static_assert(!std::is_constructible_v<quantity_point<sea_level_origin, kilometre, int>,
|
||||
quantity_point<dynamic_origin<dim_length>, metre, int>>,
|
||||
"non-equivalent origins");
|
||||
static_assert(!std::is_constructible_v<quantity_point<dynamic_origin<dim_time>, second, int>, sys_seconds>,
|
||||
"non-equivalent origins, no implicit conversion from `clock_origin`");
|
||||
|
||||
// assignment operator
|
||||
|
||||
static_assert([]() { quantity_point<dim_length, metre, int> l1(1_q_m), l2{}; return l2 = l1; }().relative() == 1_q_m);
|
||||
static_assert([]() { quantity_point<dynamic_origin<dim_length>, metre, int> l1(1_q_m), l2{}; return l2 = l1; }().relative() == 1_q_m);
|
||||
|
||||
// static member functions
|
||||
|
||||
static_assert(quantity_point<dim_length, metre, int>::min().relative().number() == std::numeric_limits<int>::lowest());
|
||||
static_assert(quantity_point<dim_length, metre, int>::max().relative().number() == std::numeric_limits<int>::max());
|
||||
static_assert(quantity_point<dim_length, metre, double>::min().relative().number() ==
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, int>::min().relative().number() == std::numeric_limits<int>::lowest());
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, int>::max().relative().number() == std::numeric_limits<int>::max());
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, double>::min().relative().number() ==
|
||||
std::numeric_limits<double>::lowest());
|
||||
static_assert(quantity_point<dim_length, metre, double>::max().relative().number() ==
|
||||
static_assert(quantity_point<dynamic_origin<dim_length>, metre, double>::max().relative().number() ==
|
||||
std::numeric_limits<double>::max());
|
||||
|
||||
// unary member operators
|
||||
@ -114,19 +131,19 @@ static_assert(quantity_point<dim_length, metre, double>::max().relative().number
|
||||
static_assert([](auto v) {
|
||||
auto vv = v++;
|
||||
return std::pair(v, vv);
|
||||
}(km) == std::pair(quantity_point<dim_length, metre, int>(1001_q_m), quantity_point<dim_length, metre, int>(1000_q_m)));
|
||||
}(km) == std::pair(quantity_point<dynamic_origin<dim_length>, metre, int>(1001_q_m), quantity_point<dynamic_origin<dim_length>, metre, int>(1000_q_m)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = ++v;
|
||||
return std::pair(v, vv);
|
||||
}(km) == std::pair(quantity_point<dim_length, metre, int>(1001_q_m), quantity_point<dim_length, metre, int>(1001_q_m)));
|
||||
}(km) == std::pair(quantity_point<dynamic_origin<dim_length>, metre, int>(1001_q_m), quantity_point<dynamic_origin<dim_length>, metre, int>(1001_q_m)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = v--;
|
||||
return std::pair(v, vv);
|
||||
}(km) == std::pair(quantity_point<dim_length, metre, int>(999_q_m), quantity_point<dim_length, metre, int>(1000_q_m)));
|
||||
}(km) == std::pair(quantity_point<dynamic_origin<dim_length>, metre, int>(999_q_m), quantity_point<dynamic_origin<dim_length>, metre, int>(1000_q_m)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = --v;
|
||||
return std::pair(v, vv);
|
||||
}(km) == std::pair(quantity_point<dim_length, metre, int>(999_q_m), quantity_point<dim_length, metre, int>(999_q_m)));
|
||||
}(km) == std::pair(quantity_point<dynamic_origin<dim_length>, metre, int>(999_q_m), quantity_point<dynamic_origin<dim_length>, metre, int>(999_q_m)));
|
||||
|
||||
// compound assignment
|
||||
|
||||
@ -135,23 +152,23 @@ static_assert((quantity_point(2_q_m) -= 1_q_m).relative().number() == 1);
|
||||
|
||||
// non-member arithmetic operators
|
||||
|
||||
static_assert(compare<decltype(quantity_point<dim_length, metre, int>() + length<metre, double>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(compare<decltype(length<metre, int>() + quantity_point<dim_length, metre, double>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(compare<decltype(quantity_point<dim_length, kilometre, int>() + length<metre, double>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(compare<decltype(length<kilometre, int>() + quantity_point<dim_length, metre, double>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(compare<decltype(quantity_point<dim_length, metre, double>() - length<metre, int>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(compare<decltype(quantity_point<dim_length, kilometre, double>() - length<metre, int>()),
|
||||
quantity_point<dim_length, metre, double>>);
|
||||
static_assert(compare<decltype(quantity_point<dynamic_origin<dim_length>, metre, int>() + length<metre, double>()),
|
||||
quantity_point<dynamic_origin<dim_length>, metre, double>>);
|
||||
static_assert(compare<decltype(length<metre, int>() + quantity_point<dynamic_origin<dim_length>, metre, double>()),
|
||||
quantity_point<dynamic_origin<dim_length>, metre, double>>);
|
||||
static_assert(compare<decltype(quantity_point<dynamic_origin<dim_length>, kilometre, int>() + length<metre, double>()),
|
||||
quantity_point<dynamic_origin<dim_length>, metre, double>>);
|
||||
static_assert(compare<decltype(length<kilometre, int>() + quantity_point<dynamic_origin<dim_length>, metre, double>()),
|
||||
quantity_point<dynamic_origin<dim_length>, metre, double>>);
|
||||
static_assert(compare<decltype(quantity_point<dynamic_origin<dim_length>, metre, double>() - length<metre, int>()),
|
||||
quantity_point<dynamic_origin<dim_length>, metre, double>>);
|
||||
static_assert(compare<decltype(quantity_point<dynamic_origin<dim_length>, kilometre, double>() - length<metre, int>()),
|
||||
quantity_point<dynamic_origin<dim_length>, metre, double>>);
|
||||
static_assert(
|
||||
compare<decltype(quantity_point<dim_length, metre, double>() - quantity_point<dim_length, metre, int>()),
|
||||
compare<decltype(quantity_point<dynamic_origin<dim_length>, metre, double>() - quantity_point<dynamic_origin<dim_length>, metre, int>()),
|
||||
length<metre, double>>);
|
||||
static_assert(
|
||||
compare<decltype(quantity_point<dim_length, kilometre, double>() - quantity_point<dim_length, metre, int>()),
|
||||
compare<decltype(quantity_point<dynamic_origin<dim_length>, kilometre, double>() - quantity_point<dynamic_origin<dim_length>, metre, int>()),
|
||||
length<metre, double>>);
|
||||
|
||||
static_assert((1_q_m + km).relative().number() == 1001);
|
||||
@ -159,6 +176,13 @@ static_assert((quantity_point(1_q_m) + 1_q_km).relative().number() == 1001);
|
||||
static_assert((km - 1_q_m).relative().number() == 999);
|
||||
static_assert((quantity_point(1_q_km) - quantity_point(1_q_m)).number() == 999);
|
||||
|
||||
template<typename Int>
|
||||
concept invalid_subtraction = requires(quantity_point<dynamic_origin<dim_length>, metre, Int> lhs,
|
||||
quantity_point<sea_level_origin, metre, Int> rhs) {
|
||||
requires !requires { rhs - lhs; };
|
||||
};
|
||||
static_assert(invalid_subtraction<int>);
|
||||
|
||||
// comparators
|
||||
|
||||
static_assert(quantity_point(2_q_m) + 1_q_m == quantity_point(3_q_m));
|
||||
@ -190,6 +214,14 @@ static_assert(quantity_point(999_q_m) < quantity_point(1_q_km));
|
||||
static_assert(quantity_point(1000_q_m) >= quantity_point(1_q_km));
|
||||
static_assert(quantity_point(1000_q_m) <= quantity_point(1_q_km));
|
||||
|
||||
template<typename Int>
|
||||
concept invalid_comparisons = requires(quantity_point<dynamic_origin<dim_length>, metre, Int> lhs,
|
||||
quantity_point<sea_level_origin, metre, Int> rhs) {
|
||||
requires !requires { lhs == rhs; };
|
||||
requires !requires { lhs < rhs; };
|
||||
};
|
||||
static_assert(invalid_comparisons<int>);
|
||||
|
||||
// alias units
|
||||
|
||||
static_assert(quantity_point(2_q_l) + 2_q_ml == quantity_point(2002_q_ml));
|
||||
@ -199,19 +231,19 @@ static_assert(2_q_dm3 + quantity_point(2_q_cm3) == quantity_point(2002_q_ml));
|
||||
|
||||
// is_quantity_point
|
||||
|
||||
static_assert(QuantityPoint<quantity_point<dim_length, millimetre, int>>);
|
||||
static_assert(QuantityPoint<quantity_point<dynamic_origin<dim_length>, millimetre, int>>);
|
||||
|
||||
// common_quantity_point
|
||||
|
||||
static_assert(compare<
|
||||
common_quantity_point<quantity_point<dim_length, metre, int>, quantity_point<dim_length, kilometre, int>>,
|
||||
quantity_point<dim_length, metre, int>>);
|
||||
static_assert(compare<common_quantity_point<quantity_point<dim_length, kilometre, long long>,
|
||||
quantity_point<dim_length, metre, int>>,
|
||||
quantity_point<dim_length, metre, long long>>);
|
||||
static_assert(compare<common_quantity_point<quantity_point<dim_length, kilometre, long long>,
|
||||
quantity_point<dim_length, millimetre, double>>,
|
||||
quantity_point<dim_length, millimetre, double>>);
|
||||
common_quantity_point<quantity_point<dynamic_origin<dim_length>, metre, int>, quantity_point<dynamic_origin<dim_length>, kilometre, int>>,
|
||||
quantity_point<dynamic_origin<dim_length>, metre, int>>);
|
||||
static_assert(compare<common_quantity_point<quantity_point<dynamic_origin<dim_length>, kilometre, long long>,
|
||||
quantity_point<dynamic_origin<dim_length>, metre, int>>,
|
||||
quantity_point<dynamic_origin<dim_length>, metre, long long>>);
|
||||
static_assert(compare<common_quantity_point<quantity_point<dynamic_origin<dim_length>, kilometre, long long>,
|
||||
quantity_point<dynamic_origin<dim_length>, millimetre, double>>,
|
||||
quantity_point<dynamic_origin<dim_length>, millimetre, double>>);
|
||||
|
||||
// common_type
|
||||
|
||||
@ -224,11 +256,11 @@ static_assert(std::equality_comparable_with<decltype(quantity_point(1_q_m)), dec
|
||||
|
||||
// quantity_cast
|
||||
|
||||
static_assert(quantity_point_cast<quantity_point<dim_length, metre, int>>(quantity_point(2_q_km)).relative().number() ==
|
||||
static_assert(quantity_point_cast<quantity_point<dynamic_origin<dim_length>, metre, int>>(quantity_point(2_q_km)).relative().number() ==
|
||||
2000);
|
||||
static_assert(
|
||||
quantity_point_cast<quantity_point<dim_length, kilometre, int>>(quantity_point(2000_q_m)).relative().number() == 2);
|
||||
static_assert(quantity_point_cast<quantity_point<dim_length, metre, int>>(quantity_point(1.23_q_m)).relative().number() ==
|
||||
quantity_point_cast<quantity_point<dynamic_origin<dim_length>, kilometre, int>>(quantity_point(2000_q_m)).relative().number() == 2);
|
||||
static_assert(quantity_point_cast<quantity_point<dynamic_origin<dim_length>, metre, int>>(quantity_point(1.23_q_m)).relative().number() ==
|
||||
1);
|
||||
static_assert(quantity_point_cast<length<metre, int>>(quantity_point(2_q_km)).relative().number() == 2000);
|
||||
static_assert(quantity_point_cast<length<kilometre, int>>(quantity_point(2000_q_m)).relative().number() == 2);
|
||||
@ -238,6 +270,13 @@ static_assert(quantity_point_cast<kilometre>(quantity_point(2000_q_m)).relative(
|
||||
static_assert(quantity_point_cast<int>(quantity_point(1.23_q_m)).relative().number() == 1);
|
||||
static_assert(quantity_point_cast<dim_speed, kilometre_per_hour>(quantity_point(2000.0_q_m / 3600.0_q_s)).relative().number() == 2);
|
||||
|
||||
template<typename Int>
|
||||
concept invalid_cast = requires(Int i) {
|
||||
requires !requires { quantity_point_cast<quantity_point<dynamic_origin<dim_time>, second, Int>>(quantity_point(i * m)); };
|
||||
requires !requires { quantity_point_cast<quantity_point<dynamic_origin<dim_length>, metre, Int>>(quantity_point<sea_level_origin, metre, Int>(i * m)); };
|
||||
};
|
||||
static_assert(invalid_cast<int>);
|
||||
|
||||
// time
|
||||
|
||||
static_assert(quantity_point{1_q_h} == quantity_point{3600_q_s});
|
||||
@ -263,6 +302,6 @@ concept dimensional_analysis = requires(T t)
|
||||
pow<2>(t);
|
||||
};
|
||||
|
||||
static_assert(!dimensional_analysis<quantity_point<dim_length, metre, int>>);
|
||||
static_assert(!dimensional_analysis<quantity_point<dynamic_origin<dim_length>, metre, int>>);
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user