mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[poincare] Define Unit class
This commit is contained in:
committed by
Léa Saviot
parent
a82ff2b703
commit
92d17145b2
@@ -143,6 +143,7 @@ poincare_src += $(addprefix poincare/src/,\
|
||||
trigonometry.cpp \
|
||||
trigonometry_cheat_table.cpp \
|
||||
undefined.cpp \
|
||||
unit.cpp \
|
||||
unreal.cpp \
|
||||
variable_context.cpp \
|
||||
)
|
||||
|
||||
@@ -99,6 +99,7 @@ class Expression : public TreeHandle {
|
||||
friend class Tangent;
|
||||
friend class Trigonometry;
|
||||
friend class TrigonometryCheatTable;
|
||||
friend class Unit;
|
||||
|
||||
friend class AdditionNode;
|
||||
friend class DerivativeNode;
|
||||
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
MatrixTranspose,
|
||||
PredictionInterval,
|
||||
Matrix,
|
||||
Unit,
|
||||
EmptyExpression
|
||||
};
|
||||
|
||||
|
||||
448
poincare/include/poincare/unit.h
Normal file
448
poincare/include/poincare/unit.h
Normal file
@@ -0,0 +1,448 @@
|
||||
#ifndef POINCARE_UNIT_H
|
||||
#define POINCARE_UNIT_H
|
||||
|
||||
#include <poincare/expression.h>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
class UnitNode final : public ExpressionNode {
|
||||
public:
|
||||
|
||||
/* The units having the same physical dimension are grouped together.
|
||||
* Each such group has a standard representative with a standard prefix.
|
||||
*
|
||||
* A standard unit is a derived unit, when defined from base units
|
||||
* or otherwise a base unit (if no definition is provided).
|
||||
*
|
||||
* Each representative has
|
||||
* - a root symbol
|
||||
* - a definition
|
||||
* - a list of allowed prefixes
|
||||
* Given a Dimension, a representative in that Dimension and a Prefix
|
||||
* allowed for that representative, one may get a symbol and an Expression.
|
||||
*/
|
||||
|
||||
class Prefix {
|
||||
public:
|
||||
constexpr Prefix(const char * symbol, int8_t exponent) :
|
||||
m_symbol(symbol),
|
||||
m_exponent(exponent)
|
||||
{}
|
||||
const char * symbol() const { return m_symbol; }
|
||||
const int8_t exponent() const { return m_exponent; }
|
||||
size_t serialize(char * buffer, size_t length) const;
|
||||
private:
|
||||
const char * m_symbol;
|
||||
int8_t m_exponent;
|
||||
};
|
||||
|
||||
class Representative {
|
||||
public:
|
||||
constexpr Representative(const char * rootSymbol, const char * definition, const Prefix * allowedPrefixes, size_t numberOfAllowedPrefixes) :
|
||||
m_rootSymbol(rootSymbol),
|
||||
m_definition(definition),
|
||||
m_allowedPrefixes(allowedPrefixes),
|
||||
m_allowedPrefixesUpperBound(allowedPrefixes + numberOfAllowedPrefixes)
|
||||
{
|
||||
}
|
||||
const char * rootSymbol() const { return m_rootSymbol; }
|
||||
const char * definition() const { return m_definition; }
|
||||
const Prefix * allowedPrefixes() const { return m_allowedPrefixes; }
|
||||
const Prefix * allowedPrefixesUpperBound() const { return m_allowedPrefixesUpperBound; }
|
||||
bool canParse(const char * symbol, size_t length,
|
||||
const Prefix * * prefix) const;
|
||||
size_t serialize(char * buffer, size_t length, const Prefix * prefix) const;
|
||||
private:
|
||||
const char * m_rootSymbol;
|
||||
const char * m_definition;
|
||||
const Prefix * m_allowedPrefixes;
|
||||
const Prefix * m_allowedPrefixesUpperBound;
|
||||
};
|
||||
|
||||
class Dimension {
|
||||
public:
|
||||
constexpr Dimension(const Representative * representatives, size_t numberOfRepresentatives, const Prefix * stdRepresentativePrefix) :
|
||||
m_representatives(representatives),
|
||||
m_representativesUpperBound(representatives + numberOfRepresentatives),
|
||||
m_stdRepresentativePrefix(stdRepresentativePrefix)
|
||||
{
|
||||
}
|
||||
const Representative * stdRepresentative() const { return m_representatives; }
|
||||
const Representative * representativesUpperBound() const { return m_representativesUpperBound; }
|
||||
const Prefix * stdRepresentativePrefix() const { return m_stdRepresentativePrefix; }
|
||||
bool canParse(const char * symbol, size_t length,
|
||||
const Representative * * representative, const Prefix * * prefix) const;
|
||||
private:
|
||||
const Representative * m_representatives;
|
||||
const Representative * m_representativesUpperBound;
|
||||
const Prefix * m_stdRepresentativePrefix;
|
||||
};
|
||||
|
||||
UnitNode(const Dimension * dimension, const Representative * representative, const Prefix * prefix) :
|
||||
ExpressionNode(),
|
||||
m_dimension(dimension),
|
||||
m_representative(representative),
|
||||
m_prefix(prefix)
|
||||
{}
|
||||
|
||||
// TreeNode
|
||||
size_t size() const override { return sizeof(UnitNode); }
|
||||
int numberOfChildren() const override { return 0; }
|
||||
#if POINCARE_TREE_LOG
|
||||
virtual void logNodeName(std::ostream & stream) const override {
|
||||
stream << "Unit";
|
||||
}
|
||||
virtual void logAttributes(std::ostream & stream) const override {
|
||||
stream << " symbol=\"" << m_prefix->symbol() << m_representative->rootSymbol() << "\"";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Expression Properties
|
||||
Type type() const override { return Type::Unit; }
|
||||
Sign sign(Context * context) const override;
|
||||
|
||||
/* Layout */
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
/* Approximation */
|
||||
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, complexFormat, angleUnit); }
|
||||
Evaluation<double> approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, complexFormat, angleUnit); }
|
||||
|
||||
// Comparison
|
||||
int simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted) const override;
|
||||
|
||||
// Simplification
|
||||
Expression shallowReduce(ReductionContext reductionContext) override;
|
||||
Expression shallowBeautify(ReductionContext reductionContext) override;
|
||||
LayoutShape leftLayoutShape() const override { return LayoutShape::OneLetter; } // TODO
|
||||
|
||||
const Dimension * dimension() const { return m_dimension; }
|
||||
const Representative * representative() const { return m_representative; }
|
||||
const Prefix * prefix() const { return m_prefix; }
|
||||
void setPrefix(const Prefix * prefix) { m_prefix = prefix; }
|
||||
|
||||
private:
|
||||
const Dimension * m_dimension;
|
||||
const Representative * m_representative;
|
||||
const Prefix * m_prefix;
|
||||
|
||||
template<typename T> Evaluation<T> templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
||||
};
|
||||
|
||||
class Unit final : public Expression {
|
||||
public:
|
||||
typedef UnitNode::Prefix Prefix;
|
||||
typedef UnitNode::Representative Representative;
|
||||
typedef UnitNode::Dimension Dimension;
|
||||
static constexpr const Prefix
|
||||
PicoPrefix = Prefix("p", -12),
|
||||
NanoPrefix = Prefix("n", -9),
|
||||
MicroPrefix = Prefix("u", -6), // FIXME μ
|
||||
MilliPrefix = Prefix("m", -3),
|
||||
CentiPrefix = Prefix("c", -2),
|
||||
DeciPrefix = Prefix("d", -1),
|
||||
EmptyPrefix = Prefix("", 0),
|
||||
DecaPrefix = Prefix("da", 1),
|
||||
HectoPrefix = Prefix("h", 2),
|
||||
KiloPrefix = Prefix("k", 3),
|
||||
MegaPrefix = Prefix("M", 6),
|
||||
GigaPrefix = Prefix("G", 9),
|
||||
TeraPrefix = Prefix("T", 12);
|
||||
static constexpr const Prefix
|
||||
NoPrefix[] = {
|
||||
EmptyPrefix
|
||||
},
|
||||
NegativeLongScalePrefixes[] = {
|
||||
PicoPrefix,
|
||||
NanoPrefix,
|
||||
MicroPrefix,
|
||||
MilliPrefix,
|
||||
EmptyPrefix,
|
||||
},
|
||||
PositiveLongScalePrefixes[] = {
|
||||
EmptyPrefix,
|
||||
KiloPrefix,
|
||||
MegaPrefix,
|
||||
GigaPrefix,
|
||||
TeraPrefix,
|
||||
},
|
||||
AllPrefixes[] = {
|
||||
PicoPrefix,
|
||||
NanoPrefix,
|
||||
MicroPrefix,
|
||||
MilliPrefix,
|
||||
CentiPrefix,
|
||||
DeciPrefix,
|
||||
EmptyPrefix,
|
||||
DecaPrefix,
|
||||
HectoPrefix,
|
||||
KiloPrefix,
|
||||
MegaPrefix,
|
||||
GigaPrefix,
|
||||
TeraPrefix,
|
||||
};
|
||||
static constexpr size_t
|
||||
NoPrefixCount = sizeof(NoPrefix)/sizeof(Prefix),
|
||||
NegativeLongScalePrefixesCount = sizeof(NegativeLongScalePrefixes)/sizeof(Prefix),
|
||||
PositiveLongScalePrefixesCount = sizeof(PositiveLongScalePrefixes)/sizeof(Prefix),
|
||||
AllPrefixesCount = sizeof(AllPrefixes)/sizeof(Prefix);
|
||||
static constexpr const Representative
|
||||
TimeRepresentatives[] = {
|
||||
Representative("s", nullptr,
|
||||
NegativeLongScalePrefixes, NegativeLongScalePrefixesCount),
|
||||
Representative("min", "60*s",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("h", "60*60*s",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("day", "24*60*60*s",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("week", "7*24*60*60*s",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("month", "30*7*24*60*60*s",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("year", "365.25*24*60*60*s",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
DistanceRepresentatives[] = {
|
||||
Representative("m", nullptr,
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
Representative("ang", "10^-10*m",
|
||||
NoPrefix, NoPrefixCount), //FIXME Codepoint
|
||||
Representative("au", "149587870700*m",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("ly", "299792458*m/s*year",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("pc", "180*60*60/π*au",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
MassRepresentatives[] = {
|
||||
Representative("g", nullptr,
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
Representative("t", "1000kg",
|
||||
PositiveLongScalePrefixes, PositiveLongScalePrefixesCount),
|
||||
Representative("Da", "(6.02214076*10^23*1000)^-1*kg",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
CurrentRepresentatives[] = {
|
||||
Representative("A", nullptr,
|
||||
NegativeLongScalePrefixes, NegativeLongScalePrefixesCount),
|
||||
},
|
||||
TemperatureRepresentatives[] = {
|
||||
Representative("K", nullptr,
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
AmountOfSubstanceRepresentatives[] = {
|
||||
Representative("mol", nullptr,
|
||||
NegativeLongScalePrefixes, NegativeLongScalePrefixesCount),
|
||||
},
|
||||
LuminousIntensityRepresentatives[] = {
|
||||
Representative("cd", nullptr,
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
FrequencyRepresentatives[] = {
|
||||
Representative("Hz", "s^-1",
|
||||
PositiveLongScalePrefixes, PositiveLongScalePrefixesCount),
|
||||
},
|
||||
ForceRepresentatives[] = {
|
||||
Representative("N", "kg*m*s^-2",
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
},
|
||||
PressureRepresentatives[] = {
|
||||
Representative("Pa", "kg*m^-1*s^-2",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("bar", "1000hPa",
|
||||
NoPrefix, NoPrefixCount),
|
||||
Representative("atm", "101325Pa",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
EnergyRepresentatives[] = {
|
||||
Representative("J", "kg*m^2*s^-2",
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
Representative("eV", "1.602176634*10^−19*J",
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
},
|
||||
PowerRepresentatives[] = {
|
||||
Representative("W", "kg*m^2*s^-3",
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
},
|
||||
ElectricChargeRepresentatives[] = {
|
||||
Representative("C", "A*s",
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
},
|
||||
ElectricPotentialRepresentatives[] = {
|
||||
Representative("V", "kg*m^2*s^-3*A^-1",
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
},
|
||||
ElectricCapacitanceRepresentatives[] = {
|
||||
Representative("F", "A^2*s^4*kg^-1*m^-2",
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
},
|
||||
ElectricResistanceRepresentatives[] = {
|
||||
Representative("Ohm", "kg*m^2*s^-3*A^-2",
|
||||
AllPrefixes, AllPrefixesCount), //FIXME Omega CodePoint?
|
||||
},
|
||||
ElectricConductanceRepresentatives[] = {
|
||||
Representative("S", "A^2*s^3*kg^-1*m^-2",
|
||||
AllPrefixes, AllPrefixesCount),
|
||||
},
|
||||
MagneticFluxRepresentatives[] = {
|
||||
Representative("Wb", "kg*m^2*s^-2*A^-1",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
MagneticFieldRepresentatives[] = {
|
||||
Representative("T", "kg*s^-2*A^-1",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
InductanceRepresentatives[] = {
|
||||
Representative("H", "kg*m^2*s^-2*A^-2",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
CatalyticActivityRepresentatives[] = {
|
||||
Representative("kat", "mol*s^-1",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
SurfaceRepresentatives[] = {
|
||||
Representative("ha", "10^4*m^2",
|
||||
NoPrefix, NoPrefixCount),
|
||||
},
|
||||
VolumeRepresentatives[] = {
|
||||
Representative("L", "10^-3*m^3",
|
||||
NoPrefix, NoPrefixCount),
|
||||
};
|
||||
static constexpr const Dimension DimensionTable[] = {
|
||||
/* The current table is sorted from most to least simple units.
|
||||
* The order determines the behavior of simplification.
|
||||
*/
|
||||
Dimension(
|
||||
TimeRepresentatives,
|
||||
sizeof(TimeRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
DistanceRepresentatives,
|
||||
sizeof(DistanceRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
MassRepresentatives,
|
||||
sizeof(MassRepresentatives)/sizeof(Representative),
|
||||
&KiloPrefix
|
||||
),
|
||||
Dimension(
|
||||
CurrentRepresentatives,
|
||||
sizeof(CurrentRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
TemperatureRepresentatives,
|
||||
sizeof(TemperatureRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
AmountOfSubstanceRepresentatives,
|
||||
sizeof(AmountOfSubstanceRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
LuminousIntensityRepresentatives,
|
||||
sizeof(LuminousIntensityRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
FrequencyRepresentatives,
|
||||
sizeof(FrequencyRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
ForceRepresentatives,
|
||||
sizeof(ForceRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
PressureRepresentatives,
|
||||
sizeof(PressureRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
EnergyRepresentatives,
|
||||
sizeof(EnergyRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
PowerRepresentatives,
|
||||
sizeof(PowerRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
ElectricChargeRepresentatives,
|
||||
sizeof(ElectricChargeRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
ElectricPotentialRepresentatives,
|
||||
sizeof(ElectricPotentialRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
ElectricCapacitanceRepresentatives,
|
||||
sizeof(ElectricCapacitanceRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
ElectricResistanceRepresentatives,
|
||||
sizeof(ElectricResistanceRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
ElectricConductanceRepresentatives,
|
||||
sizeof(ElectricConductanceRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
MagneticFluxRepresentatives,
|
||||
sizeof(MagneticFluxRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
MagneticFieldRepresentatives,
|
||||
sizeof(MagneticFieldRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
InductanceRepresentatives,
|
||||
sizeof(InductanceRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
CatalyticActivityRepresentatives,
|
||||
sizeof(CatalyticActivityRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
SurfaceRepresentatives,
|
||||
sizeof(SurfaceRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
Dimension(
|
||||
VolumeRepresentatives,
|
||||
sizeof(VolumeRepresentatives)/sizeof(Representative),
|
||||
&EmptyPrefix
|
||||
),
|
||||
};
|
||||
static constexpr const Unit::Dimension * DimensionTableUpperBound =
|
||||
DimensionTable + sizeof(DimensionTable)/sizeof(Dimension);
|
||||
static bool CanParse(const char * symbol, size_t length,
|
||||
const Dimension * * dimension, const Representative * * representative, const Prefix * * prefix);
|
||||
|
||||
Unit(const UnitNode * node) : Expression(node) {}
|
||||
static Unit Builder(const Dimension * dimension, const Representative * representative, const Prefix * prefix);
|
||||
|
||||
// Simplification
|
||||
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
|
||||
Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -83,6 +83,7 @@
|
||||
#include <poincare/symbol.h>
|
||||
#include <poincare/tangent.h>
|
||||
#include <poincare/undefined.h>
|
||||
#include <poincare/unit.h>
|
||||
#include <poincare/unreal.h>
|
||||
#include <poincare/variable_context.h>
|
||||
|
||||
|
||||
240
poincare/src/unit.cpp
Normal file
240
poincare/src/unit.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
#include <poincare/unit.h>
|
||||
#include <poincare/multiplication.h>
|
||||
#include <poincare/power.h>
|
||||
#include <poincare/rational.h>
|
||||
#include <poincare/layout_helper.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
static inline int minInt(int x, int y) { return x < y ? x : y; }
|
||||
|
||||
size_t UnitNode::Prefix::serialize(char * buffer, size_t length) const {
|
||||
return minInt(strlcpy(buffer, m_symbol, length), length - 1);
|
||||
}
|
||||
|
||||
bool UnitNode::Representative::canParse(const char * symbol, size_t length,
|
||||
const Prefix * * prefix) const
|
||||
{
|
||||
const Prefix * pre = m_allowedPrefixes;
|
||||
while (pre < m_allowedPrefixesUpperBound) {
|
||||
const char * prefixSymbol = pre->symbol();
|
||||
if (strncmp(symbol, prefixSymbol, length) == 0 &&
|
||||
prefixSymbol[length] == 0)
|
||||
{
|
||||
*prefix = pre;
|
||||
return true;
|
||||
}
|
||||
pre++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t UnitNode::Representative::serialize(char * buffer, size_t length, const Prefix * prefix) const {
|
||||
size_t prefixLength = prefix->serialize(buffer, length);
|
||||
buffer += prefixLength;
|
||||
length -= prefixLength;
|
||||
return prefixLength + minInt(strlcpy(buffer, m_rootSymbol, length), length - 1);
|
||||
}
|
||||
|
||||
bool UnitNode::Dimension::canParse(const char * symbol, size_t length,
|
||||
const Representative * * representative, const Prefix * * prefix) const
|
||||
{
|
||||
const Representative * rep = m_representatives;
|
||||
while (rep < m_representativesUpperBound) {
|
||||
const char * rootSymbol = rep->rootSymbol();
|
||||
size_t rootSymbolLength = strlen(rootSymbol);
|
||||
int potentialPrefixLength = length - rootSymbolLength;
|
||||
if (potentialPrefixLength >= 0 &&
|
||||
strncmp(rootSymbol, symbol + potentialPrefixLength, rootSymbolLength) == 0 &&
|
||||
rep->canParse(symbol, potentialPrefixLength, prefix))
|
||||
{
|
||||
*representative = rep;
|
||||
return true;
|
||||
}
|
||||
rep++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ExpressionNode::Sign UnitNode::sign(Context * context) const {
|
||||
return Sign::Positive;
|
||||
}
|
||||
|
||||
int UnitNode::simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted) const {
|
||||
if (!ascending) {
|
||||
return e->simplificationOrderSameType(this, true, canBeInterrupted);
|
||||
}
|
||||
assert(type() == e->type());
|
||||
const UnitNode * eNode = static_cast<const UnitNode *>(e);
|
||||
const ptrdiff_t dimdiff = eNode->dimension() - m_dimension;
|
||||
if (dimdiff != 0) {
|
||||
return dimdiff;
|
||||
}
|
||||
const ptrdiff_t repdiff = eNode->representative() - m_representative;
|
||||
if (repdiff != 0) {
|
||||
return repdiff;
|
||||
}
|
||||
const ptrdiff_t prediff = eNode->prefix() - m_prefix;
|
||||
return prediff;
|
||||
}
|
||||
|
||||
Layout UnitNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
||||
static constexpr size_t bufferSize = 10;
|
||||
char buffer[bufferSize];
|
||||
int length = serialize(buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits);
|
||||
assert(length < bufferSize);
|
||||
return LayoutHelper::String(buffer, length);
|
||||
}
|
||||
|
||||
int UnitNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
||||
return m_representative->serialize(buffer, bufferSize, m_prefix);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Evaluation<T> UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
|
||||
return Complex<T>::Undefined();
|
||||
}
|
||||
|
||||
Expression UnitNode::shallowReduce(ReductionContext reductionContext) {
|
||||
return Unit(this).shallowReduce(reductionContext);
|
||||
}
|
||||
|
||||
Expression UnitNode::shallowBeautify(ReductionContext reductionContext) {
|
||||
return Unit(this).shallowBeautify(reductionContext);
|
||||
}
|
||||
|
||||
constexpr const Unit::Prefix
|
||||
Unit::PicoPrefix,
|
||||
Unit::NanoPrefix,
|
||||
Unit::MicroPrefix,
|
||||
Unit::MilliPrefix,
|
||||
Unit::CentiPrefix,
|
||||
Unit::DeciPrefix,
|
||||
Unit::EmptyPrefix,
|
||||
Unit::DecaPrefix,
|
||||
Unit::HectoPrefix,
|
||||
Unit::KiloPrefix,
|
||||
Unit::MegaPrefix,
|
||||
Unit::GigaPrefix,
|
||||
Unit::TeraPrefix;
|
||||
constexpr const Unit::Prefix
|
||||
Unit::NoPrefix[],
|
||||
Unit::NegativeLongScalePrefixes[],
|
||||
Unit::PositiveLongScalePrefixes[],
|
||||
Unit::AllPrefixes[];
|
||||
constexpr size_t
|
||||
Unit::NoPrefixCount,
|
||||
Unit::NegativeLongScalePrefixesCount,
|
||||
Unit::PositiveLongScalePrefixesCount,
|
||||
Unit::AllPrefixesCount;
|
||||
constexpr const Unit::Representative
|
||||
Unit::TimeRepresentatives[],
|
||||
Unit::DistanceRepresentatives[],
|
||||
Unit::MassRepresentatives[],
|
||||
Unit::CurrentRepresentatives[],
|
||||
Unit::TemperatureRepresentatives[],
|
||||
Unit::AmountOfSubstanceRepresentatives[],
|
||||
Unit::LuminousIntensityRepresentatives[],
|
||||
Unit::FrequencyRepresentatives[],
|
||||
Unit::ForceRepresentatives[],
|
||||
Unit::PressureRepresentatives[],
|
||||
Unit::EnergyRepresentatives[],
|
||||
Unit::PowerRepresentatives[],
|
||||
Unit::ElectricChargeRepresentatives[],
|
||||
Unit::ElectricPotentialRepresentatives[],
|
||||
Unit::ElectricCapacitanceRepresentatives[],
|
||||
Unit::ElectricResistanceRepresentatives[],
|
||||
Unit::ElectricConductanceRepresentatives[],
|
||||
Unit::MagneticFluxRepresentatives[],
|
||||
Unit::MagneticFieldRepresentatives[],
|
||||
Unit::InductanceRepresentatives[],
|
||||
Unit::CatalyticActivityRepresentatives[],
|
||||
Unit::SurfaceRepresentatives[],
|
||||
Unit::VolumeRepresentatives[];
|
||||
constexpr const Unit::Dimension Unit::DimensionTable[];
|
||||
constexpr const Unit::Dimension * Unit::DimensionTableUpperBound;
|
||||
|
||||
bool Unit::CanParse(const char * symbol, size_t length,
|
||||
const Dimension * * dimension, const Representative * * representative, const Prefix * * prefix)
|
||||
{
|
||||
for (const Dimension * dim = DimensionTable; dim < DimensionTableUpperBound; dim++) {
|
||||
if (dim->canParse(symbol, length, representative, prefix)) {
|
||||
*dimension = dim;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit Unit::Builder(const Dimension * dimension, const Representative * representative, const Prefix * prefix) {
|
||||
void * bufferNode = TreePool::sharedPool()->alloc(sizeof(UnitNode));
|
||||
UnitNode * node = new (bufferNode) UnitNode(dimension, representative, prefix);
|
||||
TreeHandle h = TreeHandle::BuildWithGhostChildren(node);
|
||||
return static_cast<Unit &>(h);
|
||||
}
|
||||
|
||||
Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
|
||||
UnitNode * unitNode = static_cast<UnitNode *>(node());
|
||||
const Dimension * dim = unitNode->dimension();
|
||||
const Representative * rep = unitNode->representative();
|
||||
const Prefix * pre = unitNode->prefix();
|
||||
int8_t prefixMultiplier = pre->exponent();
|
||||
if (rep == dim->stdRepresentative()) {
|
||||
const Prefix * stdPre = dim->stdRepresentativePrefix();
|
||||
unitNode->setPrefix(stdPre);
|
||||
prefixMultiplier -= stdPre->exponent();
|
||||
}
|
||||
Expression result = *this;
|
||||
if (rep->definition() != nullptr) {
|
||||
result = Expression::Parse(rep->definition(), nullptr).deepReduce(reductionContext);
|
||||
}
|
||||
if (prefixMultiplier != 0) {
|
||||
Expression multiplier = Power::Builder(Rational::Builder(10), Rational::Builder(prefixMultiplier));
|
||||
if (result.type() != ExpressionNode::Type::Multiplication) {
|
||||
result = Multiplication::Builder(multiplier, result.clone());
|
||||
} else {
|
||||
static_cast<Multiplication &>(result).addChildAtIndexInPlace(
|
||||
multiplier,
|
||||
0,
|
||||
result.numberOfChildren());
|
||||
}
|
||||
}
|
||||
replaceWithInPlace(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
Expression Unit::shallowBeautify(ExpressionNode::ReductionContext reductionContext) {
|
||||
Expression ancestor = parent();
|
||||
// Check that the exponent, if any, of a Unit is an integer
|
||||
if (!ancestor.isUninitialized() && ancestor.type() == ExpressionNode::Type::Power) {
|
||||
Expression exponent = ancestor.childAtIndex(1);
|
||||
if (!(exponent.type() == ExpressionNode::Type::Rational && static_cast<Rational &>(exponent).isInteger())) {
|
||||
goto UnitCheckUnsuccessful;
|
||||
}
|
||||
ancestor = ancestor.parent();
|
||||
}
|
||||
/* Check homogeneity: at this point, ancestor must be
|
||||
* - either uninitialized
|
||||
* - or a Multiplication whose parent is uninitialized.
|
||||
*/
|
||||
if (!ancestor.isUninitialized() && ancestor.type() == ExpressionNode::Type::Multiplication) {
|
||||
ancestor = ancestor.parent();
|
||||
}
|
||||
if (ancestor.isUninitialized()) {
|
||||
return *this;
|
||||
}
|
||||
UnitCheckUnsuccessful:
|
||||
/* If the latter checks are not successfully passed, then the function
|
||||
* returns replaceWithUndefinedInPlace.
|
||||
* TODO Something else should be returned in order to report a more
|
||||
* specific error. For instance: inhomogeneous expression.
|
||||
*/
|
||||
return replaceWithUndefinedInPlace();
|
||||
}
|
||||
|
||||
template Evaluation<float> UnitNode::templatedApproximate<float>(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
||||
template Evaluation<double> UnitNode::templatedApproximate<double>(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user