forked from mpusz/mp-units
Merge branch 'master' of github.com:mpusz/units
This commit is contained in:
61
src/include/units/bits/pow.h
Normal file
61
src/include/units/bits/pow.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// 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 <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
constexpr std::intmax_t ipow10(std::intmax_t exp)
|
||||
{
|
||||
assert(exp >= 0);
|
||||
if (exp == 0) return 1;
|
||||
std::intmax_t result = 1;
|
||||
while (exp > 0) {
|
||||
result *= 10;
|
||||
--exp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Rep>
|
||||
constexpr Rep fpow10(std::intmax_t exp)
|
||||
{
|
||||
if (exp == 0) return Rep(1.0);
|
||||
Rep result = Rep(1.0);
|
||||
if (exp < 0) {
|
||||
while (exp < 0) {
|
||||
result = result / Rep(10.0);
|
||||
++exp;
|
||||
}
|
||||
} else {
|
||||
while (exp > 0) {
|
||||
result = result * Rep(10.0);
|
||||
--exp;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
@@ -23,6 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/downcasting.h>
|
||||
#include <units/concepts.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/symbol_text.h>
|
||||
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <units/bits/common_quantity.h>
|
||||
#include <units/bits/dimension_op.h>
|
||||
#include <units/bits/pow.h>
|
||||
#include <units/bits/to_string.h>
|
||||
#include <units/quantity_cast.h>
|
||||
|
||||
@@ -342,9 +343,9 @@ template<typename D1, typename U1, typename Rep1, typename D2, typename U2, type
|
||||
using common_rep = decltype(lhs.count() * rhs.count());
|
||||
const ratio r = U1::ratio * U2::ratio;
|
||||
if constexpr (treat_as_floating_point<common_rep>) {
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
|
||||
} else {
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * ipow10(r.exp)) / static_cast<common_rep>(r.den);
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::ipow10(r.exp)) / static_cast<common_rep>(r.den);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,9 @@
|
||||
#include <units/customization_points.h>
|
||||
#include <units/bits/dimension_op.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <units/bits/pow.h>
|
||||
#include <units/quantity.h>
|
||||
#include <units/quantity_point.h>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -35,38 +38,6 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
constexpr std::intmax_t ipow10(std::intmax_t exp)
|
||||
{
|
||||
assert(exp >= 0);
|
||||
if (exp == 0) return 1;
|
||||
std::intmax_t result = 1;
|
||||
while (exp > 0) {
|
||||
result *= 10;
|
||||
--exp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Rep>
|
||||
constexpr Rep fpow10(std::intmax_t exp)
|
||||
{
|
||||
if (exp == 0) return Rep(1.0);
|
||||
Rep result = Rep(1.0);
|
||||
if (exp < 0) {
|
||||
while (exp < 0) {
|
||||
result = result / Rep(10.0);
|
||||
++exp;
|
||||
}
|
||||
} else {
|
||||
while (exp > 0) {
|
||||
result = result * Rep(10.0);
|
||||
--exp;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// QuantityOf
|
||||
template<typename T, typename Dim>
|
||||
concept QuantityOf = Quantity<T> && Dimension<Dim> && equivalent_dim<typename T::dimension, Dim>;
|
||||
@@ -92,13 +63,13 @@ struct quantity_cast_impl<To, CRatio, CRep, true, true, false> {
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(fpow10<CRep>(CRatio.exp))));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(detail::fpow10<CRep>(CRatio.exp))));
|
||||
} else {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(ipow10(CRatio.exp))));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(detail::ipow10(CRatio.exp))));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(ipow10(-CRatio.exp))));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(detail::ipow10(-CRatio.exp))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,21 +93,21 @@ struct quantity_cast_impl<To, CRatio, CRep, false, false, false> {
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) *
|
||||
static_cast<CRep>(fpow10<CRep>(CRatio.exp)) *
|
||||
static_cast<CRep>(detail::fpow10<CRep>(CRatio.exp)) *
|
||||
(static_cast<CRep>(CRatio.num) /
|
||||
static_cast<CRep>(CRatio.den))));
|
||||
} else {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) *
|
||||
static_cast<CRep>(CRatio.num) *
|
||||
static_cast<CRep>(ipow10(CRatio.exp)) /
|
||||
static_cast<CRep>(detail::ipow10(CRatio.exp)) /
|
||||
static_cast<CRep>(CRatio.den)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) *
|
||||
static_cast<CRep>(CRatio.num) /
|
||||
(static_cast<CRep>(CRatio.den) *
|
||||
static_cast<CRep>(ipow10(-CRatio.exp)))));
|
||||
static_cast<CRep>(detail::ipow10(-CRatio.exp)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,13 +128,13 @@ struct quantity_cast_impl<To, CRatio, CRep, true, false, false> {
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(fpow10<CRep>(CRatio.exp)) * (CRep{1} / static_cast<CRep>(CRatio.den))));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(detail::fpow10<CRep>(CRatio.exp)) * (CRep{1} / static_cast<CRep>(CRatio.den))));
|
||||
} else {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(ipow10(CRatio.exp)) / static_cast<CRep>(CRatio.den)));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(detail::ipow10(CRatio.exp)) / static_cast<CRep>(CRatio.den)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) / (static_cast<CRep>(ipow10(-CRatio.exp)) * static_cast<CRep>(CRatio.den))));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) / (static_cast<CRep>(detail::ipow10(-CRatio.exp)) * static_cast<CRep>(CRatio.den))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,13 +155,13 @@ struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(fpow10<CRep>(CRatio.exp))));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(detail::fpow10<CRep>(CRatio.exp))));
|
||||
} else {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(ipow10(CRatio.exp))));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(detail::ipow10(CRatio.exp))));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) / static_cast<CRep>(ipow10(-CRatio.exp))));
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) / static_cast<CRep>(detail::ipow10(-CRatio.exp))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,13 +173,13 @@ struct quantity_cast_impl<To, CRatio, CRep, true, true, false> {
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * fpow10<CRep>(CRatio.exp)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * detail::fpow10<CRep>(CRatio.exp)));
|
||||
} else {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * ipow10(CRatio.exp)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * detail::ipow10(CRatio.exp)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() / ipow10(-CRatio.exp)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() / detail::ipow10(-CRatio.exp)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,13 +200,13 @@ struct quantity_cast_impl<To, CRatio, CRep, false, false, false> {
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * fpow10<CRep>(CRatio.exp) * (CRatio.num / CRatio.den)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * detail::fpow10<CRep>(CRatio.exp) * (CRatio.num / CRatio.den)));
|
||||
} else {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * ipow10(CRatio.exp) / CRatio.den));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * detail::ipow10(CRatio.exp) / CRatio.den));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count()) * CRatio.num / (CRatio.den * ipow10(-CRatio.exp)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count()) * CRatio.num / (CRatio.den * detail::ipow10(-CRatio.exp)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,13 +227,13 @@ struct quantity_cast_impl<To, CRatio, CRep, true, false, false> {
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * fpow10<CRep>(CRatio.exp) / CRatio.den));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * detail::fpow10<CRep>(CRatio.exp) / CRatio.den));
|
||||
} else {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * ipow10(CRatio.exp) / CRatio.den));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * detail::ipow10(CRatio.exp) / CRatio.den));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() / (ipow10(-CRatio.exp) * CRatio.den)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() / (detail::ipow10(-CRatio.exp) * CRatio.den)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,13 +254,13 @@ struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * fpow10<CRep>(CRatio.exp)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * detail::fpow10<CRep>(CRatio.exp)));
|
||||
} else {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * ipow10(CRatio.exp)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * detail::ipow10(CRatio.exp)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num / ipow10(-CRatio.exp)));
|
||||
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num / detail::ipow10(-CRatio.exp)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "units/physical/si/frequency.h"
|
||||
#include "units/physical/si/speed.h"
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
using namespace units;
|
||||
@@ -65,7 +66,7 @@ template<typename T>
|
||||
struct expl_constructible : scalar_ops<expl_constructible<T>> {
|
||||
T value_{};
|
||||
expl_constructible() = default;
|
||||
constexpr expl_constructible(T v) : value_(std::move(v)) {}
|
||||
constexpr explicit expl_constructible(T v) : value_(std::move(v)) {}
|
||||
// no conversion to fundamental arithmetic types
|
||||
};
|
||||
|
||||
@@ -172,60 +173,60 @@ using namespace units::physical::si;
|
||||
// Quantity from Scalar
|
||||
// int <- int
|
||||
static_assert(length<metre, int>(expl_impl<int>(1)).count() == 1);
|
||||
// static_assert(length<metre, int>(impl_expl<int>(1)).count() == 1); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, int>, impl_expl<int>>);
|
||||
static_assert(length<metre, int>(int(impl_expl<int>(1))).count() == 1);
|
||||
// static_assert(length<metre, expl_impl<int>>(1).count() == expl_impl<int>{1}); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, expl_impl<int>>, int>);
|
||||
static_assert(length<metre, expl_impl<int>>(expl_impl<int>(1)).count() == expl_impl<int>{1});
|
||||
static_assert(length<metre, impl_expl<int>>(1).count() == impl_expl<int>{1});
|
||||
|
||||
// double <- double
|
||||
static_assert(length<metre, double>(expl_impl<double>(1.0)).count() == 1.0);
|
||||
// static_assert(length<metre, double>(impl_expl<double>(1.0)).count() == 1.0); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, double>, impl_expl<double>>);
|
||||
static_assert(length<metre, double>(double(impl_expl<double>(1.0))).count() == 1.0);
|
||||
// static_assert(length<metre, expl_impl<double>>(1.0).count() == expl_impl<double>{1.0}); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, expl_impl<double>>, double>);
|
||||
static_assert(length<metre, expl_impl<double>>(expl_impl<double>(1.0)).count() == expl_impl<double>{1.0});
|
||||
static_assert(length<metre, impl_expl<double>>(1.0).count() == impl_expl<double>{1.0});
|
||||
|
||||
// double <- int
|
||||
static_assert(length<metre, double>(expl_impl<int>(1)).count() == 1.0);
|
||||
// static_assert(length<metre, double>(impl_expl<int>(1)).count() == 1.0); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, double>, impl_expl<int>>);
|
||||
static_assert(length<metre, double>(int(impl_expl<int>(1))).count() == 1.0);
|
||||
// static_assert(length<metre, expl_impl<double>>(1).count() == expl_impl<double>{1}); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, expl_impl<double>>, int>);
|
||||
static_assert(length<metre, expl_impl<double>>(expl_impl<double>(1)).count() == expl_impl<double>{1});
|
||||
static_assert(length<metre, impl_expl<double>>(1).count() == impl_expl<double>{1.0});
|
||||
|
||||
// int <- double
|
||||
// static_assert(length<metre, int>(expl_impl<double>(1.0)).count() == 1); // should not compile (truncating conversion)
|
||||
// static_assert(length<metre, impl_expl<int>>(1.0).count() == impl_expl<int>{1}); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<metre, int>, expl_impl<double>>);
|
||||
static_assert(!std::is_constructible_v<length<metre, impl_expl<int>>, double>);
|
||||
|
||||
// Quantity from other Quantity with different Rep
|
||||
// int <- int
|
||||
static_assert(length<metre, int>(length<metre, expl_impl<int>>(expl_impl<int>(1))).count() == 1);
|
||||
// static_assert(length<metre, int>(length<metre, impl_expl<int>>(1)).count() == 1); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, int>, length<metre, impl_expl<int>>>);
|
||||
static_assert(length<metre, int>(quantity_cast<int>(length<metre, impl_expl<int>>(1))).count() == 1);
|
||||
// static_assert(length<metre, expl_impl<int>>(length<metre, int>(1)).count() == expl_impl<int>{1}); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, expl_impl<int>>, length<metre, int>>);
|
||||
static_assert(length<metre, expl_impl<int>>(quantity_cast<expl_impl<int>>(length<metre, int>(1))).count() == expl_impl<int>{1});
|
||||
static_assert(length<metre, impl_expl<int>>(length<metre, int>(1)).count() == impl_expl<int>{1});
|
||||
|
||||
// double <- double
|
||||
static_assert(length<metre, double>(length<metre, expl_impl<double>>(expl_impl<double>(1.0))).count() == 1.0);
|
||||
// static_assert(length<metre, double>(length<metre, impl_expl<double>>(1.0)).count() == 1.0); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, double>, length<metre, impl_expl<double>>>);
|
||||
static_assert(length<metre, double>(quantity_cast<double>(length<metre, impl_expl<double>>(1.0))).count() == 1.0);
|
||||
// static_assert(length<metre, expl_impl<double>>(length<metre>(1.0).count() == expl_impl<double>{1.0}); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, expl_impl<double>>, length<metre, double>>);
|
||||
static_assert(length<metre, expl_impl<double>>(quantity_cast<expl_impl<double>>(length<metre>(1.0))).count() == expl_impl<double>{1.0});
|
||||
static_assert(length<metre, impl_expl<double>>(length<metre>(1.0)).count() == impl_expl<double>{1.0});
|
||||
|
||||
// double <- int
|
||||
static_assert(length<metre, double>(length<metre, expl_impl<int>>(expl_impl<int>(1))).count() == 1.0);
|
||||
// static_assert(length<metre, double>(length<metre, impl_expl<int>>(1)).count() == 1.0); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, double>, length<metre, impl_expl<int>>>);
|
||||
static_assert(length<metre, double>(quantity_cast<int>(length<metre, impl_expl<int>>(1))).count() == 1.0);
|
||||
// static_assert(length<metre, expl_impl<double>>(length<metre, int>(1)).count() == expl_impl<double>{1}); // should not compile (not convertible)
|
||||
static_assert(!std::is_constructible_v<length<metre, expl_impl<double>>, length<metre, int>>);
|
||||
static_assert(length<metre, expl_impl<double>>(quantity_cast<expl_impl<double>>(length<metre, int>(1))).count() == expl_impl<double>{1});
|
||||
static_assert(length<metre, impl_expl<double>>(length<metre, int>(1)).count() == impl_expl<double>{1.0});
|
||||
|
||||
// int <- double
|
||||
// static_assert(length<metre, int>(length<metre, expl_impl<double>>(1.0)).count() == 1); // should not compile (truncating conversion)
|
||||
// static_assert(length<metre, impl_expl<int>>(length<metre, double>(1.0)).count() == impl_expl<int>{1}); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<metre, int>, length<metre, expl_impl<double>>>);
|
||||
static_assert(!std::is_constructible_v<length<metre, impl_expl<int>>, length<metre, double>>);
|
||||
|
||||
// unit conversions
|
||||
|
||||
@@ -236,43 +237,43 @@ static_assert(length<metre, impl_expl<int>>(length<kilometre, impl_expl<int>>(1)
|
||||
static_assert(length<metre, expl_impl<int>>(length<kilometre, expl_impl<int>>(expl_impl<int>(1))).count() == expl_impl<int>(1000));
|
||||
static_assert(length<metre, expl_expl<int>>(length<kilometre, expl_expl<int>>(expl_expl<int>(1))).count() == expl_expl<int>(1000));
|
||||
|
||||
// static_assert(length<kilometre, impl<int>>(length<metre, impl<int>>(2000)).count() == impl<int>(2)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<kilometre, impl<int>>, length<metre, impl<int>>>);
|
||||
static_assert(length<kilometre, impl<int>>(quantity_cast<kilometre>(length<metre, impl<int>>(2000))).count() == impl<int>(2));
|
||||
// static_assert(length<kilometre, expl<int>>(length<metre, expl<int>>(expl<int>(2000))).count() == expl<int>(2)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<kilometre, expl<int>>, length<metre, expl<int>>>);
|
||||
static_assert(length<kilometre, expl<int>>(quantity_cast<kilometre>(length<metre, expl<int>>(expl<int>(2000)))).count() == expl<int>(2));
|
||||
// static_assert(length<kilometre, impl_impl<int>>(length<metre, impl_impl<int>>(2000)).count() == impl_impl<int>(2)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<kilometre, impl_impl<int>>, length<metre, impl_impl<int>>>);
|
||||
static_assert(length<kilometre, impl_impl<int>>(quantity_cast<kilometre>(length<metre, impl_impl<int>>(2000))).count() == impl_impl<int>(2));
|
||||
// static_assert(length<kilometre, impl_expl<int>>(length<metre, impl_expl<int>>(2000)).count() == impl_expl<int>(2)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<kilometre, impl_expl<int>>, length<metre, impl_expl<int>>>);
|
||||
static_assert(length<kilometre, impl_expl<int>>(quantity_cast<kilometre>(length<metre, impl_expl<int>>(2000))).count() == impl_expl<int>(2));
|
||||
// static_assert(length<kilometre, expl_impl<int>>(length<metre, expl_impl<int>>(expl_impl<int>(2000))).count() == expl_impl<int>(2)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<kilometre, expl_impl<int>>, length<metre, expl_impl<int>>>);
|
||||
static_assert(length<kilometre, expl_impl<int>>(quantity_cast<kilometre>(length<metre, expl_impl<int>>(expl_impl<int>(2000)))).count() == expl_impl<int>(2));
|
||||
// static_assert(length<kilometre, expl_expl<int>>(length<metre, expl_expl<int>>(expl_expl<int>(2000))).count() == expl_expl<int>(2)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<kilometre, expl_expl<int>>, length<metre, expl_expl<int>>>);
|
||||
static_assert(length<kilometre, expl_expl<int>>(quantity_cast<kilometre>(length<metre, expl_expl<int>>(expl_expl<int>(2000)))).count() == expl_expl<int>(2));
|
||||
|
||||
// static_assert(speed<metre_per_second, impl<int>>(speed<kilometre_per_hour, impl<int>>(72)).count() == impl<int>(20)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<metre_per_second, impl<int>>, speed<kilometre_per_hour, impl<int>>>);
|
||||
static_assert(speed<metre_per_second, impl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, impl<int>>(72))).count() == impl<int>(20));
|
||||
// static_assert(speed<metre_per_second, expl<int>>(speed<kilometre_per_hour, expl<int>>(expl(72))).count() == expl<int>(20)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<metre_per_second, expl<int>>, speed<kilometre_per_hour, expl<int>>>);
|
||||
static_assert(speed<metre_per_second, expl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, expl<int>>(expl<int>(72)))).count() == expl<int>(20));
|
||||
// static_assert(speed<metre_per_second, impl_impl<int>>(speed<kilometre_per_hour, impl_impl<int>>(72)).count() == impl_impl<int>(20)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<metre_per_second, impl_impl<int>>, speed<kilometre_per_hour, impl_impl<int>>>);
|
||||
static_assert(speed<metre_per_second, impl_impl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, impl_impl<int>>(72))).count() == impl_impl<int>(20));
|
||||
// static_assert(speed<metre_per_second, impl_expl<int>>(speed<kilometre_per_hour, impl_expl<int>>(72)).count() == impl_expl<int>(20)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<metre_per_second, impl_expl<int>>, speed<kilometre_per_hour, impl_expl<int>>>);
|
||||
static_assert(speed<metre_per_second, impl_expl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, impl_expl<int>>(72))).count() == impl_expl<int>(20));
|
||||
// static_assert(speed<metre_per_second, expl_impl<int>>(speed<kilometre_per_hour, expl_impl<int>>(expl_impl(72))).count() == expl_impl<int>(20)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<metre_per_second, expl_impl<int>>, speed<kilometre_per_hour, expl_impl<int>>>);
|
||||
static_assert(speed<metre_per_second, expl_impl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, expl_impl<int>>(expl_impl<int>(72)))).count() == expl_impl<int>(20));
|
||||
// static_assert(speed<metre_per_second, expl_expl<int>>(speed<kilometre_per_hour, expl_expl<int>>(expl_expl(72))).count() == expl_expl<int>(20)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<metre_per_second, expl_expl<int>>, speed<kilometre_per_hour, expl_expl<int>>>);
|
||||
static_assert(speed<metre_per_second, expl_expl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, expl_expl<int>>(expl_expl<int>(72)))).count() == expl_expl<int>(20));
|
||||
|
||||
// static_assert(speed<kilometre_per_hour, impl<int>>(speed<metre_per_second, impl<int>>(20)).count() == impl<int>(72)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, impl<int>>, speed<metre_per_second, impl<int>>>);
|
||||
static_assert(speed<kilometre_per_hour, impl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, impl<int>>(20))).count() == impl<int>(72));
|
||||
// static_assert(speed<kilometre_per_hour, expl<int>>(speed<metre_per_second, expl<int>>(expl<int>(20))).count() == expl<int>(72)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, expl<int>>, speed<metre_per_second, expl<int>>>);
|
||||
static_assert(speed<kilometre_per_hour, expl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, expl<int>>(expl<int>(20)))).count() == expl<int>(72));
|
||||
// static_assert(speed<kilometre_per_hour, impl_impl<int>>(speed<metre_per_second, impl_impl<int>>(20)).count() == impl_impl<int>(72)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, impl_impl<int>>, speed<metre_per_second, impl_impl<int>>>);
|
||||
static_assert(speed<kilometre_per_hour, impl_impl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, impl_impl<int>>(20))).count() == impl_impl<int>(72));
|
||||
// static_assert(speed<kilometre_per_hour, impl_expl<int>>(speed<metre_per_second, impl_expl<int>>(20)).count() == impl_expl<int>(72)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, impl_expl<int>>, speed<metre_per_second, impl_expl<int>>>);
|
||||
static_assert(speed<kilometre_per_hour, impl_expl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, impl_expl<int>>(20))).count() == impl_expl<int>(72));
|
||||
// static_assert(speed<kilometre_per_hour, expl_impl<int>>(speed<metre_per_second, expl_impl<int>>(expl_impl<int>(20))).count() == expl_impl<int>(72)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, expl_impl<int>>, speed<metre_per_second, expl_impl<int>>>);
|
||||
static_assert(speed<kilometre_per_hour, expl_impl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, expl_impl<int>>(expl_impl<int>(20)))).count() == expl_impl<int>(72));
|
||||
// static_assert(speed<kilometre_per_hour, expl_expl<int>>(speed<metre_per_second, expl_expl<int>>(expl_expl<int>(20))).count() == expl_expl<int>(72)); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, expl_expl<int>>, speed<metre_per_second, expl_expl<int>>>);
|
||||
static_assert(speed<kilometre_per_hour, expl_expl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, expl_expl<int>>(expl_expl<int>(20)))).count() == expl_expl<int>(72));
|
||||
|
||||
} // namespace
|
||||
|
@@ -47,7 +47,7 @@ concept invalid_types = requires
|
||||
!requires { typename quantity<metre, DimLength, double>; }; // reordered arguments
|
||||
};
|
||||
|
||||
static_assert(invalid_types<physical::si::dim_length>);
|
||||
static_assert(invalid_types<dim_length>);
|
||||
|
||||
// member types
|
||||
|
||||
@@ -226,12 +226,16 @@ static_assert(quantity_point_cast<int>(quantity_point(1.23q_m)).relative().count
|
||||
|
||||
// time
|
||||
|
||||
#if COMP_MSVC || COMP_GCC >= 10
|
||||
static_assert(!std::equality_comparable_with<quantity_point<dim_time, second, int>,
|
||||
quantity_point<dim_length, metre, int>>); // different dimensions
|
||||
#endif
|
||||
static_assert(quantity_point{1q_h} == quantity_point{3600q_s});
|
||||
|
||||
template<typename Metre>
|
||||
constexpr bool no_crossdimensional_equality = !requires
|
||||
{
|
||||
quantity_point(1q_s) == quantity_point(length<Metre, int>(1));
|
||||
};
|
||||
|
||||
static_assert(no_crossdimensional_equality<metre>);
|
||||
|
||||
// length
|
||||
|
||||
static_assert(quantity_point(1q_km) == quantity_point(1000q_m));
|
||||
|
@@ -36,10 +36,15 @@ using namespace units::physical::si;
|
||||
|
||||
// class invariants
|
||||
|
||||
// constexpr quantity<si::dim_length, second, int> error(0); // should not compile (unit of a different dimension)
|
||||
// constexpr quantity<si::dim_length, metre, quantity<si::dim_length, metre, int>> error(0); // should not compile (quantity used as Rep)
|
||||
// constexpr quantity<metre, si::dim_length, double> error(0); // should not compile (reordered arguments)
|
||||
// constexpr quantity<si::dim_length, scaled_unit<ratio(-1, 1), metre>, int> error(0); // should not compile (negative unit ratio)
|
||||
template<typename DimLength>
|
||||
concept invalid_types = requires
|
||||
{
|
||||
!requires { typename quantity<DimLength, second, int>; }; // unit of a different dimension
|
||||
!requires { typename quantity<DimLength, metre, quantity<DimLength, metre, int>>; }; // quantity used as Rep
|
||||
!requires { typename quantity<metre, DimLength, double>; }; // reordered arguments
|
||||
};
|
||||
|
||||
static_assert(invalid_types<dim_length>);
|
||||
|
||||
// member types
|
||||
|
||||
@@ -56,18 +61,21 @@ static_assert(km.count() == 1000);
|
||||
static_assert(length<metre, int>(km).count() == km.count());
|
||||
|
||||
static_assert(length<metre, int>(1).count() == 1);
|
||||
// static_assert(length<metre, int>(1.0).count() == 1); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<metre, int>, double>); // truncating conversion
|
||||
static_assert(length<metre, double>(1.0).count() == 1.0);
|
||||
static_assert(length<metre, double>(1).count() == 1.0);
|
||||
static_assert(length<metre, double>(3.14).count() == 3.14);
|
||||
|
||||
static_assert(length<metre, int>(km).count() == 1000);
|
||||
// static_assert(length<metre, int>(length<metre, double>(3.14)).count() == 3); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<metre, int>,
|
||||
length<metre, double>>); // truncating conversion
|
||||
static_assert(length<metre, double>(1000.0q_m).count() == 1000.0);
|
||||
static_assert(length<metre, double>(km).count() == 1000.0);
|
||||
static_assert(length<metre, int>(1q_km).count() == 1000);
|
||||
// static_assert(length<metre, int>(1q_s).count() == 1); // should not compile (different dimensions)
|
||||
//static_assert(length<kilometre, int>(1010q_m).count() == 1); // should not compile (truncating conversion)
|
||||
static_assert(!std::is_constructible_v<length<metre, int>,
|
||||
physical::si::time<second, int>>); // different dimensions
|
||||
static_assert(!std::is_constructible_v<length<kilometre, int>,
|
||||
length<metre, int>>); // truncating conversion
|
||||
|
||||
// assignment operator
|
||||
|
||||
@@ -89,24 +97,22 @@ static_assert((-km).count() == -1000);
|
||||
static_assert((+(-km)).count() == -1000);
|
||||
static_assert((-(-km)).count() == 1000);
|
||||
|
||||
// binary member operators
|
||||
|
||||
static_assert([](auto v) {
|
||||
auto vv = v++;
|
||||
return std::make_pair(v, vv);
|
||||
}(km) == std::make_pair(length<metre, int>(1001), length<metre, int>(1000)));
|
||||
return std::pair(v, vv);
|
||||
}(km) == std::pair(length<metre, int>(1001), length<metre, int>(1000)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = ++v;
|
||||
return std::make_pair(v, vv);
|
||||
}(km) == std::make_pair(length<metre, int>(1001), length<metre, int>(1001)));
|
||||
return std::pair(v, vv);
|
||||
}(km) == std::pair(length<metre, int>(1001), length<metre, int>(1001)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = v--;
|
||||
return std::make_pair(v, vv);
|
||||
}(km) == std::make_pair(length<metre, int>(999), length<metre, int>(1000)));
|
||||
return std::pair(v, vv);
|
||||
}(km) == std::pair(length<metre, int>(999), length<metre, int>(1000)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = --v;
|
||||
return std::make_pair(v, vv);
|
||||
}(km) == std::make_pair(length<metre, int>(999), length<metre, int>(999)));
|
||||
return std::pair(v, vv);
|
||||
}(km) == std::pair(length<metre, int>(999), length<metre, int>(999)));
|
||||
|
||||
// compound assignment
|
||||
|
||||
@@ -116,22 +122,29 @@ static_assert((1q_m *= 2).count() == 2);
|
||||
static_assert((2q_m /= 2).count() == 1);
|
||||
static_assert((7q_m %= 2).count() == 1);
|
||||
static_assert((7q_m %= 2q_m).count() == 1);
|
||||
// static_assert((7.m %= 2.).count() == 1); // should not compile (operation not allowed for floating-point types)
|
||||
// static_assert((7.m %= 2).count() == 1); // should not compile (operation not allowed for floating-point types)
|
||||
// static_assert((7q_m %= 2.).count() == 1); // should not compile (operation not allowed for floating-point types)
|
||||
static_assert((7q_m %= 2q_m).count() == 1);
|
||||
// static_assert((7.m %= 2.m).count() == 1); // should not compile (operation not allowed for floating-point types)
|
||||
// static_assert((7.m %= 2q_m).count() == 1); // should not compile (operation not allowed for floating-point types)
|
||||
// static_assert((7q_m %= 2.m).count() == 1); // should not compile (operation not allowed for floating-point types)
|
||||
|
||||
// static_assert(2q_m += 3.5q_m); // should not compile
|
||||
static_assert((2.5q_m += 3q_m).count() == 5.5);
|
||||
static_assert((2.5q_m += 3.5q_m).count() == 6);
|
||||
|
||||
// static_assert(2q_m *= 3.5); // should not compile
|
||||
static_assert((2.5q_m *= 3).count() == 7.5);
|
||||
static_assert((2.5q_m *= 3.5).count() == 8.75);
|
||||
|
||||
// operations not allowed for the respective quantities
|
||||
template<typename Metre>
|
||||
concept invalid_compound_assignments = requires()
|
||||
{
|
||||
!requires(length<Metre, double> l) { l %= 2.; };
|
||||
!requires(length<Metre, double> l) { l %= 2; };
|
||||
!requires(length<Metre, int> l) { l %= 2.; };
|
||||
!requires(length<Metre, double> l) { l %= 2.q_m; };
|
||||
!requires(length<Metre, double> l) { l %= 2q_m; };
|
||||
!requires(length<Metre, int> l) { l %= 2.q_m; };
|
||||
!requires(length<Metre, int> l) { l += 3.5q_m; };
|
||||
!requires(length<Metre, int> l) { l *= 3.5q_m; };
|
||||
};
|
||||
|
||||
static_assert(invalid_compound_assignments<metre>);
|
||||
|
||||
// non-member arithmetic operators
|
||||
|
||||
static_assert(is_same_v<decltype(length<metre, int>() + length<metre, double>()), length<metre, double>>);
|
||||
@@ -253,9 +266,13 @@ static_assert(quantity_cast<int>(1.23q_m).count() == 1);
|
||||
|
||||
// time
|
||||
|
||||
// static_assert(1q_s == 1q_m); // should not compile (different dimensions)
|
||||
static_assert(1q_h == 3600q_s);
|
||||
|
||||
template<typename Metre>
|
||||
constexpr bool no_crossdimensional_equality = !requires { 1q_s == length<Metre, int>(1); };
|
||||
|
||||
static_assert(no_crossdimensional_equality<metre>);
|
||||
|
||||
// length
|
||||
|
||||
static_assert(1q_km == 1000q_m);
|
||||
|
@@ -29,7 +29,6 @@ using namespace units;
|
||||
static_assert(ratio(2, 4) == ratio(1, 2));
|
||||
|
||||
// basic exponents tests
|
||||
// note use of ::type is required because template params are changed while stamping out template
|
||||
static_assert(ratio(2, 40, 1) == ratio(1, 20, 1));
|
||||
static_assert(ratio(20, 4, -1) == ratio(10, 2, -1));
|
||||
static_assert(ratio(200, 5) == ratio(20'000, 50, -1));
|
||||
@@ -89,4 +88,10 @@ static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10));
|
||||
static_assert(common_ratio(ratio(1), ratio(1, 1, 3)) == ratio(1));
|
||||
static_assert(common_ratio(ratio(10, 1, -1), ratio(1, 1, -3)) == ratio(1, 1, -3));
|
||||
|
||||
// nonzero denominator
|
||||
template <auto> struct require_constant; // [range.split.view]
|
||||
template <auto F> concept constant = requires { typename require_constant<F()>; };
|
||||
|
||||
static_assert(!constant<[] { ratio(1, 0); }>);
|
||||
|
||||
} // namespace
|
||||
|
@@ -40,7 +40,9 @@ struct hour : named_scaled_unit<hour, "h", no_prefix, ratio(36, 1, 2), second> {
|
||||
struct dim_time : base_dimension<"time", second> {};
|
||||
|
||||
struct kelvin : named_unit<kelvin, "K", no_prefix> {};
|
||||
// struct kilokelvin : prefixed_unit<kilokelvin, si::kilo, kelvin> {}; // should not compile (prefix not allowed for this reference unit)
|
||||
#if COMP_MSVC || COMP_GCC >= 10
|
||||
static_assert([]<Prefix P>(P) { return !requires { typename prefixed_unit<struct kilokelvin, P, kelvin>; }; }(si::kilo{})); // negative unit ratio
|
||||
#endif
|
||||
|
||||
struct metre_per_second : unit<metre_per_second> {};
|
||||
struct dim_speed : derived_dimension<dim_speed, metre_per_second, units::exp<dim_length, 1>, units::exp<dim_time, -1>> {};
|
||||
@@ -51,6 +53,9 @@ static_assert(is_same_v<downcast<scaled_unit<ratio(1, 1, -2), metre>>, centimetr
|
||||
static_assert(is_same_v<downcast<scaled_unit<ratio(yard::ratio.num, yard::ratio.den, yard::ratio.exp), metre>>, yard>);
|
||||
static_assert(is_same_v<downcast<scaled_unit<yard::ratio * ratio(1, 3), metre>>, foot>);
|
||||
static_assert(is_same_v<downcast<scaled_unit<kilometre::ratio / hour::ratio, metre_per_second>>, kilometre_per_hour>);
|
||||
#if COMP_MSVC || COMP_GCC >= 10
|
||||
static_assert([]<ratio R>() { return !requires { typename scaled_unit<R, metre>; }; }.template operator()<ratio(-1, 1)>()); // negative unit ratio
|
||||
#endif
|
||||
|
||||
static_assert(centimetre::symbol == "cm");
|
||||
static_assert(kilometre::symbol == "km");
|
||||
|
Reference in New Issue
Block a user