Merge pull request #17 from icu-units/units_exportconverter

Export addSingleFactorConstant in header file
This commit is contained in:
Hugo 2020-07-07 22:55:13 +02:00 committed by GitHub
commit f357b5558e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 159 additions and 146 deletions

View file

@ -18,133 +18,102 @@
U_NAMESPACE_BEGIN
namespace units {
namespace {
/* Internal Structure */
enum Constants {
CONSTANT_FT2M, // ft2m stands for foot to meter.
CONSTANT_PI, // PI
CONSTANT_GRAVITY, // Gravity
CONSTANT_G,
CONSTANT_GAL_IMP2M3, // Gallon imp to m3
CONSTANT_LB2KG, // Pound to Kilogram
// Must be the last element.
CONSTANTS_COUNT
};
typedef enum SigNum {
NEGATIVE = -1,
POSITIVE = 1,
} SigNum;
/* Represents a conversion factor */
struct Factor {
double factorNum = 1;
double factorDen = 1;
double offset = 0;
bool reciprocal = false;
int32_t constants[CONSTANTS_COUNT] = {};
void multiplyBy(const Factor &rhs) {
factorNum *= rhs.factorNum;
factorDen *= rhs.factorDen;
for (int i = 0; i < CONSTANTS_COUNT; i++) {
constants[i] += rhs.constants[i];
}
// NOTE
// We need the offset when the source and the target are simple units. e.g. the source is
// celsius and the target is Fahrenheit. Therefore, we just keep the value using `std::max`.
offset = std::max(rhs.offset, offset);
void Factor::multiplyBy(const Factor &rhs) {
factorNum *= rhs.factorNum;
factorDen *= rhs.factorDen;
for (int i = 0; i < CONSTANTS_COUNT; i++) {
constants[i] += rhs.constants[i];
}
void divideBy(const Factor &rhs) {
factorNum *= rhs.factorDen;
factorDen *= rhs.factorNum;
for (int i = 0; i < CONSTANTS_COUNT; i++) {
constants[i] -= rhs.constants[i];
}
// NOTE
// We need the offset when the source and the target are simple units. e.g. the source is
// celsius and the target is Fahrenheit. Therefore, we just keep the value using `std::max`.
offset = std::max(rhs.offset, offset);
}
// NOTE
// We need the offset when the source and the target are simple units. e.g. the source is
// celsius and the target is Fahrenheit. Therefore, we just keep the value using `std::max`.
offset = std::max(rhs.offset, offset);
void Factor::divideBy(const Factor &rhs) {
factorNum *= rhs.factorDen;
factorDen *= rhs.factorNum;
for (int i = 0; i < CONSTANTS_COUNT; i++) {
constants[i] -= rhs.constants[i];
}
// Apply the power to the factor.
void power(int32_t power) {
// multiply all the constant by the power.
for (int i = 0; i < CONSTANTS_COUNT; i++) {
constants[i] *= power;
}
// NOTE
// We need the offset when the source and the target are simple units. e.g. the source is
// celsius and the target is Fahrenheit. Therefore, we just keep the value using `std::max`.
offset = std::max(rhs.offset, offset);
}
bool shouldFlip = power < 0; // This means that after applying the absolute power, we should flip
// the Numerator and Denominator.
factorNum = std::pow(factorNum, std::abs(power));
factorDen = std::pow(factorDen, std::abs(power));
if (shouldFlip) {
// Flip Numerator and Denominator.
std::swap(factorNum, factorDen);
}
void Factor::power(int32_t power) {
// multiply all the constant by the power.
for (int i = 0; i < CONSTANTS_COUNT; i++) {
constants[i] *= power;
}
// Flip the `Factor`, for example, factor= 2/3, flippedFactor = 3/2
void flip() {
bool shouldFlip = power < 0; // This means that after applying the absolute power, we should flip
// the Numerator and Denominator.
factorNum = std::pow(factorNum, std::abs(power));
factorDen = std::pow(factorDen, std::abs(power));
if (shouldFlip) {
// Flip Numerator and Denominator.
std::swap(factorNum, factorDen);
}
}
for (int i = 0; i < CONSTANTS_COUNT; i++) {
constants[i] *= -1;
}
void Factor::flip() {
std::swap(factorNum, factorDen);
for (int i = 0; i < CONSTANTS_COUNT; i++) {
constants[i] *= -1;
}
}
void Factor::applySiPrefix(UMeasureSIPrefix siPrefix) {
if (siPrefix == UMeasureSIPrefix::UMEASURE_SI_PREFIX_ONE) return; // No need to do anything
double siApplied = std::pow(10.0, std::abs(siPrefix));
if (siPrefix < 0) {
factorDen *= siApplied;
return;
}
// Apply SI prefix to the `Factor`
void applySiPrefix(UMeasureSIPrefix siPrefix) {
if (siPrefix == UMeasureSIPrefix::UMEASURE_SI_PREFIX_ONE) return; // No need to do anything
factorNum *= siApplied;
}
double siApplied = std::pow(10.0, std::abs(siPrefix));
void Factor::substituteConstants() {
double constantsValues[CONSTANTS_COUNT];
if (siPrefix < 0) {
factorDen *= siApplied;
return;
// TODO: Load those constant values from units data.
constantsValues[CONSTANT_FT2M] = 0.3048;
constantsValues[CONSTANT_PI] = 411557987.0 / 131002976.0;
constantsValues[CONSTANT_GRAVITY] = 9.80665;
constantsValues[CONSTANT_G] = 6.67408E-11;
constantsValues[CONSTANT_LB2KG] = 0.45359237;
constantsValues[CONSTANT_GAL_IMP2M3] = 0.00454609;
for (int i = 0; i < CONSTANTS_COUNT; i++) {
if (this->constants[i] == 0) {
continue;
}
factorNum *= siApplied;
}
auto absPower = std::abs(this->constants[i]);
SigNum powerSig = this->constants[i] < 0 ? SigNum::NEGATIVE : SigNum::POSITIVE;
double absConstantValue = std::pow(constantsValues[i], absPower);
void substituteConstants() {
double constantsValues[CONSTANTS_COUNT];
// TODO: Load those constant values from units data.
constantsValues[CONSTANT_FT2M] = 0.3048;
constantsValues[CONSTANT_PI] = 411557987.0 / 131002976.0;
constantsValues[CONSTANT_GRAVITY] = 9.80665;
constantsValues[CONSTANT_G] = 6.67408E-11;
constantsValues[CONSTANT_LB2KG] = 0.45359237;
constantsValues[CONSTANT_GAL_IMP2M3] = 0.00454609;
for (int i = 0; i < CONSTANTS_COUNT; i++) {
if (this->constants[i] == 0) {
continue;
}
auto absPower = std::abs(this->constants[i]);
SigNum powerSig = this->constants[i] < 0 ? SigNum::NEGATIVE : SigNum::POSITIVE;
double absConstantValue = std::pow(constantsValues[i], absPower);
if (powerSig == SigNum::NEGATIVE) {
this->factorDen *= absConstantValue;
} else {
this->factorNum *= absConstantValue;
}
this->constants[i] = 0;
if (powerSig == SigNum::NEGATIVE) {
this->factorDen *= absConstantValue;
} else {
this->factorNum *= absConstantValue;
}
this->constants[i] = 0;
}
};
}
namespace {
/* Helpers */
@ -184,44 +153,6 @@ double strHasDivideSignToDouble(StringPiece strWithDivide, UErrorCode &status) {
return strToDouble(strWithDivide, status);
}
/*
* Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
*/
void addSingleFactorConstant(StringPiece baseStr, int32_t power, SigNum sigNum, Factor &factor,
UErrorCode &status) {
if (baseStr == "ft_to_m") {
factor.constants[CONSTANT_FT2M] += power * sigNum;
} else if (baseStr == "ft2_to_m2") {
factor.constants[CONSTANT_FT2M] += 2 * power * sigNum;
} else if (baseStr == "ft3_to_m3") {
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
} else if (baseStr == "in3_to_m3") {
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
factor.factorDen *= 12 * 12 * 12;
} else if (baseStr == "gal_to_m3") {
factor.factorNum *= 231;
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
factor.factorDen *= 12 * 12 * 12;
} else if (baseStr == "gal_imp_to_m3") {
factor.constants[CONSTANT_GAL_IMP2M3] += power * sigNum;
} else if (baseStr == "G") {
factor.constants[CONSTANT_G] += power * sigNum;
} else if (baseStr == "gravity") {
factor.constants[CONSTANT_GRAVITY] += power * sigNum;
} else if (baseStr == "lb_to_kg") {
factor.constants[CONSTANT_LB2KG] += power * sigNum;
} else if (baseStr == "PI") {
factor.constants[CONSTANT_PI] += power * sigNum;
} else {
if (sigNum == SigNum::NEGATIVE) {
factor.factorDen *= std::pow(strToDouble(baseStr, status), power);
} else {
factor.factorNum *= std::pow(strToDouble(baseStr, status), power);
}
}
}
/*
Adds single factor to a `Factor` object. Single factor means "23^2", "23.3333", "ft2m^3" ...etc.
However, complex factor are not included, such as "ft2m^3*200/3"
@ -387,6 +318,41 @@ void loadConversionRate(ConversionRate &conversionRate, const MeasureUnit &sourc
} // namespace
void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, SigNum sigNum,
Factor &factor, UErrorCode &status) {
if (baseStr == "ft_to_m") {
factor.constants[CONSTANT_FT2M] += power * sigNum;
} else if (baseStr == "ft2_to_m2") {
factor.constants[CONSTANT_FT2M] += 2 * power * sigNum;
} else if (baseStr == "ft3_to_m3") {
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
} else if (baseStr == "in3_to_m3") {
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
factor.factorDen *= 12 * 12 * 12;
} else if (baseStr == "gal_to_m3") {
factor.factorNum *= 231;
factor.constants[CONSTANT_FT2M] += 3 * power * sigNum;
factor.factorDen *= 12 * 12 * 12;
} else if (baseStr == "gal_imp_to_m3") {
factor.constants[CONSTANT_GAL_IMP2M3] += power * sigNum;
} else if (baseStr == "G") {
factor.constants[CONSTANT_G] += power * sigNum;
} else if (baseStr == "gravity") {
factor.constants[CONSTANT_GRAVITY] += power * sigNum;
} else if (baseStr == "lb_to_kg") {
factor.constants[CONSTANT_LB2KG] += power * sigNum;
} else if (baseStr == "PI") {
factor.constants[CONSTANT_PI] += power * sigNum;
} else {
if (sigNum == SigNum::NEGATIVE) {
factor.factorDen *= std::pow(strToDouble(baseStr, status), power);
} else {
factor.factorNum *= std::pow(strToDouble(baseStr, status), power);
}
}
}
/**
* Extracts the compound base unit of a compound unit (`source`). For example, if the source unit is
* `square-mile-per-hour`, the compound base unit will be `square-meter-per-second`

View file

@ -16,6 +16,53 @@
U_NAMESPACE_BEGIN
namespace units {
/* Internal Structure */
enum Constants {
CONSTANT_FT2M, // ft2m stands for foot to meter.
CONSTANT_PI, // PI
CONSTANT_GRAVITY, // Gravity
CONSTANT_G,
CONSTANT_GAL_IMP2M3, // Gallon imp to m3
CONSTANT_LB2KG, // Pound to Kilogram
// Must be the last element.
CONSTANTS_COUNT
};
typedef enum SigNum {
NEGATIVE = -1,
POSITIVE = 1,
} SigNum;
/* Represents a conversion factor */
struct Factor {
double factorNum = 1;
double factorDen = 1;
double offset = 0;
bool reciprocal = false;
int32_t constants[CONSTANTS_COUNT] = {};
void multiplyBy(const Factor &rhs);
void divideBy(const Factor &rhs);
// Apply the power to the factor.
void power(int32_t power);
// Flip the `Factor`, for example, factor= 2/3, flippedFactor = 3/2
void flip();
// Apply SI prefix to the `Factor`
void applySiPrefix(UMeasureSIPrefix siPrefix);
void substituteConstants();
};
/*
* Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
*/
void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, SigNum sigNum,
Factor &factor, UErrorCode &status);
/**
* Represents the conversion rate between `source` and `target`.
*/