From 539b7d43cfb48ecfb5ffcc8178494125d60fb682 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Sun, 7 Jul 2024 21:09:59 +0200 Subject: [PATCH] Base: Units: hide internals --- src/App/Expression.cpp | 52 +-- src/Base/Unit.cpp | 552 ++++++++++++++++++------------ src/Base/Unit.h | 42 +-- src/Base/UnitPyImp.cpp | 41 +-- src/Gui/DlgUnitsCalculatorImp.cpp | 4 +- 5 files changed, 373 insertions(+), 318 deletions(-) diff --git a/src/App/Expression.cpp b/src/App/Expression.cpp index 7ec87852da..a664624149 100644 --- a/src/App/Expression.cpp +++ b/src/App/Expression.cpp @@ -2453,56 +2453,12 @@ Py::Object FunctionExpression::evaluate(const Expression *expr, int f, const std case ABS: unit = v1.getUnit(); break; - case SQRT: { - unit = v1.getUnit(); - - // All components of unit must be either zero or dividable by 2 - UnitSignature s = unit.getSignature(); - if ( !((s.Length % 2) == 0) && - ((s.Mass % 2) == 0) && - ((s.Time % 2) == 0) && - ((s.ElectricCurrent % 2) == 0) && - ((s.ThermodynamicTemperature % 2) == 0) && - ((s.AmountOfSubstance % 2) == 0) && - ((s.LuminousIntensity % 2) == 0) && - ((s.Angle % 2) == 0)) - _EXPR_THROW("All dimensions must be even to compute the square root.",expr); - - unit = Unit(s.Length /2, - s.Mass / 2, - s.Time / 2, - s.ElectricCurrent / 2, - s.ThermodynamicTemperature / 2, - s.AmountOfSubstance / 2, - s.LuminousIntensity / 2, - s.Angle); + case SQRT: + unit = v1.getUnit().sqrt(); break; - } - case CBRT: { - unit = v1.getUnit(); - - // All components of unit must be either zero or dividable by 3 - UnitSignature s = unit.getSignature(); - if ( !((s.Length % 3) == 0) && - ((s.Mass % 3) == 0) && - ((s.Time % 3) == 0) && - ((s.ElectricCurrent % 3) == 0) && - ((s.ThermodynamicTemperature % 3) == 0) && - ((s.AmountOfSubstance % 3) == 0) && - ((s.LuminousIntensity % 3) == 0) && - ((s.Angle % 3) == 0)) - _EXPR_THROW("All dimensions must be multiples of 3 to compute the cube root.",expr); - - unit = Unit(s.Length /3, - s.Mass / 3, - s.Time / 3, - s.ElectricCurrent / 3, - s.ThermodynamicTemperature / 3, - s.AmountOfSubstance / 3, - s.LuminousIntensity / 3, - s.Angle); + case CBRT: + unit = v1.getUnit().cbrt(); break; - } case ATAN2: if (e2.isNone()) _EXPR_THROW("Invalid second argument.",expr); diff --git a/src/Base/Unit.cpp b/src/Base/Unit.cpp index d60c3178d7..ac276af573 100644 --- a/src/Base/Unit.cpp +++ b/src/Base/Unit.cpp @@ -35,24 +35,28 @@ using namespace Base; // clang-format off -static inline void checkPow(UnitSignature sig, double exp) -{ - auto isInt = [](double value) { - return std::fabs(std::round(value) - value) < std::numeric_limits::epsilon(); - }; - if (!isInt(sig.Length * exp) || - !isInt(sig.Mass * exp) || - !isInt(sig.Time * exp) || - !isInt(sig.ElectricCurrent * exp) || - !isInt(sig.ThermodynamicTemperature * exp) || - !isInt(sig.AmountOfSubstance * exp) || - !isInt(sig.LuminousIntensity * exp) || - !isInt(sig.Angle * exp)) { - throw Base::UnitsMismatchError("pow() of unit not possible"); - } -} +constexpr int UnitSignatureLengthBits = 4; +constexpr int UnitSignatureMassBits = 4; +constexpr int UnitSignatureTimeBits = 4; +constexpr int UnitSignatureElectricCurrentBits = 4; +constexpr int UnitSignatureThermodynamicTemperatureBits = 4; +constexpr int UnitSignatureAmountOfSubstanceBits = 4; +constexpr int UnitSignatureLuminousIntensityBits = 4; +constexpr int UnitSignatureAngleBits = 4; -static inline void checkRange(const char * op, int length, int mass, int time, int electricCurrent, +struct UnitSignature { + int32_t Length: UnitSignatureLengthBits; + int32_t Mass: UnitSignatureMassBits; + int32_t Time: UnitSignatureTimeBits; + int32_t ElectricCurrent: UnitSignatureElectricCurrentBits; + int32_t ThermodynamicTemperature: UnitSignatureThermodynamicTemperatureBits; + int32_t AmountOfSubstance: UnitSignatureAmountOfSubstanceBits; + int32_t LuminousIntensity: UnitSignatureLuminousIntensityBits; + int32_t Angle: UnitSignatureAngleBits; +}; + +static inline uint32_t sigVal(const std::string &op, + int length, int mass, int time, int electricCurrent, int thermodynamicTemperature, int amountOfSubstance, int luminousIntensity, int angle) { if ( ( length >= (1 << (UnitSignatureLengthBits - 1)) ) || @@ -63,7 +67,7 @@ static inline void checkRange(const char * op, int length, int mass, int time, i ( amountOfSubstance >= (1 << (UnitSignatureAmountOfSubstanceBits - 1)) ) || ( luminousIntensity >= (1 << (UnitSignatureLuminousIntensityBits - 1)) ) || ( angle >= (1 << (UnitSignatureAngleBits - 1)) ) ) { - throw Base::OverflowError((std::string("Unit overflow in ") + std::string(op)).c_str()); + throw Base::OverflowError(("Unit overflow in " + op).c_str()); } if ( ( length < -(1 << (UnitSignatureLengthBits - 1)) ) || ( mass < -(1 << (UnitSignatureMassBits - 1)) ) || @@ -73,10 +77,25 @@ static inline void checkRange(const char * op, int length, int mass, int time, i ( amountOfSubstance < -(1 << (UnitSignatureAmountOfSubstanceBits - 1)) ) || ( luminousIntensity < -(1 << (UnitSignatureLuminousIntensityBits - 1)) ) || ( angle < -(1 << (UnitSignatureAngleBits - 1)) ) ) { - throw Base::UnderflowError((std::string("Unit underflow in ") + std::string(op)).c_str()); + throw Base::UnderflowError(("Unit underflow in " + op).c_str()); } + + UnitSignature Sig; + Sig.Length = length; + Sig.Mass = mass; + Sig.Time = time; + Sig.ElectricCurrent = electricCurrent; + Sig.ThermodynamicTemperature = thermodynamicTemperature; + Sig.AmountOfSubstance = amountOfSubstance; + Sig.LuminousIntensity = luminousIntensity; + Sig.Angle = angle; + + uint32_t ret; + memcpy(&ret, &Sig, sizeof(ret)); + return ret; } + Unit::Unit(int8_t Length, //NOLINT int8_t Mass, int8_t Time, @@ -86,37 +105,21 @@ Unit::Unit(int8_t Length, //NOLINT int8_t LuminousIntensity, int8_t Angle) { - checkRange("unit", - Length, - Mass, - Time, - ElectricCurrent, - ThermodynamicTemperature, - AmountOfSubstance, - LuminousIntensity, - Angle); - - Sig.Length = Length; - Sig.Mass = Mass; - Sig.Time = Time; - Sig.ElectricCurrent = ElectricCurrent; - Sig.ThermodynamicTemperature = ThermodynamicTemperature; - Sig.AmountOfSubstance = AmountOfSubstance; - Sig.LuminousIntensity = LuminousIntensity; - Sig.Angle = Angle; + Val = sigVal("unit", + Length, + Mass, + Time, + ElectricCurrent, + ThermodynamicTemperature, + AmountOfSubstance, + LuminousIntensity, + Angle); } Unit::Unit() //NOLINT { - Sig.Length = 0; - Sig.Mass = 0; - Sig.Time = 0; - Sig.ElectricCurrent = 0; - Sig.ThermodynamicTemperature = 0; - Sig.AmountOfSubstance = 0; - Sig.LuminousIntensity = 0; - Sig.Angle = 0; + Val = 0; } Unit::Unit(const QString& expr) // NOLINT @@ -125,218 +128,335 @@ Unit::Unit(const QString& expr) // NOLINT *this = Quantity::parse(expr).getUnit(); } catch (const Base::ParserError&) { - Sig.Length = 0; - Sig.Mass = 0; - Sig.Time = 0; - Sig.ElectricCurrent = 0; - Sig.ThermodynamicTemperature = 0; - Sig.AmountOfSubstance = 0; - Sig.LuminousIntensity = 0; - Sig.Angle = 0; + Val = 0; } } Unit Unit::pow(double exp) const { - checkPow(Sig, exp); - checkRange("pow()", - static_cast(Sig.Length * exp), - static_cast(Sig.Mass * exp), - static_cast(Sig.Time * exp), - static_cast(Sig.ElectricCurrent * exp), - static_cast(Sig.ThermodynamicTemperature * exp), - static_cast(Sig.AmountOfSubstance * exp), - static_cast(Sig.LuminousIntensity * exp), - static_cast(Sig.Angle * exp)); + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + auto isInt = [](double value) { + return std::fabs(std::round(value) - value) < std::numeric_limits::epsilon(); + }; + if (!isInt(sig.Length * exp) || + !isInt(sig.Mass * exp) || + !isInt(sig.Time * exp) || + !isInt(sig.ElectricCurrent * exp) || + !isInt(sig.ThermodynamicTemperature * exp) || + !isInt(sig.AmountOfSubstance * exp) || + !isInt(sig.LuminousIntensity * exp) || + !isInt(sig.Angle * exp)) + throw Base::UnitsMismatchError("pow() of unit not possible"); Unit result; - result.Sig.Length = static_cast(Sig.Length * exp); - result.Sig.Mass = static_cast(Sig.Mass * exp); - result.Sig.Time = static_cast(Sig.Time * exp); - result.Sig.ElectricCurrent = static_cast(Sig.ElectricCurrent * exp); - result.Sig.ThermodynamicTemperature = static_cast(Sig.ThermodynamicTemperature * exp); - result.Sig.AmountOfSubstance = static_cast(Sig.AmountOfSubstance * exp); - result.Sig.LuminousIntensity = static_cast(Sig.LuminousIntensity * exp); - result.Sig.Angle = static_cast(Sig.Angle * exp); + result.Val = sigVal("pow()", + sig.Length * exp, + sig.Mass * exp, + sig.Time * exp, + sig.ElectricCurrent * exp, + sig.ThermodynamicTemperature * exp, + sig.AmountOfSubstance * exp, + sig.LuminousIntensity * exp, + sig.Angle * exp); return result; } -bool Unit::isEmpty()const +Unit Unit::sqrt() const { - return (this->Sig.Length == 0) - && (this->Sig.Mass == 0) - && (this->Sig.Time == 0) - && (this->Sig.ElectricCurrent == 0) - && (this->Sig.ThermodynamicTemperature == 0) - && (this->Sig.AmountOfSubstance == 0) - && (this->Sig.LuminousIntensity == 0) - && (this->Sig.Angle == 0); + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + // All components of unit must be either zero or dividable by 2 + if (!((sig.Length % 2) == 0) && + ((sig.Mass % 2) == 0) && + ((sig.Time % 2) == 0) && + ((sig.ElectricCurrent % 2) == 0) && + ((sig.ThermodynamicTemperature % 2) == 0) && + ((sig.AmountOfSubstance % 2) == 0) && + ((sig.LuminousIntensity % 2) == 0) && + ((sig.Angle % 2) == 0)) + throw Base::UnitsMismatchError("sqrt() needs even dimensions"); + + Unit result; + result.Val = sigVal("sqrt()", + sig.Length >> 1, + sig.Mass >> 1, + sig.Time >> 1, + sig.ElectricCurrent >> 1, + sig.ThermodynamicTemperature >> 1, + sig.AmountOfSubstance >> 1, + sig.LuminousIntensity >> 1, + sig.Angle >> 1); + + return result; +} + +Unit Unit::cbrt() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + // All components of unit must be either zero or dividable by 3 + if (!((sig.Length % 3) == 0) && + ((sig.Mass % 3) == 0) && + ((sig.Time % 3) == 0) && + ((sig.ElectricCurrent % 3) == 0) && + ((sig.ThermodynamicTemperature % 3) == 0) && + ((sig.AmountOfSubstance % 3) == 0) && + ((sig.LuminousIntensity % 3) == 0) && + ((sig.Angle % 3) == 0)) + throw Base::UnitsMismatchError("cbrt() needs dimensions to be multiples of 3"); + + Unit result; + result.Val = sigVal("cbrt()", + sig.Length / 3, + sig.Mass / 3, + sig.Time / 3, + sig.ElectricCurrent / 3, + sig.ThermodynamicTemperature / 3, + sig.AmountOfSubstance / 3, + sig.LuminousIntensity / 3, + sig.Angle / 3); + + return result; +} + +int Unit::length() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + return sig.Length; +} + +int Unit::mass() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + return sig.Mass; +} + + +int Unit::time() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + return sig.Time; +} + +int Unit::electricCurrent() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + return sig.ElectricCurrent; +} + +int Unit::thermodynamicTemperature() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + return sig.ThermodynamicTemperature; +} + +int Unit::amountOfSubstance() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + return sig.AmountOfSubstance; +} + +int Unit::luminousIntensity() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + return sig.LuminousIntensity; +} + +int Unit::angle() const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + return sig.Angle; +} + +bool Unit::isEmpty() const +{ + return Val == 0; +} + +int Unit::operator [](int index) const +{ + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + + switch (index) { + case 0: + return sig.Length; + case 1: + return sig.Mass; + case 2: + return sig.Time; + case 3: + return sig.ElectricCurrent; + case 4: + return sig.ThermodynamicTemperature; + case 5: + return sig.AmountOfSubstance; + case 6: + return sig.LuminousIntensity; + case 7: + return sig.Angle; + default: + throw Base::IndexError("Unknown Unit element"); + } } bool Unit::operator ==(const Unit& that) const { - return (this->Sig.Length == that.Sig.Length) - && (this->Sig.Mass == that.Sig.Mass) - && (this->Sig.Time == that.Sig.Time) - && (this->Sig.ElectricCurrent == that.Sig.ElectricCurrent) - && (this->Sig.ThermodynamicTemperature == that.Sig.ThermodynamicTemperature) - && (this->Sig.AmountOfSubstance == that.Sig.AmountOfSubstance) - && (this->Sig.LuminousIntensity == that.Sig.LuminousIntensity) - && (this->Sig.Angle == that.Sig.Angle); + return Val == that.Val; } - Unit Unit::operator *(const Unit &right) const { - checkRange("* operator", - Sig.Length +right.Sig.Length, - Sig.Mass + right.Sig.Mass, - Sig.Time + right.Sig.Time, - Sig.ElectricCurrent + right.Sig.ElectricCurrent, - Sig.ThermodynamicTemperature + right.Sig.ThermodynamicTemperature, - Sig.AmountOfSubstance + right.Sig.AmountOfSubstance, - Sig.LuminousIntensity + right.Sig.LuminousIntensity, - Sig.Angle + right.Sig.Angle); - Unit result; - result.Sig.Length = Sig.Length + right.Sig.Length; - result.Sig.Mass = Sig.Mass + right.Sig.Mass; - result.Sig.Time = Sig.Time + right.Sig.Time; - result.Sig.ElectricCurrent = Sig.ElectricCurrent + right.Sig.ElectricCurrent; - result.Sig.ThermodynamicTemperature = Sig.ThermodynamicTemperature + right.Sig.ThermodynamicTemperature; - result.Sig.AmountOfSubstance = Sig.AmountOfSubstance + right.Sig.AmountOfSubstance; - result.Sig.LuminousIntensity = Sig.LuminousIntensity + right.Sig.LuminousIntensity; - result.Sig.Angle = Sig.Angle + right.Sig.Angle; + UnitSignature sig, rsig; + + memcpy(&sig, &Val, sizeof(Val)); + memcpy(&rsig, &right.Val, sizeof(right.Val)); + result.Val = sigVal("* operator", + sig.Length + rsig.Length, + sig.Mass + rsig.Mass, + sig.Time + rsig.Time, + sig.ElectricCurrent + rsig.ElectricCurrent, + sig.ThermodynamicTemperature + rsig.ThermodynamicTemperature, + sig.AmountOfSubstance + rsig.AmountOfSubstance, + sig.LuminousIntensity + rsig.LuminousIntensity, + sig.Angle + rsig.Angle); return result; } Unit Unit::operator /(const Unit &right) const { - checkRange("/ operator", - Sig.Length - right.Sig.Length, - Sig.Mass - right.Sig.Mass, - Sig.Time - right.Sig.Time, - Sig.ElectricCurrent - right.Sig.ElectricCurrent, - Sig.ThermodynamicTemperature - right.Sig.ThermodynamicTemperature, - Sig.AmountOfSubstance - right.Sig.AmountOfSubstance, - Sig.LuminousIntensity - right.Sig.LuminousIntensity, - Sig.Angle - right.Sig.Angle); - Unit result; - result.Sig.Length = Sig.Length - right.Sig.Length; - result.Sig.Mass = Sig.Mass - right.Sig.Mass; - result.Sig.Time = Sig.Time - right.Sig.Time; - result.Sig.ElectricCurrent = Sig.ElectricCurrent - right.Sig.ElectricCurrent; - result.Sig.ThermodynamicTemperature = Sig.ThermodynamicTemperature - right.Sig.ThermodynamicTemperature; - result.Sig.AmountOfSubstance = Sig.AmountOfSubstance - right.Sig.AmountOfSubstance; - result.Sig.LuminousIntensity = Sig.LuminousIntensity - right.Sig.LuminousIntensity; - result.Sig.Angle = Sig.Angle - right.Sig.Angle; + UnitSignature sig, rsig; + + memcpy(&sig, &Val, sizeof(Val)); + memcpy(&rsig, &right.Val, sizeof(right.Val)); + result.Val = sigVal("/ operator", + sig.Length - rsig.Length, + sig.Mass - rsig.Mass, + sig.Time - rsig.Time, + sig.ElectricCurrent - rsig.ElectricCurrent, + sig.ThermodynamicTemperature - rsig.ThermodynamicTemperature, + sig.AmountOfSubstance - rsig.AmountOfSubstance, + sig.LuminousIntensity - rsig.LuminousIntensity, + sig.Angle - rsig.Angle); return result; } QString Unit::getString() const { - std::stringstream ret; - if (isEmpty()) { return {}; } - if (Sig.Length > 0 || - Sig.Mass > 0 || - Sig.Time > 0 || - Sig.ElectricCurrent > 0 || - Sig.ThermodynamicTemperature> 0 || - Sig.AmountOfSubstance > 0 || - Sig.LuminousIntensity > 0 || - Sig.Angle > 0 ){ + std::stringstream ret; + UnitSignature sig; + memcpy(&sig, &Val, sizeof(Val)); + + if (sig.Length > 0 || + sig.Mass > 0 || + sig.Time > 0 || + sig.ElectricCurrent > 0 || + sig.ThermodynamicTemperature > 0 || + sig.AmountOfSubstance > 0 || + sig.LuminousIntensity > 0 || + sig.Angle > 0 ) { bool mult = false; - if (Sig.Length > 0) { + if (sig.Length > 0) { mult = true; ret << "mm"; - if (Sig.Length > 1) { - ret << "^" << Sig.Length; + if (sig.Length > 1) { + ret << "^" << sig.Length; } } - if (Sig.Mass > 0) { + if (sig.Mass > 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "kg"; - if (Sig.Mass > 1) { - ret << "^" << Sig.Mass; + if (sig.Mass > 1) { + ret << "^" << sig.Mass; } } - if (Sig.Time > 0) { + if (sig.Time > 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "s"; - if (Sig.Time > 1) { - ret << "^" << Sig.Time; + if (sig.Time > 1) { + ret << "^" << sig.Time; } } - if (Sig.ElectricCurrent > 0) { + if (sig.ElectricCurrent > 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "A"; - if (Sig.ElectricCurrent > 1) { - ret << "^" << Sig.ElectricCurrent; + if (sig.ElectricCurrent > 1) { + ret << "^" << sig.ElectricCurrent; } } - if (Sig.ThermodynamicTemperature > 0) { + if (sig.ThermodynamicTemperature > 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "K"; - if (Sig.ThermodynamicTemperature > 1) { - ret << "^" << Sig.ThermodynamicTemperature; + if (sig.ThermodynamicTemperature > 1) { + ret << "^" << sig.ThermodynamicTemperature; } } - if (Sig.AmountOfSubstance > 0){ + if (sig.AmountOfSubstance > 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "mol"; - if (Sig.AmountOfSubstance > 1) { - ret << "^" << Sig.AmountOfSubstance; + if (sig.AmountOfSubstance > 1) { + ret << "^" << sig.AmountOfSubstance; } } - if (Sig.LuminousIntensity > 0) { + if (sig.LuminousIntensity > 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "cd"; - if (Sig.LuminousIntensity > 1) { - ret << "^" << Sig.LuminousIntensity; + if (sig.LuminousIntensity > 1) { + ret << "^" << sig.LuminousIntensity; } } - if (Sig.Angle > 0) { + if (sig.Angle > 0) { if (mult) { - ret<<'*'; + ret << '*'; } - mult = true; //NOLINT + mult = true; ret << "deg"; - if (Sig.Angle > 1) { - ret << "^" << Sig.Angle; + if (sig.Angle > 1) { + ret << "^" << sig.Angle; } } } @@ -344,113 +464,113 @@ QString Unit::getString() const ret << "1"; } - if (Sig.Length < 0 || - Sig.Mass < 0 || - Sig.Time < 0 || - Sig.ElectricCurrent < 0 || - Sig.ThermodynamicTemperature< 0 || - Sig.AmountOfSubstance < 0 || - Sig.LuminousIntensity < 0 || - Sig.Angle < 0 ){ + if (sig.Length < 0 || + sig.Mass < 0 || + sig.Time < 0 || + sig.ElectricCurrent < 0 || + sig.ThermodynamicTemperature < 0 || + sig.AmountOfSubstance < 0 || + sig.LuminousIntensity < 0 || + sig.Angle < 0 ) { ret << "/"; int nnom = 0; - nnom += Sig.Length<0?1:0; - nnom += Sig.Mass<0?1:0; - nnom += Sig.Time<0?1:0; - nnom += Sig.ElectricCurrent<0?1:0; - nnom += Sig.ThermodynamicTemperature<0?1:0; - nnom += Sig.AmountOfSubstance<0?1:0; - nnom += Sig.LuminousIntensity<0?1:0; - nnom += Sig.Angle<0?1:0; + nnom += sig.Length < 0 ? 1 : 0; + nnom += sig.Mass < 0 ? 1 : 0; + nnom += sig.Time < 0 ? 1 : 0; + nnom += sig.ElectricCurrent < 0 ? 1 : 0; + nnom += sig.ThermodynamicTemperature < 0 ? 1 : 0; + nnom += sig.AmountOfSubstance < 0 ? 1 : 0; + nnom += sig.LuminousIntensity < 0 ? 1 : 0; + nnom += sig.Angle < 0 ? 1 : 0; if (nnom > 1) { ret << '('; } - bool mult=false; - if (Sig.Length < 0) { + bool mult = false; + if (sig.Length < 0) { ret << "mm"; mult = true; - if (Sig.Length < -1) { - ret << "^" << abs(Sig.Length); + if (sig.Length < -1) { + ret << "^" << abs(sig.Length); } } - if (Sig.Mass < 0) { + if (sig.Mass < 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "kg"; - if (Sig.Mass < -1) { - ret << "^" << abs(Sig.Mass); + if (sig.Mass < -1) { + ret << "^" << abs(sig.Mass); } } - if (Sig.Time < 0) { + if (sig.Time < 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "s"; - if (Sig.Time < -1) { - ret << "^" << abs(Sig.Time); + if (sig.Time < -1) { + ret << "^" << abs(sig.Time); } } - if (Sig.ElectricCurrent < 0) { + if (sig.ElectricCurrent < 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "A"; - if (Sig.ElectricCurrent < -1) { - ret << "^" << abs(Sig.ElectricCurrent); + if (sig.ElectricCurrent < -1) { + ret << "^" << abs(sig.ElectricCurrent); } } - if (Sig.ThermodynamicTemperature < 0) { + if (sig.ThermodynamicTemperature < 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "K"; - if (Sig.ThermodynamicTemperature < -1) { - ret << "^" << abs(Sig.ThermodynamicTemperature); + if (sig.ThermodynamicTemperature < -1) { + ret << "^" << abs(sig.ThermodynamicTemperature); } } - if (Sig.AmountOfSubstance < 0) { + if (sig.AmountOfSubstance < 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "mol"; - if (Sig.AmountOfSubstance < -1) { - ret << "^" << abs(Sig.AmountOfSubstance); + if (sig.AmountOfSubstance < -1) { + ret << "^" << abs(sig.AmountOfSubstance); } } - if (Sig.LuminousIntensity < 0) { + if (sig.LuminousIntensity < 0) { if (mult) { - ret<<'*'; + ret << '*'; } mult = true; ret << "cd"; - if (Sig.LuminousIntensity < -1) { - ret << "^" << abs(Sig.LuminousIntensity); + if (sig.LuminousIntensity < -1) { + ret << "^" << abs(sig.LuminousIntensity); } } - if (Sig.Angle < 0) { + if (sig.Angle < 0) { if (mult) { - ret<<'*'; + ret << '*'; } - mult = true; //NOLINT + mult = true; ret << "deg"; - if (Sig.Angle < -1) { - ret << "^" << abs(Sig.Angle); + if (sig.Angle < -1) { + ret << "^" << abs(sig.Angle); } } diff --git a/src/Base/Unit.h b/src/Base/Unit.h index 81ec17ec51..fa9204f446 100644 --- a/src/Base/Unit.h +++ b/src/Base/Unit.h @@ -31,29 +31,6 @@ namespace Base { -#define UnitSignatureLengthBits 4 -#define UnitSignatureMassBits 4 -#define UnitSignatureTimeBits 4 -#define UnitSignatureElectricCurrentBits 4 -#define UnitSignatureThermodynamicTemperatureBits 4 -#define UnitSignatureAmountOfSubstanceBits 4 -#define UnitSignatureLuminousIntensityBits 4 -#define UnitSignatureAngleBits 4 - -// Hint: -// https://en.cppreference.com/w/cpp/language/bit_field -// https://stackoverflow.com/questions/33723631/signed-bit-field-in-c14 -struct UnitSignature -{ - int32_t Length: UnitSignatureLengthBits; - int32_t Mass: UnitSignatureMassBits; - int32_t Time: UnitSignatureTimeBits; - int32_t ElectricCurrent: UnitSignatureElectricCurrentBits; - int32_t ThermodynamicTemperature: UnitSignatureThermodynamicTemperatureBits; - int32_t AmountOfSubstance: UnitSignatureAmountOfSubstanceBits; - int32_t LuminousIntensity: UnitSignatureLuminousIntensityBits; - int32_t Angle: UnitSignatureAngleBits; -}; /** * The Unit class. */ @@ -76,11 +53,11 @@ public: /// Destruction ~Unit() = default; - /** 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; @@ -91,12 +68,17 @@ public: Unit& operator=(const Unit&) = default; Unit& operator=(Unit&&) = default; Unit pow(double exp) const; + Unit sqrt() const; + Unit cbrt() const; //@} - /// get the unit signature - const UnitSignature& getSignature() const - { - return Sig; - } + int length() const; + int mass() const; + int time() const; + int electricCurrent() const; + int thermodynamicTemperature() const; + int amountOfSubstance() const; + int luminousIntensity() const; + int angle() const; bool isEmpty() const; QString getString() const; @@ -177,7 +159,7 @@ public: //@} private: - UnitSignature Sig; + uint32_t Val; }; inline Unit& Unit::operator*=(const Unit& that) diff --git a/src/Base/UnitPyImp.cpp b/src/Base/UnitPyImp.cpp index 364ffb6641..14be93f524 100644 --- a/src/Base/UnitPyImp.cpp +++ b/src/Base/UnitPyImp.cpp @@ -34,23 +34,24 @@ using namespace Base; // returns a string which represents the object e.g. when printed in python std::string UnitPy::representation() const { - const UnitSignature& Sig = getUnitPtr()->getSignature(); std::stringstream ret; + Unit* self = getUnitPtr(); + ret << "Unit: "; - ret << getUnitPtr()->getString().toUtf8().constData() << " ("; - ret << Sig.Length << ","; - ret << Sig.Mass << ","; - ret << Sig.Time << ","; - ret << Sig.ElectricCurrent << ","; - ret << Sig.ThermodynamicTemperature << ","; - ret << Sig.AmountOfSubstance << ","; - ret << Sig.LuminousIntensity << ","; - ret << Sig.Angle << ")"; - std::string type = getUnitPtr()->getTypeString().toUtf8().constData(); + ret << self->getString().toUtf8().constData() << " ("; + 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().toUtf8().constData(); if (!type.empty()) { ret << " [" << type << "]"; } - return ret.str(); } @@ -211,20 +212,16 @@ Py::String UnitPy::getType() const Py::Tuple UnitPy::getSignature() const { - const UnitSignature& Sig = getUnitPtr()->getSignature(); Py::Tuple tuple(8); - tuple.setItem(0, Py::Long(Sig.Length)); - tuple.setItem(1, Py::Long(Sig.Mass)); - tuple.setItem(2, Py::Long(Sig.Time)); - tuple.setItem(3, Py::Long(Sig.ElectricCurrent)); - tuple.setItem(4, Py::Long(Sig.ThermodynamicTemperature)); - tuple.setItem(5, Py::Long(Sig.AmountOfSubstance)); - tuple.setItem(6, Py::Long(Sig.LuminousIntensity)); - tuple.setItem(7, Py::Long(Sig.Angle)); + Unit* self = getUnitPtr(); + + for (auto i = 0; i < tuple.size(); i++) { + tuple.setItem(i, Py::Long((*self)[i])); + } + return tuple; } - PyObject* UnitPy::getCustomAttributes(const char* /*attr*/) const { return nullptr; diff --git a/src/Gui/DlgUnitsCalculatorImp.cpp b/src/Gui/DlgUnitsCalculatorImp.cpp index 0718370ac2..df857745e1 100644 --- a/src/Gui/DlgUnitsCalculatorImp.cpp +++ b/src/Gui/DlgUnitsCalculatorImp.cpp @@ -201,11 +201,11 @@ void DlgUnitsCalculator::onUnitsBoxActivated(int index) // SI units use [m], not [mm] for lengths // Base::Quantity q = ui->quantitySpinBox->value(); - int32_t old = q.getUnit().getSignature().Length; + int32_t old = q.getUnit().length(); double value = q.getValue(); Base::Unit unit = units[index]; - int32_t len = unit.getSignature().Length; + int32_t len = unit.length(); ui->quantitySpinBox->setValue(Base::Quantity(value * std::pow(10.0, 3 * (len - old)), unit)); }