Base: Units: refactor

Refactor Units making it constexpr, immutable, with repetition reduced.
Separate data from code.

Constexpr constructed units allow constructing predefined Quantities
from predefined unit types.
This commit is contained in:
bofdahof
2025-01-01 18:17:00 +10:00
committed by Ladislav Michl
parent f8d2789a43
commit 847e2f5c85
8 changed files with 729 additions and 1155 deletions

View File

@@ -294,162 +294,150 @@ void Quantity::setInvalid()
}
// === Predefined types =====================================================
// clang-format off
const Quantity Quantity::NanoMetre ( 1.0e-6 , Unit::Length );
const Quantity Quantity::MicroMetre ( 1.0e-3 , Unit::Length );
const Quantity Quantity::MilliMetre ( 1.0 , Unit::Length );
const Quantity Quantity::CentiMetre ( 10.0 , Unit::Length );
const Quantity Quantity::DeciMetre ( 100.0 , Unit::Length );
const Quantity Quantity::Metre ( 1.0e3 , Unit::Length );
const Quantity Quantity::KiloMetre ( 1.0e6 , Unit::Length );
const Quantity Quantity::NanoMetre(1.0e-6, Unit(1));
const Quantity Quantity::MicroMetre(1.0e-3, Unit(1));
const Quantity Quantity::MilliMetre(1.0, Unit(1));
const Quantity Quantity::CentiMetre(10.0, Unit(1));
const Quantity Quantity::DeciMetre(100.0, Unit(1));
const Quantity Quantity::Metre(1.0e3, Unit(1));
const Quantity Quantity::KiloMetre(1.0e6, Unit(1));
const Quantity Quantity::MilliLiter ( 1000.0 , Unit::Volume );
const Quantity Quantity::Liter ( 1.0e6 , Unit::Volume );
const Quantity Quantity::MilliLiter(1000.0, Unit(3));
const Quantity Quantity::Liter(1.0e6, Unit(3));
const Quantity Quantity::Hertz ( 1.0 , Unit::Frequency );
const Quantity Quantity::KiloHertz ( 1.0e3 , Unit::Frequency );
const Quantity Quantity::MegaHertz ( 1.0e6 , Unit::Frequency );
const Quantity Quantity::GigaHertz ( 1.0e9 , Unit::Frequency );
const Quantity Quantity::TeraHertz ( 1.0e12 , Unit::Frequency );
const Quantity Quantity::Hertz(1.0, Unit(0, 0, -1));
const Quantity Quantity::KiloHertz(1.0e3, Unit(0, 0, -1));
const Quantity Quantity::MegaHertz(1.0e6, Unit(0, 0, -1));
const Quantity Quantity::GigaHertz(1.0e9, Unit(0, 0, -1));
const Quantity Quantity::TeraHertz(1.0e12, Unit(0, 0, -1));
const Quantity Quantity::MicroGram ( 1.0e-9 , Unit::Mass );
const Quantity Quantity::MilliGram ( 1.0e-6 , Unit::Mass );
const Quantity Quantity::Gram ( 1.0e-3 , Unit::Mass );
const Quantity Quantity::KiloGram ( 1.0 , Unit::Mass );
const Quantity Quantity::Ton ( 1.0e3 , Unit::Mass );
const Quantity Quantity::MicroGram(1.0e-9, Unit(0, 1));
const Quantity Quantity::MilliGram(1.0e-6, Unit(0, 1));
const Quantity Quantity::Gram(1.0e-3, Unit(0, 1));
const Quantity Quantity::KiloGram(1.0, Unit(0, 1));
const Quantity Quantity::Ton(1.0e3, Unit(0, 1));
const Quantity Quantity::Second ( 1.0 , Unit::TimeSpan );
const Quantity Quantity::Minute ( 60.0 , Unit::TimeSpan );
const Quantity Quantity::Hour ( 3600.0 , Unit::TimeSpan );
const Quantity Quantity::Second(1.0, Unit(0, 0, 1));
const Quantity Quantity::Minute(60.0, Unit(0, 0, 1));
const Quantity Quantity::Hour(3600.0, Unit(0, 0, 1));
const Quantity Quantity::Ampere ( 1.0 , Unit::ElectricCurrent );
const Quantity Quantity::MilliAmpere ( 0.001 , Unit::ElectricCurrent );
const Quantity Quantity::KiloAmpere ( 1000.0 , Unit::ElectricCurrent );
const Quantity Quantity::MegaAmpere ( 1.0e6 , Unit::ElectricCurrent );
const Quantity Quantity::Ampere(1.0, Unit(0, 0, 0, 1));
const Quantity Quantity::MilliAmpere(0.001, Unit(0, 0, 0, 1));
const Quantity Quantity::KiloAmpere(1000.0, Unit(0, 0, 0, 1));
const Quantity Quantity::MegaAmpere(1.0e6, Unit(0, 0, 0, 1));
const Quantity Quantity::Kelvin ( 1.0 , Unit::Temperature );
const Quantity Quantity::MilliKelvin ( 0.001 , Unit::Temperature );
const Quantity Quantity::MicroKelvin ( 0.000001 , Unit::Temperature );
const Quantity Quantity::Kelvin(1.0, Unit(0, 0, 0, 0, 1));
const Quantity Quantity::MilliKelvin(0.001, Unit(0, 0, 0, 0, 1));
const Quantity Quantity::MicroKelvin(0.000001, Unit(0, 0, 0, 0, 1));
const Quantity Quantity::MilliMole ( 0.001 , Unit::AmountOfSubstance );
const Quantity Quantity::Mole ( 1.0 , Unit::AmountOfSubstance );
const Quantity Quantity::MilliMole(0.001, Unit(0, 0, 0, 0, 0, 1));
const Quantity Quantity::Mole(1.0, Unit(0, 0, 0, 0, 0, 1));
const Quantity Quantity::Candela ( 1.0 , Unit::LuminousIntensity );
const Quantity Quantity::Candela(1.0, Unit(0, 0, 0, 0, 0, 0, 1));
const Quantity Quantity::Inch ( 25.4 , Unit::Length );
const Quantity Quantity::Foot ( 304.8 , Unit::Length );
const Quantity Quantity::Thou ( 0.0254 , Unit::Length );
const Quantity Quantity::Yard ( 914.4 , Unit::Length );
const Quantity Quantity::Mile ( 1609344.0 , Unit::Length );
const Quantity Quantity::Inch(25.4, Unit(1));
const Quantity Quantity::Foot(304.8, Unit(1));
const Quantity Quantity::Thou(0.0254, Unit(1));
const Quantity Quantity::Yard(914.4, Unit(1));
const Quantity Quantity::Mile(1609344.0, Unit(1));
const Quantity Quantity::MilePerHour ( 447.04 , Unit::Velocity );
const Quantity Quantity::SquareFoot ( 92903.04 , Unit::Area );
const Quantity Quantity::CubicFoot ( 28316846.592 , Unit::Volume );
const Quantity Quantity::MilePerHour(447.04, Unit(1, 0, -1));
const Quantity Quantity::SquareFoot(92903.04, Unit(2));
const Quantity Quantity::CubicFoot(28316846.592, Unit(3));
const Quantity Quantity::Pound ( 0.45359237 , Unit::Mass );
const Quantity Quantity::Ounce ( 0.0283495231 , Unit::Mass );
const Quantity Quantity::Stone ( 6.35029318 , Unit::Mass );
const Quantity Quantity::Hundredweights ( 50.80234544 , Unit::Mass );
const Quantity Quantity::Pound(0.45359237, Unit(0, 1));
const Quantity Quantity::Ounce(0.0283495231, Unit(0, 1));
const Quantity Quantity::Stone(6.35029318, Unit(0, 1));
const Quantity Quantity::Hundredweights(50.80234544, Unit(0, 1));
const Quantity Quantity::PoundForce ( 4448.22 , Unit::Force ); // lbf are ~= 4.44822 Newton
const Quantity Quantity::PoundForce(4448.22, Unit(1, 1, -2)); // lbf are ~= 4.44822 Newton
const Quantity Quantity::Newton ( 1000.0 , Unit::Force ); // Newton (kg*m/s^2)
const Quantity Quantity::MilliNewton ( 1.0 , Unit::Force );
const Quantity Quantity::KiloNewton ( 1e+6 , Unit::Force );
const Quantity Quantity::MegaNewton ( 1e+9 , Unit::Force );
const Quantity Quantity::Newton(1000.0, Unit(1, 1, -2)); // Newton (kg*m/s^2)
const Quantity Quantity::MilliNewton(1.0, Unit(1, 1, -2));
const Quantity Quantity::KiloNewton(1e+6, Unit(1, 1, -2));
const Quantity Quantity::MegaNewton(1e+9, Unit(1, 1, -2));
const Quantity Quantity::NewtonPerMeter ( 1.00 , Unit::Stiffness ); // Newton per meter (N/m or kg/s^2)
const Quantity Quantity::MilliNewtonPerMeter ( 1e-3 , Unit::Stiffness );
const Quantity Quantity::KiloNewtonPerMeter ( 1e3 , Unit::Stiffness );
const Quantity Quantity::MegaNewtonPerMeter ( 1e6 , Unit::Stiffness );
const Quantity Quantity::NewtonPerMeter(1.00, Unit(0, 1, -2)); // Newton per meter (N/m or kg/s^2)
const Quantity Quantity::MilliNewtonPerMeter(1e-3, Unit(0, 1, -2));
const Quantity Quantity::KiloNewtonPerMeter(1e3, Unit(0, 1, -2));
const Quantity Quantity::MegaNewtonPerMeter(1e6, Unit(0, 1, -2));
const Quantity Quantity::Pascal ( 0.001 , Unit::CompressiveStrength ); // Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::KiloPascal ( 1.00 , Unit::CompressiveStrength );
const Quantity Quantity::MegaPascal ( 1000.0 , Unit::CompressiveStrength );
const Quantity Quantity::GigaPascal ( 1e+6 , Unit::CompressiveStrength );
const Quantity Quantity::Pascal(0.001, Unit(-1, 1, -2)); // Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::KiloPascal(1.00, Unit(-1, 1, -2));
const Quantity Quantity::MegaPascal(1000.0, Unit(-1, 1, -2));
const Quantity Quantity::GigaPascal(1e+6, Unit(-1, 1, -2));
const Quantity Quantity::MilliBar ( 0.1 , Unit::CompressiveStrength );
const Quantity Quantity::Bar ( 100.0 , Unit::CompressiveStrength ); // 1 bar = 100 kPa
const Quantity Quantity::MilliBar(0.1, Unit(-1, 1, -2));
const Quantity Quantity::Bar(100.0, Unit(-1, 1, -2)); // 1 bar = 100 kPa
const Quantity Quantity::Torr ( 101.325 / 760.0 , Unit::CompressiveStrength ); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::mTorr ( 0.101325 / 760.0 , Unit::CompressiveStrength ); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::yTorr ( 0.000101325 / 760.0 , Unit::CompressiveStrength ); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity
Quantity::Torr(101.325 / 760.0,
Unit(-1, 1, -2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity
Quantity::mTorr(0.101325 / 760.0,
Unit(-1, 1, -2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity
Quantity::yTorr(0.000101325 / 760.0,
Unit(-1, 1, -2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::PSI ( 6.894744825494 , Unit::CompressiveStrength ); // pounds/in^2
const Quantity Quantity::KSI ( 6894.744825494 , Unit::CompressiveStrength ); // 1000 x pounds/in^2
const Quantity Quantity::MPSI ( 6894744.825494 , Unit::CompressiveStrength ); // 1000 ksi
const Quantity Quantity::PSI(6.894744825494, Unit(-1, 1, -2)); // pounds/in^2
const Quantity Quantity::KSI(6894.744825494, Unit(-1, 1, -2)); // 1000 x pounds/in^2
const Quantity Quantity::MPSI(6894744.825494, Unit(-1, 1, -2)); // 1000 ksi
const Quantity Quantity::Watt ( 1e+6 , Unit::Power ); // Watt (kg*m^2/s^3)
const Quantity Quantity::MilliWatt ( 1e+3 , Unit::Power );
const Quantity Quantity::KiloWatt ( 1e+9 , Unit::Power );
const Quantity Quantity::VoltAmpere ( 1e+6 , Unit::Power ); // VoltAmpere (kg*m^2/s^3)
const Quantity Quantity::Watt(1e+6, Unit(2, 1, -3)); // Watt (kg*m^2/s^3)
const Quantity Quantity::MilliWatt(1e+3, Unit(2, 1, -3));
const Quantity Quantity::KiloWatt(1e+9, Unit(2, 1, -3));
const Quantity Quantity::VoltAmpere(1e+6, Unit(2, 1, -3)); // VoltAmpere (kg*m^2/s^3)
const Quantity Quantity::Volt ( 1e+6 , Unit::ElectricPotential ); // Volt (kg*m^2/A/s^3)
const Quantity Quantity::MilliVolt ( 1e+3 , Unit::ElectricPotential );
const Quantity Quantity::KiloVolt ( 1e+9 , Unit::ElectricPotential );
const Quantity Quantity::Volt(1e+6, Unit(2, 1, -3, -1)); // Volt (kg*m^2/A/s^3)
const Quantity Quantity::MilliVolt(1e+3, Unit(2, 1, -3, -1));
const Quantity Quantity::KiloVolt(1e+9, Unit(2, 1, -3, -1));
const Quantity Quantity::MegaSiemens ( 1.0 , Unit::ElectricalConductance );
const Quantity Quantity::KiloSiemens ( 1e-3 , Unit::ElectricalConductance );
const Quantity Quantity::Siemens ( 1e-6 , Unit::ElectricalConductance ); // Siemens (A^2*s^3/kg/m^2)
const Quantity Quantity::MilliSiemens ( 1e-9 , Unit::ElectricalConductance );
const Quantity Quantity::MicroSiemens ( 1e-12 , Unit::ElectricalConductance );
const Quantity Quantity::MegaSiemens(1.0, Unit(-2, -1, 3, 2));
const Quantity Quantity::KiloSiemens(1e-3, Unit(-2, -1, 3, 2));
const Quantity Quantity::Siemens(1e-6, Unit(-2, -1, 3, 2)); // Siemens (A^2*s^3/kg/m^2)
const Quantity Quantity::MilliSiemens(1e-9, Unit(-2, -1, 3, 2));
const Quantity Quantity::MicroSiemens(1e-12, Unit(-2, -1, 3, 2));
const Quantity Quantity::Ohm ( 1e+6 , Unit::ElectricalResistance ); // Ohm (kg*m^2/A^2/s^3)
const Quantity Quantity::KiloOhm ( 1e+9 , Unit::ElectricalResistance );
const Quantity Quantity::MegaOhm ( 1e+12 , Unit::ElectricalResistance );
const Quantity Quantity::Ohm(1e+6, Unit(2, 1, -3, -2)); // Ohm (kg*m^2/A^2/s^3)
const Quantity Quantity::KiloOhm(1e+9, Unit(2, 1, -3, -2));
const Quantity Quantity::MegaOhm(1e+12, Unit(2, 1, -3, -2));
const Quantity Quantity::Coulomb ( 1.0 , Unit::ElectricCharge ); // Coulomb (A*s)
const Quantity Quantity::Coulomb(1.0, Unit(0, 0, 1, 1)); // Coulomb (A*s)
const Quantity Quantity::Tesla ( 1.0 , Unit::MagneticFluxDensity ); // Tesla (kg/s^2/A)
const Quantity Quantity::Gauss ( 1e-4 , Unit::MagneticFluxDensity ); // 1 G = 1e-4 T
const Quantity Quantity::Tesla(1.0, Unit(0, 1, -2, -1)); // Tesla (kg/s^2/A)
const Quantity Quantity::Gauss(1e-4, Unit(0, 1, -2, -1)); // 1 G = 1e-4 T
const Quantity Quantity::Weber ( 1e6 , Unit::MagneticFlux ); // Weber (kg*m^2/s^2/A)
const Quantity Quantity::Weber(1e6, Unit(2, 1, -2, -1)); // Weber (kg*m^2/s^2/A)
const Quantity Quantity::PicoFarad ( 1e-18 , Unit::ElectricalCapacitance );
const Quantity Quantity::NanoFarad ( 1e-15 , Unit::ElectricalCapacitance );
const Quantity Quantity::MicroFarad ( 1e-12 , Unit::ElectricalCapacitance );
const Quantity Quantity::MilliFarad ( 1e-9 , Unit::ElectricalCapacitance );
const Quantity Quantity::Farad ( 1e-6 , Unit::ElectricalCapacitance ); // Farad (s^4*A^2/m^2/kg)
// disable Oersted because people need to input e.g. a field strength of
// 1 ampere per meter -> 1 A/m and not get the recalculation to Oersted
// const Quantity Quantity::Oersted(0.07957747, Unit(-1, 0, 0, 1));// Oersted (A/m)
const Quantity Quantity::NanoHenry ( 1e-3 , Unit::ElectricalInductance );
const Quantity Quantity::MicroHenry ( 1.0 , Unit::ElectricalInductance );
const Quantity Quantity::MilliHenry ( 1e+3 , Unit::ElectricalInductance );
const Quantity Quantity::Henry ( 1e+6 , Unit::ElectricalInductance ); // Henry (kg*m^2/s^2/A^2)
const Quantity Quantity::PicoFarad(1e-18, Unit(-2, -1, 4, 2));
const Quantity Quantity::NanoFarad(1e-15, Unit(-2, -1, 4, 2));
const Quantity Quantity::MicroFarad(1e-12, Unit(-2, -1, 4, 2));
const Quantity Quantity::MilliFarad(1e-9, Unit(-2, -1, 4, 2));
const Quantity Quantity::Farad(1e-6, Unit(-2, -1, 4, 2)); // Farad (s^4*A^2/m^2/kg)
const Quantity Quantity::Joule ( 1e+6 , Unit::Moment ); // Joule (kg*m^2/s^2)
const Quantity Quantity::MilliJoule ( 1e+3 , Unit::Moment );
const Quantity Quantity::KiloJoule ( 1e+9 , Unit::Moment );
const Quantity Quantity::NewtonMeter ( 1e+6 , Unit::Moment ); // Joule (kg*m^2/s^2)
const Quantity Quantity::VoltAmpereSecond ( 1e+6 , Unit::Moment ); // Joule (kg*m^2/s^2)
const Quantity Quantity::WattSecond ( 1e+6 , Unit::Moment ); // Joule (kg*m^2/s^2)
const Quantity Quantity::KiloWattHour ( 3.6e+12 , Unit::Moment ); // 1 kWh = 3.6e6 J
const Quantity Quantity::ElectronVolt ( 1.602176634e-13 , Unit::Moment ); // 1 eV = 1.602176634e-19 J
const Quantity Quantity::KiloElectronVolt ( 1.602176634e-10 , Unit::Moment );
const Quantity Quantity::MegaElectronVolt ( 1.602176634e-7 , Unit::Moment );
const Quantity Quantity::Calorie ( 4.1868e+6 , Unit::Moment ); // 1 cal = 4.1868 J
const Quantity Quantity::KiloCalorie ( 4.1868e+9 , Unit::Moment );
const Quantity Quantity::NanoHenry(1e-3, Unit(2, 1, -2, -2));
const Quantity Quantity::MicroHenry(1.0, Unit(2, 1, -2, -2));
const Quantity Quantity::MilliHenry(1e+3, Unit(2, 1, -2, -2));
const Quantity Quantity::Henry(1e+6, Unit(2, 1, -2, -2)); // Henry (kg*m^2/s^2/A^2)
const Quantity Quantity::Joule(1e+6, Unit(2, 1, -2)); // Joule (kg*m^2/s^2)
const Quantity Quantity::MilliJoule(1e+3, Unit(2, 1, -2));
const Quantity Quantity::KiloJoule(1e+9, Unit(2, 1, -2));
const Quantity Quantity::NewtonMeter(1e+6, Unit(2, 1, -2)); // Joule (kg*m^2/s^2)
const Quantity Quantity::VoltAmpereSecond(1e+6, Unit(2, 1, -2)); // Joule (kg*m^2/s^2)
const Quantity Quantity::WattSecond(1e+6, Unit(2, 1, -2)); // Joule (kg*m^2/s^2)
const Quantity Quantity::KiloWattHour(3.6e+12, Unit(2, 1, -2)); // 1 kWh = 3.6e6 J
const Quantity Quantity::ElectronVolt(1.602176634e-13, Unit(2, 1, -2)); // 1 eV = 1.602176634e-19 J
const Quantity Quantity::KiloElectronVolt(1.602176634e-10, Unit(2, 1, -2));
const Quantity Quantity::MegaElectronVolt(1.602176634e-7, Unit(2, 1, -2));
const Quantity Quantity::Calorie(4.1868e+6, Unit(2, 1, -2)); // 1 cal = 4.1868 J
const Quantity Quantity::KiloCalorie(4.1868e+9, Unit(2, 1, -2));
const Quantity Quantity::KMH(277.778, Unit(1, 0, -1)); // km/h
const Quantity Quantity::MPH(447.04, Unit(1, 0, -1)); // Mile/h
const Quantity Quantity::AngMinute(1.0 / 60.0, Unit(0, 0, 0, 0, 0, 0, 0, 1)); // angular minute
const Quantity Quantity::AngSecond(1.0 / 3600.0, Unit(0, 0, 0, 0, 0, 0, 0, 1)); // angular second
const Quantity
Quantity::Degree(1.0,
Unit(0, 0, 0, 0, 0, 0, 0, 1)); // degree (internal standard angle)
const Quantity Quantity::Radian(180 / std::numbers::pi, Unit(0, 0, 0, 0, 0, 0, 0, 1)); // radian
const Quantity Quantity::Gon(360.0 / 400.0, Unit(0, 0, 0, 0, 0, 0, 0, 1)); // gon
const Quantity Quantity::KMH ( 277.778 , Unit::Velocity ); // km/h
const Quantity Quantity::MPH ( 447.04 , Unit::Velocity ); // Mile/h
const Quantity Quantity::AngMinute ( 1.0 / 60.0 , Unit::Angle ); // angular minute
const Quantity Quantity::AngSecond ( 1.0 / 3600.0 , Unit::Angle ); // angular second
const Quantity Quantity::Degree ( 1.0 , Unit::Angle ); // degree (internal standard angle)
const Quantity Quantity::Radian ( 180 / std::numbers::pi, Unit::Angle ); // radian
const Quantity Quantity::Gon ( 360.0 / 400.0 , Unit::Angle ); // gon
// clang-format on
// === Parser & Scanner stuff ===============================================

View File

@@ -91,45 +91,37 @@ int QuantityPy::PyInit(PyObject* args, PyObject* /*kwd*/)
*self = *(static_cast<QuantityPy*>(object)->getQuantityPtr());
return 0;
}
PyErr_Clear(); // set by PyArg_ParseTuple()
double f = std::numeric_limits<double>::max();
if (PyArg_ParseTuple(args, "dO!", &f, &(UnitPy::Type), &object)) {
*self = Quantity(f, *(static_cast<UnitPy*>(object)->getUnitPtr()));
return 0;
}
PyErr_Clear(); // set by PyArg_ParseTuple()
if (PyArg_ParseTuple(args, "dO!", &f, &(QuantityPy::Type), &object)) {
PyErr_SetString(PyExc_TypeError, "Second argument must be a Unit not a Quantity");
return -1;
}
int i1 = 0;
int i2 = 0;
int i3 = 0;
int i4 = 0;
int i5 = 0;
int i6 = 0;
int i7 = 0;
int i8 = 0;
PyErr_Clear(); // set by PyArg_ParseTuple()
int i1 {0};
int i2 {0};
int i3 {0};
int i4 {0};
int i5 {0};
int i6 {0};
int i7 {0};
int i8 {0};
if (PyArg_ParseTuple(args, "|diiiiiiii", &f, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
if (f < std::numeric_limits<double>::max()) {
*self = Quantity(f,
Unit {static_cast<int8_t>(i1),
static_cast<int8_t>(i2),
static_cast<int8_t>(i3),
static_cast<int8_t>(i4),
static_cast<int8_t>(i5),
static_cast<int8_t>(i6),
static_cast<int8_t>(i7),
static_cast<int8_t>(i8)});
*self = Quantity {f, Unit(i1, i2, i3, i4, i5, i6, i7, i8)};
}
return 0;
}
PyErr_Clear(); // set by PyArg_ParseTuple()
char* string {};
if (PyArg_ParseTuple(args, "et", "utf-8", &string)) {
std::string str(string);
@@ -144,13 +136,13 @@ int QuantityPy::PyInit(PyObject* args, PyObject* /*kwd*/)
return 0;
}
PyErr_Clear(); // set by PyArg_ParseTuple()
if (PyArg_ParseTuple(args, "det", &f, "utf-8", &string)) {
std::string unit(string);
std::string str(string);
PyMem_Free(string);
try {
*self = Quantity(f, unit);
*self = Quantity(f, str);
}
catch (const ParserError& e) {
PyErr_SetString(PyExc_ValueError, e.what());
@@ -210,7 +202,7 @@ PyObject* QuantityPy::getValueAs(PyObject* args) const
};
auto tryUnitPartsAndValue = [&]() -> std::optional<Quantity> {
double f = std::numeric_limits<double>::max();
double f;
int i1 {0};
int i2 {0};
int i3 {0};
@@ -219,20 +211,11 @@ PyObject* QuantityPy::getValueAs(PyObject* args) const
int i6 {0};
int i7 {0};
int i8 {0};
PyErr_Clear();
if (!PyArg_ParseTuple(args, "d|iiiiiiii", &f, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
return std::nullopt;
}
if (f >= std::numeric_limits<double>::max()) {
return std::nullopt;
}
auto re = [](auto val) {
return static_cast<int8_t>(val);
};
return Quantity {f, Unit {re(i1), re(i2), re(i3), re(i4), re(i5), re(i6), re(i7), re(i8)}};
return Quantity {f, Unit(i1, i2, i3, i4, i5, i6, i7, i8)};
};
auto tryString = [&]() -> std::optional<Quantity> {

File diff suppressed because it is too large Load Diff

View File

@@ -1,178 +1,178 @@
/***************************************************************************
* Copyright (c) 2011 Jürgen Riegel <juergen.riegel@web.de> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef BASE_Unit_H
#define BASE_Unit_H
#include <array>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include <FCGlobal.h>
#include "Exception.h"
namespace Base
{
/**
* The Unit class.
*/
class BaseExport Unit
constexpr auto unitSymbols =
std::to_array<std::string_view>({"mm", "kg", "s", "A", "K", "mol", "cd", "deg"});
constexpr auto unitNumExponents {unitSymbols.size()};
using UnitExponents = std::array<int8_t, unitNumExponents>;
constexpr auto unitExponentLimit {8};
class BaseExport Unit final
{
public:
/// default constructor
explicit Unit(int8_t Length,
int8_t Mass = 0,
int8_t Time = 0,
int8_t ElectricCurrent = 0,
int8_t ThermodynamicTemperature = 0,
int8_t AmountOfSubstance = 0,
int8_t LuminousIntensity = 0,
int8_t Angle = 0);
Unit();
Unit(const Unit&) = default;
Unit(Unit&&) = default;
explicit Unit(const std::string& expr);
/// Destruction
~Unit() = default;
Unit() = default;
explicit constexpr Unit(const UnitExponents exps, const std::string_view name = "")
: _exps {exps}
, _name {name}
{
checkRange();
}
/// helper constructor to ease Unit construction from Python
explicit Unit(const int length,
const int mass = 0,
const int time = 0,
const int electricCurrent = 0,
const int thermodynamicTemperature = 0,
const int amountOfSubstance = 0,
const int luminousIntensity = 0,
const int angle = 0);
/** Operators. */
//@{
inline Unit& operator*=(const Unit& that);
inline Unit& operator/=(const Unit& that);
int operator[](int index) const;
Unit operator*(const Unit&) const;
Unit operator/(const Unit&) const;
bool operator==(const Unit&) const;
bool operator!=(const Unit& that) const;
Unit& operator=(const Unit&) = default;
Unit& operator=(Unit&&) = default;
Unit pow(double exp) const;
Unit sqrt() const;
Unit cbrt() const;
//@}
int length() const;
int mass() const;
int time() const;
int electricCurrent() const;
int thermodynamicTemperature() const;
int amountOfSubstance() const;
int luminousIntensity() const;
int angle() const;
Unit& operator*=(const Unit& that);
Unit& operator/=(const Unit& that);
Unit operator*(const Unit&) const;
Unit operator/(const Unit&) const;
std::string getString() const;
/// get the type as an string such as "Area", "Length" or "Pressure".
std::string getTypeString() const;
[[nodiscard]] Unit pow(const double exp) const;
[[nodiscard]] Unit root(const uint8_t num) const;
/** Predefined Unit types. */
//@{
static const Unit One;
/// Length unit
static const Unit Length;
/// Mass unit
static const Unit Mass;
[[nodiscard]] UnitExponents exponents() const;
[[nodiscard]] int length() const;
/// Angle
[[nodiscard]] std::string getString() const; // E.g. kg, mm^2, mm*kg/s^2
[[nodiscard]] std::string getTypeString() const; // E.g. "Area", "Length", "Pressure"
[[nodiscard]] std::string representation() const; // E.g. "Unit: mm (1,0,0,0,0,0,0,0) [Length]"
Unit sqrt() const
{
return root(2);
}
Unit cbrt() const
{
return root(3);
}
private:
UnitExponents _exps {};
std::string_view _name;
constexpr void checkRange()
{
for (const auto exp : _exps) {
if (exp >= unitExponentLimit) {
throw OverflowError("Unit exponent overflow");
}
if (exp < -unitExponentLimit) {
throw UnderflowError("Unit exponent underflow");
}
}
}
/** Returns posIndexes, negIndexes*/
std::pair<std::vector<size_t>, std::vector<size_t>> nonZeroValsIndexes() const;
public:
static const Unit Acceleration;
static const Unit AmountOfSubstance;
static const Unit Angle;
static const Unit AngleOfFriction;
static const Unit Density;
static const Unit Area;
static const Unit Volume;
static const Unit TimeSpan;
static const Unit Frequency;
static const Unit Velocity;
static const Unit Acceleration;
static const Unit Temperature;
static const Unit CompressiveStrength;
static const Unit CurrentDensity;
static const Unit Density;
static const Unit DissipationRate;
static const Unit DynamicViscosity;
static const Unit ElectricalCapacitance;
static const Unit ElectricalConductance;
static const Unit ElectricalConductivity;
static const Unit ElectricalInductance;
static const Unit ElectricalResistance;
static const Unit ElectricCharge;
static const Unit ElectricCurrent;
static const Unit ElectricPotential;
static const Unit ElectricCharge;
static const Unit SurfaceChargeDensity;
static const Unit VolumeChargeDensity;
static const Unit ElectromagneticPotential;
static const Unit Force;
static const Unit Frequency;
static const Unit HeatFlux;
static const Unit InverseArea;
static const Unit InverseLength;
static const Unit InverseVolume;
static const Unit KinematicViscosity;
static const Unit Length;
static const Unit LuminousIntensity;
static const Unit MagneticFieldStrength;
static const Unit MagneticFlux;
static const Unit MagneticFluxDensity;
static const Unit Magnetization;
static const Unit ElectricalCapacitance;
static const Unit ElectricalInductance;
static const Unit ElectricalConductance;
static const Unit ElectricalResistance;
static const Unit ElectricalConductivity;
static const Unit ElectromagneticPotential;
static const Unit AmountOfSubstance;
static const Unit LuminousIntensity;
// Pressure
static const Unit CompressiveStrength;
static const Unit Mass;
static const Unit Moment;
static const Unit One;
static const Unit Pressure;
static const Unit Power;
static const Unit ShearModulus;
static const Unit Stress;
static const Unit UltimateTensileStrength;
static const Unit YieldStrength;
static const Unit YoungsModulus;
static const Unit SpecificEnergy;
static const Unit SpecificHeat;
static const Unit Stiffness;
static const Unit StiffnessDensity;
static const Unit Force;
static const Unit Work;
static const Unit Power;
static const Unit Moment;
static const Unit SpecificEnergy;
static const Unit Stress;
static const Unit SurfaceChargeDensity;
static const Unit Temperature;
static const Unit TimeSpan;
static const Unit ThermalConductivity;
static const Unit ThermalExpansionCoefficient;
static const Unit VolumetricThermalExpansionCoefficient;
static const Unit SpecificHeat;
static const Unit ThermalTransferCoefficient;
static const Unit HeatFlux;
static const Unit DynamicViscosity;
static const Unit KinematicViscosity;
static const Unit UltimateTensileStrength;
static const Unit VacuumPermittivity;
static const Unit Velocity;
static const Unit Volume;
static const Unit VolumeChargeDensity;
static const Unit VolumeFlowRate;
static const Unit DissipationRate;
static const Unit InverseLength;
static const Unit InverseArea;
static const Unit InverseVolume;
//@}
private:
uint32_t Val;
static const Unit VolumetricThermalExpansionCoefficient;
static const Unit Work;
static const Unit YieldStrength;
static const Unit YoungsModulus;
};
inline Unit& Unit::operator*=(const Unit& that)
{
*this = *this * that;
return *this;
}
inline Unit& Unit::operator/=(const Unit& that)
{
*this = *this / that;
return *this;
}
} // namespace Base
#endif // BASE_Unit_H

View File

@@ -21,6 +21,10 @@
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <algorithm>
#include <ranges>
#endif
#include "Unit.h"
@@ -35,25 +39,7 @@ using namespace Base;
// returns a string which represents the object e.g. when printed in python
std::string UnitPy::representation() const
{
std::stringstream ret;
Unit* self = getUnitPtr();
ret << "Unit: ";
ret << self->getString() << " (";
ret << (*self).length() << ",";
ret << (*self).mass() << ",";
ret << (*self).time() << ",";
ret << (*self).electricCurrent() << ",";
ret << (*self).thermodynamicTemperature() << ",";
ret << (*self).amountOfSubstance() << ",";
ret << (*self).luminousIntensity() << ",";
ret << (*self).angle() << ")";
std::string type = self->getTypeString();
if (!type.empty()) {
ret << " [" << type << "]";
}
return ret.str();
return getUnitPtr()->representation();
}
PyObject* UnitPy::PyMake(PyTypeObject* /*unused*/, PyObject* /*unused*/, PyObject* /*unused*/)
@@ -98,14 +84,14 @@ int UnitPy::PyInit(PyObject* args, PyObject* /*kwd*/)
}
PyErr_Clear(); // set by PyArg_ParseTuple()
int i1 = 0;
int i2 = 0;
int i3 = 0;
int i4 = 0;
int i5 = 0;
int i6 = 0;
int i7 = 0;
int i8 = 0;
int i1 {0};
int i2 {0};
int i3 {0};
int i4 {0};
int i5 {0};
int i6 {0};
int i7 {0};
int i8 {0};
if (PyArg_ParseTuple(args, "|iiiiiiii", &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
try {
*self = Unit(i1, i2, i3, i4, i5, i6, i7, i8);
@@ -115,6 +101,10 @@ int UnitPy::PyInit(PyObject* args, PyObject* /*kwd*/)
PyErr_SetString(PyExc_OverflowError, e.what());
return -1;
}
catch (const UnderflowError& e) {
PyErr_SetString(PyExc_OverflowError, e.what());
return -1;
}
}
PyErr_SetString(PyExc_TypeError, "Either string, (float,8 ints), Unit() or Quantity()");
@@ -213,13 +203,11 @@ Py::String UnitPy::getType() const
Py::Tuple UnitPy::getSignature() const
{
Py::Tuple tuple(8);
Unit* self = getUnitPtr();
for (auto i = 0; i < tuple.size(); i++) {
tuple.setItem(i, Py::Long((*self)[i]));
}
Py::Tuple tuple {unitNumExponents};
auto exps = getUnitPtr()->exponents();
std::ranges::for_each(exps, [&, pos {0}](auto exp) mutable {
tuple.setItem(pos++, Py::Long {exp});
});
return tuple;
}

View File

@@ -30,6 +30,7 @@
#include "Dialogs/DlgUnitsCalculatorImp.h"
#include "ui_DlgUnitsCalculator.h"
#include <Base/Quantity.h>
#include <Base/UnitsApi.h>
using namespace Gui::Dialog;
@@ -133,19 +134,24 @@ void DlgUnitsCalculator::textChanged(QString unit)
void DlgUnitsCalculator::valueChanged(const Quantity& quant)
{
std::string unitTypeStr;
try {
unitTypeStr =
Quantity::parse(ui->UnitInput->text().toStdString()).getUnit().getTypeString();
}
catch (const Base::ParserError&) {
}
// first check the unit, if it is invalid, getTypeString() outputs an empty string
// explicitly check for "ee" like in "eeV" because this would trigger an exception in Unit
// since it expects then a scientific notation number like "1e3"
if ((ui->UnitInput->text().mid(0, 2) == QStringLiteral("ee"))
|| Unit(ui->UnitInput->text().toStdString()).getTypeString().empty()) {
if ((ui->UnitInput->text().mid(0, 2) == QStringLiteral("ee")) || unitTypeStr.empty()) {
ui->ValueOutput->setText(
QStringLiteral("%1 %2").arg(tr("unknown unit:"), ui->UnitInput->text()));
ui->pushButton_Copy->setEnabled(false);
}
else { // the unit is valid
// we can only convert units of the same type, thus check
if (Unit(ui->UnitInput->text().toStdString()).getTypeString()
!= quant.getUnit().getTypeString()) {
if (unitTypeStr != quant.getUnit().getTypeString()) {
ui->ValueOutput->setText(tr("unit mismatch"));
ui->pushButton_Copy->setEnabled(false);
}

View File

@@ -37,16 +37,12 @@ protected:
App::DocumentObject* this_obj() { return _this_obj; }
Base::Quantity parse_expression_text_as_quantity(const char* expression_text) {
auto expression = App::ExpressionParser::parse(this_obj(), expression_text);
auto expression_value = expression->getValueAsAny();
auto quantity_result = App::any_cast<Base::Quantity>(expression_value);
return quantity_result;
const auto expression = App::ExpressionParser::parse(this_obj(), expression_text);
return App::any_cast<Base::Quantity>(expression->getValueAsAny());
}
Base::Quantity parse_quantity_text_as_quantity(const char* quantity_text) {
auto quantity_str = std::string(quantity_text);
auto quantity_result = Base::Quantity::parse(quantity_str);
return quantity_result;
return Base::Quantity::parse(quantity_text);
}
private:

View File

@@ -3,191 +3,154 @@
#include <Base/Exception.h>
// NOLINTBEGIN
TEST(Unit, TestString)
using namespace Base;
TEST(Unit, string_simple_numerator_no_denominator)
{
auto toString = [](const Base::Unit& unit) {
return unit.getString();
};
EXPECT_EQ(toString(Base::Unit(0, 0, 0, 0, 0, 0, 0, 0)), "");
EXPECT_EQ(toString(Base::Unit(1, 0, 0, 0, 0, 0, 0, 0)), "mm");
EXPECT_EQ(toString(Base::Unit(0, 1, 0, 0, 0, 0, 0, 0)), "kg");
EXPECT_EQ(toString(Base::Unit(0, 0, 1, 0, 0, 0, 0, 0)), "s");
EXPECT_EQ(toString(Base::Unit(0, 0, 0, 1, 0, 0, 0, 0)), "A");
EXPECT_EQ(toString(Base::Unit(0, 0, 0, 0, 1, 0, 0, 0)), "K");
EXPECT_EQ(toString(Base::Unit(0, 0, 0, 0, 0, 1, 0, 0)), "mol");
EXPECT_EQ(toString(Base::Unit(0, 0, 0, 0, 0, 0, 1, 0)), "cd");
EXPECT_EQ(toString(Base::Unit(0, 0, 0, 0, 0, 0, 0, 1)), "deg");
EXPECT_EQ(toString(Base::Unit(2, 0, 0, 0, 0, 0, 0, 0)), "mm^2");
EXPECT_EQ(toString(Base::Unit(1, 1, -2, 0, 0, 0, 0, 0)), "mm*kg/s^2");
EXPECT_EQ(Unit::Length.getString(), "mm");
}
TEST(Unit, TestTypeString)
TEST(Unit, string_complex_numerator_no_denominator)
{
auto toString = [](const Base::Unit& unit) {
return unit.getTypeString();
};
EXPECT_EQ(toString(Base::Unit::Acceleration), "Acceleration");
EXPECT_EQ(toString(Base::Unit::AmountOfSubstance), "AmountOfSubstance");
EXPECT_EQ(toString(Base::Unit::Angle), "Angle");
EXPECT_EQ(toString(Base::Unit::AngleOfFriction), "Angle"); // same unit as Angle
EXPECT_EQ(toString(Base::Unit::Area), "Area");
EXPECT_EQ(toString(Base::Unit::CurrentDensity), "CurrentDensity");
EXPECT_EQ(toString(Base::Unit::Density), "Density");
EXPECT_EQ(toString(Base::Unit::DissipationRate), "DissipationRate");
EXPECT_EQ(toString(Base::Unit::DynamicViscosity), "DynamicViscosity");
EXPECT_EQ(toString(Base::Unit::ElectricalCapacitance), "ElectricalCapacitance");
EXPECT_EQ(toString(Base::Unit::ElectricalConductance), "ElectricalConductance");
EXPECT_EQ(toString(Base::Unit::ElectricalConductivity), "ElectricalConductivity");
EXPECT_EQ(toString(Base::Unit::ElectricalInductance), "ElectricalInductance");
EXPECT_EQ(toString(Base::Unit::ElectricalResistance), "ElectricalResistance");
EXPECT_EQ(toString(Base::Unit::ElectricCharge), "ElectricCharge");
EXPECT_EQ(toString(Base::Unit::ElectricCurrent), "ElectricCurrent");
EXPECT_EQ(toString(Base::Unit::ElectricPotential), "ElectricPotential");
EXPECT_EQ(toString(Base::Unit::Frequency), "Frequency");
EXPECT_EQ(toString(Base::Unit::Force), "Force");
EXPECT_EQ(toString(Base::Unit::HeatFlux), "HeatFlux");
EXPECT_EQ(toString(Base::Unit::InverseArea), "InverseArea");
EXPECT_EQ(toString(Base::Unit::InverseLength), "InverseLength");
EXPECT_EQ(toString(Base::Unit::InverseVolume), "InverseVolume");
EXPECT_EQ(toString(Base::Unit::KinematicViscosity), "KinematicViscosity");
EXPECT_EQ(toString(Base::Unit::Length), "Length");
EXPECT_EQ(toString(Base::Unit::LuminousIntensity), "LuminousIntensity");
EXPECT_EQ(toString(Base::Unit::MagneticFieldStrength), "MagneticFieldStrength");
EXPECT_EQ(toString(Base::Unit::MagneticFlux), "MagneticFlux");
EXPECT_EQ(toString(Base::Unit::MagneticFluxDensity), "MagneticFluxDensity");
EXPECT_EQ(toString(Base::Unit::Magnetization),
"MagneticFieldStrength"); // same as MagneticFieldStrength
EXPECT_EQ(toString(Base::Unit::Mass), "Mass");
EXPECT_EQ(toString(Base::Unit::Pressure), "Pressure");
EXPECT_EQ(toString(Base::Unit::Power), "Power");
EXPECT_EQ(toString(Base::Unit::ShearModulus), "Pressure"); // same as Pressure
EXPECT_EQ(toString(Base::Unit::SpecificEnergy), "SpecificEnergy");
EXPECT_EQ(toString(Base::Unit::SpecificHeat), "SpecificHeat");
EXPECT_EQ(toString(Base::Unit::Stiffness), "Stiffness");
EXPECT_EQ(toString(Base::Unit::Stress), "Pressure"); // same as Pressure
EXPECT_EQ(toString(Base::Unit::Temperature), "Temperature");
EXPECT_EQ(toString(Base::Unit::ThermalConductivity), "ThermalConductivity");
EXPECT_EQ(toString(Base::Unit::ThermalExpansionCoefficient), "ThermalExpansionCoefficient");
EXPECT_EQ(toString(Base::Unit::ThermalTransferCoefficient), "ThermalTransferCoefficient");
EXPECT_EQ(toString(Base::Unit::TimeSpan), "TimeSpan");
EXPECT_EQ(toString(Base::Unit::UltimateTensileStrength), "Pressure"); // same as Pressure
EXPECT_EQ(toString(Base::Unit::VacuumPermittivity), "VacuumPermittivity");
EXPECT_EQ(toString(Base::Unit::Velocity), "Velocity");
EXPECT_EQ(toString(Base::Unit::Volume), "Volume");
EXPECT_EQ(toString(Base::Unit::VolumeFlowRate), "VolumeFlowRate");
EXPECT_EQ(toString(Base::Unit::VolumetricThermalExpansionCoefficient),
"ThermalExpansionCoefficient");
EXPECT_EQ(toString(Base::Unit::Work), "Work");
EXPECT_EQ(toString(Base::Unit::YieldStrength), "Pressure"); // same as Pressure
EXPECT_EQ(toString(Base::Unit::YoungsModulus), "Pressure"); // same unit as Pressure
EXPECT_EQ(Unit::Area.getString(), "mm^2");
}
TEST(Unit, strings)
TEST(Unit, string_complex_single_denominator)
{
EXPECT_STREQ(Base::Unit::Acceleration.getString().c_str(), "mm/s^2");
EXPECT_STREQ(Base::Unit::AmountOfSubstance.getString().c_str(), "mol");
EXPECT_STREQ(Base::Unit::Angle.getString().c_str(), "deg");
EXPECT_STREQ(Base::Unit::AngleOfFriction.getString().c_str(), "deg");
EXPECT_STREQ(Base::Unit::Area.getString().c_str(), "mm^2");
EXPECT_STREQ(Base::Unit::CurrentDensity.getString().c_str(), "A/mm^2");
EXPECT_STREQ(Base::Unit::Density.getString().c_str(), "kg/mm^3");
EXPECT_STREQ(Base::Unit::DissipationRate.getString().c_str(), "mm^2/s^3");
EXPECT_EQ(Unit::DissipationRate.getString(), "mm^2/s^3");
}
TEST(Unit, string_no_numerator)
{
EXPECT_EQ(Unit::InverseArea.getString(), "1/mm^2");
}
TEST(Unit, string_complex_multi_denominator)
{
EXPECT_EQ(Unit::MagneticFlux.getString(), "mm^2*kg/(s^2*A)");
}
TEST(Unit, type_string)
{
EXPECT_EQ(Unit::MagneticFlux.getTypeString(), "MagneticFlux");
}
TEST(Unit, TestEqual)
{
Base::Unit unit {1};
EXPECT_EQ(unit.pow(2) == Base::Unit {2}, true);
EXPECT_TRUE(Unit::Length == Unit::Length);
}
TEST(Unit, TestNotEqual)
{
Base::Unit unit {1};
EXPECT_EQ(unit.pow(2) != Base::Unit {1}, true);
EXPECT_TRUE(Unit::Length != Unit::Area);
}
TEST(Unit, multiply_One_is_One)
{
EXPECT_EQ(Unit::One * Unit::One, Unit::One);
}
TEST(Unit, TestMult)
{
EXPECT_EQ(Base::Unit {} * Base::Unit {}, Base::Unit {});
EXPECT_EQ(Base::Unit(0, 1) * Base::Unit(1, 0), Base::Unit(1, 1));
constexpr UnitExponents arr {1, 1, 0, 0, 0, 0, 0, 0};
EXPECT_EQ(Unit::Mass * Unit::Length, Unit {arr});
}
TEST(Unit, TestDiv)
TEST(Unit, div)
{
EXPECT_EQ(Base::Unit {} * Base::Unit {}, Base::Unit {});
EXPECT_EQ(Base::Unit(0, 1) / Base::Unit(1, 0), Base::Unit(-1, 1));
EXPECT_EQ(Unit::Area / Unit::Length, Unit::Length);
}
TEST(Unit, TestPowNoDim)
TEST(Unit, div_by_One_does_nothing)
{
Base::Unit unit {};
EXPECT_EQ(unit.pow(2), Base::Unit {0});
EXPECT_EQ(unit == Base::Unit::One, true);
EXPECT_EQ(Unit::Area / Unit::One, Unit::Area);
}
TEST(Unit, TestPowEQ1)
TEST(Unit, pow_0_is_One)
{
Base::Unit unit {2};
EXPECT_EQ(unit.pow(1), Base::Unit {2});
EXPECT_EQ(Unit::Area.pow(0), Unit::One);
}
TEST(Unit, TestPowEQ0)
TEST(Unit, pow_1_leaves_unit_unchanged)
{
Base::Unit unit {2};
EXPECT_EQ(unit.pow(0), Base::Unit {0});
EXPECT_EQ(Unit::Area.pow(1), Unit::Area);
}
TEST(Unit, TestPowGT1)
TEST(Unit, pow_2_is_squared)
{
Base::Unit unit {2};
EXPECT_EQ(unit.pow(2), Base::Unit {4});
EXPECT_EQ(Unit::Length.pow(2), Unit::Area);
}
TEST(Unit, TestPowLT1)
TEST(Unit, pow_3_is_cubed)
{
Base::Unit unit {3};
EXPECT_EQ(unit.pow(1.0 / 3.0), Base::Unit {1});
EXPECT_EQ(Unit::Length.pow(3), Unit::Volume);
}
TEST(Unit, TestPow3DIV2)
TEST(Unit, pow_less_than_one)
{
Base::Unit unit {3};
EXPECT_THROW(unit.pow(3.0 / 2.0), Base::UnitsMismatchError);
EXPECT_EQ(Unit::Volume.pow(1.0 / 3.0), Unit::Length);
}
TEST(Unit, TestOverflow)
TEST(Unit, one_still_one_after_pow)
{
// this tests _that_ the expected exception is thrown
EXPECT_THROW(
{
try {
Base::Unit unit {3};
unit.pow(10000);
}
catch (const Base::OverflowError& e) {
// and this tests that it has the correct message
EXPECT_STREQ("Unit overflow in pow()", e.what());
throw;
}
},
Base::OverflowError);
EXPECT_EQ(Unit::One.pow(2), Unit::One);
}
TEST(Unit, TestUnderflow)
TEST(Unit, square_root)
{
// this tests _that_ the expected exception is thrown
EXPECT_THROW(
{
try {
Base::Unit unit {3};
unit.pow(-10000);
}
catch (const Base::UnderflowError& e) {
// and this tests that it has the correct message
EXPECT_STREQ("Unit underflow in pow()", e.what());
throw;
}
},
Base::UnderflowError);
EXPECT_EQ(Unit::Area.root(2), Unit::Length);
}
// NOLINTEND
TEST(Unit, cube_root)
{
EXPECT_EQ(Unit::Volume.root(3), Unit::Length);
}
TEST(Unit, zero_root)
{
EXPECT_THROW([[maybe_unused]] auto res = Unit::Area.root(0), UnitsMismatchError);
}
TEST(Unit, one_root)
{
EXPECT_EQ(Unit::Area.root(1), Unit::Area);
}
TEST(Unit, TestPow3div2)
{
EXPECT_THROW([[maybe_unused]] auto res = Unit::Volume.pow(3.0 / 2.0), UnitsMismatchError);
}
TEST(Unit, overflow)
{
constexpr UnitExponents arr {99, 0, 0, 0, 0, 0, 0, 0};
EXPECT_THROW([[maybe_unused]] auto res = Unit {arr}, OverflowError);
}
TEST(Unit, underflow)
{
constexpr UnitExponents arr {-99, 0, 0, 0, 0, 0, 0, 0};
EXPECT_THROW([[maybe_unused]] auto res = Unit {arr}, UnderflowError);
}
TEST(Unit, representation_simple)
{
const std::string expect {"Unit: mm (1,0,0,0,0,0,0,0) [Length]"};
const auto actual = Unit::Length.representation();
EXPECT_EQ(actual, expect);
}
TEST(Unit, representation_complex)
{
const std::string expect {"Unit: mm^2*kg/(s^2*A) (2,1,-2,-1,0,0,0,0) [MagneticFlux]"};
const auto actual = Unit::MagneticFlux.representation();
EXPECT_EQ(actual, expect);
}
TEST(Unit, representation_no_name)
{
constexpr Unit unit {{1, 1}};
const std::string expect {"Unit: mm*kg (1,1,0,0,0,0,0,0)"};
const auto actual = unit.representation();
EXPECT_EQ(actual, expect);
}