[wpimath] Make various classes constexpr (#7237)

This commit is contained in:
Tyler Veness
2024-10-22 06:58:06 -07:00
committed by GitHub
parent 0c824bd447
commit 05c7fd929b
21 changed files with 235 additions and 307 deletions

View File

@@ -30,8 +30,12 @@ namespace frc {
* @return The robot's field-relative pose.
*/
WPILIB_DLLEXPORT
frc::Pose3d ObjectToRobotPose(const frc::Pose3d& objectInField,
const frc::Transform3d& cameraToObject,
const frc::Transform3d& robotToCamera);
constexpr frc::Pose3d ObjectToRobotPose(const frc::Pose3d& objectInField,
const frc::Transform3d& cameraToObject,
const frc::Transform3d& robotToCamera) {
const auto objectToCamera = cameraToObject.Inverse();
const auto cameraToRobot = robotToCamera.Inverse();
return objectInField + objectToCamera + cameraToRobot;
}
} // namespace frc

View File

@@ -7,6 +7,7 @@
#include <numbers>
#include <type_traits>
#include <gcem.hpp>
#include <wpi/SymbolExports.h>
#include "units/angle.h"
@@ -28,10 +29,10 @@ namespace frc {
*/
template <typename T>
requires std::is_arithmetic_v<T> || units::traits::is_unit_t_v<T>
T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
constexpr T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
T magnitude;
if constexpr (std::is_arithmetic_v<T>) {
magnitude = std::abs(value);
magnitude = gcem::abs(value);
} else {
magnitude = units::math::abs(value);
}

View File

@@ -209,7 +209,11 @@ Vectord<N> MakeWhiteNoiseVector(const std::array<double, N>& stdDevs) {
* @return The vector.
*/
WPILIB_DLLEXPORT
Eigen::Vector3d PoseTo3dVector(const Pose2d& pose);
constexpr Eigen::Vector3d PoseTo3dVector(const Pose2d& pose) {
return Eigen::Vector3d{{pose.Translation().X().value(),
pose.Translation().Y().value(),
pose.Rotation().Radians().value()}};
}
/**
* Converts a Pose2d into a vector of [x, y, std::cos(theta), std::sin(theta)].
@@ -219,7 +223,11 @@ Eigen::Vector3d PoseTo3dVector(const Pose2d& pose);
* @return The vector.
*/
WPILIB_DLLEXPORT
Eigen::Vector4d PoseTo4dVector(const Pose2d& pose);
constexpr Eigen::Vector4d PoseTo4dVector(const Pose2d& pose) {
return Eigen::Vector4d{{pose.Translation().X().value(),
pose.Translation().Y().value(), pose.Rotation().Cos(),
pose.Rotation().Sin()}};
}
/**
* Returns true if (A, B) is a stabilizable pair.
@@ -306,7 +314,10 @@ bool IsDetectable(const Matrixd<States, States>& A,
* @return The vector.
*/
WPILIB_DLLEXPORT
Eigen::Vector3d PoseToVector(const Pose2d& pose);
constexpr Eigen::Vector3d PoseToVector(const Pose2d& pose) {
return Eigen::Vector3d{
{pose.X().value(), pose.Y().value(), pose.Rotation().Radians().value()}};
}
/**
* Clamps input vector between system's minimum and maximum allowable input.
@@ -318,12 +329,12 @@ Eigen::Vector3d PoseToVector(const Pose2d& pose);
* @return Clamped input vector.
*/
template <int Inputs>
Vectord<Inputs> ClampInputMaxMagnitude(const Vectord<Inputs>& u,
const Vectord<Inputs>& umin,
const Vectord<Inputs>& umax) {
constexpr Vectord<Inputs> ClampInputMaxMagnitude(const Vectord<Inputs>& u,
const Vectord<Inputs>& umin,
const Vectord<Inputs>& umax) {
Vectord<Inputs> result;
for (int i = 0; i < Inputs; ++i) {
result(i) = std::clamp(u(i), umin(i), umax(i));
result.coeffRef(i) = std::clamp(u.coeff(i), umin.coeff(i), umax.coeff(i));
}
return result;
}

View File

@@ -5,13 +5,14 @@
#pragma once
#include <algorithm>
#include <cmath>
#include <initializer_list>
#include <span>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include <Eigen/QR>
#include <gcem.hpp>
#include <wpi/array.h>
#include <wpi/circular_buffer.h>
@@ -80,7 +81,8 @@ class LinearFilter {
* @param ffGains The "feedforward" or FIR gains.
* @param fbGains The "feedback" or IIR gains.
*/
LinearFilter(std::span<const double> ffGains, std::span<const double> fbGains)
constexpr LinearFilter(std::span<const double> ffGains,
std::span<const double> fbGains)
: m_inputs(ffGains.size()),
m_outputs(fbGains.size()),
m_inputGains(ffGains.begin(), ffGains.end()),
@@ -92,10 +94,11 @@ class LinearFilter {
m_outputs.emplace_front(0.0);
}
static int instances = 0;
instances++;
wpi::math::MathSharedStore::ReportUsage(
wpi::math::MathUsageId::kFilter_Linear, instances);
if (!std::is_constant_evaluated()) {
++instances;
wpi::math::MathSharedStore::ReportUsage(
wpi::math::MathUsageId::kFilter_Linear, instances);
}
}
/**
@@ -104,8 +107,8 @@ class LinearFilter {
* @param ffGains The "feedforward" or FIR gains.
* @param fbGains The "feedback" or IIR gains.
*/
LinearFilter(std::initializer_list<double> ffGains,
std::initializer_list<double> fbGains)
constexpr LinearFilter(std::initializer_list<double> ffGains,
std::initializer_list<double> fbGains)
: LinearFilter({ffGains.begin(), ffGains.end()},
{fbGains.begin(), fbGains.end()}) {}
@@ -124,9 +127,9 @@ class LinearFilter {
* @param period The period in seconds between samples taken by the
* user.
*/
static LinearFilter<T> SinglePoleIIR(double timeConstant,
units::second_t period) {
double gain = std::exp(-period.value() / timeConstant);
static constexpr LinearFilter<T> SinglePoleIIR(double timeConstant,
units::second_t period) {
double gain = gcem::exp(-period.value() / timeConstant);
return LinearFilter({1.0 - gain}, {-gain});
}
@@ -144,8 +147,9 @@ class LinearFilter {
* @param period The period in seconds between samples taken by the
* user.
*/
static LinearFilter<T> HighPass(double timeConstant, units::second_t period) {
double gain = std::exp(-period.value() / timeConstant);
static constexpr LinearFilter<T> HighPass(double timeConstant,
units::second_t period) {
double gain = gcem::exp(-period.value() / timeConstant);
return LinearFilter({gain, -gain}, {-gain});
}
@@ -213,7 +217,7 @@ class LinearFilter {
Matrixd<Samples, Samples> S;
for (int row = 0; row < Samples; ++row) {
for (int col = 0; col < Samples; ++col) {
S(row, col) = std::pow(stencil[col], row);
S(row, col) = gcem::pow(stencil[col], row);
}
}
@@ -224,7 +228,7 @@ class LinearFilter {
}
Vectord<Samples> a =
S.householderQr().solve(d) / std::pow(period.value(), Derivative);
S.householderQr().solve(d) / gcem::pow(period.value(), Derivative);
// Reverse gains list
std::vector<double> ffGains;
@@ -266,7 +270,7 @@ class LinearFilter {
/**
* Reset the filter state.
*/
void Reset() {
constexpr void Reset() {
std::fill(m_inputs.begin(), m_inputs.end(), T{0.0});
std::fill(m_outputs.begin(), m_outputs.end(), T{0.0});
}
@@ -321,7 +325,8 @@ class LinearFilter {
* @throws std::runtime_error if size of inputBuffer or outputBuffer does not
* match the size of ffGains and fbGains provided in the constructor.
*/
void Reset(std::span<const T> inputBuffer, std::span<const T> outputBuffer) {
constexpr void Reset(std::span<const T> inputBuffer,
std::span<const T> outputBuffer) {
// Clear buffers
Reset();
@@ -346,7 +351,7 @@ class LinearFilter {
*
* @return The filtered value at this step
*/
T Calculate(T input) {
constexpr T Calculate(T input) {
T retVal{0.0};
// Rotate the inputs
@@ -376,7 +381,7 @@ class LinearFilter {
*
* @return The last value.
*/
T LastValue() const { return m_lastOutput; }
constexpr T LastValue() const { return m_lastOutput; }
private:
wpi::circular_buffer<T> m_inputs;
@@ -385,6 +390,9 @@ class LinearFilter {
std::vector<double> m_outputGains;
T m_lastOutput{0.0};
// Usage reporting instances
inline static int instances = 0;
/**
* Factorial of n.
*

View File

@@ -25,7 +25,8 @@ class MedianFilter {
*
* @param size The number of samples in the moving window.
*/
explicit MedianFilter(size_t size) : m_valueBuffer(size), m_size{size} {}
constexpr explicit MedianFilter(size_t size)
: m_valueBuffer(size), m_size{size} {}
/**
* Calculates the moving-window median for the next value of the input stream.
@@ -33,7 +34,7 @@ class MedianFilter {
* @param next The next input value.
* @return The median of the moving window, updated to include the next value.
*/
T Calculate(T next) {
constexpr T Calculate(T next) {
// Insert next value at proper point in sorted array
wpi::insert_sorted(m_orderedValues, next);
@@ -66,12 +67,12 @@ class MedianFilter {
*
* @return The last value.
*/
T LastValue() const { return m_valueBuffer.front(); }
constexpr T LastValue() const { return m_valueBuffer.front(); }
/**
* Resets the filter, clearing the window of all elements.
*/
void Reset() {
constexpr void Reset() {
m_orderedValues.clear();
m_valueBuffer.reset();
}

View File

@@ -5,9 +5,7 @@
#pragma once
#include <algorithm>
#include <array>
#include <functional>
#include <map>
#include <optional>
#include <utility>
#include <vector>

View File

@@ -45,7 +45,7 @@ struct WPILIB_DLLEXPORT ChassisSpeeds {
*
* @return Twist2d.
*/
Twist2d ToTwist2d(units::second_t dt) const {
constexpr Twist2d ToTwist2d(units::second_t dt) const {
return Twist2d{vx * dt, vy * dt, omega * dt};
}
@@ -68,10 +68,10 @@ struct WPILIB_DLLEXPORT ChassisSpeeds {
*
* @return Discretized ChassisSpeeds.
*/
static ChassisSpeeds Discretize(units::meters_per_second_t vx,
units::meters_per_second_t vy,
units::radians_per_second_t omega,
units::second_t dt) {
static constexpr ChassisSpeeds Discretize(units::meters_per_second_t vx,
units::meters_per_second_t vy,
units::radians_per_second_t omega,
units::second_t dt) {
// Construct the desired pose after a timestep, relative to the current
// pose. The desired pose has decoupled translation and rotation.
Pose2d desiredDeltaPose{vx * dt, vy * dt, omega * dt};
@@ -101,8 +101,8 @@ struct WPILIB_DLLEXPORT ChassisSpeeds {
*
* @return Discretized ChassisSpeeds.
*/
static ChassisSpeeds Discretize(const ChassisSpeeds& continuousSpeeds,
units::second_t dt) {
static constexpr ChassisSpeeds Discretize(
const ChassisSpeeds& continuousSpeeds, units::second_t dt) {
return Discretize(continuousSpeeds.vx, continuousSpeeds.vy,
continuousSpeeds.omega, dt);
}
@@ -123,7 +123,7 @@ struct WPILIB_DLLEXPORT ChassisSpeeds {
* @return ChassisSpeeds object representing the speeds in the robot's frame
* of reference.
*/
static ChassisSpeeds FromFieldRelativeSpeeds(
static constexpr ChassisSpeeds FromFieldRelativeSpeeds(
units::meters_per_second_t vx, units::meters_per_second_t vy,
units::radians_per_second_t omega, const Rotation2d& robotAngle) {
// CW rotation into chassis frame
@@ -148,7 +148,7 @@ struct WPILIB_DLLEXPORT ChassisSpeeds {
* @return ChassisSpeeds object representing the speeds in the robot's frame
* of reference.
*/
static ChassisSpeeds FromFieldRelativeSpeeds(
static constexpr ChassisSpeeds FromFieldRelativeSpeeds(
const ChassisSpeeds& fieldRelativeSpeeds, const Rotation2d& robotAngle) {
return FromFieldRelativeSpeeds(fieldRelativeSpeeds.vx,
fieldRelativeSpeeds.vy,
@@ -171,7 +171,7 @@ struct WPILIB_DLLEXPORT ChassisSpeeds {
* @return ChassisSpeeds object representing the speeds in the field's frame
* of reference.
*/
static ChassisSpeeds FromRobotRelativeSpeeds(
static constexpr ChassisSpeeds FromRobotRelativeSpeeds(
units::meters_per_second_t vx, units::meters_per_second_t vy,
units::radians_per_second_t omega, const Rotation2d& robotAngle) {
// CCW rotation out of chassis frame
@@ -196,7 +196,7 @@ struct WPILIB_DLLEXPORT ChassisSpeeds {
* @return ChassisSpeeds object representing the speeds in the field's frame
* of reference.
*/
static ChassisSpeeds FromRobotRelativeSpeeds(
static constexpr ChassisSpeeds FromRobotRelativeSpeeds(
const ChassisSpeeds& robotRelativeSpeeds, const Rotation2d& robotAngle) {
return FromRobotRelativeSpeeds(robotRelativeSpeeds.vx,
robotRelativeSpeeds.vy,

View File

@@ -4,6 +4,8 @@
#pragma once
#include <type_traits>
#include <wpi/SymbolExports.h>
#include "frc/geometry/Twist2d.h"
@@ -36,10 +38,12 @@ class WPILIB_DLLEXPORT DifferentialDriveKinematics
* empirical value may be larger than the physical measured value due to
* scrubbing effects.
*/
explicit DifferentialDriveKinematics(units::meter_t trackWidth)
constexpr explicit DifferentialDriveKinematics(units::meter_t trackWidth)
: trackWidth(trackWidth) {
wpi::math::MathSharedStore::ReportUsage(
wpi::math::MathUsageId::kKinematics_DifferentialDrive, 1);
if (!std::is_constant_evaluated()) {
wpi::math::MathSharedStore::ReportUsage(
wpi::math::MathUsageId::kKinematics_DifferentialDrive, 1);
}
}
/**
@@ -83,12 +87,13 @@ class WPILIB_DLLEXPORT DifferentialDriveKinematics
(rightDistance - leftDistance) / trackWidth * 1_rad};
}
Twist2d ToTwist2d(const DifferentialDriveWheelPositions& start,
const DifferentialDriveWheelPositions& end) const override {
constexpr Twist2d ToTwist2d(
const DifferentialDriveWheelPositions& start,
const DifferentialDriveWheelPositions& end) const override {
return ToTwist2d(end.left - start.left, end.right - start.right);
}
DifferentialDriveWheelPositions Interpolate(
constexpr DifferentialDriveWheelPositions Interpolate(
const DifferentialDriveWheelPositions& start,
const DifferentialDriveWheelPositions& end, double t) const override {
return start.Interpolate(end, t);

View File

@@ -31,18 +31,10 @@ struct WPILIB_DLLEXPORT DifferentialDriveWheelPositions {
* @param other The other object.
* @return Whether the two objects are equal.
*/
bool operator==(const DifferentialDriveWheelPositions& other) const = default;
constexpr bool operator==(
const DifferentialDriveWheelPositions& other) const = default;
/**
* Checks inequality between this DifferentialDriveWheelPositions and another
* object.
*
* @param other The other object.
* @return Whether the two objects are not equal.
*/
bool operator!=(const DifferentialDriveWheelPositions& other) const = default;
DifferentialDriveWheelPositions Interpolate(
constexpr DifferentialDriveWheelPositions Interpolate(
const DifferentialDriveWheelPositions& endValue, double t) const {
return {wpi::Lerp(left, endValue.left, t),
wpi::Lerp(right, endValue.right, t)};

View File

@@ -6,6 +6,7 @@
#include <wpi/SymbolExports.h>
#include "units/math.h"
#include "units/velocity.h"
namespace frc {
@@ -35,7 +36,15 @@ struct WPILIB_DLLEXPORT DifferentialDriveWheelSpeeds {
*
* @param attainableMaxSpeed The absolute max speed that a wheel can reach.
*/
void Desaturate(units::meters_per_second_t attainableMaxSpeed);
constexpr void Desaturate(units::meters_per_second_t attainableMaxSpeed) {
auto realMaxSpeed =
units::math::max(units::math::abs(left), units::math::abs(right));
if (realMaxSpeed > attainableMaxSpeed) {
left = left / realMaxSpeed * attainableMaxSpeed;
right = right / realMaxSpeed * attainableMaxSpeed;
}
}
/**
* Adds two DifferentialDriveWheelSpeeds and returns the sum.

View File

@@ -40,18 +40,10 @@ struct WPILIB_DLLEXPORT MecanumDriveWheelPositions {
* @param other The other object.
* @return Whether the two objects are equal.
*/
bool operator==(const MecanumDriveWheelPositions& other) const = default;
constexpr bool operator==(const MecanumDriveWheelPositions& other) const =
default;
/**
* Checks inequality between this MecanumDriveWheelPositions and another
* object.
*
* @param other The other object.
* @return Whether the two objects are not equal.
*/
bool operator!=(const MecanumDriveWheelPositions& other) const = default;
MecanumDriveWheelPositions Interpolate(
constexpr MecanumDriveWheelPositions Interpolate(
const MecanumDriveWheelPositions& endValue, double t) const {
return {wpi::Lerp(frontLeft, endValue.frontLeft, t),
wpi::Lerp(frontRight, endValue.frontRight, t),

View File

@@ -4,8 +4,13 @@
#pragma once
#include <algorithm>
#include <array>
#include <cmath>
#include <wpi/SymbolExports.h>
#include "units/math.h"
#include "units/velocity.h"
namespace frc {
@@ -45,7 +50,25 @@ struct WPILIB_DLLEXPORT MecanumDriveWheelSpeeds {
*
* @param attainableMaxSpeed The absolute max speed that a wheel can reach.
*/
void Desaturate(units::meters_per_second_t attainableMaxSpeed);
constexpr void Desaturate(units::meters_per_second_t attainableMaxSpeed) {
std::array<units::meters_per_second_t, 4> wheelSpeeds{frontLeft, frontRight,
rearLeft, rearRight};
units::meters_per_second_t realMaxSpeed = units::math::abs(
*std::max_element(wheelSpeeds.begin(), wheelSpeeds.end(),
[](const auto& a, const auto& b) {
return units::math::abs(a) < units::math::abs(b);
}));
if (realMaxSpeed > attainableMaxSpeed) {
for (int i = 0; i < 4; ++i) {
wheelSpeeds[i] = wheelSpeeds[i] / realMaxSpeed * attainableMaxSpeed;
}
frontLeft = wheelSpeeds[0];
frontRight = wheelSpeeds[1];
rearLeft = wheelSpeeds[2];
rearRight = wheelSpeeds[3];
}
}
/**
* Adds two MecanumDriveWheelSpeeds and returns the sum.

View File

@@ -8,7 +8,6 @@
#include <wpi/SymbolExports.h>
#include "frc/geometry/Rotation2d.h"
#include "units/angle.h"
#include "units/length.h"
#include "units/math.h"
@@ -33,10 +32,13 @@ struct WPILIB_DLLEXPORT SwerveModulePosition {
* @param other The other object.
* @return Whether the two objects are equal.
*/
bool operator==(const SwerveModulePosition& other) const;
constexpr bool operator==(const SwerveModulePosition& other) const {
return units::math::abs(distance - other.distance) < 1E-9_m &&
angle == other.angle;
}
SwerveModulePosition Interpolate(const SwerveModulePosition& endValue,
double t) const {
constexpr SwerveModulePosition Interpolate(
const SwerveModulePosition& endValue, double t) const {
return {wpi::Lerp(distance, endValue.distance, t),
wpi::Lerp(angle, endValue.angle, t)};
}

View File

@@ -32,7 +32,10 @@ struct WPILIB_DLLEXPORT SwerveModuleState {
* @param other The other object.
* @return Whether the two objects are equal.
*/
bool operator==(const SwerveModuleState& other) const;
constexpr bool operator==(const SwerveModuleState& other) const {
return units::math::abs(speed - other.speed) < 1E-9_mps &&
angle == other.angle;
}
/**
* Minimize the change in the heading this swerve module state would
@@ -42,7 +45,7 @@ struct WPILIB_DLLEXPORT SwerveModuleState {
*
* @param currentAngle The current module angle.
*/
void Optimize(const Rotation2d& currentAngle) {
constexpr void Optimize(const Rotation2d& currentAngle) {
auto delta = angle - currentAngle;
if (units::math::abs(delta.Degrees()) > 90_deg) {
speed *= -1;
@@ -60,8 +63,15 @@ struct WPILIB_DLLEXPORT SwerveModuleState {
* @param currentAngle The current module angle.
*/
[[deprecated("Use instance method instead.")]]
static SwerveModuleState Optimize(const SwerveModuleState& desiredState,
const Rotation2d& currentAngle);
constexpr static SwerveModuleState Optimize(
const SwerveModuleState& desiredState, const Rotation2d& currentAngle) {
auto delta = desiredState.angle - currentAngle;
if (units::math::abs(delta.Degrees()) > 90_deg) {
return {-desiredState.speed, desiredState.angle + Rotation2d{180_deg}};
} else {
return {desiredState.speed, desiredState.angle};
}
}
/**
* Scales speed by cosine of angle error. This scales down movement
@@ -70,7 +80,7 @@ struct WPILIB_DLLEXPORT SwerveModuleState {
*
* @param currentAngle The current module angle.
*/
void CosineScale(const Rotation2d& currentAngle) {
constexpr void CosineScale(const Rotation2d& currentAngle) {
speed *= (angle - currentAngle).Cos();
}
};

View File

@@ -109,8 +109,8 @@ namespace units
namespace units
{
template<typename T> inline constexpr const char* name(const T&);
template<typename T> inline constexpr const char* abbreviation(const T&);
template<typename T> constexpr const char* name(const T&);
template<typename T> constexpr const char* abbreviation(const T&);
}
//------------------------------
@@ -231,11 +231,11 @@ namespace units
* @param abbreviation - abbreviated unit name, e.g. 'm'
*/
#define UNIT_ADD_NAME(namespaceName, nameSingular, abbrev)\
template<> inline constexpr const char* name(const namespaceName::nameSingular ## _t&)\
template<> constexpr const char* name(const namespaceName::nameSingular ## _t&)\
{\
return #nameSingular;\
}\
template<> inline constexpr const char* abbreviation(const namespaceName::nameSingular ## _t&)\
template<> constexpr const char* abbreviation(const namespaceName::nameSingular ## _t&)\
{\
return #abbrev;\
}
@@ -255,11 +255,11 @@ template<> inline constexpr const char* abbreviation(const namespaceName::nameSi
#define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation)\
namespace literals\
{\
inline constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation(long double d)\
constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation(long double d)\
{\
return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\
}\
inline constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation (unsigned long long d)\
constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation (unsigned long long d)\
{\
return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\
}\
@@ -365,7 +365,7 @@ template<> inline constexpr const char* abbreviation(const namespaceName::nameSi
namespace traits\
{\
template<typename... T> struct is_ ## unitCategory ## _unit : std::integral_constant<bool, units::all_true<units::traits::detail::is_ ## unitCategory ## _unit_impl<std::decay_t<T>>::value...>::value> {};\
template<typename... T> inline constexpr bool is_ ## unitCategory ## _unit_v = is_ ## unitCategory ## _unit<T...>::value;\
template<typename... T> constexpr bool is_ ## unitCategory ## _unit_v = is_ ## unitCategory ## _unit<T...>::value;\
}\
template <typename T>\
concept unitCategory ## _unit = traits::is_ ## unitCategory ## _unit_v<T>;
@@ -593,7 +593,7 @@ namespace units
has_den<T>::value>
{};
template<class T>
inline constexpr bool is_ratio_v = is_ratio<T>::value;
constexpr bool is_ratio_v = is_ratio<T>::value;
}
//------------------------------
@@ -619,7 +619,7 @@ namespace units
template<bool... Args>
struct all_true : std::is_same<units::bool_pack<true, Args...>, units::bool_pack<Args..., true>> {};
template<bool... Args>
inline constexpr bool all_true_t_v = all_true<Args...>::type::value;
constexpr bool all_true_t_v = all_true<Args...>::type::value;
/** @endcond */ // DOXYGEN IGNORE
/**
@@ -721,7 +721,7 @@ namespace units
template<class T>
struct is_unit : std::is_base_of<units::detail::_unit, T>::type {};
template<class T>
inline constexpr bool is_unit_v = is_unit<T>::value;
constexpr bool is_unit_v = is_unit<T>::value;
}
/** @} */ // end of TypeTraits
@@ -1532,7 +1532,7 @@ namespace units
struct is_convertible_unit : std::is_same <traits::base_unit_of<typename units::traits::unit_traits<U1>::base_unit_type>,
base_unit_of<typename units::traits::unit_traits<U2>::base_unit_type >> {};
template<class U1, class U2>
inline constexpr bool is_convertible_unit_v = is_convertible_unit<U1, U2>::value;
constexpr bool is_convertible_unit_v = is_convertible_unit<U1, U2>::value;
}
//------------------------------
@@ -1554,35 +1554,35 @@ namespace units
/// convert dispatch for units which are both the same
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::false_type) noexcept
static constexpr T convert(const T& value, std::true_type, std::false_type, std::false_type) noexcept
{
return value;
}
/// convert dispatch for units which are both the same
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::true_type) noexcept
static constexpr T convert(const T& value, std::true_type, std::false_type, std::true_type) noexcept
{
return value;
}
/// convert dispatch for units which are both the same
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::false_type) noexcept
static constexpr T convert(const T& value, std::true_type, std::true_type, std::false_type) noexcept
{
return value;
}
/// convert dispatch for units which are both the same
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::true_type) noexcept
static constexpr T convert(const T& value, std::true_type, std::true_type, std::true_type) noexcept
{
return value;
}
/// convert dispatch for units of different types w/ no translation and no PI
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::false_type) noexcept
static constexpr T convert(const T& value, std::false_type, std::false_type, std::false_type) noexcept
{
return ((value * Ratio::num) / Ratio::den);
}
@@ -1590,7 +1590,7 @@ namespace units
/// convert dispatch for units of different types w/ no translation, but has PI in numerator
// constepxr with PI in numerator
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr
static constexpr
std::enable_if_t<(PiRatio::num / PiRatio::den >= 1 && PiRatio::num % PiRatio::den == 0), T>
convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
{
@@ -1600,7 +1600,7 @@ namespace units
/// convert dispatch for units of different types w/ no translation, but has PI in denominator
// constexpr with PI in denominator
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr
static constexpr
std::enable_if_t<(PiRatio::num / PiRatio::den <= -1 && PiRatio::num % PiRatio::den == 0), T>
convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
{
@@ -1619,14 +1619,14 @@ namespace units
/// convert dispatch for units of different types with a translation, but no PI
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::true_type) noexcept
static constexpr T convert(const T& value, std::false_type, std::false_type, std::true_type) noexcept
{
return ((value * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
}
/// convert dispatch for units of different types with a translation AND PI
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline constexpr T convert(const T& value, const std::false_type, const std::true_type, const std::true_type) noexcept
static constexpr T convert(const T& value, const std::false_type, const std::true_type, const std::true_type) noexcept
{
return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
}
@@ -1649,7 +1649,7 @@ namespace units
* @returns value, converted from units of `UnitFrom` to `UnitTo`.
*/
template<class UnitFrom, class UnitTo, typename T = UNIT_LIB_DEFAULT_TYPE>
static inline constexpr T convert(const T& value) noexcept
static constexpr T convert(const T& value) noexcept
{
static_assert(traits::is_unit<UnitFrom>::value, "Template parameter `UnitFrom` must be a `unit` type.");
static_assert(traits::is_unit<UnitTo>::value, "Template parameter `UnitTo` must be a `unit` type.");
@@ -1727,7 +1727,7 @@ namespace units
template<class T, class Ret>
struct has_value_member : traits::detail::has_value_member_impl<T, Ret>::type {};
template<class T, class Ret>
inline constexpr bool has_value_member_v = has_value_member<T, Ret>::value;
constexpr bool has_value_member_v = has_value_member<T, Ret>::value;
}
/** @endcond */ // END DOXYGEN IGNORE
@@ -1867,7 +1867,7 @@ namespace units
template<class T>
struct is_unit_t : std::is_base_of<units::detail::_unit_t, T>::type {};
template<class T>
inline constexpr bool is_unit_t_v = is_unit_t<T>::value;
constexpr bool is_unit_t_v = is_unit_t<T>::value;
}
/**
@@ -1969,7 +1969,7 @@ namespace units
* @param[in] value value of the unit_t
*/
template<class Ty, class = typename std::enable_if<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>::type>
inline constexpr unit_t(const Ty value) noexcept : nls(value)
constexpr unit_t(const Ty value) noexcept : nls(value)
{
}
@@ -1980,7 +1980,7 @@ namespace units
* @param[in] value value of the unit_t
*/
template<class Rep, class Period, class = std::enable_if_t<std::is_arithmetic<Rep>::value && traits::is_ratio<Period>::value>>
inline constexpr unit_t(const std::chrono::duration<Rep, Period>& value) noexcept :
constexpr unit_t(const std::chrono::duration<Rep, Period>& value) noexcept :
nls(units::convert<unit<std::ratio<1,1000000000>, category::time_unit>, Units>(static_cast<T>(std::chrono::duration_cast<std::chrono::nanoseconds>(value).count())))
{
@@ -1992,7 +1992,7 @@ namespace units
* @param[in] rhs unit to copy.
*/
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
inline constexpr unit_t(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept :
constexpr unit_t(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept :
nls(units::convert<UnitsRhs, Units, T>(rhs.m_value), std::true_type() /*store linear value*/)
{
@@ -2029,7 +2029,7 @@ namespace units
* @returns true IFF the value of `this` is less than the value of `rhs`
*/
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
inline constexpr bool operator<(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
constexpr bool operator<(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return (nls::m_value < units::convert<UnitsRhs, Units>(rhs.m_value));
}
@@ -2041,7 +2041,7 @@ namespace units
* @returns true IFF the value of `this` is less than or equal to the value of `rhs`
*/
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
inline constexpr bool operator<=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
constexpr bool operator<=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return (nls::m_value <= units::convert<UnitsRhs, Units>(rhs.m_value));
}
@@ -2053,7 +2053,7 @@ namespace units
* @returns true IFF the value of `this` is greater than the value of `rhs`
*/
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
inline constexpr bool operator>(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
constexpr bool operator>(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return (nls::m_value > units::convert<UnitsRhs, Units>(rhs.m_value));
}
@@ -2065,7 +2065,7 @@ namespace units
* @returns true IFF the value of `this` is greater than or equal to the value of `rhs`
*/
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
inline constexpr bool operator>=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
constexpr bool operator>=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return (nls::m_value >= units::convert<UnitsRhs, Units>(rhs.m_value));
}
@@ -2078,7 +2078,7 @@ namespace units
* @note This may not be suitable for all applications when the underlying_type of unit_t is a double.
*/
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs, std::enable_if_t<std::is_floating_point<T>::value || std::is_floating_point<Ty>::value, int> = 0>
inline constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < std::numeric_limits<T>::epsilon() *
detail::abs(nls::m_value + units::convert<UnitsRhs, Units>(rhs.m_value)) ||
@@ -2086,7 +2086,7 @@ namespace units
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs, std::enable_if_t<std::is_integral<T>::value && std::is_integral<Ty>::value, int> = 0>
inline constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return nls::m_value == units::convert<UnitsRhs, Units>(rhs.m_value);
}
@@ -2099,7 +2099,7 @@ namespace units
* @note This may not be suitable for all applications when the underlying_type of unit_t is a double.
*/
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
inline constexpr bool operator!=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
constexpr bool operator!=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return !(*this == rhs);
}
@@ -2108,7 +2108,7 @@ namespace units
* @brief unit value
* @returns value of the unit in it's underlying, non-safe type.
*/
inline constexpr underlying_type value() const noexcept
constexpr underlying_type value() const noexcept
{
return static_cast<underlying_type>(*this);
}
@@ -2118,7 +2118,7 @@ namespace units
* @returns value of the unit converted to an arithmetic, non-safe type.
*/
template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>>
inline constexpr Ty to() const noexcept
constexpr Ty to() const noexcept
{
return static_cast<Ty>(*this);
}
@@ -2129,7 +2129,7 @@ namespace units
* linear scales, this is equivalent to `value`.
*/
template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>>
inline constexpr Ty toLinearized() const noexcept
constexpr Ty toLinearized() const noexcept
{
return static_cast<Ty>(m_value);
}
@@ -2144,7 +2144,7 @@ namespace units
* *this.
*/
template<class U>
inline constexpr unit_t<U> convert() const noexcept
constexpr unit_t<U> convert() const noexcept
{
static_assert(traits::is_unit<U>::value, "Template parameter `U` must be a unit type.");
return unit_t<U>(*this);
@@ -2155,7 +2155,7 @@ namespace units
* @details only enabled for scalar unit types.
*/
template<class Ty, std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0>
inline constexpr operator Ty() const noexcept
constexpr operator Ty() const noexcept
{
// this conversion also resolves any PI exponents, by converting from a non-zero PI ratio to a zero-pi ratio.
return static_cast<Ty>(units::convert<Units, unit<std::ratio<1>, units::category::scalar_unit>>((*this)()));
@@ -2166,7 +2166,7 @@ namespace units
* @details only enabled for non-dimensionless unit types.
*/
template<class Ty, std::enable_if_t<!traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0>
inline constexpr explicit operator Ty() const noexcept
constexpr explicit operator Ty() const noexcept
{
return static_cast<Ty>((*this)());
}
@@ -2176,7 +2176,7 @@ namespace units
* @details only enabled for time unit types.
*/
template<typename U = Units, std::enable_if_t<units::traits::is_convertible_unit<U, unit<std::ratio<1>, category::time_unit>>::value, int> = 0>
inline constexpr operator std::chrono::nanoseconds() const noexcept
constexpr operator std::chrono::nanoseconds() const noexcept
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double, std::nano>(units::convert<Units, unit<std::ratio<1,1000000000>, category::time_unit>>((*this)())));
}
@@ -2184,7 +2184,7 @@ namespace units
/**
* @brief returns the unit name
*/
inline constexpr const char* name() const noexcept
constexpr const char* name() const noexcept
{
return units::name(*this);
}
@@ -2192,7 +2192,7 @@ namespace units
/**
* @brief returns the unit abbreviation
*/
inline constexpr const char* abbreviation() const noexcept
constexpr const char* abbreviation() const noexcept
{
return units::abbreviation(*this);
}
@@ -2218,7 +2218,7 @@ namespace units
* @param[in] value Arithmetic value that represents a quantity in units of `UnitType`.
*/
template<class UnitType, typename T, class = std::enable_if_t<std::is_arithmetic<T>::value>>
inline constexpr UnitType make_unit(const T value) noexcept
constexpr UnitType make_unit(const T value) noexcept
{
static_assert(traits::is_unit_t<UnitType>::value, "Template parameter `UnitType` must be a unit type (_t).");
@@ -2282,7 +2282,7 @@ namespace units
#endif
template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
inline unit_t<Units, T, NonLinearScale>& operator+=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
constexpr unit_t<Units, T, NonLinearScale>& operator+=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
{
static_assert(traits::is_convertible_unit_t<unit_t<Units, T, NonLinearScale>, RhsType>::value ||
(traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value),
@@ -2293,7 +2293,7 @@ namespace units
}
template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
inline unit_t<Units, T, NonLinearScale>& operator-=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
constexpr unit_t<Units, T, NonLinearScale>& operator-=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
{
static_assert(traits::is_convertible_unit_t<unit_t<Units, T, NonLinearScale>, RhsType>::value ||
(traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value),
@@ -2304,7 +2304,7 @@ namespace units
}
template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
inline unit_t<Units, T, NonLinearScale>& operator*=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
constexpr unit_t<Units, T, NonLinearScale>& operator*=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
{
static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value),
"right-hand side parameter must be dimensionless.");
@@ -2314,7 +2314,7 @@ namespace units
}
template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
inline unit_t<Units, T, NonLinearScale>& operator/=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
constexpr unit_t<Units, T, NonLinearScale>& operator/=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
{
static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value),
"right-hand side parameter must be dimensionless.");
@@ -2329,14 +2329,14 @@ namespace units
// unary addition: +T
template<class Units, typename T, template<typename> class NonLinearScale>
constexpr inline unit_t<Units, T, NonLinearScale> operator+(const unit_t<Units, T, NonLinearScale>& u) noexcept
constexpr unit_t<Units, T, NonLinearScale> operator+(const unit_t<Units, T, NonLinearScale>& u) noexcept
{
return u;
}
// prefix increment: ++T
template<class Units, typename T, template<typename> class NonLinearScale>
inline unit_t<Units, T, NonLinearScale>& operator++(unit_t<Units, T, NonLinearScale>& u) noexcept
constexpr unit_t<Units, T, NonLinearScale>& operator++(unit_t<Units, T, NonLinearScale>& u) noexcept
{
u = unit_t<Units, T, NonLinearScale>(u() + 1);
return u;
@@ -2344,7 +2344,7 @@ namespace units
// postfix increment: T++
template<class Units, typename T, template<typename> class NonLinearScale>
inline unit_t<Units, T, NonLinearScale> operator++(unit_t<Units, T, NonLinearScale>& u, int) noexcept
constexpr unit_t<Units, T, NonLinearScale> operator++(unit_t<Units, T, NonLinearScale>& u, int) noexcept
{
auto ret = u;
u = unit_t<Units, T, NonLinearScale>(u() + 1);
@@ -2353,14 +2353,14 @@ namespace units
// unary addition: -T
template<class Units, typename T, template<typename> class NonLinearScale>
constexpr inline unit_t<Units, T, NonLinearScale> operator-(const unit_t<Units, T, NonLinearScale>& u) noexcept
constexpr unit_t<Units, T, NonLinearScale> operator-(const unit_t<Units, T, NonLinearScale>& u) noexcept
{
return unit_t<Units, T, NonLinearScale>(-u());
}
// prefix increment: --T
template<class Units, typename T, template<typename> class NonLinearScale>
inline unit_t<Units, T, NonLinearScale>& operator--(unit_t<Units, T, NonLinearScale>& u) noexcept
constexpr unit_t<Units, T, NonLinearScale>& operator--(unit_t<Units, T, NonLinearScale>& u) noexcept
{
u = unit_t<Units, T, NonLinearScale>(u() - 1);
return u;
@@ -2368,7 +2368,7 @@ namespace units
// postfix increment: T--
template<class Units, typename T, template<typename> class NonLinearScale>
inline unit_t<Units, T, NonLinearScale> operator--(unit_t<Units, T, NonLinearScale>& u, int) noexcept
constexpr unit_t<Units, T, NonLinearScale> operator--(unit_t<Units, T, NonLinearScale>& u, int) noexcept
{
auto ret = u;
u = unit_t<Units, T, NonLinearScale>(u() - 1);
@@ -2393,7 +2393,7 @@ namespace units
* @sa unit_t::to
*/
template<typename T, typename Units, class = std::enable_if_t<std::is_arithmetic<T>::value && traits::is_unit_t<Units>::value>>
inline constexpr T unit_cast(const Units& value) noexcept
constexpr T unit_cast(const Units& value) noexcept
{
return static_cast<T>(value);
}
@@ -2418,7 +2418,7 @@ namespace units
template<typename... T>
struct has_linear_scale : std::integral_constant<bool, units::all_true<std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T>::underlying_type>, T>::value...>::value > {};
template<typename... T>
inline constexpr bool has_linear_scale_v = has_linear_scale<T...>::value;
constexpr bool has_linear_scale_v = has_linear_scale<T...>::value;
#else
template<typename T1, typename T2 = T1, typename T3 = T1>
struct has_linear_scale : std::integral_constant<bool,
@@ -2426,7 +2426,7 @@ namespace units
std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value &&
std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T3>::underlying_type>, T3>::value> {};
template<typename T1, typename T2 = T1, typename T3 = T1>
inline constexpr bool has_linear_scale_v = has_linear_scale<T1, T2, T3>::value;
constexpr bool has_linear_scale_v = has_linear_scale<T1, T2, T3>::value;
#endif
/**
@@ -2440,7 +2440,7 @@ namespace units
template<typename... T>
struct has_decibel_scale : std::integral_constant<bool, units::all_true<std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T>::underlying_type>, T>::value...>::value> {};
template<typename... T>
inline constexpr bool has_decibel_scale_v = has_decibel_scale<T...>::value;
constexpr bool has_decibel_scale_v = has_decibel_scale<T...>::value;
#else
template<typename T1, typename T2 = T1, typename T3 = T1>
struct has_decibel_scale : std::integral_constant<bool,
@@ -2448,7 +2448,7 @@ namespace units
std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value &&
std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T3>::value> {};
template<typename T1, typename T2 = T1, typename T3 = T1>
inline constexpr bool has_decibel_scale_v = has_decibel_scale<T1, T2, T3>::value;
constexpr bool has_decibel_scale_v = has_decibel_scale<T1, T2, T3>::value;
#endif
/**
@@ -2464,7 +2464,7 @@ namespace units
std::is_same<typename units::traits::unit_t_traits<T1>::non_linear_scale_type, typename units::traits::unit_t_traits<T2>::non_linear_scale_type>::value>
{};
template<typename T1, typename T2>
inline constexpr bool is_same_scale_v = is_same_scale<T1, T2>::value;
constexpr bool is_same_scale_v = is_same_scale<T1, T2>::value;
}
//----------------------------------
@@ -2489,17 +2489,17 @@ namespace units
template<typename T>
struct linear_scale
{
inline constexpr linear_scale() = default; ///< default constructor.
inline constexpr linear_scale(const linear_scale&) = default;
constexpr linear_scale() = default; ///< default constructor.
constexpr linear_scale(const linear_scale&) = default;
inline ~linear_scale() = default;
inline linear_scale& operator=(const linear_scale&) = default;
#if defined(_MSC_VER) && (_MSC_VER > 1800)
inline constexpr linear_scale(linear_scale&&) = default;
constexpr linear_scale(linear_scale&&) = default;
inline linear_scale& operator=(linear_scale&&) = default;
#endif
template<class... Args>
inline constexpr linear_scale(const T& value, Args&&...) noexcept : m_value(value) {} ///< constructor.
inline constexpr T operator()() const noexcept { return m_value; } ///< returns value.
constexpr linear_scale(const T& value, Args&&...) noexcept : m_value(value) {} ///< constructor.
constexpr T operator()() const noexcept { return m_value; } ///< returns value.
T m_value; ///< linearized value.
};
@@ -2542,7 +2542,7 @@ namespace units
/// Addition operator for unit_t types with a linear_scale.
template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
inline constexpr UnitTypeLhs operator+(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
constexpr UnitTypeLhs operator+(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
@@ -2551,21 +2551,21 @@ namespace units
/// Addition operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline constexpr dimensionless::scalar_t operator+(const dimensionless::scalar_t& lhs, T rhs) noexcept
constexpr dimensionless::scalar_t operator+(const dimensionless::scalar_t& lhs, T rhs) noexcept
{
return dimensionless::scalar_t(lhs() + rhs);
}
/// Addition operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline constexpr dimensionless::scalar_t operator+(T lhs, const dimensionless::scalar_t& rhs) noexcept
constexpr dimensionless::scalar_t operator+(T lhs, const dimensionless::scalar_t& rhs) noexcept
{
return dimensionless::scalar_t(lhs + rhs());
}
/// Subtraction operator for unit_t types with a linear_scale.
template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
inline constexpr UnitTypeLhs operator-(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
constexpr UnitTypeLhs operator-(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
@@ -2574,14 +2574,14 @@ namespace units
/// Subtraction operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline constexpr dimensionless::scalar_t operator-(const dimensionless::scalar_t& lhs, T rhs) noexcept
constexpr dimensionless::scalar_t operator-(const dimensionless::scalar_t& lhs, T rhs) noexcept
{
return dimensionless::scalar_t(lhs() - rhs);
}
/// Subtraction operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline constexpr dimensionless::scalar_t operator-(T lhs, const dimensionless::scalar_t& rhs) noexcept
constexpr dimensionless::scalar_t operator-(T lhs, const dimensionless::scalar_t& rhs) noexcept
{
return dimensionless::scalar_t(lhs - rhs());
}
@@ -2589,7 +2589,7 @@ namespace units
/// Multiplication type for convertible unit_t types with a linear scale. @returns the multiplied value, with the same type as left-hand side unit.
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
inline constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>>
constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>>
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
@@ -2600,7 +2600,7 @@ namespace units
/// Multiplication type for non-convertible unit_t types with a linear scale. @returns the multiplied value, whose type is a compound unit of the left and right hand side values.
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<!traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
inline constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
@@ -2611,7 +2611,7 @@ namespace units
/// Multiplication by a dimensionless unit for unit_t types with a linear scale.
template<class UnitTypeLhs, typename UnitTypeRhs,
std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
inline constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
// the cast makes sure factors of PI are handled as expected
return UnitTypeLhs(lhs() * static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
@@ -2620,7 +2620,7 @@ namespace units
/// Multiplication by a dimensionless unit for unit_t types with a linear scale.
template<class UnitTypeLhs, typename UnitTypeRhs,
std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
inline constexpr UnitTypeRhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
constexpr UnitTypeRhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
// the cast makes sure factors of PI are handled as expected
return UnitTypeRhs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) * rhs());
@@ -2629,7 +2629,7 @@ namespace units
/// Multiplication by a scalar for unit_t types with a linear scale.
template<class UnitTypeLhs, typename T,
std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0>
inline constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, T rhs) noexcept
constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, T rhs) noexcept
{
return UnitTypeLhs(lhs() * rhs);
}
@@ -2637,7 +2637,7 @@ namespace units
/// Multiplication by a scalar for unit_t types with a linear scale.
template<class UnitTypeRhs, typename T,
std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0>
inline constexpr UnitTypeRhs operator*(T lhs, const UnitTypeRhs& rhs) noexcept
constexpr UnitTypeRhs operator*(T lhs, const UnitTypeRhs& rhs) noexcept
{
return UnitTypeRhs(lhs * rhs());
}
@@ -2645,7 +2645,7 @@ namespace units
/// Division for convertible unit_t types with a linear scale. @returns the lhs divided by rhs value, whose type is a scalar
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
inline constexpr dimensionless::scalar_t operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
constexpr dimensionless::scalar_t operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
@@ -2655,7 +2655,7 @@ namespace units
/// Division for non-convertible unit_t types with a linear scale. @returns the lhs divided by the rhs, with a compound unit type of lhs/rhs
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<!traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
inline constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>>
constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>>
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
@@ -2666,7 +2666,7 @@ namespace units
/// Division by a dimensionless unit for unit_t types with a linear scale
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
inline constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
return UnitTypeLhs(lhs() / static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
}
@@ -2674,7 +2674,7 @@ namespace units
/// Division of a dimensionless unit by a unit_t type with a linear scale
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
inline constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
{
return unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) / rhs());
@@ -2683,7 +2683,7 @@ namespace units
/// Division by a scalar for unit_t types with a linear scale
template<class UnitTypeLhs, typename T,
std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0>
inline constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, T rhs) noexcept
constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, T rhs) noexcept
{
return UnitTypeLhs(lhs() / rhs);
}
@@ -2691,7 +2691,7 @@ namespace units
/// Division of a scalar by a unit_t type with a linear scale
template<class UnitTypeRhs, typename T,
std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0>
inline constexpr auto operator/(T lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
constexpr auto operator/(T lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
{
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
return unit_t<inverse<UnitsRhs>>
@@ -2807,7 +2807,7 @@ namespace units
* @returns new unit_t, raised to the given exponent
*/
template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>>
inline constexpr auto pow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
constexpr auto pow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
{
return unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
(gcem::pow(value(), power));
@@ -2822,7 +2822,7 @@ namespace units
* @returns new unit_t, raised to the given exponent
*/
template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>>
inline constexpr auto cpow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
constexpr auto cpow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
{
static_assert(power >= 0, "cpow cannot accept negative numbers. Try units::math::pow instead.");
return unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
@@ -2843,18 +2843,18 @@ namespace units
template<typename T>
struct decibel_scale
{
inline constexpr decibel_scale() = default;
inline constexpr decibel_scale(const decibel_scale&) = default;
constexpr decibel_scale() = default;
constexpr decibel_scale(const decibel_scale&) = default;
inline ~decibel_scale() = default;
inline decibel_scale& operator=(const decibel_scale&) = default;
#if defined(_MSC_VER) && (_MSC_VER > 1800)
inline constexpr decibel_scale(decibel_scale&&) = default;
constexpr decibel_scale(decibel_scale&&) = default;
inline decibel_scale& operator=(decibel_scale&&) = default;
#endif
inline constexpr decibel_scale(const T value) noexcept : m_value(std::pow(10, value / 10)) {}
constexpr decibel_scale(const T value) noexcept : m_value(std::pow(10, value / 10)) {}
template<class... Args>
inline constexpr decibel_scale(const T value, std::true_type, Args&&...) noexcept : m_value(value) {}
inline constexpr T operator()() const noexcept { return 10 * std::log10(m_value); }
constexpr decibel_scale(const T value, std::true_type, Args&&...) noexcept : m_value(value) {}
constexpr T operator()() const noexcept { return 10 * std::log10(m_value); }
T m_value; ///< linearized value
};
@@ -3060,7 +3060,7 @@ namespace units {
std::is_base_of<units::detail::_unit_value_t<Units>, T>::value>
{};
template<typename T, typename Units = typename traits::unit_value_t_traits<T>::unit_type>
inline constexpr bool is_unit_value_t_v = is_unit_value_t<T, Units>::value;
constexpr bool is_unit_value_t_v = is_unit_value_t<T, Units>::value;
/**
* @ingroup TypeTraits
@@ -3074,7 +3074,7 @@ namespace units {
static_assert(is_base_unit<Category>::value, "Template parameter `Category` must be a `base_unit` type.");
};
template<typename Category, typename T>
inline constexpr bool is_unit_value_t_category_v = is_unit_value_t_category<Category, T>::value;
constexpr bool is_unit_value_t_category_v = is_unit_value_t_category<Category, T>::value;
}
/** @cond */ // DOXYGEN IGNORE