[poincare] Unit: ensure one unique instance of each prefix

This commit is contained in:
Émilie Feral
2020-05-06 14:37:37 +02:00
parent bcbdc9312e
commit a48f65ba95
4 changed files with 76 additions and 74 deletions

View File

@@ -38,7 +38,6 @@ public:
m_symbol(symbol),
m_exponent(exponent)
{}
inline bool operator==(const Prefix& p) const { return m_exponent == p.m_exponent && strcmp(m_symbol, p.m_symbol) == 0; }
const char * symbol() const { return m_symbol; }
int8_t exponent() const { return m_exponent; }
int serialize(char * buffer, int bufferSize) const;
@@ -57,19 +56,19 @@ public:
Yes
};
template <size_t N>
constexpr Representative(const char * rootSymbol, const char * definition, const Prefixable prefixable, const Prefix (&outputPrefixes)[N]) :
constexpr Representative(const char * rootSymbol, const char * definition, const Prefixable prefixable, const Prefix * const (&outputPrefixes)[N]) :
m_rootSymbol(rootSymbol),
m_definition(definition),
m_prefixable(prefixable),
m_outputPrefixes(outputPrefixes),
m_outputPrefixesUpperBound(outputPrefixes + N)
m_outputPrefixesLength(N)
{
}
const char * rootSymbol() const { return m_rootSymbol; }
const char * definition() const { return m_definition; }
bool isPrefixable() const { return m_prefixable == Prefixable::Yes; }
const Prefix * outputPrefixes() const { return m_outputPrefixes; }
const Prefix * outputPrefixesUpperBound() const { return m_outputPrefixesUpperBound; }
const Prefix * const * outputPrefixes() const { return m_outputPrefixes; }
size_t outputPrefixesLength() const { return m_outputPrefixesLength; }
bool canParse(const char * symbol, size_t length,
const Prefix * * prefix) const;
int serialize(char * buffer, int bufferSize, const Prefix * prefix) const;
@@ -78,8 +77,8 @@ public:
const char * m_rootSymbol;
const char * m_definition;
const Prefixable m_prefixable;
const Prefix * m_outputPrefixes;
const Prefix * m_outputPrefixesUpperBound;
const Prefix * const * m_outputPrefixes;
const size_t m_outputPrefixesLength;
};
class Dimension {
@@ -203,58 +202,57 @@ public:
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,
},
LongScalePrefixes[] = {
PicoPrefix,
NanoPrefix,
MicroPrefix,
MilliPrefix,
EmptyPrefix,
KiloPrefix,
MegaPrefix,
GigaPrefix,
TeraPrefix,
},
NegativePrefixes[] = {
PicoPrefix,
NanoPrefix,
MicroPrefix,
MilliPrefix,
CentiPrefix,
DeciPrefix,
EmptyPrefix,
},
AllPrefixes[] = {
PicoPrefix,
NanoPrefix,
MicroPrefix,
MilliPrefix,
CentiPrefix,
DeciPrefix,
EmptyPrefix,
DecaPrefix,
HectoPrefix,
KiloPrefix,
MegaPrefix,
GigaPrefix,
TeraPrefix,
static constexpr const Prefix * NoPrefix[] = {
&EmptyPrefix
};
static constexpr const Prefix * NegativeLongScalePrefixes[] = {
&PicoPrefix,
&NanoPrefix,
&MicroPrefix,
&MilliPrefix,
&EmptyPrefix,
};
static constexpr const Prefix * PositiveLongScalePrefixes[] = {
&EmptyPrefix,
&KiloPrefix,
&MegaPrefix,
&GigaPrefix,
&TeraPrefix,
};
static constexpr const Prefix * LongScalePrefixes[] = {
&PicoPrefix,
&NanoPrefix,
&MicroPrefix,
&MilliPrefix,
&EmptyPrefix,
&KiloPrefix,
&MegaPrefix,
&GigaPrefix,
&TeraPrefix,
};
static constexpr const Prefix * NegativePrefixes[] = {
&PicoPrefix,
&NanoPrefix,
&MicroPrefix,
&MilliPrefix,
&CentiPrefix,
&DeciPrefix,
&EmptyPrefix,
};
static constexpr const Prefix * AllPrefixes[] = {
&PicoPrefix,
&NanoPrefix,
&MicroPrefix,
&MilliPrefix,
&CentiPrefix,
&DeciPrefix,
&EmptyPrefix,
&DecaPrefix,
&HectoPrefix,
&KiloPrefix,
&MegaPrefix,
&GigaPrefix,
&TeraPrefix,
};
static constexpr size_t NumberOfBaseUnits = UnitNode::NumberOfBaseUnits;
static constexpr const Representative

View File

@@ -30,8 +30,9 @@ bool UnitNode::Representative::canParse(const char * symbol, size_t length,
*prefix = &Unit::EmptyPrefix;
return length == 0;
}
const Prefix * pre = Unit::AllPrefixes;
while (pre < Unit::AllPrefixes + sizeof(Unit::AllPrefixes)/sizeof(Unit::Prefix)) {
size_t numberOfPrefixes = sizeof(Unit::AllPrefixes)/sizeof(Unit::Prefix *);
for (size_t i = 0; i < numberOfPrefixes; i++) {
const Prefix * pre = Unit::AllPrefixes[i];
const char * prefixSymbol = pre->symbol();
if (strncmp(symbol, prefixSymbol, length) == 0 &&
prefixSymbol[length] == 0)
@@ -66,7 +67,8 @@ const UnitNode::Prefix * UnitNode::Representative::bestPrefixForValue(double & v
* magnitude of 'value'.
*/
const int orderOfMagnitude = IEEE754<double>::exponentBase10(std::fabs(value));
for (const Prefix * pre = m_outputPrefixes; pre < m_outputPrefixesUpperBound; pre++) {
for (size_t i = 0; i < m_outputPrefixesLength; i++) {
const Prefix * pre = m_outputPrefixes[i];
unsigned int newDiff = absInt(orderOfMagnitude - pre->exponent() * exponent);
if (newDiff < diff) {
diff = newDiff;
@@ -234,13 +236,12 @@ constexpr const Unit::Prefix
Unit::MegaPrefix,
Unit::GigaPrefix,
Unit::TeraPrefix;
constexpr const Unit::Prefix
Unit::NoPrefix[],
Unit::NegativeLongScalePrefixes[],
Unit::PositiveLongScalePrefixes[],
Unit::LongScalePrefixes[],
Unit::NegativePrefixes[],
Unit::AllPrefixes[];
constexpr const Unit::Prefix * const Unit::NoPrefix[];
constexpr const Unit::Prefix * const Unit::NegativeLongScalePrefixes[];
constexpr const Unit::Prefix * const Unit::PositiveLongScalePrefixes[];
constexpr const Unit::Prefix * const Unit::LongScalePrefixes[];
constexpr const Unit::Prefix * const Unit::NegativePrefixes[];
constexpr const Unit::Prefix * const Unit::AllPrefixes[];
constexpr const Unit::Representative
Unit::TimeRepresentatives[],
Unit::DistanceRepresentatives[],
@@ -392,16 +393,16 @@ Expression Unit::removeUnit(Expression * unit) {
}
bool Unit::isSecond() const {
return node()->dimension() == TimeDimension && node()->representative() == SecondRepresentative && *(node()->prefix()) == EmptyPrefix;
return node()->dimension() == TimeDimension && node()->representative() == SecondRepresentative && node()->prefix() == &EmptyPrefix;
}
bool Unit::isMeter() const {
return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && *(node()->prefix()) == EmptyPrefix;
return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && node()->prefix() == &EmptyPrefix;
}
bool Unit::isKilogram() const {
return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && *(node()->prefix()) == KiloPrefix;
return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && node()->prefix() == &KiloPrefix;
}
bool Unit::IsISSpeed(Expression & e) {

View File

@@ -294,7 +294,9 @@ QUIZ_CASE(poincare_parsing_units) {
Expression unit = parse_expression(buffer, nullptr, false);
quiz_assert_print_if_failure(unit.type() == ExpressionNode::Type::Unit, "Should be parsed as a Unit");
if (rep->isPrefixable()) {
for (const Unit::Prefix * pre = Unit::AllPrefixes; pre < Unit::AllPrefixes + sizeof(Unit::AllPrefixes)/sizeof(Unit::Prefix); pre++) {
size_t numberOfPrefixes = sizeof(Unit::AllPrefixes)/sizeof(Unit::Prefix *);
for (size_t i = 0; i < numberOfPrefixes; i++) {
const Unit::Prefix * pre = Unit::AllPrefixes[i];
Unit::Builder(dim, rep, pre).serialize(buffer, bufferSize, Preferences::PrintFloatMode::Decimal, Preferences::VeryShortNumberOfSignificantDigits);
Expression unit = parse_expression(buffer, nullptr, false);
quiz_assert_print_if_failure(unit.type() == ExpressionNode::Type::Unit, "Should be parsed as a Unit");

View File

@@ -245,7 +245,8 @@ QUIZ_CASE(poincare_simplification_units) {
Unit::Builder(dim, rep, &Unit::EmptyPrefix).serialize(buffer+strlen("1×"), bufferSize-strlen("1×"), Preferences::PrintFloatMode::Decimal, Preferences::VeryShortNumberOfSignificantDigits);
assert_parsed_expression_simplify_to(buffer, buffer);
if (rep->isPrefixable()) {
for (const Unit::Prefix * pre = rep->outputPrefixes(); pre < rep->outputPrefixesUpperBound(); pre++) {
for (size_t i = 0; i < rep->outputPrefixesLength(); i++) {
const Unit::Prefix * pre = rep->outputPrefixes()[i];
Unit::Builder(dim, rep, pre).serialize(buffer+strlen("1×"), bufferSize-strlen("1×"), Preferences::PrintFloatMode::Decimal, Preferences::VeryShortNumberOfSignificantDigits);
assert_parsed_expression_simplify_to(buffer, buffer);
}