ICU-20568 Support smart units / unit contexts / preferences
Explore Usage-related error codes, address icu-units/icu#36. PR: https://github.com/icu-units/icu/pull/56 Commit: d5d7fdccfef887bb1af180bba3e2a0286dc32135 Implement Precision handling in UsagePrefsHandler::processQuantity PR: https://github.com/icu-units/icu/pull/61 Commit: 16547f32986600a46e4adf20a6870c1708dd1c75 Support Mixed Units in NumberFormatter when using usage() PR: https://github.com/icu-units/icu/pull/52 Commit: cc5a12202133855e15ffba889acffc10aad2d46b For MixedUnits, use the correct ListFormatter styles. PR: https://github.com/icu-units/icu/pull/66 Commit: 77bb747002d36626386f18e45c68c44b276cf575 Read the CLDR testData test files from the new location. PR: https://github.com/icu-units/icu/pull/68 Commit: 6eb992e2b3c0bbe4870b554a5aa855b3636566d4 Fix double-precision maths in unit conversions PR: https://github.com/icu-units/icu/pull/71 Commit: 78e88fbddef0f6817654d58c9c5dfeb6606324b9 Support .unit(MIXED_UNIT) without .usage(...). PR: https://github.com/icu-units/icu/pull/72 Commit: 56ac7959375b8c9363ff022185165e52490c6c00 More commits: - Reorder numbertest_api.cpp tests for consistent order. - NumberFormatterApiTest: fold unitPipeline() into unitCompoundMeasure() - Add some 'template class' instantiations for MSVC. - Make trimField handle all whitespace, improve test messages - Drop templated 'appendAll': it requires copy constructor - Add protected MaybeStackArray::copyFrom() - Add TODO(icu-units#67) and commented-out test case: use kUndefinedField for now - Provide correct output order for units like "inch-and-foot" - MSVC: export MaybeStackVector<MeasureUnit> - Code review feedback: dependencies.txt and doc comments - Consistent naming for code files: units_*
This commit is contained in:
parent
1b853904cd
commit
e3123c83a4
@ -387,6 +387,20 @@ public:
|
||||
* caller becomes responsible for deleting the array
|
||||
*/
|
||||
inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
|
||||
|
||||
protected:
|
||||
// Resizes the array to the size of src, then copies the contents of src.
|
||||
void copyFrom(const MaybeStackArray &src, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (this->resize(src.capacity, 0) == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T));
|
||||
}
|
||||
|
||||
private:
|
||||
T *ptr;
|
||||
int32_t capacity;
|
||||
|
@ -55,7 +55,6 @@ class U_I18N_API FormattedStringBuilder : public UMemory {
|
||||
// Convention: bottom 4 bits for field, top 4 bits for field category.
|
||||
// Field category 0 implies the number category so that the number field
|
||||
// literals can be directly passed as a Field type.
|
||||
// See the helper functions in "StringBuilderFieldUtils" below.
|
||||
// Exported as U_I18N_API so it can be used by other exports on Windows.
|
||||
struct U_I18N_API Field {
|
||||
uint8_t bits;
|
||||
|
@ -202,6 +202,7 @@
|
||||
<ClCompile Include="number_multiplier.cpp" />
|
||||
<ClCompile Include="number_currencysymbols.cpp" />
|
||||
<ClCompile Include="number_skeletons.cpp" />
|
||||
<ClCompile Include="number_symbolswrapper.cpp" />
|
||||
<ClCompile Include="number_capi.cpp" />
|
||||
<ClCompile Include="string_segment.cpp" />
|
||||
<ClCompile Include="numparse_parsednumber.cpp" />
|
||||
@ -251,10 +252,10 @@
|
||||
<ClCompile Include="ufieldpositer.cpp" />
|
||||
<ClCompile Include="ulocdata.cpp" />
|
||||
<ClCompile Include="umsg.cpp" />
|
||||
<ClCompile Include="unitconverter.cpp" />
|
||||
<ClCompile Include="complexunitsconverter.cpp" />
|
||||
<ClCompile Include="unitsrouter.cpp" />
|
||||
<ClCompile Include="unitsdata.cpp" />
|
||||
<ClCompile Include="units_complexconverter.cpp" />
|
||||
<ClCompile Include="units_converter.cpp" />
|
||||
<ClCompile Include="units_data.cpp" />
|
||||
<ClCompile Include="units_router.cpp" />
|
||||
<ClCompile Include="unum.cpp" />
|
||||
<ClCompile Include="unumsys.cpp" />
|
||||
<ClCompile Include="upluralrules.cpp" />
|
||||
@ -470,13 +471,14 @@
|
||||
<ClInclude Include="number_scientific.h" />
|
||||
<ClInclude Include="formatted_string_builder.h" />
|
||||
<ClInclude Include="number_types.h" />
|
||||
<ClCompile Include="number_usageprefs.h" />
|
||||
<ClInclude Include="number_usageprefs.h" />
|
||||
<ClInclude Include="number_utypes.h" />
|
||||
<ClInclude Include="number_utils.h" />
|
||||
<ClInclude Include="number_mapper.h" />
|
||||
<ClInclude Include="number_multiplier.h" />
|
||||
<ClInclude Include="number_currencysymbols.h" />
|
||||
<ClInclude Include="number_skeletons.h" />
|
||||
<ClInclude Include="number_symbolswrapper.h" />
|
||||
<ClInclude Include="string_segment.h" />
|
||||
<ClInclude Include="numparse_impl.h" />
|
||||
<ClInclude Include="numparse_symbols.h" />
|
||||
@ -490,10 +492,10 @@
|
||||
<ClInclude Include="numparse_utils.h" />
|
||||
<ClInclude Include="numrange_impl.h" />
|
||||
<ClInclude Include="formattedval_impl.h" />
|
||||
<ClInclude Include="unitconverter.h" />
|
||||
<ClInclude Include="complexunitsconverter.h" />
|
||||
<ClInclude Include="unitsrouter.h" />
|
||||
<ClInclude Include="unitsdata.h" />
|
||||
<ClInclude Include="units_complexconverter.h" />
|
||||
<ClInclude Include="units_converter.h" />
|
||||
<ClInclude Include="units_data.h" />
|
||||
<ClInclude Include="units_router.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="i18n.rc" />
|
||||
|
@ -588,6 +588,9 @@
|
||||
<ClCompile Include="formatted_string_builder.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="number_usageprefs.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="number_utils.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
@ -603,6 +606,9 @@
|
||||
<ClCompile Include="number_skeletons.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="number_symbolswrapper.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="number_capi.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
@ -651,16 +657,16 @@
|
||||
<ClCompile Include="erarules.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="unitconverter.cpp">
|
||||
<ClCompile Include="units_complexconverter.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="complexunitsconverter.cpp">
|
||||
<ClCompile Include="units_converter.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="unitsrouter.cpp">
|
||||
<ClCompile Include="units_data.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="unitsdata.cpp">
|
||||
<ClCompile Include="units_router.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
@ -914,6 +920,9 @@
|
||||
<ClInclude Include="number_utypes.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="number_usageprefs.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="number_utils.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
@ -929,6 +938,9 @@
|
||||
<ClInclude Include="number_skeletons.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="number_symbolswrapper.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="string_segment.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
@ -1007,16 +1019,16 @@
|
||||
<ClInclude Include="umsg_imp.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="unitconveter.h">
|
||||
<ClInclude Include="units_complexconverter.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="complexunitsconverter.h">
|
||||
<ClInclude Include="units_converter.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="unitsrouter.h">
|
||||
<ClInclude Include="units_data.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="unitsdata.h">
|
||||
<ClInclude Include="units_router.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vzone.h">
|
||||
|
@ -483,10 +483,10 @@
|
||||
<ClCompile Include="ufieldpositer.cpp" />
|
||||
<ClCompile Include="ulocdata.cpp" />
|
||||
<ClCompile Include="umsg.cpp" />
|
||||
<ClCompile Include="unitconverter.cpp" />
|
||||
<ClCompile Include="complexunitsconverter.cpp" />
|
||||
<ClCompile Include="unitsrouter.cpp" />
|
||||
<ClCompile Include="unitsdata.cpp" />
|
||||
<ClCompile Include="units_complexconverter.cpp" />
|
||||
<ClCompile Include="units_converter.cpp" />
|
||||
<ClCompile Include="units_data.cpp" />
|
||||
<ClCompile Include="units_router.cpp" />
|
||||
<ClCompile Include="unum.cpp" />
|
||||
<ClCompile Include="unumsys.cpp" />
|
||||
<ClCompile Include="upluralrules.cpp" />
|
||||
@ -723,10 +723,10 @@
|
||||
<ClInclude Include="numparse_utils.h" />
|
||||
<ClInclude Include="numrange_impl.h" />
|
||||
<ClInclude Include="formattedval_impl.h" />
|
||||
<ClInclude Include="unitconverter.h" />
|
||||
<ClInclude Include="complexunitsconverter.h" />
|
||||
<ClInclude Include="unitsrouter.h" />
|
||||
<ClInclude Include="unitsdata.h" />
|
||||
<ClInclude Include="units_complexconverter.h" />
|
||||
<ClInclude Include="units_converter.h" />
|
||||
<ClInclude Include="units_data.h" />
|
||||
<ClInclude Include="units_router.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="i18n.rc" />
|
||||
|
@ -520,123 +520,6 @@ LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale
|
||||
return LocalizedNumberFormatter(std::move(fMacros), locale);
|
||||
}
|
||||
|
||||
SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) {
|
||||
doCopyFrom(other);
|
||||
}
|
||||
|
||||
SymbolsWrapper::SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT {
|
||||
doMoveFrom(std::move(src));
|
||||
}
|
||||
|
||||
SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
doCleanup();
|
||||
doCopyFrom(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SymbolsWrapper& SymbolsWrapper::operator=(SymbolsWrapper&& src) U_NOEXCEPT {
|
||||
if (this == &src) {
|
||||
return *this;
|
||||
}
|
||||
doCleanup();
|
||||
doMoveFrom(std::move(src));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SymbolsWrapper::~SymbolsWrapper() {
|
||||
doCleanup();
|
||||
}
|
||||
|
||||
void SymbolsWrapper::setTo(const DecimalFormatSymbols& dfs) {
|
||||
doCleanup();
|
||||
fType = SYMPTR_DFS;
|
||||
fPtr.dfs = new DecimalFormatSymbols(dfs);
|
||||
}
|
||||
|
||||
void SymbolsWrapper::setTo(const NumberingSystem* ns) {
|
||||
doCleanup();
|
||||
fType = SYMPTR_NS;
|
||||
fPtr.ns = ns;
|
||||
}
|
||||
|
||||
void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) {
|
||||
fType = other.fType;
|
||||
switch (fType) {
|
||||
case SYMPTR_NONE:
|
||||
// No action necessary
|
||||
break;
|
||||
case SYMPTR_DFS:
|
||||
// Memory allocation failures are exposed in copyErrorTo()
|
||||
if (other.fPtr.dfs != nullptr) {
|
||||
fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs);
|
||||
} else {
|
||||
fPtr.dfs = nullptr;
|
||||
}
|
||||
break;
|
||||
case SYMPTR_NS:
|
||||
// Memory allocation failures are exposed in copyErrorTo()
|
||||
if (other.fPtr.ns != nullptr) {
|
||||
fPtr.ns = new NumberingSystem(*other.fPtr.ns);
|
||||
} else {
|
||||
fPtr.ns = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolsWrapper::doMoveFrom(SymbolsWrapper&& src) {
|
||||
fType = src.fType;
|
||||
switch (fType) {
|
||||
case SYMPTR_NONE:
|
||||
// No action necessary
|
||||
break;
|
||||
case SYMPTR_DFS:
|
||||
fPtr.dfs = src.fPtr.dfs;
|
||||
src.fPtr.dfs = nullptr;
|
||||
break;
|
||||
case SYMPTR_NS:
|
||||
fPtr.ns = src.fPtr.ns;
|
||||
src.fPtr.ns = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolsWrapper::doCleanup() {
|
||||
switch (fType) {
|
||||
case SYMPTR_NONE:
|
||||
// No action necessary
|
||||
break;
|
||||
case SYMPTR_DFS:
|
||||
delete fPtr.dfs;
|
||||
break;
|
||||
case SYMPTR_NS:
|
||||
delete fPtr.ns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SymbolsWrapper::isDecimalFormatSymbols() const {
|
||||
return fType == SYMPTR_DFS;
|
||||
}
|
||||
|
||||
bool SymbolsWrapper::isNumberingSystem() const {
|
||||
return fType == SYMPTR_NS;
|
||||
}
|
||||
|
||||
const DecimalFormatSymbols* SymbolsWrapper::getDecimalFormatSymbols() const {
|
||||
U_ASSERT(fType == SYMPTR_DFS);
|
||||
return fPtr.dfs;
|
||||
}
|
||||
|
||||
const NumberingSystem* SymbolsWrapper::getNumberingSystem() const {
|
||||
U_ASSERT(fType == SYMPTR_NS);
|
||||
return fPtr.ns;
|
||||
}
|
||||
|
||||
|
||||
FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
|
||||
auto results = new UFormattedNumberData();
|
||||
|
@ -25,9 +25,6 @@ using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
|
||||
|
||||
MicroPropsGenerator::~MicroPropsGenerator() = default;
|
||||
|
||||
|
||||
NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& status)
|
||||
: NumberFormatterImpl(macros, true, status) {
|
||||
}
|
||||
@ -162,6 +159,8 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
|
||||
|| !(isPercent || isPermille)
|
||||
|| isCompactNotation
|
||||
);
|
||||
bool isMixedUnit = isCldrUnit && (uprv_strcmp(macros.unit.getType(), "") == 0) &&
|
||||
macros.unit.getComplexity(status) == UMEASURE_UNIT_MIXED;
|
||||
|
||||
// Select the numbering system.
|
||||
LocalPointer<const NumberingSystem> nsLocal;
|
||||
@ -241,7 +240,8 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
|
||||
// Unit Preferences and Conversions as our first step
|
||||
if (macros.usage.isSet()) {
|
||||
if (!isCldrUnit) {
|
||||
// We only support "usage" when the input unit is a CLDR Unit.
|
||||
// We only support "usage" when the input unit is specified, and is
|
||||
// a CLDR Unit.
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
@ -249,6 +249,10 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
|
||||
new UsagePrefsHandler(macros.locale, macros.unit, macros.usage.fUsage, chain, status);
|
||||
fUsagePrefsHandler.adoptInsteadAndCheckErrorCode(usagePrefsHandler, status);
|
||||
chain = fUsagePrefsHandler.getAlias();
|
||||
} else if (isMixedUnit) {
|
||||
auto unitConversionHandler = new UnitConversionHandler(macros.unit, chain, status);
|
||||
fUnitConversionHandler.adoptInsteadAndCheckErrorCode(unitConversionHandler, status);
|
||||
chain = fUnitConversionHandler.getAlias();
|
||||
}
|
||||
|
||||
// Multiplier
|
||||
@ -265,16 +269,14 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
|
||||
precision = Precision::integer().withMinDigits(2);
|
||||
} else if (isCurrency) {
|
||||
precision = Precision::currency(UCURR_USAGE_STANDARD);
|
||||
} else if (macros.usage.isSet()) {
|
||||
// Bogus Precision - it will get set in the UsagePrefsHandler instead
|
||||
precision = Precision();
|
||||
} else {
|
||||
precision = Precision::maxFraction(6);
|
||||
}
|
||||
UNumberFormatRoundingMode roundingMode;
|
||||
if (macros.roundingMode != kDefaultMode) {
|
||||
roundingMode = macros.roundingMode;
|
||||
} else {
|
||||
// Temporary until ICU 64
|
||||
roundingMode = precision.fRoundingMode;
|
||||
}
|
||||
roundingMode = macros.roundingMode;
|
||||
fMicros.rounder = {precision, roundingMode, currency, status};
|
||||
if (U_FAILURE(status)) {
|
||||
return nullptr;
|
||||
@ -375,6 +377,14 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
|
||||
resolvePluralRules(macros.rules, macros.locale, status), chain, status),
|
||||
status);
|
||||
chain = fLongNameMultiplexer.getAlias();
|
||||
} else if (isMixedUnit) {
|
||||
fMixedUnitLongNameHandler.adoptInsteadAndCheckErrorCode(new MixedUnitLongNameHandler(),
|
||||
status);
|
||||
MixedUnitLongNameHandler::forMeasureUnit(
|
||||
macros.locale, macros.unit, unitWidth,
|
||||
resolvePluralRules(macros.rules, macros.locale, status), chain,
|
||||
fMixedUnitLongNameHandler.getAlias(), status);
|
||||
chain = fMixedUnitLongNameHandler.getAlias();
|
||||
} else {
|
||||
fLongNameHandler.adoptInsteadAndCheckErrorCode(new LongNameHandler(), status);
|
||||
LongNameHandler::forMeasureUnit(macros.locale, macros.unit, macros.perUnit, unitWidth,
|
||||
|
@ -94,6 +94,7 @@ class NumberFormatterImpl : public UMemory {
|
||||
// Other fields possibly used by the number formatting pipeline:
|
||||
// TODO: Convert more of these LocalPointers to value objects to reduce the number of news?
|
||||
LocalPointer<const UsagePrefsHandler> fUsagePrefsHandler;
|
||||
LocalPointer<const UnitConversionHandler> fUnitConversionHandler;
|
||||
LocalPointer<const DecimalFormatSymbols> fSymbols;
|
||||
LocalPointer<const PluralRules> fRules;
|
||||
LocalPointer<const ParsedPatternInfo> fPatternInfo;
|
||||
@ -101,6 +102,10 @@ class NumberFormatterImpl : public UMemory {
|
||||
LocalPointer<MutablePatternModifier> fPatternModifier;
|
||||
LocalPointer<ImmutablePatternModifier> fImmutablePatternModifier;
|
||||
LocalPointer<LongNameHandler> fLongNameHandler;
|
||||
// TODO: use a common base class that enables fLongNameHandler,
|
||||
// fLongNameMultiplexer, and fMixedUnitLongNameHandler to be merged into one
|
||||
// member?
|
||||
LocalPointer<MixedUnitLongNameHandler> fMixedUnitLongNameHandler;
|
||||
LocalPointer<const LongNameMultiplexer> fLongNameMultiplexer;
|
||||
LocalPointer<const CompactHandler> fCompactHandler;
|
||||
|
||||
|
@ -40,6 +40,9 @@ IntegerWidth IntegerWidth::truncateAt(int32_t maxInt) {
|
||||
}
|
||||
|
||||
void IntegerWidth::apply(impl::DecimalQuantity& quantity, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (fHasError) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
} else if (fUnion.minMaxInt.fMaxInt == -1) {
|
||||
|
@ -38,6 +38,7 @@ constexpr int32_t DNAM_INDEX = StandardPlural::Form::COUNT;
|
||||
* `per` forms.
|
||||
*/
|
||||
constexpr int32_t PER_INDEX = StandardPlural::Form::COUNT + 1;
|
||||
// Number of keys in the array populated by PluralTableSink.
|
||||
constexpr int32_t ARRAY_LENGTH = StandardPlural::Form::COUNT + 2;
|
||||
|
||||
static int32_t getIndex(const char* pluralKeyword, UErrorCode& status) {
|
||||
@ -52,6 +53,11 @@ static int32_t getIndex(const char* pluralKeyword, UErrorCode& status) {
|
||||
}
|
||||
}
|
||||
|
||||
// Selects a string out of the `strings` array which corresponds to the
|
||||
// specified plural form, with fallback to the OTHER form.
|
||||
//
|
||||
// The `strings` array must have ARRAY_LENGTH items: one corresponding to each
|
||||
// of the plural forms, plus a display name ("dnam") and a "per" form.
|
||||
static UnicodeString getWithPlural(
|
||||
const UnicodeString* strings,
|
||||
StandardPlural::Form plural,
|
||||
@ -101,12 +107,18 @@ class PluralTableSink : public ResourceSink {
|
||||
|
||||
// NOTE: outArray MUST have room for all StandardPlural values. No bounds checking is performed.
|
||||
|
||||
// Populates outArray with `locale`-specific values for `unit` through use of
|
||||
// PluralTableSink, reading from resources *unitsNarrow* and *unitsShort* (for
|
||||
// width UNUM_UNIT_WIDTH_NARROW), or just *unitsShort* (for width
|
||||
// UNUM_UNIT_WIDTH_SHORT). For other widths, it would read just "units".
|
||||
//
|
||||
// outArray must be of fixed length ARRAY_LENGTH.
|
||||
/**
|
||||
* Populates outArray with `locale`-specific values for `unit` through use of
|
||||
* PluralTableSink. Only the set of basic units are supported!
|
||||
*
|
||||
* Reading from resources *unitsNarrow* and *unitsShort* (for width
|
||||
* UNUM_UNIT_WIDTH_NARROW), or just *unitsShort* (for width
|
||||
* UNUM_UNIT_WIDTH_SHORT). For other widths, it reads just "units".
|
||||
*
|
||||
* @param unit must have a type and subtype (i.e. it must be a unit listed in
|
||||
* gTypes and gSubTypes in measunit.cpp).
|
||||
* @param outArray must be of fixed length ARRAY_LENGTH.
|
||||
*/
|
||||
void getMeasureData(const Locale &locale, const MeasureUnit &unit, const UNumberUnitWidth &width,
|
||||
UnicodeString *outArray, UErrorCode &status) {
|
||||
PluralTableSink sink(outArray);
|
||||
@ -204,24 +216,26 @@ UnicodeString getPerUnitFormat(const Locale& locale, const UNumberUnitWidth &wid
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(units,hugovdm): deal properly with "perUnit" parameter here:
|
||||
void LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef,
|
||||
const MeasureUnit &perUnit, const UNumberUnitWidth &width,
|
||||
const PluralRules *rules, const MicroPropsGenerator *parent,
|
||||
LongNameHandler *fillIn, UErrorCode &status) {
|
||||
if (fillIn == nullptr) {
|
||||
status = U_INTERNAL_PROGRAM_ERROR;
|
||||
return;
|
||||
}
|
||||
// Not valid for mixed units that aren't built-in units, and there should
|
||||
// not be any built-in mixed units!
|
||||
U_ASSERT(uprv_strlen(unitRef.getType()) > 0 || unitRef.getComplexity(status) != UMEASURE_UNIT_MIXED);
|
||||
U_ASSERT(fillIn != nullptr);
|
||||
if (uprv_strlen(unitRef.getType()) == 0 || uprv_strlen(perUnit.getType()) == 0) {
|
||||
// TODO(ICU-20941): Unsanctioned unit. Not yet fully supported. Set an error code.
|
||||
// TODO(ICU-20941): Unsanctioned unit. Not yet fully supported. Set an
|
||||
// error code. Once we support not-built-in units here, unitRef may be
|
||||
// anything, but if not built-in, perUnit has to be "none".
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
MeasureUnit unit = unitRef;
|
||||
if (uprv_strcmp(perUnit.getType(), "none") != 0) {
|
||||
// Compound unit: first try to simplify (e.g., meters per second is its own unit).
|
||||
// Compound unit: first try to simplify (e.g. "meter per second" is a
|
||||
// built-in unit).
|
||||
bool isResolved = false;
|
||||
MeasureUnit resolved = MeasureUnit::resolveUnitPerUnit(unit, perUnit, &isResolved);
|
||||
if (isResolved) {
|
||||
@ -244,7 +258,6 @@ void LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitR
|
||||
status);
|
||||
}
|
||||
|
||||
// TODO(units,hugovdm): deal properly with "perUnit" parameter here:
|
||||
void LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit,
|
||||
const MeasureUnit &perUnit, const UNumberUnitWidth &width,
|
||||
const PluralRules *rules, const MicroPropsGenerator *parent,
|
||||
@ -390,6 +403,131 @@ const Modifier* LongNameHandler::getModifier(Signum /*signum*/, StandardPlural::
|
||||
return &fModifiers[plural];
|
||||
}
|
||||
|
||||
void MixedUnitLongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &mixedUnit,
|
||||
const UNumberUnitWidth &width, const PluralRules *rules,
|
||||
const MicroPropsGenerator *parent,
|
||||
MixedUnitLongNameHandler *fillIn, UErrorCode &status) {
|
||||
U_ASSERT(mixedUnit.getComplexity(status) == UMEASURE_UNIT_MIXED);
|
||||
U_ASSERT(fillIn != nullptr);
|
||||
|
||||
LocalArray<MeasureUnit> individualUnits =
|
||||
mixedUnit.splitToSingleUnits(fillIn->fMixedUnitCount, status);
|
||||
fillIn->fMixedUnitData.adoptInstead(new UnicodeString[fillIn->fMixedUnitCount * ARRAY_LENGTH]);
|
||||
for (int32_t i = 0; i < fillIn->fMixedUnitCount; i++) {
|
||||
// Grab data for each of the components.
|
||||
UnicodeString *unitData = &fillIn->fMixedUnitData[i * ARRAY_LENGTH];
|
||||
getMeasureData(loc, individualUnits[i], width, unitData, status);
|
||||
}
|
||||
|
||||
UListFormatterWidth listWidth = ULISTFMT_WIDTH_SHORT;
|
||||
if (width == UNUM_UNIT_WIDTH_NARROW) {
|
||||
listWidth = ULISTFMT_WIDTH_NARROW;
|
||||
} else if (width == UNUM_UNIT_WIDTH_FULL_NAME) {
|
||||
// This might be the same as SHORT in most languages:
|
||||
listWidth = ULISTFMT_WIDTH_WIDE;
|
||||
}
|
||||
fillIn->fListFormatter.adoptInsteadAndCheckErrorCode(
|
||||
ListFormatter::createInstance(loc, ULISTFMT_TYPE_UNITS, listWidth, status), status);
|
||||
fillIn->rules = rules;
|
||||
fillIn->parent = parent;
|
||||
|
||||
// We need a localised NumberFormatter for the integers of the bigger units
|
||||
// (providing Arabic numerals, for example).
|
||||
fillIn->fIntegerFormatter = NumberFormatter::withLocale(loc);
|
||||
}
|
||||
|
||||
void MixedUnitLongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps µs,
|
||||
UErrorCode &status) const {
|
||||
U_ASSERT(fMixedUnitCount > 1);
|
||||
if (parent != nullptr) {
|
||||
parent->processQuantity(quantity, micros, status);
|
||||
}
|
||||
micros.modOuter = getMixedUnitModifier(quantity, micros, status);
|
||||
}
|
||||
|
||||
const Modifier *MixedUnitLongNameHandler::getMixedUnitModifier(DecimalQuantity &quantity,
|
||||
MicroProps µs,
|
||||
UErrorCode &status) const {
|
||||
// TODO(icu-units#21): mixed units without usage() is not yet supported.
|
||||
// That should be the only reason why this happens, so delete this whole if
|
||||
// once fixed:
|
||||
if (micros.mixedMeasuresCount == 0) {
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return µs.helpers.emptyWeakModifier;
|
||||
}
|
||||
U_ASSERT(micros.mixedMeasuresCount > 0);
|
||||
// mixedMeasures does not contain the last value:
|
||||
U_ASSERT(fMixedUnitCount == micros.mixedMeasuresCount + 1);
|
||||
U_ASSERT(fListFormatter.isValid());
|
||||
|
||||
// Algorithm:
|
||||
//
|
||||
// For the mixed-units measurement of: "3 yard, 1 foot, 2.6 inch", we should
|
||||
// find "3 yard" and "1 foot" in micros.mixedMeasures.
|
||||
//
|
||||
// Obtain long-names with plural forms corresponding to measure values:
|
||||
// * {0} yards, {0} foot, {0} inches
|
||||
//
|
||||
// Format the integer values appropriately and modify with the format
|
||||
// strings:
|
||||
// - 3 yards, 1 foot
|
||||
//
|
||||
// Use ListFormatter to combine, with one placeholder:
|
||||
// - 3 yards, 1 foot and {0} inches
|
||||
//
|
||||
// Return a SimpleModifier for this pattern, letting the rest of the
|
||||
// pipeline take care of the remaining inches.
|
||||
|
||||
LocalArray<UnicodeString> outputMeasuresList(new UnicodeString[fMixedUnitCount], status);
|
||||
if (U_FAILURE(status)) {
|
||||
return µs.helpers.emptyWeakModifier;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < micros.mixedMeasuresCount; i++) {
|
||||
DecimalQuantity fdec;
|
||||
fdec.setToLong(micros.mixedMeasures[i]);
|
||||
StandardPlural::Form pluralForm = utils::getStandardPlural(rules, fdec);
|
||||
|
||||
UnicodeString simpleFormat =
|
||||
getWithPlural(&fMixedUnitData[i * ARRAY_LENGTH], pluralForm, status);
|
||||
SimpleFormatter compiledFormatter(simpleFormat, 0, 1, status);
|
||||
|
||||
UnicodeString num;
|
||||
auto appendable = UnicodeStringAppendable(num);
|
||||
fIntegerFormatter.formatDecimalQuantity(fdec, status).appendTo(appendable, status);
|
||||
compiledFormatter.format(num, outputMeasuresList[i], status);
|
||||
}
|
||||
|
||||
UnicodeString *finalSimpleFormats = &fMixedUnitData[(fMixedUnitCount - 1) * ARRAY_LENGTH];
|
||||
StandardPlural::Form finalPlural = utils::getPluralSafe(micros.rounder, rules, quantity, status);
|
||||
UnicodeString finalSimpleFormat = getWithPlural(finalSimpleFormats, finalPlural, status);
|
||||
SimpleFormatter finalFormatter(finalSimpleFormat, 0, 1, status);
|
||||
finalFormatter.format(UnicodeString(u"{0}"), outputMeasuresList[fMixedUnitCount - 1], status);
|
||||
|
||||
// Combine list into a "premixed" pattern
|
||||
UnicodeString premixedFormatPattern;
|
||||
fListFormatter->format(outputMeasuresList.getAlias(), fMixedUnitCount, premixedFormatPattern,
|
||||
status);
|
||||
SimpleFormatter premixedCompiled(premixedFormatPattern, 0, 1, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return µs.helpers.emptyWeakModifier;
|
||||
}
|
||||
|
||||
// Return a SimpleModifier for the "premixed" pattern
|
||||
micros.helpers.mixedUnitModifier =
|
||||
SimpleModifier(premixedCompiled, kUndefinedField, false, {this, SIGNUM_POS_ZERO, finalPlural});
|
||||
return µs.helpers.mixedUnitModifier;
|
||||
}
|
||||
|
||||
const Modifier *MixedUnitLongNameHandler::getModifier(Signum /*signum*/,
|
||||
StandardPlural::Form /*plural*/) const {
|
||||
// TODO(units): investigate this method when investigating where
|
||||
// LongNameHandler::getModifier() gets used. To be sure it remains
|
||||
// unreachable:
|
||||
UPRV_UNREACHABLE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LongNameMultiplexer *
|
||||
LongNameMultiplexer::forMeasureUnits(const Locale &loc, const MaybeStackVector<MeasureUnit> &units,
|
||||
const UNumberUnitWidth &width, const PluralRules *rules,
|
||||
@ -399,16 +537,23 @@ LongNameMultiplexer::forMeasureUnits(const Locale &loc, const MaybeStackVector<M
|
||||
return nullptr;
|
||||
}
|
||||
U_ASSERT(units.length() > 0);
|
||||
if (result->fHandlers.resize(units.length()) == nullptr) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
result->fMeasureUnits.adoptInstead(new MeasureUnit[units.length()]);
|
||||
for (int32_t i = 0, length = units.length(); i < length; i++) {
|
||||
// Create empty new LongNameHandler:
|
||||
LongNameHandler *lnh =
|
||||
result->fLongNameHandlers.emplaceBackAndCheckErrorCode(status);
|
||||
result->fMeasureUnits[i] = *units[i];
|
||||
// Fill in LongNameHandler:
|
||||
LongNameHandler::forMeasureUnit(loc, *units[i],
|
||||
MeasureUnit(), // TODO(units): deal with COMPOUND and MIXED units
|
||||
width, rules, NULL, lnh, status);
|
||||
const MeasureUnit& unit = *units[i];
|
||||
result->fMeasureUnits[i] = unit;
|
||||
if (unit.getComplexity(status) == UMEASURE_UNIT_MIXED) {
|
||||
MixedUnitLongNameHandler *mlnh = result->fMixedUnitHandlers.createAndCheckErrorCode(status);
|
||||
MixedUnitLongNameHandler::forMeasureUnit(loc, unit, width, rules, NULL, mlnh, status);
|
||||
result->fHandlers[i] = mlnh;
|
||||
} else {
|
||||
LongNameHandler *lnh = result->fLongNameHandlers.createAndCheckErrorCode(status);
|
||||
LongNameHandler::forMeasureUnit(loc, unit, MeasureUnit(), width, rules, NULL, lnh, status);
|
||||
result->fHandlers[i] = lnh;
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -424,12 +569,15 @@ void LongNameMultiplexer::processQuantity(DecimalQuantity &quantity, MicroProps
|
||||
fParent->processQuantity(quantity, micros, status);
|
||||
|
||||
// Call the correct LongNameHandler based on outputUnit
|
||||
for (int i = 0; i < fLongNameHandlers.length(); i++) {
|
||||
for (int i = 0; i < fHandlers.getCapacity(); i++) {
|
||||
if (fMeasureUnits[i] == micros.outputUnit) {
|
||||
fLongNameHandlers[i]->processQuantity(quantity, micros, status);
|
||||
fHandlers[i]->processQuantity(quantity, micros, status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
// We shouldn't receive any outputUnit for which we haven't already got a
|
||||
// LongNameHandler:
|
||||
status = U_INTERNAL_PROGRAM_ERROR;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define __NUMBER_LONGNAMES_H__
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "unicode/listformatter.h"
|
||||
#include "unicode/uversion.h"
|
||||
#include "number_utils.h"
|
||||
#include "number_modifiers.h"
|
||||
@ -34,17 +35,47 @@ class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public
|
||||
forCurrencyLongNames(const Locale &loc, const CurrencyUnit ¤cy, const PluralRules *rules,
|
||||
const MicroPropsGenerator *parent, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Construct a localized LongNameHandler for the specified MeasureUnit.
|
||||
*
|
||||
* Compound units can be constructed via `unit` and `perUnit`. Both of these
|
||||
* must then be built-in units.
|
||||
*
|
||||
* Mixed units are not supported, use MixedUnitLongNameHandler::forMeasureUnit.
|
||||
*
|
||||
* This function uses a fillIn intead of returning a pointer, because we
|
||||
* want to fill in instances in a MemoryPool (which cannot adopt pointers it
|
||||
* didn't create itself).
|
||||
*
|
||||
* @param loc The desired locale.
|
||||
* @param unit The measure unit to construct a LongNameHandler for. If
|
||||
* `perUnit` is also defined, `unit` must not be a mixed unit.
|
||||
* @param perUnit If `unit` is a mixed unit, `perUnit` must be "none".
|
||||
* @param width Specifies the desired unit rendering.
|
||||
* @param rules Does not take ownership.
|
||||
* @param parent Does not take ownership.
|
||||
* @param fillIn Required.
|
||||
*/
|
||||
static void forMeasureUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
|
||||
const UNumberUnitWidth &width, const PluralRules *rules,
|
||||
const MicroPropsGenerator *parent, LongNameHandler *fillIn,
|
||||
UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Selects the plural-appropriate Modifier from the set of fModifiers based
|
||||
* on the plural form.
|
||||
*/
|
||||
void
|
||||
processQuantity(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const U_OVERRIDE;
|
||||
|
||||
// TODO(units): investigate whether we might run into Mixed Unit trouble
|
||||
// with this. This override for ModifierStore::getModifier does not support
|
||||
// mixed units: investigate under which circumstances it gets called (check
|
||||
// both ImmutablePatternModifier and in NumberRangeFormatterImpl).
|
||||
const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE;
|
||||
|
||||
private:
|
||||
// A set of pre-computed modifiers, one for each plural form.
|
||||
SimpleModifier fModifiers[StandardPlural::Form::COUNT];
|
||||
// Not owned
|
||||
const PluralRules *rules;
|
||||
@ -58,34 +89,136 @@ class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public
|
||||
LongNameHandler() : rules(nullptr), parent(nullptr) {
|
||||
}
|
||||
|
||||
friend class MemoryPool<LongNameHandler>; // To enable emplaceBack();
|
||||
// Enables MemoryPool<LongNameHandler>::emplaceBack(): requires access to
|
||||
// the private constructors.
|
||||
friend class MemoryPool<LongNameHandler>;
|
||||
|
||||
// Allow macrosToMicroGenerator to call the private default constructor.
|
||||
friend class NumberFormatterImpl;
|
||||
|
||||
// Fills in LongNameHandler fields for formatting compound units identified
|
||||
// via `unit` and `perUnit`. Both `unit` and `perUnit` need to be built-in
|
||||
// units (for which data exists).
|
||||
static void forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
|
||||
const UNumberUnitWidth &width, const PluralRules *rules,
|
||||
const MicroPropsGenerator *parent, LongNameHandler *fillIn,
|
||||
UErrorCode &status);
|
||||
|
||||
// Sets fModifiers to use the patterns from `simpleFormats`.
|
||||
void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status);
|
||||
|
||||
// Sets fModifiers to a combination of `leadFormats` (one per plural form)
|
||||
// and `trailFormat` appended to each.
|
||||
//
|
||||
// With a leadFormat of "{0}m" and a trailFormat of "{0}/s", it produces a
|
||||
// pattern of "{0}m/s" by inserting the leadFormat pattern into trailFormat.
|
||||
void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
|
||||
Field field, UErrorCode &status);
|
||||
};
|
||||
|
||||
const int MAX_PREFS_COUNT = 10;
|
||||
// Similar to LongNameHandler, but only for MIXED units.
|
||||
class MixedUnitLongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory {
|
||||
public:
|
||||
/**
|
||||
* Construct a localized MixedUnitLongNameHandler for the specified
|
||||
* MeasureUnit. It must be a MIXED unit.
|
||||
*
|
||||
* This function uses a fillIn intead of returning a pointer, because we
|
||||
* want to fill in instances in a MemoryPool (which cannot adopt pointers it
|
||||
* didn't create itself).
|
||||
*
|
||||
* @param loc The desired locale.
|
||||
* @param mixedUnit The mixed measure unit to construct a
|
||||
* MixedUnitLongNameHandler for.
|
||||
* @param width Specifies the desired unit rendering.
|
||||
* @param rules Does not take ownership.
|
||||
* @param parent Does not take ownership.
|
||||
* @param fillIn Required.
|
||||
*/
|
||||
static void forMeasureUnit(const Locale &loc, const MeasureUnit &mixedUnit,
|
||||
const UNumberUnitWidth &width, const PluralRules *rules,
|
||||
const MicroPropsGenerator *parent, MixedUnitLongNameHandler *fillIn,
|
||||
UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Produces a plural-appropriate Modifier for a mixed unit: `quantity` is
|
||||
* taken as the final smallest unit, while the larger unit values must be
|
||||
* provided via `micros.mixedMeasures`.
|
||||
*/
|
||||
void processQuantity(DecimalQuantity &quantity, MicroProps µs,
|
||||
UErrorCode &status) const U_OVERRIDE;
|
||||
|
||||
// Required for ModifierStore. And ModifierStore is required by
|
||||
// SimpleModifier constructor's last parameter. We assert his will never get
|
||||
// called though.
|
||||
const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Not owned
|
||||
const PluralRules *rules;
|
||||
// Not owned
|
||||
const MicroPropsGenerator *parent;
|
||||
|
||||
// Total number of units in the MeasureUnit this LongNameHandler was
|
||||
// configured for: for "foot-and-inch", this will be 2. (If not a mixed unit,
|
||||
// this will be 1.)
|
||||
int32_t fMixedUnitCount = 1;
|
||||
// If this LongNameHandler is for a mixed unit, this stores unit data for
|
||||
// each of the individual units. For each unit, it stores ARRAY_LENGTH
|
||||
// strings, as returned by getMeasureData. (Each unit with index `i` has
|
||||
// ARRAY_LENGTH strings starting at index `i*ARRAY_LENGTH` in this array.)
|
||||
LocalArray<UnicodeString> fMixedUnitData;
|
||||
// A localized NumberFormatter used to format the integer-valued bigger
|
||||
// units of Mixed Unit measurements.
|
||||
LocalizedNumberFormatter fIntegerFormatter;
|
||||
// A localised list formatter for joining mixed units together.
|
||||
LocalPointer<ListFormatter> fListFormatter;
|
||||
|
||||
MixedUnitLongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent)
|
||||
: rules(rules), parent(parent) {
|
||||
}
|
||||
|
||||
MixedUnitLongNameHandler() : rules(nullptr), parent(nullptr) {
|
||||
}
|
||||
|
||||
// Allow macrosToMicroGenerator to call the private default constructor.
|
||||
friend class NumberFormatterImpl;
|
||||
|
||||
// Enables MemoryPool<LongNameHandler>::emplaceBack(): requires access to
|
||||
// the private constructors.
|
||||
friend class MemoryPool<MixedUnitLongNameHandler>;
|
||||
|
||||
// Fills in LongNameHandler fields for formatting mixed units. Each unit in
|
||||
// a mixed unit must be a built-in unit.
|
||||
static void forMixedUnit(const Locale &loc, const MeasureUnit &unit, const UNumberUnitWidth &width,
|
||||
const PluralRules *rules, const MicroPropsGenerator *parent,
|
||||
MixedUnitLongNameHandler *fillIn, UErrorCode &status);
|
||||
|
||||
// For a mixed unit, returns a Modifier that takes only one parameter: the
|
||||
// smallest and final unit of the set. The bigger units' values and labels
|
||||
// get baked into this Modifier, together with the unit label of the final
|
||||
// unit.
|
||||
const Modifier *getMixedUnitModifier(DecimalQuantity &quantity, MicroProps µs,
|
||||
UErrorCode &status) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A MicroPropsGenerator that multiplexes between different LongNameHandlers,
|
||||
* depending on the outputUnit (micros.helpers.outputUnit should be set earlier
|
||||
* in the chain).
|
||||
* depending on the outputUnit.
|
||||
*
|
||||
* See processQuantity() for the input requirements.
|
||||
*/
|
||||
class LongNameMultiplexer : public MicroPropsGenerator, public UMemory {
|
||||
public:
|
||||
// FIXME: docstring?
|
||||
// Produces a multiplexer for LongNameHandlers, one for each unit in
|
||||
// `units`. An individual unit might be a mixed unit.
|
||||
static LongNameMultiplexer *forMeasureUnits(const Locale &loc,
|
||||
const MaybeStackVector<MeasureUnit> &units,
|
||||
const UNumberUnitWidth &width, const PluralRules *rules,
|
||||
const MicroPropsGenerator *parent, UErrorCode &status);
|
||||
|
||||
// The output unit must be provided via `micros.outputUnit`, it must match
|
||||
// one of the units provided to the factory function.
|
||||
void processQuantity(DecimalQuantity &quantity, MicroProps µs,
|
||||
UErrorCode &status) const U_OVERRIDE;
|
||||
|
||||
@ -95,8 +228,14 @@ class LongNameMultiplexer : public MicroPropsGenerator, public UMemory {
|
||||
* earlier MicroPropsGenerators in the chain, LongNameMultiplexer keeps the
|
||||
* parent link, while the LongNameHandlers are given no parents.
|
||||
*/
|
||||
MaybeStackVector<LongNameHandler> fLongNameHandlers;
|
||||
MemoryPool<LongNameHandler> fLongNameHandlers;
|
||||
MemoryPool<MixedUnitLongNameHandler> fMixedUnitHandlers;
|
||||
// Unowned pointers to instances owned by MaybeStackVectors.
|
||||
MaybeStackArray<MicroPropsGenerator *, 8> fHandlers;
|
||||
// Each MeasureUnit corresponds to the same-index MicroPropsGenerator
|
||||
// pointed to in fHandlers.
|
||||
LocalArray<MeasureUnit> fMeasureUnits;
|
||||
|
||||
const MicroPropsGenerator *fParent;
|
||||
|
||||
LongNameMultiplexer(const MicroPropsGenerator *parent) : fParent(parent) {
|
||||
|
@ -92,6 +92,8 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
|
||||
int32_t minSig = properties.minimumSignificantDigits;
|
||||
int32_t maxSig = properties.maximumSignificantDigits;
|
||||
double roundingIncrement = properties.roundingIncrement;
|
||||
// Not assigning directly to macros.roundingMode here: we change
|
||||
// roundingMode if and when we also change macros.precision.
|
||||
RoundingMode roundingMode = properties.roundingMode.getOrDefault(UNUM_ROUND_HALFEVEN);
|
||||
bool explicitMinMaxFrac = minFrac != -1 || maxFrac != -1;
|
||||
bool explicitMinMaxSig = minSig != -1 || maxSig != -1;
|
||||
@ -145,7 +147,7 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
|
||||
precision = Precision::constructCurrency(currencyUsage);
|
||||
}
|
||||
if (!precision.isBogus()) {
|
||||
precision.fRoundingMode = roundingMode;
|
||||
macros.roundingMode = roundingMode;
|
||||
macros.precision = precision;
|
||||
}
|
||||
|
||||
@ -239,7 +241,7 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
|
||||
// TODO: Reset maxSig_ = 1 + minFrac_ to follow the spec.
|
||||
macros.precision = Precision::constructSignificant(minSig_, maxSig_);
|
||||
}
|
||||
macros.precision.fRoundingMode = roundingMode;
|
||||
macros.roundingMode = roundingMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,51 @@
|
||||
U_NAMESPACE_BEGIN namespace number {
|
||||
namespace impl {
|
||||
|
||||
/**
|
||||
* A copyable container for the integer values of mixed unit measurements.
|
||||
*
|
||||
* If memory allocation fails during copying, no values are copied and status is
|
||||
* set to U_MEMORY_ALLOCATION_ERROR.
|
||||
*/
|
||||
class IntMeasures : public MaybeStackArray<int64_t, 2> {
|
||||
public:
|
||||
/**
|
||||
* Default constructor initializes with internal T[stackCapacity] buffer.
|
||||
*
|
||||
* Stack Capacity: most mixed units are expected to consist of two or three
|
||||
* subunits, so one or two integer measures should be enough.
|
||||
*/
|
||||
IntMeasures() : MaybeStackArray<int64_t, 2>() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* If memory allocation fails during copying, no values are copied and
|
||||
* status is set to U_MEMORY_ALLOCATION_ERROR.
|
||||
*/
|
||||
IntMeasures(const IntMeasures &other) : MaybeStackArray<int64_t, 2>() {
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
// Assignment operator
|
||||
IntMeasures &operator=(const IntMeasures &rhs) {
|
||||
if (this == &rhs) {
|
||||
return *this;
|
||||
}
|
||||
copyFrom(rhs, status);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Move constructor */
|
||||
IntMeasures(IntMeasures &&src) = default;
|
||||
|
||||
/** Move assignment */
|
||||
IntMeasures &operator=(IntMeasures &&src) = default;
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
};
|
||||
|
||||
// TODO(units): generated by MicroPropsGenerator, but inherits from it too. Do
|
||||
// we want to better document why? There's an explanation for processQuantity:
|
||||
// * As MicroProps is the "base instance", this implementation of
|
||||
@ -41,22 +86,48 @@ struct MicroProps : public MicroPropsGenerator {
|
||||
|
||||
// Note: This struct has no direct ownership of the following pointers.
|
||||
const DecimalFormatSymbols* symbols;
|
||||
|
||||
// Pointers to Modifiers provided by the number formatting pipeline (when
|
||||
// the value is known):
|
||||
|
||||
// A Modifier provided by LongNameHandler, used for currency long names and
|
||||
// units. If there is no LongNameHandler needed, this should be an
|
||||
// EmptyModifier. (This is typically the third modifier applied.)
|
||||
const Modifier* modOuter;
|
||||
// A Modifier for short currencies and compact notation. (This is typically
|
||||
// the second modifier applied.)
|
||||
const Modifier* modMiddle = nullptr;
|
||||
// A Modifier provided by ScientificHandler, used for scientific notation.
|
||||
// This is typically the first modifier applied.
|
||||
const Modifier* modInner;
|
||||
|
||||
// The following "helper" fields may optionally be used during the MicroPropsGenerator.
|
||||
// They live here to retain memory.
|
||||
struct {
|
||||
// The ScientificModifier for which ScientificHandler is responsible.
|
||||
// ScientificHandler::processQuantity() modifies this Modifier.
|
||||
ScientificModifier scientificModifier;
|
||||
// EmptyModifier used for modOuter
|
||||
EmptyModifier emptyWeakModifier{false};
|
||||
// EmptyModifier used for modInner
|
||||
EmptyModifier emptyStrongModifier{true};
|
||||
MultiplierFormatHandler multiplier;
|
||||
// A Modifier used for Mixed Units. When formatting mixed units,
|
||||
// LongNameHandler assigns this Modifier.
|
||||
SimpleModifier mixedUnitModifier;
|
||||
} helpers;
|
||||
|
||||
// The MeasureUnit with which the output measurement is represented.
|
||||
// The MeasureUnit with which the output is represented. May also have
|
||||
// UMEASURE_UNIT_MIXED complexity, in which case mixedMeasures comes into
|
||||
// play.
|
||||
MeasureUnit outputUnit;
|
||||
|
||||
// In the case of mixed units, this is the set of integer-only units
|
||||
// *preceding* the final unit.
|
||||
IntMeasures mixedMeasures;
|
||||
// Number of mixedMeasures that have been populated
|
||||
int32_t mixedMeasuresCount = 0;
|
||||
|
||||
MicroProps() = default;
|
||||
|
||||
MicroProps(const MicroProps& other) = default;
|
||||
|
@ -5,13 +5,16 @@
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "charstr.h"
|
||||
#include "uassert.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
#include "number_types.h"
|
||||
#include "number_decimalquantity.h"
|
||||
#include "double-conversion.h"
|
||||
#include "number_roundingutils.h"
|
||||
#include "number_skeletons.h"
|
||||
#include "putilimp.h"
|
||||
#include "string_segment.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
@ -19,6 +22,40 @@ using namespace icu::number::impl;
|
||||
|
||||
|
||||
using double_conversion::DoubleToStringConverter;
|
||||
using icu::StringSegment;
|
||||
|
||||
// Most blueprint_helpers live in number_skeletons.cpp. This one is in
|
||||
// number_rounding.cpp for dependency reasons.
|
||||
void blueprint_helpers::parseIncrementOption(const StringSegment &segment, MacroProps ¯os,
|
||||
UErrorCode &status) {
|
||||
// Need to do char <-> UChar conversion...
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
CharString buffer;
|
||||
SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status);
|
||||
|
||||
// Utilize DecimalQuantity/decNumber to parse this for us.
|
||||
DecimalQuantity dq;
|
||||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
dq.setToDecNumber({buffer.data(), buffer.length()}, localStatus);
|
||||
if (U_FAILURE(localStatus)) {
|
||||
// throw new SkeletonSyntaxException("Invalid rounding increment", segment, e);
|
||||
status = U_NUMBER_SKELETON_SYNTAX_ERROR;
|
||||
return;
|
||||
}
|
||||
double increment = dq.toDouble();
|
||||
|
||||
// We also need to figure out how many digits. Do a brute force string operation.
|
||||
int decimalOffset = 0;
|
||||
while (decimalOffset < segment.length() && segment.charAt(decimalOffset) != '.') {
|
||||
decimalOffset++;
|
||||
}
|
||||
if (decimalOffset == segment.length()) {
|
||||
macros.precision = Precision::increment(increment);
|
||||
} else {
|
||||
int32_t fractionLength = segment.length() - decimalOffset - 1;
|
||||
macros.precision = Precision::increment(increment).withMinFraction(fractionLength);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@ -84,7 +121,7 @@ digits_t roundingutils::doubleFractionLength(double input, int8_t* singleDigit)
|
||||
|
||||
|
||||
Precision Precision::unlimited() {
|
||||
return Precision(RND_NONE, {}, kDefaultMode);
|
||||
return Precision(RND_NONE, {});
|
||||
}
|
||||
|
||||
FractionPrecision Precision::integer() {
|
||||
@ -229,7 +266,7 @@ FractionPrecision Precision::constructFraction(int32_t minFrac, int32_t maxFrac)
|
||||
settings.fMaxSig = -1;
|
||||
PrecisionUnion union_;
|
||||
union_.fracSig = settings;
|
||||
return {RND_FRACTION, union_, kDefaultMode};
|
||||
return {RND_FRACTION, union_};
|
||||
}
|
||||
|
||||
Precision Precision::constructSignificant(int32_t minSig, int32_t maxSig) {
|
||||
@ -240,7 +277,7 @@ Precision Precision::constructSignificant(int32_t minSig, int32_t maxSig) {
|
||||
settings.fMaxSig = static_cast<digits_t>(maxSig);
|
||||
PrecisionUnion union_;
|
||||
union_.fracSig = settings;
|
||||
return {RND_SIGNIFICANT, union_, kDefaultMode};
|
||||
return {RND_SIGNIFICANT, union_};
|
||||
}
|
||||
|
||||
Precision
|
||||
@ -250,7 +287,7 @@ Precision::constructFractionSignificant(const FractionPrecision &base, int32_t m
|
||||
settings.fMaxSig = static_cast<digits_t>(maxSig);
|
||||
PrecisionUnion union_;
|
||||
union_.fracSig = settings;
|
||||
return {RND_FRACTION_SIGNIFICANT, union_, kDefaultMode};
|
||||
return {RND_FRACTION_SIGNIFICANT, union_};
|
||||
}
|
||||
|
||||
IncrementPrecision Precision::constructIncrement(double increment, int32_t minFrac) {
|
||||
@ -270,18 +307,18 @@ IncrementPrecision Precision::constructIncrement(double increment, int32_t minFr
|
||||
// NOTE: In C++, we must return the correct value type with the correct union.
|
||||
// It would be invalid to return a RND_FRACTION here because the methods on the
|
||||
// IncrementPrecision type assume that the union is backed by increment data.
|
||||
return {RND_INCREMENT_ONE, union_, kDefaultMode};
|
||||
return {RND_INCREMENT_ONE, union_};
|
||||
} else if (singleDigit == 5) {
|
||||
return {RND_INCREMENT_FIVE, union_, kDefaultMode};
|
||||
return {RND_INCREMENT_FIVE, union_};
|
||||
} else {
|
||||
return {RND_INCREMENT, union_, kDefaultMode};
|
||||
return {RND_INCREMENT, union_};
|
||||
}
|
||||
}
|
||||
|
||||
CurrencyPrecision Precision::constructCurrency(UCurrencyUsage usage) {
|
||||
PrecisionUnion union_;
|
||||
union_.currencyUsage = usage;
|
||||
return {RND_CURRENCY, union_, kDefaultMode};
|
||||
return {RND_CURRENCY, union_};
|
||||
}
|
||||
|
||||
|
||||
@ -341,6 +378,9 @@ RoundingImpl::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl:
|
||||
|
||||
/** This is the method that contains the actual rounding logic. */
|
||||
void RoundingImpl::apply(impl::DecimalQuantity &value, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (fPassThrough) {
|
||||
return;
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ enum Section {
|
||||
inline bool
|
||||
getRoundingDirection(bool isEven, bool isNegative, Section section, RoundingMode roundingMode,
|
||||
UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return false;
|
||||
}
|
||||
switch (roundingMode) {
|
||||
case RoundingMode::UNUM_ROUND_UP:
|
||||
// round away from zero
|
||||
@ -187,6 +190,12 @@ class RoundingImpl {
|
||||
Precision fPrecision;
|
||||
UNumberFormatRoundingMode fRoundingMode;
|
||||
bool fPassThrough = true; // default value
|
||||
|
||||
// Permits access to fPrecision.
|
||||
friend class UsagePrefsHandler;
|
||||
|
||||
// Permits access to fPrecision.
|
||||
friend class UnitConversionHandler;
|
||||
};
|
||||
|
||||
|
||||
|
@ -152,21 +152,6 @@ UPRV_BLOCK_MACRO_BEGIN { \
|
||||
} UPRV_BLOCK_MACRO_END
|
||||
|
||||
|
||||
#define SKELETON_UCHAR_TO_CHAR(dest, src, start, end, status) (void)(dest); \
|
||||
UPRV_BLOCK_MACRO_BEGIN { \
|
||||
UErrorCode conversionStatus = U_ZERO_ERROR; \
|
||||
(dest).appendInvariantChars({FALSE, (src).getBuffer() + (start), (end) - (start)}, conversionStatus); \
|
||||
if (conversionStatus == U_INVARIANT_CONVERSION_ERROR) { \
|
||||
/* Don't propagate the invariant conversion error; it is a skeleton syntax error */ \
|
||||
(status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \
|
||||
return; \
|
||||
} else if (U_FAILURE(conversionStatus)) { \
|
||||
(status) = conversionStatus; \
|
||||
return; \
|
||||
} \
|
||||
} UPRV_BLOCK_MACRO_END
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
@ -480,6 +465,7 @@ UnicodeString skeleton::generate(const MacroProps& macros, UErrorCode& status) {
|
||||
MacroProps skeleton::parseSkeleton(
|
||||
const UnicodeString& skeletonString, int32_t& errOffset, UErrorCode& status) {
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
U_ASSERT(kSerializedStemTrie != nullptr);
|
||||
|
||||
// Add a trailing whitespace to the end of the skeleton string to make code cleaner.
|
||||
UnicodeString tempSkeletonString(skeletonString);
|
||||
@ -586,6 +572,8 @@ MacroProps skeleton::parseSkeleton(
|
||||
ParseState
|
||||
skeleton::parseStem(const StringSegment& segment, const UCharsTrie& stemTrie, SeenMacroProps& seen,
|
||||
MacroProps& macros, UErrorCode& status) {
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
|
||||
// First check for "blueprint" stems, which start with a "signal char"
|
||||
switch (segment.charAt(0)) {
|
||||
case u'.':
|
||||
@ -764,6 +752,7 @@ skeleton::parseStem(const StringSegment& segment, const UCharsTrie& stemTrie, Se
|
||||
|
||||
ParseState skeleton::parseOption(ParseState stem, const StringSegment& segment, MacroProps& macros,
|
||||
UErrorCode& status) {
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
|
||||
///// Required options: /////
|
||||
|
||||
@ -992,6 +981,7 @@ blueprint_helpers::generateCurrencyOption(const CurrencyUnit& currency, UnicodeS
|
||||
|
||||
void blueprint_helpers::parseMeasureUnitOption(const StringSegment& segment, MacroProps& macros,
|
||||
UErrorCode& status) {
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
const UnicodeString stemString = segment.toTempUnicodeString();
|
||||
|
||||
// NOTE: The category (type) of the unit is guaranteed to be a valid subtag (alphanumeric)
|
||||
@ -1007,7 +997,6 @@ void blueprint_helpers::parseMeasureUnitOption(const StringSegment& segment, Mac
|
||||
}
|
||||
|
||||
// Need to do char <-> UChar conversion...
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
CharString type;
|
||||
SKELETON_UCHAR_TO_CHAR(type, stemString, 0, firstHyphen, status);
|
||||
CharString subType;
|
||||
@ -1069,7 +1058,15 @@ void blueprint_helpers::parseIdentifierUnitOption(const StringSegment& segment,
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(ICU-20941): Clean this up.
|
||||
// Mixed units can only be represented by a full MeasureUnit instances, so
|
||||
// we ignore macros.perUnit.
|
||||
if (fullUnit.complexity == UMEASURE_UNIT_MIXED) {
|
||||
macros.unit = std::move(fullUnit).build(status);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(ICU-20941): Clean this up (see also
|
||||
// https://github.com/icu-units/icu/issues/35).
|
||||
for (int32_t i = 0; i < fullUnit.units.length(); i++) {
|
||||
SingleUnitImpl* subUnit = fullUnit.units[i];
|
||||
if (subUnit->dimensionality > 0) {
|
||||
@ -1336,36 +1333,8 @@ bool blueprint_helpers::parseFracSigOption(const StringSegment& segment, MacroPr
|
||||
return true;
|
||||
}
|
||||
|
||||
void blueprint_helpers::parseIncrementOption(const StringSegment& segment, MacroProps& macros,
|
||||
UErrorCode& status) {
|
||||
// Need to do char <-> UChar conversion...
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
CharString buffer;
|
||||
SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status);
|
||||
|
||||
// Utilize DecimalQuantity/decNumber to parse this for us.
|
||||
DecimalQuantity dq;
|
||||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
dq.setToDecNumber({buffer.data(), buffer.length()}, localStatus);
|
||||
if (U_FAILURE(localStatus)) {
|
||||
// throw new SkeletonSyntaxException("Invalid rounding increment", segment, e);
|
||||
status = U_NUMBER_SKELETON_SYNTAX_ERROR;
|
||||
return;
|
||||
}
|
||||
double increment = dq.toDouble();
|
||||
|
||||
// We also need to figure out how many digits. Do a brute force string operation.
|
||||
int decimalOffset = 0;
|
||||
while (decimalOffset < segment.length() && segment.charAt(decimalOffset) != '.') {
|
||||
decimalOffset++;
|
||||
}
|
||||
if (decimalOffset == segment.length()) {
|
||||
macros.precision = Precision::increment(increment);
|
||||
} else {
|
||||
int32_t fractionLength = segment.length() - decimalOffset - 1;
|
||||
macros.precision = Precision::increment(increment).withMinFraction(fractionLength);
|
||||
}
|
||||
}
|
||||
// blueprint_helpers::parseIncrementOption lives in number_rounding.cpp for
|
||||
// dependencies reasons.
|
||||
|
||||
void blueprint_helpers::generateIncrementOption(double increment, int32_t trailingZeros, UnicodeString& sb,
|
||||
UErrorCode&) {
|
||||
@ -1551,10 +1520,14 @@ bool GeneratorHelpers::unit(const MacroProps& macros, UnicodeString& sb, UErrorC
|
||||
} else if (utils::unitIsPermille(macros.unit)) {
|
||||
sb.append(u"permille", -1);
|
||||
return true;
|
||||
} else {
|
||||
} else if (uprv_strcmp(macros.unit.getType(), "") != 0) {
|
||||
sb.append(u"measure-unit/", -1);
|
||||
blueprint_helpers::generateMeasureUnitOption(macros.unit, sb, status);
|
||||
return true;
|
||||
} else {
|
||||
// TODO(icu-units#35): add support for not-built-in units.
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1573,7 +1546,7 @@ bool GeneratorHelpers::perUnit(const MacroProps& macros, UnicodeString& sb, UErr
|
||||
}
|
||||
}
|
||||
|
||||
bool GeneratorHelpers::usage(const MacroProps& macros, UnicodeString& sb, UErrorCode&) {
|
||||
bool GeneratorHelpers::usage(const MacroProps& macros, UnicodeString& sb, UErrorCode& /* status */) {
|
||||
if (macros.usage.fLength > 0) {
|
||||
sb.append(u"usage/", -1);
|
||||
sb.append(UnicodeString(macros.usage.fUsage, -1, US_INV));
|
||||
|
@ -246,6 +246,10 @@ void generateMeasureUnitOption(const MeasureUnit& measureUnit, UnicodeString& sb
|
||||
|
||||
void parseMeasurePerUnitOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Parses unit identifiers like "meter-per-second" and "foot-and-inch", as
|
||||
* specified via a "unit/" concise skeleton.
|
||||
*/
|
||||
void parseIdentifierUnitOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
|
||||
|
||||
void parseUnitUsageOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
|
||||
@ -355,6 +359,24 @@ struct SeenMacroProps {
|
||||
bool scale = false;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
#define SKELETON_UCHAR_TO_CHAR(dest, src, start, end, status) (void)(dest); \
|
||||
UPRV_BLOCK_MACRO_BEGIN { \
|
||||
UErrorCode conversionStatus = U_ZERO_ERROR; \
|
||||
(dest).appendInvariantChars({false, (src).getBuffer() + (start), (end) - (start)}, conversionStatus); \
|
||||
if (conversionStatus == U_INVARIANT_CONVERSION_ERROR) { \
|
||||
/* Don't propagate the invariant conversion error; it is a skeleton syntax error */ \
|
||||
(status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \
|
||||
return; \
|
||||
} else if (U_FAILURE(conversionStatus)) { \
|
||||
(status) = conversionStatus; \
|
||||
return; \
|
||||
} \
|
||||
} UPRV_BLOCK_MACRO_END
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace impl
|
||||
} // namespace number
|
||||
U_NAMESPACE_END
|
||||
|
125
icu4c/source/i18n/number_symbolswrapper.cpp
Normal file
125
icu4c/source/i18n/number_symbolswrapper.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
// © 2020 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
|
||||
#include "number_microprops.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
|
||||
SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper &other) {
|
||||
doCopyFrom(other);
|
||||
}
|
||||
|
||||
SymbolsWrapper::SymbolsWrapper(SymbolsWrapper &&src) U_NOEXCEPT {
|
||||
doMoveFrom(std::move(src));
|
||||
}
|
||||
|
||||
SymbolsWrapper &SymbolsWrapper::operator=(const SymbolsWrapper &other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
doCleanup();
|
||||
doCopyFrom(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SymbolsWrapper &SymbolsWrapper::operator=(SymbolsWrapper &&src) U_NOEXCEPT {
|
||||
if (this == &src) {
|
||||
return *this;
|
||||
}
|
||||
doCleanup();
|
||||
doMoveFrom(std::move(src));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SymbolsWrapper::~SymbolsWrapper() {
|
||||
doCleanup();
|
||||
}
|
||||
|
||||
void SymbolsWrapper::setTo(const DecimalFormatSymbols &dfs) {
|
||||
doCleanup();
|
||||
fType = SYMPTR_DFS;
|
||||
fPtr.dfs = new DecimalFormatSymbols(dfs);
|
||||
}
|
||||
|
||||
void SymbolsWrapper::setTo(const NumberingSystem *ns) {
|
||||
doCleanup();
|
||||
fType = SYMPTR_NS;
|
||||
fPtr.ns = ns;
|
||||
}
|
||||
|
||||
void SymbolsWrapper::doCopyFrom(const SymbolsWrapper &other) {
|
||||
fType = other.fType;
|
||||
switch (fType) {
|
||||
case SYMPTR_NONE:
|
||||
// No action necessary
|
||||
break;
|
||||
case SYMPTR_DFS:
|
||||
// Memory allocation failures are exposed in copyErrorTo()
|
||||
if (other.fPtr.dfs != nullptr) {
|
||||
fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs);
|
||||
} else {
|
||||
fPtr.dfs = nullptr;
|
||||
}
|
||||
break;
|
||||
case SYMPTR_NS:
|
||||
// Memory allocation failures are exposed in copyErrorTo()
|
||||
if (other.fPtr.ns != nullptr) {
|
||||
fPtr.ns = new NumberingSystem(*other.fPtr.ns);
|
||||
} else {
|
||||
fPtr.ns = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolsWrapper::doMoveFrom(SymbolsWrapper &&src) {
|
||||
fType = src.fType;
|
||||
switch (fType) {
|
||||
case SYMPTR_NONE:
|
||||
// No action necessary
|
||||
break;
|
||||
case SYMPTR_DFS:
|
||||
fPtr.dfs = src.fPtr.dfs;
|
||||
src.fPtr.dfs = nullptr;
|
||||
break;
|
||||
case SYMPTR_NS:
|
||||
fPtr.ns = src.fPtr.ns;
|
||||
src.fPtr.ns = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolsWrapper::doCleanup() {
|
||||
switch (fType) {
|
||||
case SYMPTR_NONE:
|
||||
// No action necessary
|
||||
break;
|
||||
case SYMPTR_DFS:
|
||||
delete fPtr.dfs;
|
||||
break;
|
||||
case SYMPTR_NS:
|
||||
delete fPtr.ns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SymbolsWrapper::isDecimalFormatSymbols() const {
|
||||
return fType == SYMPTR_DFS;
|
||||
}
|
||||
|
||||
bool SymbolsWrapper::isNumberingSystem() const {
|
||||
return fType == SYMPTR_NS;
|
||||
}
|
||||
|
||||
const DecimalFormatSymbols *SymbolsWrapper::getDecimalFormatSymbols() const {
|
||||
U_ASSERT(fType == SYMPTR_DFS);
|
||||
return fPtr.dfs;
|
||||
}
|
||||
|
||||
const NumberingSystem *SymbolsWrapper::getNumberingSystem() const {
|
||||
U_ASSERT(fType == SYMPTR_NS);
|
||||
return fPtr.ns;
|
||||
}
|
@ -262,7 +262,7 @@ class U_I18N_API ModifierStore {
|
||||
*/
|
||||
class U_I18N_API MicroPropsGenerator {
|
||||
public:
|
||||
virtual ~MicroPropsGenerator();
|
||||
virtual ~MicroPropsGenerator() = default;
|
||||
|
||||
/**
|
||||
* Considers the given {@link DecimalQuantity}, optionally mutates it, and
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "number_decimalquantity.h"
|
||||
#include "number_microprops.h"
|
||||
#include "number_roundingutils.h"
|
||||
#include "number_skeletons.h"
|
||||
#include "unicode/char16ptr.h"
|
||||
#include "unicode/currunit.h"
|
||||
#include "unicode/fmtable.h"
|
||||
@ -18,9 +19,13 @@
|
||||
#include "unicode/platform.h"
|
||||
#include "unicode/unum.h"
|
||||
#include "unicode/urename.h"
|
||||
#include "units_data.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
using icu::StringSegment;
|
||||
using icu::units::ConversionRates;
|
||||
|
||||
// Copy constructor
|
||||
Usage::Usage(const Usage &other) : fUsage(nullptr), fLength(other.fLength), fError(other.fError) {
|
||||
@ -41,10 +46,7 @@ Usage &Usage::operator=(const Usage &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Move constructor - can it be improved by taking over src's "this" instead of
|
||||
// copying contents? Swapping pointers makes sense for heap objects but not for
|
||||
// stack objects.
|
||||
// *this = std::move(src);
|
||||
// Move constructor
|
||||
Usage::Usage(Usage &&src) U_NOEXCEPT : fUsage(src.fUsage), fLength(src.fLength), fError(src.fError) {
|
||||
// Take ownership away from src if necessary
|
||||
src.fUsage = nullptr;
|
||||
@ -84,8 +86,43 @@ void Usage::set(StringPiece value) {
|
||||
fUsage[fLength] = 0;
|
||||
}
|
||||
|
||||
void mixedMeasuresToMicros(const MaybeStackVector<Measure> &measures, DecimalQuantity *quantity,
|
||||
MicroProps *micros, UErrorCode status) {
|
||||
micros->mixedMeasuresCount = measures.length() - 1;
|
||||
if (micros->mixedMeasuresCount > 0) {
|
||||
#ifdef U_DEBUG
|
||||
U_ASSERT(micros->outputUnit.getComplexity(status) == UMEASURE_UNIT_MIXED);
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
// Check that we received measurements with the expected MeasureUnits:
|
||||
int32_t singleUnitsCount;
|
||||
LocalArray<MeasureUnit> singleUnits =
|
||||
micros->outputUnit.splitToSingleUnits(singleUnitsCount, status);
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
U_ASSERT(measures.length() == singleUnitsCount);
|
||||
for (int32_t i = 0; i < measures.length(); i++) {
|
||||
U_ASSERT(measures[i]->getUnit() == singleUnits[i]);
|
||||
}
|
||||
#endif
|
||||
// Mixed units: except for the last value, we pass all values to the
|
||||
// LongNameHandler via micros->mixedMeasures.
|
||||
if (micros->mixedMeasures.getCapacity() < micros->mixedMeasuresCount) {
|
||||
if (micros->mixedMeasures.resize(micros->mixedMeasuresCount) == nullptr) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (int32_t i = 0; i < micros->mixedMeasuresCount; i++) {
|
||||
micros->mixedMeasures[i] = measures[i]->getNumber().getInt64();
|
||||
}
|
||||
} else {
|
||||
micros->mixedMeasuresCount = 0;
|
||||
}
|
||||
// The last value (potentially the only value) gets passed on via quantity.
|
||||
quantity->setToDouble(measures[measures.length() - 1]->getNumber().getDouble());
|
||||
}
|
||||
|
||||
UsagePrefsHandler::UsagePrefsHandler(const Locale &locale,
|
||||
const MeasureUnit inputUnit,
|
||||
const MeasureUnit &inputUnit,
|
||||
const StringPiece usage,
|
||||
const MicroPropsGenerator *parent,
|
||||
UErrorCode &status)
|
||||
@ -102,25 +139,95 @@ void UsagePrefsHandler::processQuantity(DecimalQuantity &quantity, MicroProps &m
|
||||
|
||||
quantity.roundToInfinity(); // Enables toDouble
|
||||
const auto routed = fUnitsRouter.route(quantity.toDouble(), status);
|
||||
const auto& routedUnits = routed.measures;
|
||||
micros.outputUnit = routedUnits[0]->getUnit();
|
||||
quantity.setToDouble(routedUnits[0]->getNumber().getDouble());
|
||||
|
||||
// TODO(units): here we are always overriding Precision. (1) get precision
|
||||
// from fUnitsRouter, (2) ensure we use the UnitPreference skeleton's
|
||||
// precision only when there isn't an explicit override we prefer to use.
|
||||
// This needs to be handled within
|
||||
// NumberFormatterImpl::macrosToMicroGenerator in number_formatimpl.cpp
|
||||
// TODO: Use precision from `routed` result.
|
||||
Precision precision = Precision::integer().withMinDigits(2);
|
||||
UNumberFormatRoundingMode roundingMode;
|
||||
// Temporary until ICU 64?
|
||||
roundingMode = precision.fRoundingMode;
|
||||
CurrencyUnit currency(u"", status);
|
||||
micros.rounder = {precision, roundingMode, currency, status};
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
const MaybeStackVector<Measure>& routedUnits = routed.measures;
|
||||
micros.outputUnit = routed.outputUnit.copy(status).build(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mixedMeasuresToMicros(routedUnits, &quantity, µs, status);
|
||||
|
||||
UnicodeString precisionSkeleton = routed.precision;
|
||||
if (micros.rounder.fPrecision.isBogus()) {
|
||||
if (precisionSkeleton.length() > 0) {
|
||||
micros.rounder.fPrecision = parseSkeletonToPrecision(precisionSkeleton, status);
|
||||
} else {
|
||||
// We use the same rounding mode as COMPACT notation: known to be a
|
||||
// human-friendly rounding mode: integers, but add a decimal digit
|
||||
// as needed to ensure we have at least 2 significant digits.
|
||||
micros.rounder.fPrecision = Precision::integer().withMinDigits(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Precision UsagePrefsHandler::parseSkeletonToPrecision(icu::UnicodeString precisionSkeleton,
|
||||
UErrorCode status) {
|
||||
if (U_FAILURE(status)) {
|
||||
// As a member of UsagePrefsHandler, which is a friend of Precision, we
|
||||
// get access to the default constructor.
|
||||
return {};
|
||||
}
|
||||
constexpr int32_t kSkelPrefixLen = 20;
|
||||
if (!precisionSkeleton.startsWith(UNICODE_STRING_SIMPLE("precision-increment/"))) {
|
||||
status = U_INVALID_FORMAT_ERROR;
|
||||
return {};
|
||||
}
|
||||
U_ASSERT(precisionSkeleton[kSkelPrefixLen - 1] == u'/');
|
||||
StringSegment segment(precisionSkeleton, false);
|
||||
segment.adjustOffset(kSkelPrefixLen);
|
||||
MacroProps macros;
|
||||
blueprint_helpers::parseIncrementOption(segment, macros, status);
|
||||
return macros.precision;
|
||||
}
|
||||
|
||||
UnitConversionHandler::UnitConversionHandler(const MeasureUnit &unit, const MicroPropsGenerator *parent,
|
||||
UErrorCode &status)
|
||||
: fOutputUnit(unit), fParent(parent) {
|
||||
MeasureUnitImpl temp;
|
||||
const MeasureUnitImpl &outputUnit = MeasureUnitImpl::forMeasureUnit(unit, temp, status);
|
||||
const MeasureUnitImpl *inputUnit = &outputUnit;
|
||||
MaybeStackVector<MeasureUnitImpl> singleUnits;
|
||||
U_ASSERT(outputUnit.complexity == UMEASURE_UNIT_MIXED);
|
||||
// When we wish to support unit conversion, replace the above assert with this if:
|
||||
// if (outputUnit.complexity == UMEASURE_UNIT_MIXED) {
|
||||
{
|
||||
singleUnits = outputUnit.extractIndividualUnits(status);
|
||||
U_ASSERT(singleUnits.length() > 0);
|
||||
inputUnit = singleUnits[0];
|
||||
}
|
||||
// TODO: this should become an initOnce thing? Review with other
|
||||
// ConversionRates usages.
|
||||
ConversionRates conversionRates(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
fUnitConverter.adoptInsteadAndCheckErrorCode(
|
||||
new ComplexUnitsConverter(*inputUnit, outputUnit, conversionRates, status), status);
|
||||
}
|
||||
|
||||
void UnitConversionHandler::processQuantity(DecimalQuantity &quantity, MicroProps µs,
|
||||
UErrorCode &status) const {
|
||||
fParent->processQuantity(quantity, micros, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
quantity.roundToInfinity(); // Enables toDouble
|
||||
MaybeStackVector<Measure> measures = fUnitConverter->convert(quantity.toDouble(), status);
|
||||
micros.outputUnit = fOutputUnit;
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mixedMeasuresToMicros(measures, &quantity, µs, status);
|
||||
|
||||
// TODO: add tests to explore behaviour that may suggest a more
|
||||
// human-centric default rounder?
|
||||
// if (micros.rounder.fPrecision.isBogus()) {
|
||||
// micros.rounder.fPrecision = Precision::integer().withMinDigits(2);
|
||||
// }
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
@ -9,18 +9,23 @@
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "number_types.h"
|
||||
#include "unicode/listformatter.h"
|
||||
#include "unicode/localpointer.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/measunit.h"
|
||||
#include "unicode/stringpiece.h"
|
||||
#include "unicode/uobject.h"
|
||||
#include "unitsrouter.h"
|
||||
#include "units_converter.h"
|
||||
#include "units_router.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
using ::icu::units::ComplexUnitsConverter;
|
||||
using ::icu::units::UnitsRouter;
|
||||
|
||||
namespace number {
|
||||
namespace impl {
|
||||
|
||||
using ::icu::units::UnitsRouter;
|
||||
|
||||
/**
|
||||
* A MicroPropsGenerator which uses UnitsRouter to produce output converted to a
|
||||
* MeasureUnit appropriate for a particular localized usage: see
|
||||
@ -28,12 +33,15 @@ using ::icu::units::UnitsRouter;
|
||||
*/
|
||||
class U_I18N_API UsagePrefsHandler : public MicroPropsGenerator, public UMemory {
|
||||
public:
|
||||
UsagePrefsHandler(const Locale &locale, const MeasureUnit inputUnit, const StringPiece usage,
|
||||
UsagePrefsHandler(const Locale &locale, const MeasureUnit &inputUnit, const StringPiece usage,
|
||||
const MicroPropsGenerator *parent, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Obtains the appropriate output value, MeasurementUnit and
|
||||
* Obtains the appropriate output value, MeasureUnit and
|
||||
* rounding/precision behaviour from the UnitsRouter.
|
||||
*
|
||||
* The output unit is passed on to the LongNameHandler via
|
||||
* micros.outputUnit.
|
||||
*/
|
||||
void processQuantity(DecimalQuantity &quantity, MicroProps µs,
|
||||
UErrorCode &status) const U_OVERRIDE;
|
||||
@ -52,6 +60,62 @@ class U_I18N_API UsagePrefsHandler : public MicroPropsGenerator, public UMemory
|
||||
private:
|
||||
UnitsRouter fUnitsRouter;
|
||||
const MicroPropsGenerator *fParent;
|
||||
|
||||
static Precision parseSkeletonToPrecision(icu::UnicodeString precisionSkeleton, UErrorCode status);
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
} // namespace number
|
||||
|
||||
// Export explicit template instantiations of LocalPointerBase and LocalPointer.
|
||||
// This is required when building DLLs for Windows. (See datefmt.h,
|
||||
// collationiterator.h, erarules.h and others for similar examples.)
|
||||
//
|
||||
// Note: These need to be outside of the number::impl namespace, or Clang will
|
||||
// generate a compile error.
|
||||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
#if defined(_MSC_VER)
|
||||
// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4661)
|
||||
#endif
|
||||
template class U_I18N_API LocalPointerBase<ComplexUnitsConverter>;
|
||||
template class U_I18N_API LocalPointer<ComplexUnitsConverter>;
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace number {
|
||||
namespace impl {
|
||||
|
||||
/**
|
||||
* A MicroPropsGenerator which converts a measurement from a simple MeasureUnit
|
||||
* to a Mixed MeasureUnit.
|
||||
*/
|
||||
class U_I18N_API UnitConversionHandler : public MicroPropsGenerator, public UMemory {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param unit Specifies both the input and output MeasureUnit: if it is a
|
||||
* MIXED unit, the input MeasureUnit will be just the biggest unit of
|
||||
* the sequence.
|
||||
* @param parent The parent MicroPropsGenerator.
|
||||
* @param status Receives status.
|
||||
*/
|
||||
UnitConversionHandler(const MeasureUnit &unit, const MicroPropsGenerator *parent,
|
||||
UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Obtains the appropriate output values from the Unit Converter.
|
||||
*/
|
||||
void processQuantity(DecimalQuantity &quantity, MicroProps µs,
|
||||
UErrorCode &status) const U_OVERRIDE;
|
||||
private:
|
||||
MeasureUnit fOutputUnit;
|
||||
LocalPointer<ComplexUnitsConverter> fUnitConverter;
|
||||
const MicroPropsGenerator *fParent;
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
@ -32,7 +32,6 @@ collationsettings.cpp
|
||||
collationtailoring.cpp
|
||||
collationweights.cpp
|
||||
compactdecimalformat.cpp
|
||||
complexunitsconverter.cpp
|
||||
coptccal.cpp
|
||||
cpdtrans.cpp
|
||||
csdetect.cpp
|
||||
@ -122,6 +121,7 @@ number_patternstring.cpp
|
||||
number_rounding.cpp
|
||||
number_scientific.cpp
|
||||
number_skeletons.cpp
|
||||
number_symbolswrapper.cpp
|
||||
number_usageprefs.cpp
|
||||
number_utils.cpp
|
||||
numfmt.cpp
|
||||
@ -210,9 +210,10 @@ ulocdata.cpp
|
||||
umsg.cpp
|
||||
unesctrn.cpp
|
||||
uni2name.cpp
|
||||
unitconverter.cpp
|
||||
unitsdata.cpp
|
||||
unitsrouter.cpp
|
||||
units_data.cpp
|
||||
units_complexconverter.cpp
|
||||
units_converter.cpp
|
||||
units_router.cpp
|
||||
unum.cpp
|
||||
unumsys.cpp
|
||||
upluralrules.cpp
|
||||
|
@ -707,12 +707,8 @@ class U_I18N_API Precision : public UMemory {
|
||||
typedef PrecisionUnion::FractionSignificantSettings FractionSignificantSettings;
|
||||
typedef PrecisionUnion::IncrementSettings IncrementSettings;
|
||||
|
||||
/** The Precision encapsulates the RoundingMode when used within the implementation. */
|
||||
UNumberFormatRoundingMode fRoundingMode;
|
||||
|
||||
Precision(const PrecisionType& type, const PrecisionUnion& union_,
|
||||
UNumberFormatRoundingMode roundingMode)
|
||||
: fType(type), fUnion(union_), fRoundingMode(roundingMode) {}
|
||||
Precision(const PrecisionType& type, const PrecisionUnion& union_)
|
||||
: fType(type), fUnion(union_) {}
|
||||
|
||||
Precision(UErrorCode errorCode) : fType(RND_ERROR) {
|
||||
fUnion.errorCode = errorCode;
|
||||
@ -746,8 +742,6 @@ class U_I18N_API Precision : public UMemory {
|
||||
|
||||
static CurrencyPrecision constructCurrency(UCurrencyUsage usage);
|
||||
|
||||
static Precision constructPassThrough();
|
||||
|
||||
// To allow MacroProps/MicroProps to initialize bogus instances:
|
||||
friend struct impl::MacroProps;
|
||||
friend struct impl::MicroProps;
|
||||
@ -769,9 +763,7 @@ class U_I18N_API Precision : public UMemory {
|
||||
// To allow access to the skeleton generation code:
|
||||
friend class impl::GeneratorHelpers;
|
||||
|
||||
// TODO(units): revisit when UnitsRouter is changed: do we still need this
|
||||
// once Precision is returned by UnitsRouter? For now, we allow access to
|
||||
// Precision constructor from UsagePrefsHandler:
|
||||
// To allow access to isBogus and the default (bogus) constructor:
|
||||
friend class impl::UsagePrefsHandler;
|
||||
};
|
||||
|
||||
|
@ -8,14 +8,14 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "complexunitsconverter.h"
|
||||
#include "uarrsort.h"
|
||||
#include "uassert.h"
|
||||
#include "unicode/fmtable.h"
|
||||
#include "unicode/localpointer.h"
|
||||
#include "unicode/measunit.h"
|
||||
#include "unicode/measure.h"
|
||||
#include "unitconverter.h"
|
||||
#include "units_complexconverter.h"
|
||||
#include "units_converter.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
namespace units {
|
||||
@ -30,6 +30,11 @@ ComplexUnitsConverter::ComplexUnitsConverter(const MeasureUnitImpl &inputUnit,
|
||||
|
||||
U_ASSERT(units_.length() != 0);
|
||||
|
||||
// Save the desired order of output units before we sort units_
|
||||
for (int32_t i = 0; i < units_.length(); i++) {
|
||||
outputUnits_.emplaceBackAndCheckErrorCode(status, units_[i]->copy(status).build(status));
|
||||
}
|
||||
|
||||
// NOTE:
|
||||
// This comparator is used to sort the units in a descending order. Therefore, we return -1 if
|
||||
// the left is bigger than right and so on.
|
||||
@ -101,13 +106,21 @@ UBool ComplexUnitsConverter::greaterThanOrEqual(double quantity, double limit) c
|
||||
}
|
||||
|
||||
MaybeStackVector<Measure> ComplexUnitsConverter::convert(double quantity, UErrorCode &status) const {
|
||||
// TODO(icu-units#63): test negative numbers!
|
||||
// TODO(hugovdm): return an error for "foot-and-foot"?
|
||||
MaybeStackVector<Measure> result;
|
||||
|
||||
for (int i = 0, n = unitConverters_.length(); i < n; ++i) {
|
||||
quantity = (*unitConverters_[i]).convert(quantity);
|
||||
if (i < n - 1) {
|
||||
int64_t newQuantity = floor(quantity);
|
||||
Formattable formattableNewQuantity(newQuantity);
|
||||
// The double type has 15 decimal digits of precision. For choosing
|
||||
// whether to use the current unit or the next smaller unit, we
|
||||
// therefore nudge up the number with which the thresholding
|
||||
// decision is made. However after the thresholding, we use the
|
||||
// original values to ensure unbiased accuracy (to the extent of
|
||||
// double's capabilities).
|
||||
int64_t roundedQuantity = floor(quantity * (1 + DBL_EPSILON));
|
||||
Formattable formattableNewQuantity(roundedQuantity);
|
||||
|
||||
// NOTE: Measure would own its MeasureUnit.
|
||||
MeasureUnit *type = new MeasureUnit(units_[i]->copy(status).build(status));
|
||||
@ -115,7 +128,14 @@ MaybeStackVector<Measure> ComplexUnitsConverter::convert(double quantity, UError
|
||||
|
||||
// Keep the residual of the quantity.
|
||||
// For example: `3.6 feet`, keep only `0.6 feet`
|
||||
quantity -= newQuantity;
|
||||
//
|
||||
// When the calculation is near enough +/- DBL_EPSILON, we round to
|
||||
// zero. (We also ensure no negative values here.)
|
||||
if ((quantity - roundedQuantity) / quantity < DBL_EPSILON) {
|
||||
quantity = 0;
|
||||
} else {
|
||||
quantity -= roundedQuantity;
|
||||
}
|
||||
} else { // LAST ELEMENT
|
||||
Formattable formattableQuantity(quantity);
|
||||
|
||||
@ -125,6 +145,24 @@ MaybeStackVector<Measure> ComplexUnitsConverter::convert(double quantity, UError
|
||||
}
|
||||
}
|
||||
|
||||
MaybeStackVector<Measure> orderedResult;
|
||||
int32_t unitsCount = outputUnits_.length();
|
||||
U_ASSERT(unitsCount == units_.length());
|
||||
Measure **arr = result.getAlias();
|
||||
// O(N^2) is fine: mixed units' unitsCount is usually 2 or 3.
|
||||
for (int32_t i = 0; i < unitsCount; i++) {
|
||||
for (int32_t j = i; j < unitsCount; j++) {
|
||||
// Find the next expected unit, and swap it into place.
|
||||
if (result[j]->getUnit() == *outputUnits_[i]) {
|
||||
if (j != i) {
|
||||
Measure *tmp = arr[j];
|
||||
arr[j] = arr[i];
|
||||
arr[i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -4,18 +4,36 @@
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
#ifndef __COMPLEXUNITSCONVERTER_H__
|
||||
#define __COMPLEXUNITSCONVERTER_H__
|
||||
#ifndef __UNITS_COMPLEXCONVERTER_H__
|
||||
#define __UNITS_COMPLEXCONVERTER_H__
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "measunit_impl.h"
|
||||
#include "unicode/errorcode.h"
|
||||
#include "unicode/measure.h"
|
||||
#include "unitconverter.h"
|
||||
#include "unitsdata.h"
|
||||
#include "units_converter.h"
|
||||
#include "units_data.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
// Export explicit template instantiations of MaybeStackArray, MemoryPool and
|
||||
// MaybeStackVector. This is required when building DLLs for Windows. (See
|
||||
// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
|
||||
//
|
||||
// Note: These need to be outside of the units namespace, or Clang will generate
|
||||
// a compile error.
|
||||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
template class U_I18N_API MaybeStackArray<units::UnitConverter*, 8>;
|
||||
template class U_I18N_API MemoryPool<units::UnitConverter, 8>;
|
||||
template class U_I18N_API MaybeStackVector<units::UnitConverter, 8>;
|
||||
template class U_I18N_API MaybeStackArray<MeasureUnitImpl*, 8>;
|
||||
template class U_I18N_API MemoryPool<MeasureUnitImpl, 8>;
|
||||
template class U_I18N_API MaybeStackVector<MeasureUnitImpl, 8>;
|
||||
template class U_I18N_API MaybeStackArray<MeasureUnit*, 8>;
|
||||
template class U_I18N_API MemoryPool<MeasureUnit, 8>;
|
||||
template class U_I18N_API MaybeStackVector<MeasureUnit, 8>;
|
||||
#endif
|
||||
|
||||
namespace units {
|
||||
|
||||
/**
|
||||
@ -27,7 +45,7 @@ namespace units {
|
||||
* single unit to another single unit). Therefore, `ComplexUnitsConverter` class contains multiple
|
||||
* instances of the `UnitConverter` to perform the conversion.
|
||||
*/
|
||||
class U_I18N_API ComplexUnitsConverter : UMemory {
|
||||
class U_I18N_API ComplexUnitsConverter : public UMemory {
|
||||
public:
|
||||
/**
|
||||
* Constructor of `ComplexUnitsConverter`.
|
||||
@ -59,12 +77,15 @@ class U_I18N_API ComplexUnitsConverter : UMemory {
|
||||
|
||||
private:
|
||||
MaybeStackVector<UnitConverter> unitConverters_;
|
||||
// Individual units of mixed units, sorted big to small
|
||||
MaybeStackVector<MeasureUnitImpl> units_;
|
||||
// Individual units of mixed units, sorted in desired output order
|
||||
MaybeStackVector<MeasureUnit> outputUnits_;
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif //__COMPLEXUNITSCONVERTER_H__
|
||||
#endif //__UNITS_COMPLEXCONVERTER_H__
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
@ -13,7 +13,7 @@
|
||||
#include "unicode/errorcode.h"
|
||||
#include "unicode/localpointer.h"
|
||||
#include "unicode/stringpiece.h"
|
||||
#include "unitconverter.h"
|
||||
#include "units_converter.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <stdlib.h>
|
||||
@ -516,11 +516,7 @@ double UnitConverter::convert(double inputValue) const {
|
||||
result = 1.0 / result;
|
||||
}
|
||||
|
||||
// TODO: remove the multiplication by 1.000,000,000,001 after using `decNumber`
|
||||
|
||||
// Multiply the result by 1.000,000,000,001 to fix the deterioration from using `double` (the
|
||||
// deterioration is around 15 to 17 decimal digit).
|
||||
return result * 1.000000000001;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace units
|
@ -4,16 +4,16 @@
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
#ifndef __UNITCONVERTER_H__
|
||||
#define __UNITCONVERTER_H__
|
||||
#ifndef __UNITS_CONVERTER_H__
|
||||
#define __UNITS_CONVERTER_H__
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "measunit_impl.h"
|
||||
#include "unicode/errorcode.h"
|
||||
#include "unicode/stringpiece.h"
|
||||
#include "unicode/uobject.h"
|
||||
#include "unitconverter.h"
|
||||
#include "unitsdata.h"
|
||||
#include "units_converter.h"
|
||||
#include "units_data.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
namespace units {
|
||||
@ -81,7 +81,7 @@ void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, Sign
|
||||
/**
|
||||
* Represents the conversion rate between `source` and `target`.
|
||||
*/
|
||||
struct ConversionRate : public UMemory {
|
||||
struct U_I18N_API ConversionRate : public UMemory {
|
||||
const MeasureUnitImpl source;
|
||||
const MeasureUnitImpl target;
|
||||
double factorNum = 1;
|
||||
@ -159,6 +159,6 @@ class U_I18N_API UnitConverter : public UMemory {
|
||||
} // namespace units
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif //__UNITCONVERTER_H__
|
||||
#endif //__UNITS_CONVERTER_H__
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
@ -11,7 +11,7 @@
|
||||
#include "uassert.h"
|
||||
#include "unicode/unistr.h"
|
||||
#include "unicode/ures.h"
|
||||
#include "unitsdata.h"
|
||||
#include "units_data.h"
|
||||
#include "uresimp.h"
|
||||
#include "util.h"
|
||||
#include <utility>
|
||||
@ -293,9 +293,7 @@ int32_t getPreferenceMetadataIndex(const MaybeStackVector<UnitPreferenceMetadata
|
||||
} else if (uprv_strcmp(desired.usage.data(), "default") != 0) {
|
||||
desired.usage.truncate(0).append("default", status);
|
||||
} else {
|
||||
// TODO(icu-units/icu#36): reconsider consistency of errors.
|
||||
// Currently this U_MISSING_RESOURCE_ERROR propagates when a
|
||||
// U_NUMBER_SKELETON_SYNTAX_ERROR might be much more intuitive.
|
||||
// "default" is not supposed to be missing for any valid category.
|
||||
status = U_MISSING_RESOURCE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
@ -310,6 +308,7 @@ int32_t getPreferenceMetadataIndex(const MaybeStackVector<UnitPreferenceMetadata
|
||||
idx = binarySearch(metadata, desired, &foundCategory, &foundUsage, &foundRegion, status);
|
||||
}
|
||||
if (!foundRegion) {
|
||||
// "001" is not supposed to be missing for any valid usage.
|
||||
status = U_MISSING_RESOURCE_ERROR;
|
||||
return -1;
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
#ifndef __GETUNITSDATA_H__
|
||||
#define __GETUNITSDATA_H__
|
||||
#ifndef __UNITS_DATA_H__
|
||||
#define __UNITS_DATA_H__
|
||||
|
||||
#include <limits>
|
||||
|
||||
@ -26,10 +26,10 @@ namespace units {
|
||||
* Categories are found in `unitQuantities` in the `units` resource (see
|
||||
* `units.txt`).
|
||||
*
|
||||
* TODO(hugovdm): if we give unitsdata.cpp access to the functionality of
|
||||
* `extractCompoundBaseUnit` which is currently in unitconverter.cpp, we could
|
||||
* TODO(hugovdm): if we give units_data.cpp access to the functionality of
|
||||
* `extractCompoundBaseUnit` which is currently in units_converter.cpp, we could
|
||||
* support all units for which there is a category. Does it make sense to move
|
||||
* that function to unitsdata.cpp?
|
||||
* that function to units_data.cpp?
|
||||
*/
|
||||
CharString U_I18N_API getUnitCategory(const char *baseUnitIdentifier, UErrorCode &status);
|
||||
|
||||
@ -59,6 +59,22 @@ class U_I18N_API ConversionRateInfo : public UMemory {
|
||||
CharString offset;
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
|
||||
// Export explicit template instantiations of MaybeStackArray, MemoryPool and
|
||||
// MaybeStackVector. This is required when building DLLs for Windows. (See
|
||||
// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
|
||||
//
|
||||
// Note: These need to be outside of the units namespace, or Clang will generate
|
||||
// a compile error.
|
||||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
template class U_I18N_API MaybeStackArray<units::ConversionRateInfo*, 8>;
|
||||
template class U_I18N_API MemoryPool<units::ConversionRateInfo, 8>;
|
||||
template class U_I18N_API MaybeStackVector<units::ConversionRateInfo, 8>;
|
||||
#endif
|
||||
|
||||
namespace units {
|
||||
|
||||
/**
|
||||
* Returns ConversionRateInfo for all supported conversions.
|
||||
*
|
||||
@ -136,6 +152,25 @@ class U_I18N_API UnitPreferenceMetadata : public UMemory {
|
||||
bool *foundRegion) const;
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
|
||||
// Export explicit template instantiations of MaybeStackArray, MemoryPool and
|
||||
// MaybeStackVector. This is required when building DLLs for Windows. (See
|
||||
// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
|
||||
//
|
||||
// Note: These need to be outside of the units namespace, or Clang will generate
|
||||
// a compile error.
|
||||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
template class U_I18N_API MaybeStackArray<units::UnitPreferenceMetadata*, 8>;
|
||||
template class U_I18N_API MemoryPool<units::UnitPreferenceMetadata, 8>;
|
||||
template class U_I18N_API MaybeStackVector<units::UnitPreferenceMetadata, 8>;
|
||||
template class U_I18N_API MaybeStackArray<units::UnitPreference*, 8>;
|
||||
template class U_I18N_API MemoryPool<units::UnitPreference, 8>;
|
||||
template class U_I18N_API MaybeStackVector<units::UnitPreference, 8>;
|
||||
#endif
|
||||
|
||||
namespace units {
|
||||
|
||||
/**
|
||||
* Unit Preferences information for various locales and usages.
|
||||
*/
|
||||
@ -189,6 +224,6 @@ class U_I18N_API UnitPreferences {
|
||||
} // namespace units
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif //__GETUNITSDATA_H__
|
||||
#endif //__UNITS_DATA_H__
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
@ -12,8 +12,8 @@
|
||||
#include "number_decimalquantity.h"
|
||||
#include "resource.h"
|
||||
#include "unicode/measure.h"
|
||||
#include "unitsdata.h"
|
||||
#include "unitsrouter.h"
|
||||
#include "units_data.h"
|
||||
#include "units_router.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
namespace units {
|
||||
@ -70,19 +70,19 @@ UnitsRouter::UnitsRouter(MeasureUnit inputUnit, StringPiece region, StringPiece
|
||||
RouteResult UnitsRouter::route(double quantity, UErrorCode &status) const {
|
||||
for (int i = 0, n = converterPreferences_.length(); i < n; i++) {
|
||||
const auto &converterPreference = *converterPreferences_[i];
|
||||
|
||||
if (converterPreference.converter.greaterThanOrEqual(quantity, converterPreference.limit)) {
|
||||
return RouteResult(converterPreference.converter.convert(quantity, status), //
|
||||
converterPreference.precision //
|
||||
);
|
||||
if (converterPreference.converter.greaterThanOrEqual(quantity * (1 + DBL_EPSILON),
|
||||
converterPreference.limit)) {
|
||||
return RouteResult(converterPreference.converter.convert(quantity, status),
|
||||
converterPreference.precision,
|
||||
converterPreference.targetUnit.copy(status));
|
||||
}
|
||||
}
|
||||
|
||||
// In case of the `quantity` does not fit in any converter limit, use the last converter.
|
||||
const auto &lastConverterPreference = (*converterPreferences_[converterPreferences_.length() - 1]);
|
||||
return RouteResult(lastConverterPreference.converter.convert(quantity, status), //
|
||||
lastConverterPreference.precision //
|
||||
);
|
||||
return RouteResult(lastConverterPreference.converter.convert(quantity, status),
|
||||
lastConverterPreference.precision,
|
||||
lastConverterPreference.targetUnit.copy(status));
|
||||
}
|
||||
|
||||
const MaybeStackVector<MeasureUnit> *UnitsRouter::getOutputUnits() const {
|
@ -4,18 +4,18 @@
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
#ifndef __UNITSROUTER_H__
|
||||
#define __UNITSROUTER_H__
|
||||
#ifndef __UNITS_ROUTER_H__
|
||||
#define __UNITS_ROUTER_H__
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "complexunitsconverter.h"
|
||||
#include "measunit_impl.h"
|
||||
#include "unicode/measunit.h"
|
||||
#include "unicode/stringpiece.h"
|
||||
#include "unicode/uobject.h"
|
||||
#include "unitsdata.h"
|
||||
#include "units_complexconverter.h"
|
||||
#include "units_data.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
@ -25,11 +25,25 @@ class Measure;
|
||||
namespace units {
|
||||
|
||||
struct RouteResult : UMemory {
|
||||
// A list of measures: a single measure for single units, multiple measures
|
||||
// for mixed units.
|
||||
//
|
||||
// TODO(icu-units/icu#21): figure out the right mixed unit API.
|
||||
MaybeStackVector<Measure> measures;
|
||||
|
||||
// A skeleton string starting with a precision-increment.
|
||||
//
|
||||
// TODO(hugovdm): generalise? or narrow down to only a precision-increment?
|
||||
// or document that other skeleton elements are ignored?
|
||||
UnicodeString precision;
|
||||
|
||||
RouteResult(MaybeStackVector<Measure> measures, UnicodeString precision)
|
||||
: measures(std::move(measures)), precision(std::move(precision)) {}
|
||||
// The output unit for this RouteResult. This may be a MIXED unit - for
|
||||
// example: "yard-and-foot-and-inch", for which `measures` will have three
|
||||
// elements.
|
||||
MeasureUnitImpl outputUnit;
|
||||
|
||||
RouteResult(MaybeStackVector<Measure> measures, UnicodeString precision, MeasureUnitImpl outputUnit)
|
||||
: measures(std::move(measures)), precision(std::move(precision)), outputUnit(std::move(outputUnit)) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -46,6 +60,10 @@ struct ConverterPreference : UMemory {
|
||||
double limit;
|
||||
UnicodeString precision;
|
||||
|
||||
// The output unit for this ConverterPreference. This may be a MIXED unit -
|
||||
// for example: "yard-and-foot-and-inch".
|
||||
MeasureUnitImpl targetUnit;
|
||||
|
||||
// In case there is no limit, the limit will be -inf.
|
||||
ConverterPreference(const MeasureUnitImpl &source, const MeasureUnitImpl &complexTarget,
|
||||
UnicodeString precision, const ConversionRates &ratesInfo, UErrorCode &status)
|
||||
@ -56,9 +74,25 @@ struct ConverterPreference : UMemory {
|
||||
double limit, UnicodeString precision, const ConversionRates &ratesInfo,
|
||||
UErrorCode &status)
|
||||
: converter(source, complexTarget, ratesInfo, status), limit(limit),
|
||||
precision(std::move(precision)) {}
|
||||
precision(std::move(precision)), targetUnit(complexTarget.copy(status)) {}
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
|
||||
// Export explicit template instantiations of MaybeStackArray, MemoryPool and
|
||||
// MaybeStackVector. This is required when building DLLs for Windows. (See
|
||||
// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
|
||||
//
|
||||
// Note: These need to be outside of the units namespace, or Clang will generate
|
||||
// a compile error.
|
||||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
template class U_I18N_API MaybeStackArray<units::ConverterPreference*, 8>;
|
||||
template class U_I18N_API MemoryPool<units::ConverterPreference, 8>;
|
||||
template class U_I18N_API MaybeStackVector<units::ConverterPreference, 8>;
|
||||
#endif
|
||||
|
||||
namespace units {
|
||||
|
||||
/**
|
||||
* `UnitsRouter` responsible for converting from a single unit (such as `meter` or `meter-per-second`) to
|
||||
* one of the complex units based on the limits.
|
||||
@ -114,6 +148,6 @@ class U_I18N_API UnitsRouter {
|
||||
} // namespace units
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif //__UNITSROUTER_H__
|
||||
#endif //__UNITS_ROUTER_H__
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
@ -869,7 +869,8 @@ library: i18n
|
||||
dayperiodrules
|
||||
listformatter
|
||||
formatting formattable_cnv regex regex_cnv translit
|
||||
double_conversion number_representation number_output numberformatter number_skeletons numberparser
|
||||
double_conversion number_representation number_output numberformatter
|
||||
number_skeletons number_usageprefs numberparser
|
||||
units_extra unitsformatter
|
||||
universal_time_scale
|
||||
uclean_i18n
|
||||
@ -976,11 +977,9 @@ group: number_output
|
||||
standardplural.o plurrule.o
|
||||
deps
|
||||
# FormattedNumber internals:
|
||||
number_representation format formatted_value_sbimpl
|
||||
number_representation format formatted_value_sbimpl units
|
||||
# PluralRules internals:
|
||||
unifiedcache
|
||||
# Unit Formatting
|
||||
units
|
||||
|
||||
group: numberformatter
|
||||
# ICU 60+ NumberFormatter API
|
||||
@ -989,17 +988,43 @@ group: numberformatter
|
||||
number_decimfmtprops.o
|
||||
number_fluent.o number_formatimpl.o
|
||||
number_grouping.o number_integerwidth.o number_longnames.o
|
||||
number_mapper.o number_modifiers.o number_multiplier.o
|
||||
number_mapper.o number_modifiers.o
|
||||
number_notation.o number_padding.o
|
||||
number_patternmodifier.o number_patternstring.o number_rounding.o
|
||||
number_scientific.o number_usageprefs.o
|
||||
currpinf.o dcfmtsym.o numsys.o
|
||||
number_patternmodifier.o number_patternstring.o
|
||||
number_scientific.o
|
||||
currpinf.o
|
||||
numrange_fluent.o numrange_impl.o
|
||||
deps
|
||||
decnumber double_conversion formattable units unitsformatter
|
||||
number_representation number_output
|
||||
listformatter number_representation number_output
|
||||
numsys
|
||||
number_usageprefs
|
||||
number_rounding
|
||||
number_symbolswrapper
|
||||
uclean_i18n common
|
||||
|
||||
group: numsys
|
||||
dcfmtsym.o
|
||||
numsys.o
|
||||
deps
|
||||
currency
|
||||
resourcebundle
|
||||
uclean_i18n
|
||||
|
||||
group: number_usageprefs
|
||||
number_multiplier.o
|
||||
number_usageprefs.o
|
||||
deps
|
||||
number_rounding
|
||||
number_symbolswrapper
|
||||
unitsformatter
|
||||
|
||||
group: number_rounding
|
||||
number_rounding.o
|
||||
deps
|
||||
currency
|
||||
number_representation
|
||||
|
||||
group: number_skeletons
|
||||
# Number skeleton support; separated from numberformatter
|
||||
number_skeletons.o number_capi.o number_asformat.o numrange_capi.o
|
||||
@ -1007,6 +1032,12 @@ group: number_skeletons
|
||||
numberformatter
|
||||
units_extra
|
||||
|
||||
group: number_symbolswrapper
|
||||
number_symbolswrapper.o
|
||||
deps
|
||||
platform
|
||||
numsys
|
||||
|
||||
group: numberparser
|
||||
numparse_affixes.o numparse_compositions.o numparse_currency.o
|
||||
numparse_decimal.o numparse_impl.o numparse_parsednumber.o
|
||||
@ -1076,7 +1107,7 @@ group: units
|
||||
stringenumeration errorcode
|
||||
|
||||
group: unitsformatter
|
||||
unitsdata.o unitconverter.o complexunitsconverter.o unitsrouter.o
|
||||
units_data.o units_converter.o units_complexconverter.o units_router.o
|
||||
deps
|
||||
resourcebundle units_extra double_conversion number_representation formattable sort
|
||||
|
||||
|
@ -69,7 +69,7 @@ string_segment_test.o \
|
||||
numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
|
||||
static_unisets_test.o numfmtdatadriventest.o numbertest_range.o erarulestest.o \
|
||||
formattedvaluetest.o formatted_string_builder_test.o numbertest_permutation.o \
|
||||
unitsdatatest.o unitstest.o unitsroutertest.o
|
||||
units_data_test.o units_router_test.o units_test.o
|
||||
|
||||
DEPS = $(OBJECTS:.o=.d)
|
||||
|
||||
|
@ -285,9 +285,9 @@
|
||||
<ClCompile Include="formattedvaluetest.cpp" />
|
||||
<ClCompile Include="localebuildertest.cpp" />
|
||||
<ClCompile Include="localematchertest.cpp" />
|
||||
<ClCompile Include="unitsdatatest.cpp" />
|
||||
<ClCompile Include="unitstest.cpp" />
|
||||
<ClCompile Include="unitsroutertest.cpp" />
|
||||
<ClCompile Include="units_data_test.cpp" />
|
||||
<ClCompile Include="units_router_test.cpp" />
|
||||
<ClCompile Include="units_test.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="colldata.h" />
|
||||
|
@ -550,13 +550,13 @@
|
||||
<ClCompile Include="localematchertest.cpp">
|
||||
<Filter>locales & resources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="unitsdatatest.cpp">
|
||||
<ClCompile Include="units_data_test.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="unitstest.cpp">
|
||||
<ClCompile Include="units_router_test.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="unitsroutertest.cpp">
|
||||
<ClCompile Include="units_test.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
@ -82,6 +82,7 @@ private:
|
||||
void TestNumericTimeSomeSpecialFormats();
|
||||
void TestIdentifiers();
|
||||
void TestInvalidIdentifiers();
|
||||
void TestParseToBuiltIn();
|
||||
void TestKilogramIdentifier();
|
||||
void TestCompoundUnitOperations();
|
||||
void TestDimensionlessBehaviour();
|
||||
@ -209,6 +210,7 @@ void MeasureFormatTest::runIndexedTest(
|
||||
TESTCASE_AUTO(TestNumericTimeSomeSpecialFormats);
|
||||
TESTCASE_AUTO(TestIdentifiers);
|
||||
TESTCASE_AUTO(TestInvalidIdentifiers);
|
||||
TESTCASE_AUTO(TestParseToBuiltIn);
|
||||
TESTCASE_AUTO(TestKilogramIdentifier);
|
||||
TESTCASE_AUTO(TestCompoundUnitOperations);
|
||||
TESTCASE_AUTO(TestDimensionlessBehaviour);
|
||||
@ -3514,11 +3516,23 @@ void MeasureFormatTest::TestIndividualPluralFallback() {
|
||||
// and falls back to fr for the "other" form.
|
||||
IcuTestErrorCode errorCode(*this, "TestIndividualPluralFallback");
|
||||
MeasureFormat mf("fr_CA", UMEASFMT_WIDTH_SHORT, errorCode);
|
||||
if (errorCode.errIfFailureAndReset("MeasureFormat mf(...) failed.")) {
|
||||
return;
|
||||
}
|
||||
LocalPointer<Measure> twoDeg(
|
||||
new Measure(2.0, MeasureUnit::createGenericTemperature(errorCode), errorCode), errorCode);
|
||||
if (errorCode.errIfFailureAndReset("Creating twoDeg failed.")) {
|
||||
return;
|
||||
}
|
||||
UnicodeString expected = UNICODE_STRING_SIMPLE("2\\u00B0").unescape();
|
||||
UnicodeString actual;
|
||||
assertEquals("2 deg temp in fr_CA", expected, mf.format(twoDeg.orphan(), actual, errorCode), TRUE);
|
||||
// Formattable adopts the pointer
|
||||
mf.format(Formattable(twoDeg.orphan()), actual, errorCode);
|
||||
if (errorCode.errIfFailureAndReset("mf.format(...) failed.")) {
|
||||
return;
|
||||
}
|
||||
assertEquals("2 deg temp in fr_CA", expected, actual, TRUE);
|
||||
errorCode.errIfFailureAndReset("mf.format failed");
|
||||
}
|
||||
|
||||
void MeasureFormatTest::Test20332_PersonUnits() {
|
||||
@ -3705,6 +3719,33 @@ void MeasureFormatTest::TestInvalidIdentifiers() {
|
||||
}
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestParseToBuiltIn() {
|
||||
IcuTestErrorCode status(*this, "TestParseToBuiltIn()");
|
||||
const struct TestCase {
|
||||
const char *identifier;
|
||||
MeasureUnit expectedBuiltIn;
|
||||
} cases[] = {
|
||||
{"meter-per-second-per-second", MeasureUnit::getMeterPerSecondSquared()},
|
||||
{"meter-per-second-second", MeasureUnit::getMeterPerSecondSquared()},
|
||||
{"centimeter-centimeter", MeasureUnit::getSquareCentimeter()},
|
||||
{"square-foot", MeasureUnit::getSquareFoot()},
|
||||
{"pow2-inch", MeasureUnit::getSquareInch()},
|
||||
{"milligram-per-deciliter", MeasureUnit::getMilligramPerDeciliter()},
|
||||
{"pound-force-per-pow2-inch", MeasureUnit::getPoundPerSquareInch()},
|
||||
{"yard-pow2-yard", MeasureUnit::getCubicYard()},
|
||||
{"square-yard-yard", MeasureUnit::getCubicYard()},
|
||||
};
|
||||
|
||||
for (auto &cas : cases) {
|
||||
MeasureUnit fromIdent = MeasureUnit::forIdentifier(cas.identifier, status);
|
||||
status.assertSuccess();
|
||||
assertEquals("forIdentifier returns a normal built-in unit when it exists",
|
||||
cas.expectedBuiltIn.getOffset(), fromIdent.getOffset());
|
||||
assertEquals("type", cas.expectedBuiltIn.getType(), fromIdent.getType());
|
||||
assertEquals("subType", cas.expectedBuiltIn.getSubtype(), fromIdent.getSubtype());
|
||||
}
|
||||
}
|
||||
|
||||
// Kilogram is a "base unit", although it's also "gram" with a kilo- prefix.
|
||||
// This tests that it is handled in the preferred manner.
|
||||
void MeasureFormatTest::TestKilogramIdentifier() {
|
||||
|
@ -55,6 +55,8 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition {
|
||||
void unitMeasure();
|
||||
void unitCompoundMeasure();
|
||||
void unitUsage();
|
||||
void unitUsageErrorCodes();
|
||||
void unitUsageSkeletons();
|
||||
void unitCurrency();
|
||||
void unitPercent();
|
||||
void percentParity();
|
||||
@ -85,6 +87,7 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition {
|
||||
void localPointerCAPI();
|
||||
void toObject();
|
||||
void toDecimalNumber();
|
||||
void microPropsInternals();
|
||||
|
||||
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
|
||||
|
||||
|
@ -11,12 +11,14 @@
|
||||
#include <memory>
|
||||
#include "unicode/unum.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
#include "unicode/testlog.h"
|
||||
#include "unicode/utypes.h"
|
||||
#include "number_asformat.h"
|
||||
#include "number_types.h"
|
||||
#include "number_utils.h"
|
||||
#include "numbertest.h"
|
||||
#include "unicode/utypes.h"
|
||||
#include "number_utypes.h"
|
||||
#include "number_microprops.h"
|
||||
#include "numbertest.h"
|
||||
|
||||
using number::impl::UFormattedNumberData;
|
||||
|
||||
@ -76,6 +78,8 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha
|
||||
TESTCASE_AUTO(unitMeasure);
|
||||
TESTCASE_AUTO(unitCompoundMeasure);
|
||||
TESTCASE_AUTO(unitUsage);
|
||||
TESTCASE_AUTO(unitUsageErrorCodes);
|
||||
TESTCASE_AUTO(unitUsageSkeletons);
|
||||
TESTCASE_AUTO(unitCurrency);
|
||||
TESTCASE_AUTO(unitPercent);
|
||||
if (!quick) {
|
||||
@ -113,6 +117,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha
|
||||
TESTCASE_AUTO(localPointerCAPI);
|
||||
TESTCASE_AUTO(toObject);
|
||||
TESTCASE_AUTO(toDecimalNumber);
|
||||
TESTCASE_AUTO(microPropsInternals);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
@ -520,6 +525,8 @@ void NumberFormatterApiTest::notationCompact() {
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::unitMeasure() {
|
||||
IcuTestErrorCode status(*this, "unitMeasure()");
|
||||
|
||||
assertFormatDescending(
|
||||
u"Meters Short and unit() method",
|
||||
u"measure-unit/length-meter",
|
||||
@ -686,82 +693,86 @@ void NumberFormatterApiTest::unitMeasure() {
|
||||
Locale("es-MX"),
|
||||
5,
|
||||
u"5 a\u00F1os");
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::unitUsage() {
|
||||
UnlocalizedNumberFormatter unloc_formatter =
|
||||
NumberFormatter::with().usage("road").unit(MeasureUnit::getMeter());
|
||||
|
||||
IcuTestErrorCode status(*this, "unitUsage()");
|
||||
|
||||
LocalizedNumberFormatter formatter = unloc_formatter.locale("en-ZA");
|
||||
FormattedNumber formattedNum = formatter.formatDouble(300, status);
|
||||
assertTrue(UnicodeString("unitUsage() en-ZA road, got outputUnit: \"") +
|
||||
formattedNum.getOutputUnit(status).getIdentifier() + "\"",
|
||||
MeasureUnit::getMeter() == formattedNum.getOutputUnit(status));
|
||||
assertEquals("unitUsage() en-ZA road", "300 m", formattedNum.toString(status));
|
||||
assertFormatDescendingBig(
|
||||
u"unitUsage() en-ZA road",
|
||||
u"measure-unit/length-meter usage/road",
|
||||
u"unit/meter usage/road",
|
||||
unloc_formatter,
|
||||
Locale("en-ZA"),
|
||||
u"87\u00A0650 km",
|
||||
u"8\u00A0765 km",
|
||||
u"877 km",
|
||||
u"88 km",
|
||||
u"8,8 km",
|
||||
u"877 m",
|
||||
u"88 m",
|
||||
u"8,8 m",
|
||||
u"0 m");
|
||||
|
||||
formatter = unloc_formatter.locale("en-GB");
|
||||
formattedNum = formatter.formatDouble(300, status);
|
||||
assertTrue(UnicodeString("unitUsage() en-GB road, got outputUnit: \"") +
|
||||
formattedNum.getOutputUnit(status).getIdentifier() + "\"",
|
||||
MeasureUnit::getYard() == formattedNum.getOutputUnit(status));
|
||||
assertEquals("unitUsage() en-GB road", "328 yd", formattedNum.toString(status));
|
||||
assertFormatDescendingBig(
|
||||
u"unitUsage() en-GB road",
|
||||
u"measure-unit/length-meter usage/road",
|
||||
u"unit/meter usage/road",
|
||||
unloc_formatter,
|
||||
Locale("en-GB"),
|
||||
u"54,463 mi",
|
||||
u"5,446 mi",
|
||||
u"545 mi",
|
||||
u"54 mi",
|
||||
u"5.4 mi",
|
||||
u"0.54 mi",
|
||||
u"96 yd",
|
||||
u"9.6 yd",
|
||||
u"0 yd");
|
||||
|
||||
formatter = unloc_formatter.locale("en-US");
|
||||
formattedNum = formatter.formatDouble(300, status);
|
||||
assertTrue(UnicodeString("unitUsage() en-US road, got outputUnit: \"") +
|
||||
formattedNum.getOutputUnit(status).getIdentifier() + "\"",
|
||||
MeasureUnit::getFoot() == formattedNum.getOutputUnit(status));
|
||||
assertEquals("unitUsage() en-US road", "984 ft", formattedNum.toString(status));
|
||||
assertFormatDescendingBig(
|
||||
u"unitUsage() en-US road",
|
||||
u"measure-unit/length-meter usage/road",
|
||||
u"unit/meter usage/road",
|
||||
unloc_formatter,
|
||||
// TODO(icu-units#35): skeleton generation.
|
||||
assertFormatSingle(
|
||||
u"Mixed unit",
|
||||
nullptr,
|
||||
u"unit/yard-and-foot-and-inch",
|
||||
NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier("yard-and-foot-and-inch", status)),
|
||||
Locale("en-US"),
|
||||
u"54,463 mi",
|
||||
u"5,446 mi",
|
||||
u"545 mi",
|
||||
u"54 mi",
|
||||
u"5.4 mi",
|
||||
u"0.54 mi",
|
||||
u"288 ft",
|
||||
u"29 ft",
|
||||
u"0 ft");
|
||||
3.65,
|
||||
"3 yd, 1 ft, 11.4 in");
|
||||
|
||||
// TODO(icu-units#35): skeleton generation.
|
||||
assertFormatSingle(
|
||||
u"Mixed unit, Scientific",
|
||||
nullptr,
|
||||
u"unit/yard-and-foot-and-inch E0",
|
||||
NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier("yard-and-foot-and-inch", status))
|
||||
.notation(Notation::scientific()),
|
||||
Locale("en-US"),
|
||||
3.65,
|
||||
"3 yd, 1 ft, 1.14E1 in");
|
||||
|
||||
// TODO(icu-units#35): skeleton generation.
|
||||
assertFormatSingle(
|
||||
u"Mixed Unit (Narrow Version)",
|
||||
nullptr,
|
||||
u"unit/metric-ton-and-kilogram-and-gram unit-width-narrow",
|
||||
NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
|
||||
.unitWidth(UNUM_UNIT_WIDTH_NARROW),
|
||||
Locale("en-US"),
|
||||
4.28571,
|
||||
u"4t 285kg 710g");
|
||||
|
||||
// TODO(icu-units#35): skeleton generation.
|
||||
assertFormatSingle(
|
||||
u"Mixed Unit (Short Version)",
|
||||
nullptr,
|
||||
u"unit/metric-ton-and-kilogram-and-gram unit-width-short",
|
||||
NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
|
||||
.unitWidth(UNUM_UNIT_WIDTH_SHORT),
|
||||
Locale("en-US"),
|
||||
4.28571,
|
||||
u"4 t, 285 kg, 710 g");
|
||||
|
||||
// TODO(icu-units#35): skeleton generation.
|
||||
assertFormatSingle(
|
||||
u"Mixed Unit (Full Name Version)",
|
||||
nullptr,
|
||||
u"unit/metric-ton-and-kilogram-and-gram unit-width-full-name",
|
||||
NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
|
||||
.unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
|
||||
Locale("en-US"),
|
||||
4.28571,
|
||||
u"4 metric tons, 285 kilograms, 710 grams");
|
||||
|
||||
// // TODO(icu-units#73): deal with this "1 foot 12 inches" problem.
|
||||
// // At the time of writing, this test would pass, but is commented out
|
||||
// // because it reflects undesired behaviour:
|
||||
// assertFormatSingle(
|
||||
// u"Demonstrating the \"1 foot 12 inches\" problem",
|
||||
// nullptr,
|
||||
// u"unit/foot-and-inch",
|
||||
// NumberFormatter::with()
|
||||
// .unit(MeasureUnit::forIdentifier("foot-and-inch", status))
|
||||
// .precision(Precision::maxSignificantDigits(4))
|
||||
// .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
|
||||
// Locale("en-US"),
|
||||
// 1.9999,
|
||||
// // This is undesireable but current behaviour:
|
||||
// u"1 foot, 12 inches");
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::unitCompoundMeasure() {
|
||||
IcuTestErrorCode status(*this, "unitCompoundMeasure()");
|
||||
|
||||
assertFormatDescending(
|
||||
u"Meters Per Second Short (unit that simplifies) and perUnit method",
|
||||
u"measure-unit/length-meter per-measure-unit/duration-second",
|
||||
@ -778,6 +789,17 @@ void NumberFormatterApiTest::unitCompoundMeasure() {
|
||||
u"0.008765 m/s",
|
||||
u"0 m/s");
|
||||
|
||||
// TODO(icu-units#35): does not normalize as desired: while "unit/*" does
|
||||
// get split into unit/perUnit, ".unit(*)" and "measure-unit/*" don't:
|
||||
assertFormatSingle(
|
||||
u"Built-in unit, meter-per-second",
|
||||
u"measure-unit/speed-meter-per-second",
|
||||
u"~unit/meter-per-second",
|
||||
NumberFormatter::with().unit(MeasureUnit::getMeterPerSecond()),
|
||||
Locale("en-GB"),
|
||||
2.4,
|
||||
u"2.4 m/s");
|
||||
|
||||
assertFormatDescending(
|
||||
u"Pounds Per Square Mile Short (secondary unit has per-format) and adoptPerUnit method",
|
||||
u"measure-unit/mass-pound per-measure-unit/area-square-mile",
|
||||
@ -826,6 +848,427 @@ void NumberFormatterApiTest::unitCompoundMeasure() {
|
||||
// u"0.08765 J/fur",
|
||||
// u"0.008765 J/fur",
|
||||
// u"0 J/fur");
|
||||
|
||||
// TODO(icu-units#59): THIS UNIT TEST DEMONSTRATES UNDESIREABLE BEHAVIOUR!
|
||||
// When specifying built-in types, one can give both a unit and a perUnit.
|
||||
// Resolving to a built-in unit does not always work.
|
||||
//
|
||||
// (Unit-testing philosophy: do we leave this enabled to demonstrate current
|
||||
// behaviour, and changing behaviour in the future? Or comment it out to
|
||||
// avoid asserting this is "correct"?)
|
||||
assertFormatSingle(
|
||||
u"DEMONSTRATING BAD BEHAVIOUR, TODO(icu-units#59)",
|
||||
u"measure-unit/speed-meter-per-second per-measure-unit/duration-second",
|
||||
u"measure-unit/speed-meter-per-second per-measure-unit/duration-second",
|
||||
NumberFormatter::with()
|
||||
.unit(MeasureUnit::getMeterPerSecond())
|
||||
.perUnit(MeasureUnit::getSecond()),
|
||||
Locale("en-GB"),
|
||||
2.4,
|
||||
"2.4 m/s/s");
|
||||
|
||||
// Testing the rejection of invalid specifications
|
||||
|
||||
// If .unit() is not given a built-in type, .perUnit() is not allowed
|
||||
// (because .unit is now flexible enough to handle compound units,
|
||||
// .perUnit() is supported for backward compatibility).
|
||||
LocalizedNumberFormatter nf = NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier("furlong-pascal", status))
|
||||
.perUnit(METER)
|
||||
.locale("en-GB");
|
||||
status.assertSuccess(); // Error is only returned once we try to format.
|
||||
FormattedNumber num = nf.formatDouble(2.4, status);
|
||||
if (!status.expectErrorAndReset(U_UNSUPPORTED_ERROR)) {
|
||||
errln(UnicodeString("Expected failure, got: \"") +
|
||||
nf.formatDouble(2.4, status).toString(status) + "\".");
|
||||
status.assertSuccess();
|
||||
}
|
||||
|
||||
// .perUnit() may only be passed a built-in type, "square-second" is not a
|
||||
// built-in type.
|
||||
nf = NumberFormatter::with()
|
||||
.unit(MeasureUnit::getMeter())
|
||||
.perUnit(MeasureUnit::forIdentifier("square-second", status))
|
||||
.locale("en-GB");
|
||||
status.assertSuccess(); // Error is only returned once we try to format.
|
||||
num = nf.formatDouble(2.4, status);
|
||||
if (!status.expectErrorAndReset(U_UNSUPPORTED_ERROR)) {
|
||||
errln(UnicodeString("Expected failure, got: \"") +
|
||||
nf.formatDouble(2.4, status).toString(status) + "\".");
|
||||
status.assertSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::unitUsage() {
|
||||
IcuTestErrorCode status(*this, "unitUsage()");
|
||||
UnlocalizedNumberFormatter unloc_formatter;
|
||||
LocalizedNumberFormatter formatter;
|
||||
FormattedNumber formattedNum;
|
||||
UnicodeString uTestCase;
|
||||
|
||||
unloc_formatter = NumberFormatter::with().usage("road").unit(MeasureUnit::getMeter());
|
||||
|
||||
uTestCase = u"unitUsage() en-ZA road";
|
||||
formatter = unloc_formatter.locale("en-ZA");
|
||||
formattedNum = formatter.formatDouble(321, status);
|
||||
status.errIfFailureAndReset("unitUsage() en-ZA road formatDouble");
|
||||
assertTrue(
|
||||
uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
|
||||
MeasureUnit::getMeter() == formattedNum.getOutputUnit(status));
|
||||
assertEquals(uTestCase, "300 m", formattedNum.toString(status));
|
||||
{
|
||||
static const UFieldPosition expectedFieldPositions[] = {
|
||||
{UNUM_INTEGER_FIELD, 0, 3},
|
||||
{UNUM_MEASURE_UNIT_FIELD, 4, 5}};
|
||||
assertNumberFieldPositions(
|
||||
(uTestCase + u" field positions").getTerminatedBuffer(),
|
||||
formattedNum,
|
||||
expectedFieldPositions,
|
||||
UPRV_LENGTHOF(expectedFieldPositions));
|
||||
}
|
||||
assertFormatDescendingBig(
|
||||
uTestCase.getTerminatedBuffer(),
|
||||
u"measure-unit/length-meter usage/road",
|
||||
u"unit/meter usage/road",
|
||||
unloc_formatter,
|
||||
Locale("en-ZA"),
|
||||
u"87\u00A0650 km",
|
||||
u"8\u00A0765 km",
|
||||
u"876 km", // 6.5 rounds down, 7.5 rounds up.
|
||||
u"88 km",
|
||||
u"8,8 km",
|
||||
u"900 m",
|
||||
u"90 m",
|
||||
u"10 m",
|
||||
u"0 m");
|
||||
|
||||
uTestCase = u"unitUsage() en-GB road";
|
||||
formatter = unloc_formatter.locale("en-GB");
|
||||
formattedNum = formatter.formatDouble(321, status);
|
||||
status.errIfFailureAndReset("unitUsage() en-GB road, formatDouble(...)");
|
||||
assertTrue(
|
||||
uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
|
||||
MeasureUnit::getYard() == formattedNum.getOutputUnit(status));
|
||||
status.errIfFailureAndReset("unitUsage() en-GB road, getOutputUnit(...)");
|
||||
assertEquals(uTestCase, "350 yd", formattedNum.toString(status));
|
||||
status.errIfFailureAndReset("unitUsage() en-GB road, toString(...)");
|
||||
{
|
||||
static const UFieldPosition expectedFieldPositions[] = {
|
||||
{UNUM_INTEGER_FIELD, 0, 3},
|
||||
{UNUM_MEASURE_UNIT_FIELD, 4, 6}};
|
||||
assertNumberFieldPositions(
|
||||
(uTestCase + u" field positions").getTerminatedBuffer(),
|
||||
formattedNum,
|
||||
expectedFieldPositions,
|
||||
UPRV_LENGTHOF(expectedFieldPositions));
|
||||
}
|
||||
assertFormatDescendingBig(
|
||||
uTestCase.getTerminatedBuffer(),
|
||||
u"measure-unit/length-meter usage/road",
|
||||
u"unit/meter usage/road",
|
||||
unloc_formatter,
|
||||
Locale("en-GB"),
|
||||
u"54,463 mi",
|
||||
u"5,446 mi",
|
||||
u"545 mi",
|
||||
u"54 mi",
|
||||
u"5.4 mi",
|
||||
u"0.54 mi",
|
||||
u"96 yd",
|
||||
u"9.6 yd",
|
||||
u"0 yd");
|
||||
|
||||
uTestCase = u"unitUsage() en-US road";
|
||||
formatter = unloc_formatter.locale("en-US");
|
||||
formattedNum = formatter.formatDouble(321, status);
|
||||
status.errIfFailureAndReset("unitUsage() en-US road, formatDouble(...)");
|
||||
assertTrue(
|
||||
uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
|
||||
MeasureUnit::getFoot() == formattedNum.getOutputUnit(status));
|
||||
status.errIfFailureAndReset("unitUsage() en-US road, getOutputUnit(...)");
|
||||
assertEquals(uTestCase, "1,050 ft", formattedNum.toString(status));
|
||||
status.errIfFailureAndReset("unitUsage() en-US road, toString(...)");
|
||||
{
|
||||
static const UFieldPosition expectedFieldPositions[] = {
|
||||
{UNUM_GROUPING_SEPARATOR_FIELD, 1, 2},
|
||||
{UNUM_INTEGER_FIELD, 0, 5},
|
||||
{UNUM_MEASURE_UNIT_FIELD, 6, 8}};
|
||||
assertNumberFieldPositions(
|
||||
(uTestCase + u" field positions").getTerminatedBuffer(),
|
||||
formattedNum,
|
||||
expectedFieldPositions,
|
||||
UPRV_LENGTHOF(expectedFieldPositions));
|
||||
}
|
||||
assertFormatDescendingBig(
|
||||
uTestCase.getTerminatedBuffer(),
|
||||
u"measure-unit/length-meter usage/road",
|
||||
u"unit/meter usage/road",
|
||||
unloc_formatter,
|
||||
Locale("en-US"),
|
||||
u"54,463 mi",
|
||||
u"5,446 mi",
|
||||
u"545 mi",
|
||||
u"54 mi",
|
||||
u"5.4 mi",
|
||||
u"0.54 mi",
|
||||
u"300 ft",
|
||||
u"30 ft",
|
||||
u"0 ft");
|
||||
|
||||
unloc_formatter = NumberFormatter::with().usage("person").unit(MeasureUnit::getKilogram());
|
||||
uTestCase = u"unitUsage() en-GB person";
|
||||
formatter = unloc_formatter.locale("en-GB");
|
||||
formattedNum = formatter.formatDouble(80, status);
|
||||
status.errIfFailureAndReset("unitUsage() en-GB person formatDouble");
|
||||
assertTrue(
|
||||
uTestCase + ", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
|
||||
MeasureUnit::forIdentifier("stone-and-pound", status) == formattedNum.getOutputUnit(status));
|
||||
status.errIfFailureAndReset("unitUsage() en-GB person - formattedNum.getOutputUnit(status)");
|
||||
assertEquals(uTestCase, "12 st, 8.4 lb", formattedNum.toString(status));
|
||||
status.errIfFailureAndReset("unitUsage() en-GB person, toString(...)");
|
||||
{
|
||||
static const UFieldPosition expectedFieldPositions[] = {
|
||||
// // Desired output: TODO(icu-units#67)
|
||||
// {UNUM_INTEGER_FIELD, 0, 2},
|
||||
// {UNUM_MEASURE_UNIT_FIELD, 3, 5},
|
||||
// {ULISTFMT_LITERAL_FIELD, 5, 6},
|
||||
// {UNUM_INTEGER_FIELD, 7, 8},
|
||||
// {UNUM_DECIMAL_SEPARATOR_FIELD, 8, 9},
|
||||
// {UNUM_FRACTION_FIELD, 9, 10},
|
||||
// {UNUM_MEASURE_UNIT_FIELD, 11, 13}};
|
||||
|
||||
// Current output: rather no fields than wrong fields
|
||||
{UNUM_INTEGER_FIELD, 7, 8},
|
||||
{UNUM_DECIMAL_SEPARATOR_FIELD, 8, 9},
|
||||
{UNUM_FRACTION_FIELD, 9, 10},
|
||||
};
|
||||
assertNumberFieldPositions(
|
||||
(uTestCase + u" field positions").getTerminatedBuffer(),
|
||||
formattedNum,
|
||||
expectedFieldPositions,
|
||||
UPRV_LENGTHOF(expectedFieldPositions));
|
||||
}
|
||||
assertFormatDescending(
|
||||
uTestCase.getTerminatedBuffer(),
|
||||
u"measure-unit/mass-kilogram usage/person",
|
||||
u"unit/kilogram usage/person",
|
||||
unloc_formatter,
|
||||
Locale("en-GB"),
|
||||
u"13,802 st, 7.2 lb",
|
||||
u"1,380 st, 3.5 lb",
|
||||
u"138 st, 0.35 lb",
|
||||
u"13 st, 11 lb",
|
||||
u"1 st, 5.3 lb",
|
||||
u"1 lb, 15 oz",
|
||||
u"0 lb, 3.1 oz",
|
||||
u"0 lb, 0.31 oz",
|
||||
u"0 lb, 0 oz");
|
||||
|
||||
assertFormatDescending(
|
||||
uTestCase.getTerminatedBuffer(),
|
||||
u"usage/person unit-width-narrow measure-unit/mass-kilogram",
|
||||
u"usage/person unit-width-narrow unit/kilogram",
|
||||
unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_NARROW),
|
||||
Locale("en-GB"),
|
||||
u"13,802st 7.2lb",
|
||||
u"1,380st 3.5lb",
|
||||
u"138st 0.35lb",
|
||||
u"13st 11lb",
|
||||
u"1st 5.3lb",
|
||||
u"1lb 15oz",
|
||||
u"0lb 3.1oz",
|
||||
u"0lb 0.31oz",
|
||||
u"0lb 0oz");
|
||||
|
||||
assertFormatDescending(
|
||||
uTestCase.getTerminatedBuffer(),
|
||||
u"usage/person unit-width-short measure-unit/mass-kilogram",
|
||||
u"usage/person unit-width-short unit/kilogram",
|
||||
unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_SHORT),
|
||||
Locale("en-GB"),
|
||||
u"13,802 st, 7.2 lb",
|
||||
u"1,380 st, 3.5 lb",
|
||||
u"138 st, 0.35 lb",
|
||||
u"13 st, 11 lb",
|
||||
u"1 st, 5.3 lb",
|
||||
u"1 lb, 15 oz",
|
||||
u"0 lb, 3.1 oz",
|
||||
u"0 lb, 0.31 oz",
|
||||
u"0 lb, 0 oz");
|
||||
|
||||
assertFormatDescending(
|
||||
uTestCase.getTerminatedBuffer(),
|
||||
u"usage/person unit-width-full-name measure-unit/mass-kilogram",
|
||||
u"usage/person unit-width-full-name unit/kilogram",
|
||||
unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
|
||||
Locale("en-GB"),
|
||||
u"13,802 stone, 7.2 pounds",
|
||||
u"1,380 stone, 3.5 pounds",
|
||||
u"138 stone, 0.35 pounds",
|
||||
u"13 stone, 11 pounds",
|
||||
u"1 stone, 5.3 pounds",
|
||||
u"1 pound, 15 ounces",
|
||||
u"0 pounds, 3.1 ounces",
|
||||
u"0 pounds, 0.31 ounces",
|
||||
u"0 pounds, 0 ounces");
|
||||
|
||||
assertFormatDescendingBig(
|
||||
u"Scientific notation with Usage: possible when using a reasonable Precision",
|
||||
u"scientific @### usage/default measure-unit/area-square-meter unit-width-full-name",
|
||||
u"scientific @### usage/default unit/square-meter unit-width-full-name",
|
||||
NumberFormatter::with()
|
||||
.unit(SQUARE_METER)
|
||||
.usage("default")
|
||||
.notation(Notation::scientific())
|
||||
.precision(Precision::minMaxSignificantDigits(1, 4))
|
||||
.unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
|
||||
Locale("en-ZA"),
|
||||
u"8,765E1 square kilometres",
|
||||
u"8,765E0 square kilometres",
|
||||
u"8,765E1 hectares",
|
||||
u"8,765E0 hectares",
|
||||
u"8,765E3 square metres",
|
||||
u"8,765E2 square metres",
|
||||
u"8,765E1 square metres",
|
||||
u"8,765E0 square metres",
|
||||
u"0E0 square centimetres");
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::unitUsageErrorCodes() {
|
||||
IcuTestErrorCode status(*this, "unitUsageErrorCodes()");
|
||||
UnlocalizedNumberFormatter unloc_formatter;
|
||||
|
||||
unloc_formatter = NumberFormatter::forSkeleton(u"unit/foobar", status);
|
||||
// This gives an error, because foobar is an invalid unit:
|
||||
status.expectErrorAndReset(U_NUMBER_SKELETON_SYNTAX_ERROR);
|
||||
|
||||
unloc_formatter = NumberFormatter::forSkeleton(u"usage/foobar", status);
|
||||
// This does not give an error, because usage is not looked up yet.
|
||||
status.errIfFailureAndReset("Expected behaviour: no immediate error for invalid usage");
|
||||
unloc_formatter.locale("en-GB").formatInt(1, status);
|
||||
// Lacking a unit results in a failure. The skeleton is "incomplete", but we
|
||||
// support adding the unit via the fluent API, so it is not an error until
|
||||
// we build the formatting pipeline itself.
|
||||
status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
|
||||
// Adding the unit as part of the fluent chain leads to success.
|
||||
unloc_formatter.unit(MeasureUnit::getMeter()).locale("en-GB").formatInt(1, status);
|
||||
status.assertSuccess();
|
||||
}
|
||||
|
||||
// Tests for the "skeletons" field in unitPreferenceData, as well as precision
|
||||
// and notation overrides.
|
||||
void NumberFormatterApiTest::unitUsageSkeletons() {
|
||||
IcuTestErrorCode status(*this, "unitUsageSkeletons()");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Default >300m road preference skeletons round to 50m",
|
||||
u"usage/road measure-unit/length-meter",
|
||||
u"usage/road unit/meter",
|
||||
NumberFormatter::with().unit(METER).usage("road"),
|
||||
Locale("en-ZA"),
|
||||
321,
|
||||
u"300 m");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Precision can be overridden: override takes precedence",
|
||||
u"usage/road measure-unit/length-meter @#",
|
||||
u"usage/road unit/meter @#",
|
||||
NumberFormatter::with()
|
||||
.unit(METER)
|
||||
.usage("road")
|
||||
.precision(Precision::maxSignificantDigits(2)),
|
||||
Locale("en-ZA"),
|
||||
321,
|
||||
u"320 m");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Compact notation with Usage: bizarre, but possible (short)",
|
||||
u"compact-short usage/road measure-unit/length-meter",
|
||||
u"compact-short usage/road unit/meter",
|
||||
NumberFormatter::with()
|
||||
.unit(METER)
|
||||
.usage("road")
|
||||
.notation(Notation::compactShort()),
|
||||
Locale("en-ZA"),
|
||||
987654321,
|
||||
u"988K km");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Compact notation with Usage: bizarre, but possible (short, precision override)",
|
||||
u"compact-short usage/road measure-unit/length-meter @#",
|
||||
u"compact-short usage/road unit/meter @#",
|
||||
NumberFormatter::with()
|
||||
.unit(METER)
|
||||
.usage("road")
|
||||
.notation(Notation::compactShort())
|
||||
.precision(Precision::maxSignificantDigits(2)),
|
||||
Locale("en-ZA"),
|
||||
987654321,
|
||||
u"990K km");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Compact notation with Usage: unusual but possible (long)",
|
||||
u"compact-long usage/road measure-unit/length-meter @#",
|
||||
u"compact-long usage/road unit/meter @#",
|
||||
NumberFormatter::with()
|
||||
.unit(METER)
|
||||
.usage("road")
|
||||
.notation(Notation::compactLong())
|
||||
.precision(Precision::maxSignificantDigits(2)),
|
||||
Locale("en-ZA"),
|
||||
987654321,
|
||||
u"990 thousand km");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Compact notation with Usage: unusual but possible (long, precision override)",
|
||||
u"compact-long usage/road measure-unit/length-meter @#",
|
||||
u"compact-long usage/road unit/meter @#",
|
||||
NumberFormatter::with()
|
||||
.unit(METER)
|
||||
.usage("road")
|
||||
.notation(Notation::compactLong())
|
||||
.precision(Precision::maxSignificantDigits(2)),
|
||||
Locale("en-ZA"),
|
||||
987654321,
|
||||
u"990 thousand km");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Scientific notation, not recommended, requires precision override for road",
|
||||
u"scientific usage/road measure-unit/length-meter",
|
||||
u"scientific usage/road unit/meter",
|
||||
NumberFormatter::with().unit(METER).usage("road").notation(Notation::scientific()),
|
||||
Locale("en-ZA"),
|
||||
321.45,
|
||||
// Rounding to the nearest "50" is not exponent-adjusted in scientific notation:
|
||||
u"0E2 m");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Scientific notation with Usage: possible when using a reasonable Precision",
|
||||
u"scientific usage/road measure-unit/length-meter @###",
|
||||
u"scientific usage/road unit/meter @###",
|
||||
NumberFormatter::with()
|
||||
.unit(METER)
|
||||
.usage("road")
|
||||
.notation(Notation::scientific())
|
||||
.precision(Precision::maxSignificantDigits(4)),
|
||||
Locale("en-ZA"),
|
||||
321.45, // 0.45 rounds down, 0.55 rounds up.
|
||||
u"3,214E2 m");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Scientific notation with Usage: possible when using a reasonable Precision",
|
||||
u"scientific usage/default measure-unit/length-astronomical-unit unit-width-full-name",
|
||||
u"scientific usage/default unit/astronomical-unit unit-width-full-name",
|
||||
NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier("astronomical-unit", status))
|
||||
.usage("default")
|
||||
.notation(Notation::scientific())
|
||||
.unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
|
||||
Locale("en-ZA"),
|
||||
1e20,
|
||||
u"1,5E28 kilometres");
|
||||
|
||||
status.assertSuccess();
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::unitCurrency() {
|
||||
@ -3604,6 +4047,33 @@ void NumberFormatterApiTest::toDecimalNumber() {
|
||||
"9.8765E+14", fn.toDecimalNumber<std::string>(status).c_str());
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::microPropsInternals() {
|
||||
// Verify copy construction and assignment operators.
|
||||
int64_t testValues[2] = {4, 61};
|
||||
|
||||
MicroProps mp;
|
||||
assertEquals("capacity", 2, mp.mixedMeasures.getCapacity());
|
||||
mp.mixedMeasures[0] = testValues[0];
|
||||
mp.mixedMeasures[1] = testValues[1];
|
||||
MicroProps copyConstructed(mp);
|
||||
MicroProps copyAssigned;
|
||||
int64_t *resizeResult = mp.mixedMeasures.resize(4, 4);
|
||||
assertTrue("Resize success", resizeResult != NULL);
|
||||
copyAssigned = mp;
|
||||
|
||||
assertTrue("MicroProps success status", U_SUCCESS(mp.mixedMeasures.status));
|
||||
assertTrue("Copy Constructed success status", U_SUCCESS(copyConstructed.mixedMeasures.status));
|
||||
assertTrue("Copy Assigned success status", U_SUCCESS(copyAssigned.mixedMeasures.status));
|
||||
assertEquals("Original values[0]", testValues[0], mp.mixedMeasures[0]);
|
||||
assertEquals("Original values[1]", testValues[1], mp.mixedMeasures[1]);
|
||||
assertEquals("Copy Constructed[0]", testValues[0], copyConstructed.mixedMeasures[0]);
|
||||
assertEquals("Copy Constructed[1]", testValues[1], copyConstructed.mixedMeasures[1]);
|
||||
assertEquals("Copy Assigned[0]", testValues[0], copyAssigned.mixedMeasures[0]);
|
||||
assertEquals("Copy Assigned[1]", testValues[1], copyAssigned.mixedMeasures[1]);
|
||||
assertEquals("Original capacity", 4, mp.mixedMeasures.getCapacity());
|
||||
assertEquals("Copy Constructed capacity", 2, copyConstructed.mixedMeasures.getCapacity());
|
||||
assertEquals("Copy Assigned capacity", 4, copyAssigned.mixedMeasures.getCapacity());
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::assertFormatDescending(
|
||||
const char16_t* umessage,
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unitsdata.h"
|
||||
#include "units_data.h"
|
||||
#include "intltest.h"
|
||||
|
||||
using namespace ::icu::units;
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "intltest.h"
|
||||
#include "unicode/unistr.h"
|
||||
#include "unitsrouter.h"
|
||||
#include "units_router.h"
|
||||
|
||||
|
||||
class UnitsRouterTest : public IntlTest {
|
@ -19,9 +19,10 @@
|
||||
#include "unicode/unistr.h"
|
||||
#include "unicode/unum.h"
|
||||
#include "unicode/ures.h"
|
||||
#include "unitconverter.h"
|
||||
#include "unitsdata.h"
|
||||
#include "unitsrouter.h"
|
||||
#include "units_complexconverter.h"
|
||||
#include "units_converter.h"
|
||||
#include "units_data.h"
|
||||
#include "units_router.h"
|
||||
#include "uparse.h"
|
||||
#include "uresimp.h"
|
||||
|
||||
@ -44,6 +45,7 @@ class UnitsTest : public IntlTest {
|
||||
void testUnitConstantFreshness();
|
||||
void testConversionCapability();
|
||||
void testConversions();
|
||||
void testComplexUnitsConverter();
|
||||
void testComplexUnitConverterSorting();
|
||||
void testPreferences();
|
||||
void testSiPrefixes();
|
||||
@ -62,6 +64,7 @@ void UnitsTest::runIndexedTest(int32_t index, UBool exec, const char *&name, cha
|
||||
TESTCASE_AUTO(testUnitConstantFreshness);
|
||||
TESTCASE_AUTO(testConversionCapability);
|
||||
TESTCASE_AUTO(testConversions);
|
||||
TESTCASE_AUTO(testComplexUnitsConverter);
|
||||
TESTCASE_AUTO(testComplexUnitConverterSorting);
|
||||
TESTCASE_AUTO(testPreferences);
|
||||
TESTCASE_AUTO(testSiPrefixes);
|
||||
@ -88,7 +91,7 @@ void UnitsTest::testUnitConstantFreshness() {
|
||||
addSingleFactorConstant(constant, 1, POSITIVE, factor, status);
|
||||
if (status.errDataIfFailureAndReset(
|
||||
"addSingleFactorConstant(<%s>, ...).\n\n"
|
||||
"If U_INVALID_FORMAT_ERROR, please check that \"icu4c/source/i18n/unitconverter.cpp\" "
|
||||
"If U_INVALID_FORMAT_ERROR, please check that \"icu4c/source/i18n/units_converter.cpp\" "
|
||||
"has all constants? Is \"%s\" a new constant?\n",
|
||||
constant, constant)) {
|
||||
continue;
|
||||
@ -105,7 +108,7 @@ void UnitsTest::testUnitConstantFreshness() {
|
||||
}
|
||||
DecimalQuantity dqVal;
|
||||
UErrorCode parseStatus = U_ZERO_ERROR;
|
||||
// TODO(units): unify with strToDouble() in unitconverter.cpp
|
||||
// TODO(units): unify with strToDouble() in units_converter.cpp
|
||||
dqVal.setToDecNumber(val.toStringPiece(), parseStatus);
|
||||
if (!U_SUCCESS(parseStatus)) {
|
||||
// Not simple to parse, skip validating this constant's value. (We
|
||||
@ -294,19 +297,21 @@ void UnitsTest::testArea() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims whitespace (spaces only) off of the specified string.
|
||||
* Trims whitespace off of the specified string.
|
||||
* @param field is two pointers pointing at the start and end of the string.
|
||||
* @return A StringPiece with initial and final space characters trimmed off.
|
||||
*/
|
||||
StringPiece trimField(char *(&field)[2]) {
|
||||
char *start = field[0];
|
||||
while (start < field[1] && (start[0]) == ' ') {
|
||||
start++;
|
||||
const char *start = field[0];
|
||||
start = u_skipWhitespace(start);
|
||||
if (start >= field[1]) {
|
||||
start = field[1];
|
||||
}
|
||||
int32_t length = (int32_t)(field[1] - start);
|
||||
while (length > 0 && (start[length - 1]) == ' ') {
|
||||
length--;
|
||||
const char *end = field[1];
|
||||
while ((start < end) && U_IS_INV_WHITESPACE(*(end - 1))) {
|
||||
end--;
|
||||
}
|
||||
int32_t length = (int32_t)(end - start);
|
||||
return StringPiece(start, length);
|
||||
}
|
||||
|
||||
@ -359,11 +364,13 @@ void unitsTestDataLineFn(void *context, char *fields[][2], int32_t fieldCount, U
|
||||
return;
|
||||
}
|
||||
|
||||
CharString sourceIdent(x, status);
|
||||
MeasureUnitImpl sourceUnit = MeasureUnitImpl::forIdentifier(x, status);
|
||||
if (status.errIfFailureAndReset("forIdentifier(\"%.*s\")", x.length(), x.data())) {
|
||||
return;
|
||||
}
|
||||
|
||||
CharString targetIdent(y, status);
|
||||
MeasureUnitImpl targetUnit = MeasureUnitImpl::forIdentifier(y, status);
|
||||
if (status.errIfFailureAndReset("forIdentifier(\"%.*s\")", y.length(), y.data())) {
|
||||
return;
|
||||
@ -378,14 +385,14 @@ void unitsTestDataLineFn(void *context, char *fields[][2], int32_t fieldCount, U
|
||||
// Convertibility:
|
||||
auto convertibility = extractConvertibility(sourceUnit, targetUnit, *ctx->conversionRates, status);
|
||||
if (status.errIfFailureAndReset("extractConvertibility(<%s>, <%s>, ...)",
|
||||
sourceUnit.identifier.data(), targetUnit.identifier.data())) {
|
||||
sourceIdent.data(), targetIdent.data())) {
|
||||
return;
|
||||
}
|
||||
CharString msg;
|
||||
msg.append("convertible: ", status)
|
||||
.append(sourceUnit.identifier.data(), status)
|
||||
.append(sourceIdent.data(), status)
|
||||
.append(" -> ", status)
|
||||
.append(targetUnit.identifier.data(), status);
|
||||
.append(targetIdent.data(), status);
|
||||
if (status.errIfFailureAndReset("msg construction")) {
|
||||
return;
|
||||
}
|
||||
@ -394,7 +401,7 @@ void unitsTestDataLineFn(void *context, char *fields[][2], int32_t fieldCount, U
|
||||
// Conversion:
|
||||
UnitConverter converter(sourceUnit, targetUnit, *ctx->conversionRates, status);
|
||||
if (status.errIfFailureAndReset("constructor: UnitConverter(<%s>, <%s>, status)",
|
||||
sourceUnit.identifier.data(), targetUnit.identifier.data())) {
|
||||
sourceIdent.data(), targetIdent.data())) {
|
||||
return;
|
||||
}
|
||||
double got = converter.convert(1000);
|
||||
@ -405,7 +412,7 @@ void unitsTestDataLineFn(void *context, char *fields[][2], int32_t fieldCount, U
|
||||
|
||||
/**
|
||||
* Runs data-driven unit tests for unit conversion. It looks for the test cases
|
||||
* in source/test/testdata/units/unitsTest.txt, which originates in CLDR.
|
||||
* in source/test/testdata/cldr/units/unitsTest.txt, which originates in CLDR.
|
||||
*/
|
||||
void UnitsTest::testConversions() {
|
||||
const char *filename = "unitsTest.txt";
|
||||
@ -420,7 +427,7 @@ void UnitsTest::testConversions() {
|
||||
}
|
||||
|
||||
CharString path(sourceTestDataPath, errorCode);
|
||||
path.appendPathPart("units", errorCode);
|
||||
path.appendPathPart("cldr/units", errorCode);
|
||||
path.appendPathPart(filename, errorCode);
|
||||
|
||||
ConversionRates rates(errorCode);
|
||||
@ -431,6 +438,92 @@ void UnitsTest::testConversions() {
|
||||
}
|
||||
}
|
||||
|
||||
void UnitsTest::testComplexUnitsConverter() {
|
||||
IcuTestErrorCode status(*this, "UnitsTest::testComplexUnitConversions");
|
||||
ConversionRates rates(status);
|
||||
MeasureUnit input = MeasureUnit::getFoot();
|
||||
MeasureUnit output = MeasureUnit::forIdentifier("foot-and-inch", status);
|
||||
MeasureUnitImpl tempInput, tempOutput;
|
||||
const MeasureUnitImpl &inputImpl = MeasureUnitImpl::forMeasureUnit(input, tempInput, status);
|
||||
const MeasureUnitImpl &outputImpl = MeasureUnitImpl::forMeasureUnit(output, tempOutput, status);
|
||||
auto converter = ComplexUnitsConverter(inputImpl, outputImpl, rates, status);
|
||||
|
||||
// Significantly less than 2.0.
|
||||
MaybeStackVector<Measure> measures = converter.convert(1.9999, status);
|
||||
assertEquals("measures length", 2, measures.length());
|
||||
assertEquals("1.9999: measures[0] value", 1.0, measures[0]->getNumber().getDouble(status));
|
||||
assertEquals("1.9999: measures[0] unit", MeasureUnit::getFoot().getIdentifier(),
|
||||
measures[0]->getUnit().getIdentifier());
|
||||
assertEqualsNear("1.9999: measures[1] value", 11.9988, measures[1]->getNumber().getDouble(status), 0.0001);
|
||||
assertEquals("1.9999: measures[1] unit", MeasureUnit::getInch().getIdentifier(),
|
||||
measures[1]->getUnit().getIdentifier());
|
||||
|
||||
// TODO: consider factoring out the set of tests to make this function more
|
||||
// data-driven, *after* dealing appropriately with the memory leaks that can
|
||||
// be demonstrated by this code.
|
||||
|
||||
// TODO: reusing measures results in a leak.
|
||||
// A minimal nudge under 2.0.
|
||||
MaybeStackVector<Measure> measures2 = converter.convert((2.0 - DBL_EPSILON), status);
|
||||
assertEquals("measures length", 2, measures2.length());
|
||||
assertEquals("1 - eps: measures[0] value", 2.0, measures2[0]->getNumber().getDouble(status));
|
||||
assertEquals("1 - eps: measures[0] unit", MeasureUnit::getFoot().getIdentifier(),
|
||||
measures2[0]->getUnit().getIdentifier());
|
||||
assertEquals("1 - eps: measures[1] value", 0.0, measures2[1]->getNumber().getDouble(status));
|
||||
assertEquals("1 - eps: measures[1] unit", MeasureUnit::getInch().getIdentifier(),
|
||||
measures2[1]->getUnit().getIdentifier());
|
||||
|
||||
// Testing precision with meter and light-year. 1e-16 light years is
|
||||
// 0.946073 meters, and double precision can provide only ~15 decimal
|
||||
// digits, so we don't expect to get anything less than 1 meter.
|
||||
|
||||
// An epsilon's nudge under one light-year: should give 1 ly, 0 m.
|
||||
input = MeasureUnit::getLightYear();
|
||||
output = MeasureUnit::forIdentifier("light-year-and-meter", status);
|
||||
// TODO: reusing tempInput and tempOutput results in a leak.
|
||||
MeasureUnitImpl tempInput3, tempOutput3;
|
||||
const MeasureUnitImpl &inputImpl3 = MeasureUnitImpl::forMeasureUnit(input, tempInput3, status);
|
||||
const MeasureUnitImpl &outputImpl3 = MeasureUnitImpl::forMeasureUnit(output, tempOutput3, status);
|
||||
// TODO: reusing converter results in a leak.
|
||||
ComplexUnitsConverter converter3 = ComplexUnitsConverter(inputImpl3, outputImpl3, rates, status);
|
||||
// TODO: reusing measures results in a leak.
|
||||
MaybeStackVector<Measure> measures3 = converter3.convert((2.0 - DBL_EPSILON), status);
|
||||
assertEquals("measures length", 2, measures3.length());
|
||||
assertEquals("light-year test: measures[0] value", 2.0, measures3[0]->getNumber().getDouble(status));
|
||||
assertEquals("light-year test: measures[0] unit", MeasureUnit::getLightYear().getIdentifier(),
|
||||
measures3[0]->getUnit().getIdentifier());
|
||||
assertEquals("light-year test: measures[1] value", 0.0, measures3[1]->getNumber().getDouble(status));
|
||||
assertEquals("light-year test: measures[1] unit", MeasureUnit::getMeter().getIdentifier(),
|
||||
measures3[1]->getUnit().getIdentifier());
|
||||
|
||||
// 1e-15 light years is 9.46073 meters (calculated using "bc" and the CLDR
|
||||
// conversion factor). With double-precision maths, we get 10.5. In this
|
||||
// case, we're off by almost 1 meter.
|
||||
MaybeStackVector<Measure> measures4 = converter3.convert((1.0 + 1e-15), status);
|
||||
assertEquals("measures length", 2, measures4.length());
|
||||
assertEquals("light-year test: measures[0] value", 1.0, measures4[0]->getNumber().getDouble(status));
|
||||
assertEquals("light-year test: measures[0] unit", MeasureUnit::getLightYear().getIdentifier(),
|
||||
measures4[0]->getUnit().getIdentifier());
|
||||
assertEqualsNear("light-year test: measures[1] value", 10,
|
||||
measures4[1]->getNumber().getDouble(status), 1);
|
||||
assertEquals("light-year test: measures[1] unit", MeasureUnit::getMeter().getIdentifier(),
|
||||
measures4[1]->getUnit().getIdentifier());
|
||||
|
||||
// 2e-16 light years is 1.892146 meters. We consider this in the noise, and
|
||||
// thus expect a 0. (This test fails when 2e-16 is increased to 4e-16.)
|
||||
MaybeStackVector<Measure> measures5 = converter3.convert((1.0 + 2e-16), status);
|
||||
assertEquals("measures length", 2, measures5.length());
|
||||
assertEquals("light-year test: measures[0] value", 1.0, measures5[0]->getNumber().getDouble(status));
|
||||
assertEquals("light-year test: measures[0] unit", MeasureUnit::getLightYear().getIdentifier(),
|
||||
measures5[0]->getUnit().getIdentifier());
|
||||
assertEquals("light-year test: measures[1] value", 0.0,
|
||||
measures5[1]->getNumber().getDouble(status));
|
||||
assertEquals("light-year test: measures[1] unit", MeasureUnit::getMeter().getIdentifier(),
|
||||
measures5[1]->getUnit().getIdentifier());
|
||||
|
||||
// TODO(icu-units#63): test negative numbers!
|
||||
}
|
||||
|
||||
void UnitsTest::testComplexUnitConverterSorting() {
|
||||
IcuTestErrorCode status(*this, "UnitsTest::testComplexUnitConverterSorting");
|
||||
|
||||
@ -442,11 +535,11 @@ void UnitsTest::testComplexUnitConverterSorting() {
|
||||
auto measures = complexConverter.convert(10.0, status);
|
||||
|
||||
U_ASSERT(measures.length() == 2);
|
||||
assertEquals("Sorted Data", "foot", measures[0]->getUnit().getIdentifier());
|
||||
assertEquals("Sorted Data", "inch", measures[1]->getUnit().getIdentifier());
|
||||
assertEquals("inch-and-foot unit 0", "inch", measures[0]->getUnit().getIdentifier());
|
||||
assertEquals("inch-and-foot unit 1", "foot", measures[1]->getUnit().getIdentifier());
|
||||
|
||||
assertEqualsNear("Sorted Data", 32, measures[0]->getNumber().getInt64(), 0.00001);
|
||||
assertEqualsNear("Sorted Data", 9.7008, measures[1]->getNumber().getDouble(), 0.0001);
|
||||
assertEqualsNear("inch-and-foot value 0", 9.7008, measures[0]->getNumber().getDouble(), 0.0001);
|
||||
assertEqualsNear("inch-and-foot value 1", 32, measures[1]->getNumber().getInt64(), 0.00001);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -750,7 +843,9 @@ void parsePreferencesTests(const char *filename, char delimiter, char *fields[][
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs data-driven unit tests for unit preferences.
|
||||
* Runs data-driven unit tests for unit preferences. It looks for the test cases
|
||||
* in source/test/testdata/cldr/units/unitPreferencesTest.txt, which originates
|
||||
* in CLDR.
|
||||
*/
|
||||
void UnitsTest::testPreferences() {
|
||||
const char *filename = "unitPreferencesTest.txt";
|
||||
@ -765,7 +860,7 @@ void UnitsTest::testPreferences() {
|
||||
}
|
||||
|
||||
CharString path(sourceTestDataPath, errorCode);
|
||||
path.appendPathPart("units", errorCode);
|
||||
path.appendPathPart("cldr/units", errorCode);
|
||||
path.appendPathPart(filename, errorCode);
|
||||
|
||||
parsePreferencesTests(path.data(), ';', fields, maxFields, unitPreferencesTestDataLineFn, this,
|
@ -1,453 +0,0 @@
|
||||
# This file is a copy of common/testData/units/unitPreferencesTest.txt from CLDR.
|
||||
# WIP/TODO(hugovdm): determine a good update procedure and document it.
|
||||
#
|
||||
# Test data for unit preferences
|
||||
# Copyright © 1991-2020 Unicode, Inc.
|
||||
# For terms of use, see http://www.unicode.org/copyright.html
|
||||
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
|
||||
# CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)
|
||||
#
|
||||
# Format:
|
||||
# Quantity; Usage; Region; Input (r); Input (d); Input Unit; Output (r); Output (d); Output Unit
|
||||
#
|
||||
# Use: Convert the Input amount & unit according to the Usage and Region.
|
||||
# The result should match the Output amount and unit.
|
||||
# Both rational (r) and double64 (d) forms of the input and output amounts are supplied so that implementations
|
||||
# have two options for testing based on the precision in their implementations. For example:
|
||||
# 3429 / 12500; 0.27432; meter;
|
||||
# The Output amount and Unit are repeated for mixed units. In such a case, only the smallest unit will have
|
||||
# both a rational and decimal amount; the others will have a single integer value, such as:
|
||||
# length; person-height; CA; 3429 / 12500; 0.27432; meter; 2; foot; 54 / 5; 10.8; inch
|
||||
# The input and output units are unit identifers; in particular, the output does not have further processing:
|
||||
# • no localization
|
||||
# • no adjustment for pluralization
|
||||
# • no formatted with the skeleton
|
||||
# • no suppression of zero values (for secondary -and- units such as pound in stone-and-pound)
|
||||
#
|
||||
# Generation: Set GENERATE_TESTS in TestUnits.java, and look at TestUnitPreferences results.
|
||||
|
||||
area; default; 001; 1100000; 1100000.0; square-meter; 11 / 10; 1.1; square-kilometer
|
||||
area; default; 001; 1000000; 1000000.0; square-meter; 1; 1.0; square-kilometer
|
||||
area; default; 001; 900000; 900000.0; square-meter; 90; 90.0; hectare
|
||||
area; default; 001; 10000; 10000.0; square-meter; 1; 1.0; hectare
|
||||
area; default; 001; 9000; 9000.0; square-meter; 9000; 9000.0; square-meter
|
||||
area; default; 001; 1; 1.0; square-meter; 1; 1.0; square-meter
|
||||
area; default; 001; 9 / 10; 0.9; square-meter; 9000; 9000.0; square-centimeter
|
||||
area; default; 001; 1 / 10000; 1.0E-4; square-meter; 1; 1.0; square-centimeter
|
||||
area; default; 001; 9 / 100000; 9.0E-5; square-meter; 9 / 10; 0.9; square-centimeter
|
||||
|
||||
area; default; GB; 222577103232 / 78125; 2848986.9213696; square-meter; 11 / 10; 1.1; square-mile
|
||||
area; default; GB; 40468564224 / 15625; 2589988.110336; square-meter; 1; 1.0; square-mile
|
||||
area; default; GB; 182108539008 / 78125; 2330989.2993024; square-meter; 576; 576.0; acre
|
||||
area; default; GB; 316160658 / 78125; 4046.8564224; square-meter; 1; 1.0; acre
|
||||
area; default; GB; 1422722961 / 390625; 3642.17078016; square-meter; 39204; 39204.0; square-foot
|
||||
area; default; GB; 145161 / 1562500; 0.09290304; square-meter; 1; 1.0; square-foot
|
||||
area; default; GB; 1306449 / 15625000; 0.083612736; square-meter; 648 / 5; 129.6; square-inch
|
||||
area; default; GB; 16129 / 25000000; 6.4516E-4; square-meter; 1; 1.0; square-inch
|
||||
area; default; GB; 145161 / 250000000; 5.80644E-4; square-meter; 9 / 10; 0.9; square-inch
|
||||
|
||||
area; geograph; 001; 1100000; 1100000.0; square-meter; 11 / 10; 1.1; square-kilometer
|
||||
area; geograph; 001; 1000000; 1000000.0; square-meter; 1; 1.0; square-kilometer
|
||||
area; geograph; 001; 900000; 900000.0; square-meter; 9 / 10; 0.9; square-kilometer
|
||||
|
||||
area; geograph; GB; 222577103232 / 78125; 2848986.9213696; square-meter; 11 / 10; 1.1; square-mile
|
||||
area; geograph; GB; 40468564224 / 15625; 2589988.110336; square-meter; 1; 1.0; square-mile
|
||||
area; geograph; GB; 182108539008 / 78125; 2330989.2993024; square-meter; 9 / 10; 0.9; square-mile
|
||||
|
||||
area; land; 001; 11000; 11000.0; square-meter; 11 / 10; 1.1; hectare
|
||||
area; land; 001; 10000; 10000.0; square-meter; 1; 1.0; hectare
|
||||
area; land; 001; 9000; 9000.0; square-meter; 9 / 10; 0.9; hectare
|
||||
|
||||
area; land; GB; 1738883619 / 390625; 4451.54206464; square-meter; 11 / 10; 1.1; acre
|
||||
area; land; GB; 316160658 / 78125; 4046.8564224; square-meter; 1; 1.0; acre
|
||||
area; land; GB; 1422722961 / 390625; 3642.17078016; square-meter; 9 / 10; 0.9; acre
|
||||
|
||||
concentration; blood-glucose; AG; 662435483600000000000000; 6.624354836E23; item-per-cubic-meter; 11 / 10; 1.1; millimole-per-liter
|
||||
concentration; blood-glucose; AG; 602214076000000000000000; 6.02214076E23; item-per-cubic-meter; 1; 1.0; millimole-per-liter
|
||||
concentration; blood-glucose; AG; 541992668400000000000000; 5.419926684E23; item-per-cubic-meter; 9 / 10; 0.9; millimole-per-liter
|
||||
|
||||
concentration; default; 001; 11 / 10; 1.1; item-per-cubic-meter; 11 / 10; 1.1; item-per-cubic-meter
|
||||
concentration; default; 001; 1; 1.0; item-per-cubic-meter; 1; 1.0; item-per-cubic-meter
|
||||
concentration; default; 001; 9 / 10; 0.9; item-per-cubic-meter; 9 / 10; 0.9; item-per-cubic-meter
|
||||
|
||||
consumption; default; 001; 11 / 1000000000; 1.1E-8; cubic-meter-per-meter; 11 / 10; 1.1; liter-per-100-kilometer
|
||||
consumption; default; 001; 1 / 100000000; 1.0E-8; cubic-meter-per-meter; 1; 1.0; liter-per-100-kilometer
|
||||
consumption; default; 001; 9 / 1000000000; 9.0E-9; cubic-meter-per-meter; 9 / 10; 0.9; liter-per-100-kilometer
|
||||
|
||||
consumption; vehicle-fuel; 001; 11 / 1000000000; 1.1E-8; cubic-meter-per-meter; 11 / 10; 1.1; liter-per-100-kilometer
|
||||
consumption; vehicle-fuel; 001; 1 / 100000000; 1.0E-8; cubic-meter-per-meter; 1; 1.0; liter-per-100-kilometer
|
||||
consumption; vehicle-fuel; 001; 9 / 1000000000; 9.0E-9; cubic-meter-per-meter; 9 / 10; 0.9; liter-per-100-kilometer
|
||||
|
||||
consumption; vehicle-fuel; BR; 11 / 10000000; 1.1E-6; cubic-meter-per-meter; 11 / 10; 1.1; liter-per-kilometer
|
||||
consumption; vehicle-fuel; BR; 1 / 1000000; 1.0E-6; cubic-meter-per-meter; 1; 1.0; liter-per-kilometer
|
||||
consumption; vehicle-fuel; BR; 9 / 10000000; 9.0E-7; cubic-meter-per-meter; 9 / 10; 0.9; liter-per-kilometer
|
||||
|
||||
consumption-inverse; default; 001; 110000000; 1.1E8; meter-per-cubic-meter; 11 / 10; 1.1; kilometer-per-centiliter
|
||||
consumption-inverse; default; 001; 100000000; 1.0E8; meter-per-cubic-meter; 1; 1.0; kilometer-per-centiliter
|
||||
consumption-inverse; default; 001; 90000000; 9.0E7; meter-per-cubic-meter; 9 / 10; 0.9; kilometer-per-centiliter
|
||||
|
||||
consumption-inverse; vehicle-fuel; 001; 110000000; 1.1E8; meter-per-cubic-meter; 11 / 10; 1.1; kilometer-per-centiliter
|
||||
consumption-inverse; vehicle-fuel; 001; 100000000; 1.0E8; meter-per-cubic-meter; 1; 1.0; kilometer-per-centiliter
|
||||
consumption-inverse; vehicle-fuel; 001; 90000000; 9.0E7; meter-per-cubic-meter; 9 / 10; 0.9; kilometer-per-centiliter
|
||||
|
||||
consumption-inverse; vehicle-fuel; US; 52800000000 / 112903; 467658.0781732992; meter-per-cubic-meter; 11 / 10; 1.1; mile-per-gallon
|
||||
consumption-inverse; vehicle-fuel; US; 48000000000 / 112903; 425143.707430272; meter-per-cubic-meter; 1; 1.0; mile-per-gallon
|
||||
consumption-inverse; vehicle-fuel; US; 43200000000 / 112903; 382629.3366872448; meter-per-cubic-meter; 9 / 10; 0.9; mile-per-gallon
|
||||
|
||||
consumption-inverse; vehicle-fuel; CA; 177027840000 / 454609; 389406.8089281118; meter-per-cubic-meter; 11 / 10; 1.1; mile-per-gallon-imperial
|
||||
consumption-inverse; vehicle-fuel; CA; 160934400000 / 454609; 354006.1899346471; meter-per-cubic-meter; 1; 1.0; mile-per-gallon-imperial
|
||||
consumption-inverse; vehicle-fuel; CA; 144840960000 / 454609; 318605.5709411824; meter-per-cubic-meter; 9 / 10; 0.9; mile-per-gallon-imperial
|
||||
|
||||
duration; default; 001; 95040; 95040.0; second; 11 / 10; 1.1; day
|
||||
duration; default; 001; 86400; 86400.0; second; 1; 1.0; day
|
||||
duration; default; 001; 77760; 77760.0; second; 108 / 5; 21.6; hour
|
||||
duration; default; 001; 3600; 3600.0; second; 1; 1.0; hour
|
||||
duration; default; 001; 3240; 3240.0; second; 54; 54.0; minute
|
||||
duration; default; 001; 60; 60.0; second; 1; 1.0; minute
|
||||
duration; default; 001; 54; 54.0; second; 54; 54.0; second
|
||||
duration; default; 001; 1; 1.0; second; 1; 1.0; second
|
||||
duration; default; 001; 9 / 10; 0.9; second; 900; 900.0; millisecond
|
||||
duration; default; 001; 1 / 1000; 0.001; second; 1; 1.0; millisecond
|
||||
duration; default; 001; 9 / 10000; 9.0E-4; second; 900; 900.0; microsecond
|
||||
duration; default; 001; 1 / 1000000; 1.0E-6; second; 1; 1.0; microsecond
|
||||
duration; default; 001; 9 / 10000000; 9.0E-7; second; 900; 900.0; nanosecond
|
||||
duration; default; 001; 1 / 1000000000; 1.0E-9; second; 1; 1.0; nanosecond
|
||||
duration; default; 001; 9 / 10000000000; 9.0E-10; second; 9 / 10; 0.9; nanosecond
|
||||
|
||||
duration; media; 001; 66; 66.0; second; 1; minute; 6; 6.0; second
|
||||
duration; media; 001; 60; 60.0; second; 1; minute; 0; 0.0; second
|
||||
duration; media; 001; 54; 54.0; second; 54; 54.0; second
|
||||
duration; media; 001; 1; 1.0; second; 1; 1.0; second
|
||||
duration; media; 001; 9 / 10; 0.9; second; 9 / 10; 0.9; second
|
||||
|
||||
energy; default; 001; 3960000; 3960000.0; kilogram-square-meter-per-square-second; 11 / 10; 1.1; kilowatt-hour
|
||||
energy; default; 001; 3600000; 3600000.0; kilogram-square-meter-per-square-second; 1; 1.0; kilowatt-hour
|
||||
energy; default; 001; 3240000; 3240000.0; kilogram-square-meter-per-square-second; 9 / 10; 0.9; kilowatt-hour
|
||||
|
||||
energy; food; US; 23012 / 5; 4602.4; kilogram-square-meter-per-square-second; 11 / 10; 1.1; foodcalorie
|
||||
energy; food; US; 4184; 4184.0; kilogram-square-meter-per-square-second; 1; 1.0; foodcalorie
|
||||
energy; food; US; 18828 / 5; 3765.6; kilogram-square-meter-per-square-second; 9 / 10; 0.9; foodcalorie
|
||||
|
||||
energy; food; 001; 23012 / 5; 4602.4; kilogram-square-meter-per-square-second; 11 / 10; 1.1; kilocalorie
|
||||
energy; food; 001; 4184; 4184.0; kilogram-square-meter-per-square-second; 1; 1.0; kilocalorie
|
||||
energy; food; 001; 18828 / 5; 3765.6; kilogram-square-meter-per-square-second; 9 / 10; 0.9; kilocalorie
|
||||
|
||||
length; default; 001; 1100; 1100.0; meter; 11 / 10; 1.1; kilometer
|
||||
length; default; 001; 1000; 1000.0; meter; 1; 1.0; kilometer
|
||||
length; default; 001; 900; 900.0; meter; 900; 900.0; meter
|
||||
length; default; 001; 1; 1.0; meter; 1; 1.0; meter
|
||||
length; default; 001; 9 / 10; 0.9; meter; 90; 90.0; centimeter
|
||||
length; default; 001; 1 / 100; 0.01; meter; 1; 1.0; centimeter
|
||||
length; default; 001; 9 / 1000; 0.009; meter; 9 / 10; 0.9; centimeter
|
||||
|
||||
length; default; GB; 1106424 / 625; 1770.2784; meter; 11 / 10; 1.1; mile
|
||||
length; default; GB; 201168 / 125; 1609.344; meter; 1; 1.0; mile
|
||||
length; default; GB; 905256 / 625; 1448.4096; meter; 4752; 4752.0; foot
|
||||
length; default; GB; 381 / 1250; 0.3048; meter; 1; 1.0; foot
|
||||
length; default; GB; 3429 / 12500; 0.27432; meter; 54 / 5; 10.8; inch
|
||||
length; default; GB; 127 / 5000; 0.0254; meter; 1; 1.0; inch
|
||||
length; default; GB; 1143 / 50000; 0.02286; meter; 9 / 10; 0.9; inch
|
||||
|
||||
length; person; 001; 11 / 1000; 0.011; meter; 11 / 10; 1.1; centimeter
|
||||
length; person; 001; 1 / 100; 0.01; meter; 1; 1.0; centimeter
|
||||
length; person; 001; 9 / 1000; 0.009; meter; 9 / 10; 0.9; centimeter
|
||||
|
||||
length; person; CA; 1397 / 50000; 0.02794; meter; 11 / 10; 1.1; inch
|
||||
length; person; CA; 127 / 5000; 0.0254; meter; 1; 1.0; inch
|
||||
length; person; CA; 1143 / 50000; 0.02286; meter; 9 / 10; 0.9; inch
|
||||
|
||||
length; person-height; 001; 11 / 1000; 0.011; meter; 11 / 10; 1.1; centimeter
|
||||
length; person-height; 001; 1 / 100; 0.01; meter; 1; 1.0; centimeter
|
||||
length; person-height; 001; 9 / 1000; 0.009; meter; 9 / 10; 0.9; centimeter
|
||||
|
||||
length; person-height; CA; 11811 / 12500; 0.94488; meter; 3; foot; 6 / 5; 1.2; inch
|
||||
length; person-height; CA; 1143 / 1250; 0.9144; meter; 3; foot; 0; 0.0; inch
|
||||
length; person-height; CA; 11049 / 12500; 0.88392; meter; 174 / 5; 34.8; inch
|
||||
length; person-height; CA; 127 / 5000; 0.0254; meter; 1; 1.0; inch
|
||||
length; person-height; CA; 1143 / 50000; 0.02286; meter; 9 / 10; 0.9; inch
|
||||
|
||||
length; person-height; AT; 11 / 10; 1.1; meter; 1; meter; 10; 10.0; centimeter
|
||||
length; person-height; AT; 1; 1.0; meter; 1; meter; 0; 0.0; centimeter
|
||||
length; person-height; AT; 9 / 10; 0.9; meter; 0; meter; 90; 90.0; centimeter
|
||||
|
||||
length; rainfall; BR; 11 / 1000; 0.011; meter; 11 / 10; 1.1; centimeter
|
||||
length; rainfall; BR; 1 / 100; 0.01; meter; 1; 1.0; centimeter
|
||||
length; rainfall; BR; 9 / 1000; 0.009; meter; 9 / 10; 0.9; centimeter
|
||||
|
||||
length; rainfall; US; 1397 / 50000; 0.02794; meter; 11 / 10; 1.1; inch
|
||||
length; rainfall; US; 127 / 5000; 0.0254; meter; 1; 1.0; inch
|
||||
length; rainfall; US; 1143 / 50000; 0.02286; meter; 9 / 10; 0.9; inch
|
||||
|
||||
length; rainfall; 001; 11 / 10000; 0.0011; meter; 11 / 10; 1.1; millimeter
|
||||
length; rainfall; 001; 1 / 1000; 0.001; meter; 1; 1.0; millimeter
|
||||
length; rainfall; 001; 9 / 10000; 9.0E-4; meter; 9 / 10; 0.9; millimeter
|
||||
|
||||
length; road; 001; 1000; 1000.0; meter; 1; 1.0; kilometer
|
||||
length; road; 001; 900; 900.0; meter; 9 / 10; 0.9; kilometer
|
||||
length; road; 001; 800; 800.0; meter; 800; 800.0; meter
|
||||
length; road; 001; 300; 300.0; meter; 300; 300.0; meter
|
||||
length; road; 001; 2999 / 10; 299.9; meter; 2999 / 10; 299.9; meter
|
||||
length; road; 001; 1; 1.0; meter; 1; 1.0; meter
|
||||
length; road; 001; 9 / 10; 0.9; meter; 9 / 10; 0.9; meter
|
||||
|
||||
length; road; US; 603504 / 625; 965.6064; meter; 3 / 5; 0.6; mile
|
||||
length; road; US; 100584 / 125; 804.672; meter; 1 / 2; 0.5; mile
|
||||
length; road; US; 402336 / 625; 643.7376; meter; 2112; 2112.0; foot
|
||||
length; road; US; 762 / 25; 30.48; meter; 100; 100.0; foot
|
||||
length; road; US; 380619 / 12500; 30.44952; meter; 999 / 10; 99.9; foot
|
||||
length; road; US; 381 / 1250; 0.3048; meter; 1; 1.0; foot
|
||||
length; road; US; 3429 / 12500; 0.27432; meter; 9 / 10; 0.9; foot
|
||||
|
||||
length; road; GB; 603504 / 625; 965.6064; meter; 3 / 5; 0.6; mile
|
||||
length; road; GB; 100584 / 125; 804.672; meter; 1 / 2; 0.5; mile
|
||||
length; road; GB; 402336 / 625; 643.7376; meter; 704; 704.0; yard
|
||||
length; road; GB; 2286 / 25; 91.44; meter; 100; 100.0; yard
|
||||
length; road; GB; 1141857 / 12500; 91.34856; meter; 999 / 10; 99.9; yard
|
||||
length; road; GB; 1143 / 1250; 0.9144; meter; 1; 1.0; yard
|
||||
length; road; GB; 10287 / 12500; 0.82296; meter; 9 / 10; 0.9; yard
|
||||
|
||||
length; road; SE; 11000; 11000.0; meter; 11 / 10; 1.1; mile-scandinavian
|
||||
length; road; SE; 10000; 10000.0; meter; 1; 1.0; mile-scandinavian
|
||||
length; road; SE; 9000; 9000.0; meter; 9; 9.0; kilometer
|
||||
length; road; SE; 1000; 1000.0; meter; 1; 1.0; kilometer
|
||||
length; road; SE; 900; 900.0; meter; 900; 900.0; meter
|
||||
length; road; SE; 300; 300.0; meter; 300; 300.0; meter
|
||||
length; road; SE; 2999 / 10; 299.9; meter; 2999 / 10; 299.9; meter
|
||||
length; road; SE; 1; 1.0; meter; 1; 1.0; meter
|
||||
length; road; SE; 9 / 10; 0.9; meter; 9 / 10; 0.9; meter
|
||||
|
||||
length; snowfall; 001; 11 / 1000; 0.011; meter; 11 / 10; 1.1; centimeter
|
||||
length; snowfall; 001; 1 / 100; 0.01; meter; 1; 1.0; centimeter
|
||||
length; snowfall; 001; 9 / 1000; 0.009; meter; 9 / 10; 0.9; centimeter
|
||||
|
||||
length; snowfall; US; 1397 / 50000; 0.02794; meter; 11 / 10; 1.1; inch
|
||||
length; snowfall; US; 127 / 5000; 0.0254; meter; 1; 1.0; inch
|
||||
length; snowfall; US; 1143 / 50000; 0.02286; meter; 9 / 10; 0.9; inch
|
||||
|
||||
length; vehicle; GB; 4191 / 12500; 0.33528; meter; 1; foot; 6 / 5; 1.2; inch
|
||||
length; vehicle; GB; 381 / 1250; 0.3048; meter; 1; foot; 0; 0.0; inch
|
||||
length; vehicle; GB; 3429 / 12500; 0.27432; meter; 0; foot; 54 / 5; 10.8; inch
|
||||
|
||||
length; vehicle; 001; 11 / 10; 1.1; meter; 11 / 10; 1.1; meter
|
||||
length; vehicle; 001; 1; 1.0; meter; 1; 1.0; meter
|
||||
length; vehicle; 001; 9 / 10; 0.9; meter; 9 / 10; 0.9; meter
|
||||
|
||||
length; vehicle; MX; 11 / 10; 1.1; meter; 1; meter; 10; 10.0; centimeter
|
||||
length; vehicle; MX; 1; 1.0; meter; 1; meter; 0; 0.0; centimeter
|
||||
length; vehicle; MX; 9 / 10; 0.9; meter; 0; meter; 90; 90.0; centimeter
|
||||
|
||||
length; visiblty; 001; 200; 200.0; meter; 1 / 5; 0.2; kilometer
|
||||
length; visiblty; 001; 100; 100.0; meter; 1 / 10; 0.1; kilometer
|
||||
length; visiblty; 001; 1; 1.0; meter; 1; 1.0; meter
|
||||
length; visiblty; 001; 9 / 10; 0.9; meter; 9 / 10; 0.9; meter
|
||||
length; visiblty; 001; 0; 0.0; meter; 0; 0.0; meter
|
||||
|
||||
length; visiblty; DE; 11 / 10; 1.1; meter; 11 / 10; 1.1; meter
|
||||
length; visiblty; DE; 1; 1.0; meter; 1; 1.0; meter
|
||||
length; visiblty; DE; 9 / 10; 0.9; meter; 9 / 10; 0.9; meter
|
||||
|
||||
length; visiblty; GB; 1106424 / 625; 1770.2784; meter; 11 / 10; 1.1; mile
|
||||
length; visiblty; GB; 201168 / 125; 1609.344; meter; 1; 1.0; mile
|
||||
length; visiblty; GB; 905256 / 625; 1448.4096; meter; 4752; 4752.0; foot
|
||||
length; visiblty; GB; 381 / 1250; 0.3048; meter; 1; 1.0; foot
|
||||
length; visiblty; GB; 3429 / 12500; 0.27432; meter; 9 / 10; 0.9; foot
|
||||
|
||||
mass; default; 001; 1100; 1100.0; kilogram; 11 / 10; 1.1; metric-ton
|
||||
mass; default; 001; 1000; 1000.0; kilogram; 1; 1.0; metric-ton
|
||||
mass; default; 001; 900; 900.0; kilogram; 900; 900.0; kilogram
|
||||
mass; default; 001; 1; 1.0; kilogram; 1; 1.0; kilogram
|
||||
mass; default; 001; 9 / 10; 0.9; kilogram; 900; 900.0; gram
|
||||
mass; default; 001; 1 / 1000; 0.001; kilogram; 1; 1.0; gram
|
||||
mass; default; 001; 9 / 10000; 9.0E-4; kilogram; 900; 900.0; milligram
|
||||
mass; default; 001; 1 / 1000000; 1.0E-6; kilogram; 1; 1.0; milligram
|
||||
mass; default; 001; 9 / 10000000; 9.0E-7; kilogram; 900; 900.0; microgram
|
||||
mass; default; 001; 1 / 1000000000; 1.0E-9; kilogram; 1; 1.0; microgram
|
||||
mass; default; 001; 9 / 10000000000; 9.0E-10; kilogram; 9 / 10; 0.9; microgram
|
||||
|
||||
mass; default; GB; 498951607 / 500000; 997.903214; kilogram; 11 / 10; 1.1; ton
|
||||
mass; default; GB; 45359237 / 50000; 907.18474; kilogram; 1; 1.0; ton
|
||||
mass; default; GB; 408233133 / 500000; 816.466266; kilogram; 1800; 1800.0; pound
|
||||
mass; default; GB; 45359237 / 100000000; 0.45359237; kilogram; 1; 1.0; pound
|
||||
mass; default; GB; 408233133 / 1000000000; 0.408233133; kilogram; 72 / 5; 14.4; ounce
|
||||
mass; default; GB; 45359237 / 1600000000; 0.028349523125; kilogram; 1; 1.0; ounce
|
||||
mass; default; GB; 408233133 / 16000000000; 0.0255145708125; kilogram; 9 / 10; 0.9; ounce
|
||||
|
||||
mass; person; 001; 11 / 10; 1.1; kilogram; 11 / 10; 1.1; kilogram
|
||||
mass; person; 001; 1; 1.0; kilogram; 1; 1.0; kilogram
|
||||
mass; person; 001; 9 / 10; 0.9; kilogram; 900; 900.0; gram
|
||||
mass; person; 001; 1 / 1000; 0.001; kilogram; 1; 1.0; gram
|
||||
mass; person; 001; 9 / 10000; 9.0E-4; kilogram; 9 / 10; 0.9; gram
|
||||
|
||||
mass; person; DZ; 11 / 10; 1.1; kilogram; 1; kilogram; 100; 100.0; gram
|
||||
mass; person; DZ; 1; 1.0; kilogram; 1; kilogram; 0; 0.0; gram
|
||||
mass; person; DZ; 9 / 10; 0.9; kilogram; 0; kilogram; 900; 900.0; gram
|
||||
|
||||
mass; person; US; 498951607 / 1000000000; 0.498951607; kilogram; 11 / 10; 1.1; pound
|
||||
mass; person; US; 45359237 / 100000000; 0.45359237; kilogram; 1; 1.0; pound
|
||||
mass; person; US; 408233133 / 1000000000; 0.408233133; kilogram; 0; pound; 72 / 5; 14.4; ounce
|
||||
|
||||
mass; person; GB; 3492661249 / 500000000; 6.985322498; kilogram; 1; stone; 7 / 5; 1.4; pound
|
||||
mass; person; GB; 317514659 / 50000000; 6.35029318; kilogram; 1; stone; 0; 0.0; pound
|
||||
mass; person; GB; 2857631931 / 500000000; 5.715263862; kilogram; 12; pound; 48 / 5; 9.6; ounce
|
||||
mass; person; GB; 45359237 / 100000000; 0.45359237; kilogram; 1; pound; 0; 0.0; ounce
|
||||
mass; person; GB; 408233133 / 1000000000; 0.408233133; kilogram; 0; pound; 72 / 5; 14.4; ounce
|
||||
|
||||
mass; person; HK; 498951607 / 1000000000; 0.498951607; kilogram; 1; pound; 8 / 5; 1.6; ounce
|
||||
mass; person; HK; 45359237 / 100000000; 0.45359237; kilogram; 1; pound; 0; 0.0; ounce
|
||||
mass; person; HK; 408233133 / 1000000000; 0.408233133; kilogram; 0; pound; 72 / 5; 14.4; ounce
|
||||
|
||||
mass-density; blood-glucose; 001; 11 / 1000; 0.011; kilogram-per-cubic-meter; 11 / 10; 1.1; milligram-per-deciliter
|
||||
mass-density; blood-glucose; 001; 1 / 100; 0.01; kilogram-per-cubic-meter; 1; 1.0; milligram-per-deciliter
|
||||
mass-density; blood-glucose; 001; 9 / 1000; 0.009; kilogram-per-cubic-meter; 9 / 10; 0.9; milligram-per-deciliter
|
||||
|
||||
mass-density; default; 001; 11 / 10; 1.1; kilogram-per-cubic-meter; 11 / 10; 1.1; kilogram-per-cubic-meter
|
||||
mass-density; default; 001; 1; 1.0; kilogram-per-cubic-meter; 1; 1.0; kilogram-per-cubic-meter
|
||||
mass-density; default; 001; 9 / 10; 0.9; kilogram-per-cubic-meter; 9 / 10; 0.9; kilogram-per-cubic-meter
|
||||
|
||||
power; default; 001; 1100000000; 1.1E9; kilogram-square-meter-per-cubic-second; 11 / 10; 1.1; gigawatt
|
||||
power; default; 001; 1000000000; 1.0E9; kilogram-square-meter-per-cubic-second; 1; 1.0; gigawatt
|
||||
power; default; 001; 900000000; 9.0E8; kilogram-square-meter-per-cubic-second; 900; 900.0; megawatt
|
||||
power; default; 001; 1000000; 1000000.0; kilogram-square-meter-per-cubic-second; 1; 1.0; megawatt
|
||||
power; default; 001; 900000; 900000.0; kilogram-square-meter-per-cubic-second; 900; 900.0; kilowatt
|
||||
power; default; 001; 1000; 1000.0; kilogram-square-meter-per-cubic-second; 1; 1.0; kilowatt
|
||||
power; default; 001; 900; 900.0; kilogram-square-meter-per-cubic-second; 900; 900.0; watt
|
||||
power; default; 001; 1; 1.0; kilogram-square-meter-per-cubic-second; 1; 1.0; watt
|
||||
power; default; 001; 9 / 10; 0.9; kilogram-square-meter-per-cubic-second; 900; 900.0; milliwatt
|
||||
power; default; 001; 1 / 1000; 0.001; kilogram-square-meter-per-cubic-second; 1; 1.0; milliwatt
|
||||
power; default; 001; 9 / 10000; 9.0E-4; kilogram-square-meter-per-cubic-second; 9 / 10; 0.9; milliwatt
|
||||
|
||||
power; engine; 001; 1100; 1100.0; kilogram-square-meter-per-cubic-second; 11 / 10; 1.1; kilowatt
|
||||
power; engine; 001; 1000; 1000.0; kilogram-square-meter-per-cubic-second; 1; 1.0; kilowatt
|
||||
power; engine; 001; 900; 900.0; kilogram-square-meter-per-cubic-second; 9 / 10; 0.9; kilowatt
|
||||
|
||||
power; engine; GB; 410134929370248621 / 500000000000000; 820.2698587404972; kilogram-square-meter-per-cubic-second; 11 / 10; 1.1; horsepower
|
||||
power; engine; GB; 37284993579113511 / 50000000000000; 745.6998715822702; kilogram-square-meter-per-cubic-second; 1; 1.0; horsepower
|
||||
power; engine; GB; 335564942212021599 / 500000000000000; 671.1298844240432; kilogram-square-meter-per-cubic-second; 9 / 10; 0.9; horsepower
|
||||
|
||||
pressure; baromtrc; 001; 110; 110.0; kilogram-per-meter-square-second; 11 / 10; 1.1; hectopascal
|
||||
pressure; baromtrc; 001; 100; 100.0; kilogram-per-meter-square-second; 1; 1.0; hectopascal
|
||||
pressure; baromtrc; 001; 90; 90.0; kilogram-per-meter-square-second; 9 / 10; 0.9; hectopascal
|
||||
|
||||
pressure; baromtrc; IN; 37250275043751 / 10000000000; 3725.0275043751; kilogram-per-meter-square-second; 11 / 10; 1.1; inch-ofhg
|
||||
pressure; baromtrc; IN; 3386388640341 / 1000000000; 3386.388640341; kilogram-per-meter-square-second; 1; 1.0; inch-ofhg
|
||||
pressure; baromtrc; IN; 30477497763069 / 10000000000; 3047.7497763069; kilogram-per-meter-square-second; 9 / 10; 0.9; inch-ofhg
|
||||
|
||||
pressure; baromtrc; BR; 110; 110.0; kilogram-per-meter-square-second; 11 / 10; 1.1; millibar
|
||||
pressure; baromtrc; BR; 100; 100.0; kilogram-per-meter-square-second; 1; 1.0; millibar
|
||||
pressure; baromtrc; BR; 90; 90.0; kilogram-per-meter-square-second; 9 / 10; 0.9; millibar
|
||||
|
||||
pressure; baromtrc; MX; 293309252313 / 2000000000; 146.6546261565; kilogram-per-meter-square-second; 11 / 10; 1.1; millimeter-ofhg
|
||||
pressure; baromtrc; MX; 26664477483 / 200000000; 133.322387415; kilogram-per-meter-square-second; 1; 1.0; millimeter-ofhg
|
||||
pressure; baromtrc; MX; 239980297347 / 2000000000; 119.9901486735; kilogram-per-meter-square-second; 9 / 10; 0.9; millimeter-ofhg
|
||||
|
||||
pressure; default; 001; 1100000; 1100000.0; kilogram-per-meter-square-second; 11 / 10; 1.1; megapascal
|
||||
pressure; default; 001; 1000000; 1000000.0; kilogram-per-meter-square-second; 1; 1.0; megapascal
|
||||
pressure; default; 001; 900000; 900000.0; kilogram-per-meter-square-second; 900000; 900000.0; pascal
|
||||
pressure; default; 001; 1; 1.0; kilogram-per-meter-square-second; 1; 1.0; pascal
|
||||
pressure; default; 001; 9 / 10; 0.9; kilogram-per-meter-square-second; 9 / 10; 0.9; pascal
|
||||
|
||||
pressure; default; GB; 97860875535731 / 12903200000; 7584.233022485197; kilogram-per-meter-square-second; 11 / 10; 1.1; pound-force-per-square-inch
|
||||
pressure; default; GB; 8896443230521 / 1290320000; 6894.757293168361; kilogram-per-meter-square-second; 1; 1.0; pound-force-per-square-inch
|
||||
pressure; default; GB; 80067989074689 / 12903200000; 6205.281563851525; kilogram-per-meter-square-second; 9 / 10; 0.9; pound-force-per-square-inch
|
||||
|
||||
speed; default; 001; 11 / 36; 0.3055555555555556; meter-per-second; 11 / 10; 1.1; kilometer-per-hour
|
||||
speed; default; 001; 5 / 18; 0.2777777777777778; meter-per-second; 1; 1.0; kilometer-per-hour
|
||||
speed; default; 001; 1 / 4; 0.25; meter-per-second; 9 / 10; 0.9; kilometer-per-hour
|
||||
|
||||
speed; default; GB; 15367 / 31250; 0.491744; meter-per-second; 11 / 10; 1.1; mile-per-hour
|
||||
speed; default; GB; 1397 / 3125; 0.44704; meter-per-second; 1; 1.0; mile-per-hour
|
||||
speed; default; GB; 12573 / 31250; 0.402336; meter-per-second; 9 / 10; 0.9; mile-per-hour
|
||||
|
||||
speed; wind; 001; 11 / 36; 0.3055555555555556; meter-per-second; 11 / 10; 1.1; kilometer-per-hour
|
||||
speed; wind; 001; 5 / 18; 0.2777777777777778; meter-per-second; 1; 1.0; kilometer-per-hour
|
||||
speed; wind; 001; 1 / 4; 0.25; meter-per-second; 9 / 10; 0.9; kilometer-per-hour
|
||||
|
||||
speed; wind; FI; 11 / 10; 1.1; meter-per-second; 11 / 10; 1.1; meter-per-second
|
||||
speed; wind; FI; 1; 1.0; meter-per-second; 1; 1.0; meter-per-second
|
||||
speed; wind; FI; 9 / 10; 0.9; meter-per-second; 9 / 10; 0.9; meter-per-second
|
||||
|
||||
speed; wind; US; 15367 / 31250; 0.491744; meter-per-second; 11 / 10; 1.1; mile-per-hour
|
||||
speed; wind; US; 1397 / 3125; 0.44704; meter-per-second; 1; 1.0; mile-per-hour
|
||||
speed; wind; US; 12573 / 31250; 0.402336; meter-per-second; 9 / 10; 0.9; mile-per-hour
|
||||
|
||||
temperature; default; 001; 1097 / 4; 274.25; kelvin; 11 / 10; 1.1; celsius
|
||||
temperature; default; 001; 5483 / 20; 274.15; kelvin; 1; 1.0; celsius
|
||||
temperature; default; 001; 5481 / 20; 274.05; kelvin; 9 / 10; 0.9; celsius
|
||||
|
||||
temperature; default; US; 15359 / 60; 255.9833333333333; kelvin; 11 / 10; 1.1; fahrenheit
|
||||
temperature; default; US; 46067 / 180; 255.9277777777778; kelvin; 1; 1.0; fahrenheit
|
||||
temperature; default; US; 46057 / 180; 255.8722222222222; kelvin; 9 / 10; 0.9; fahrenheit
|
||||
|
||||
temperature; weather; 001; 1097 / 4; 274.25; kelvin; 11 / 10; 1.1; celsius
|
||||
temperature; weather; 001; 5483 / 20; 274.15; kelvin; 1; 1.0; celsius
|
||||
temperature; weather; 001; 5481 / 20; 274.05; kelvin; 9 / 10; 0.9; celsius
|
||||
|
||||
temperature; weather; BS; 15359 / 60; 255.9833333333333; kelvin; 11 / 10; 1.1; fahrenheit
|
||||
temperature; weather; BS; 46067 / 180; 255.9277777777778; kelvin; 1; 1.0; fahrenheit
|
||||
temperature; weather; BS; 46057 / 180; 255.8722222222222; kelvin; 9 / 10; 0.9; fahrenheit
|
||||
|
||||
volume; default; 001; 11 / 10; 1.1; cubic-meter; 11 / 10; 1.1; cubic-meter
|
||||
volume; default; 001; 1; 1.0; cubic-meter; 1; 1.0; cubic-meter
|
||||
volume; default; 001; 9 / 10; 0.9; cubic-meter; 900000; 900000.0; cubic-centimeter
|
||||
volume; default; 001; 1 / 1000000; 1.0E-6; cubic-meter; 1; 1.0; cubic-centimeter
|
||||
volume; default; 001; 9 / 10000000; 9.0E-7; cubic-meter; 9 / 10; 0.9; cubic-centimeter
|
||||
|
||||
volume; default; GB; 608369751 / 19531250000; 0.0311485312512; cubic-meter; 11 / 10; 1.1; cubic-foot
|
||||
volume; default; GB; 55306341 / 1953125000; 0.028316846592; cubic-meter; 1; 1.0; cubic-foot
|
||||
volume; default; GB; 497757069 / 19531250000; 0.0254851619328; cubic-meter; 7776 / 5; 1555.2; cubic-inch
|
||||
volume; default; GB; 2048383 / 125000000000; 1.6387064E-5; cubic-meter; 1; 1.0; cubic-inch
|
||||
volume; default; GB; 18435447 / 1250000000000; 1.47483576E-5; cubic-meter; 9 / 10; 0.9; cubic-inch
|
||||
|
||||
volume; fluid; 001; 11 / 10000; 0.0011; cubic-meter; 11 / 10; 1.1; liter
|
||||
volume; fluid; 001; 1 / 1000; 0.001; cubic-meter; 1; 1.0; liter
|
||||
volume; fluid; 001; 9 / 10000; 9.0E-4; cubic-meter; 900; 900.0; milliliter
|
||||
volume; fluid; 001; 1 / 1000000; 1.0E-6; cubic-meter; 1; 1.0; milliliter
|
||||
volume; fluid; 001; 9 / 10000000; 9.0E-7; cubic-meter; 9 / 10; 0.9; milliliter
|
||||
|
||||
volume; fluid; US; 5204941203 / 1250000000000; 0.0041639529624; cubic-meter; 11 / 10; 1.1; gallon
|
||||
volume; fluid; US; 473176473 / 125000000000; 0.003785411784; cubic-meter; 1; 1.0; gallon
|
||||
volume; fluid; US; 4258588257 / 1250000000000; 0.0034068706056; cubic-meter; 18 / 5; 3.6; quart
|
||||
volume; fluid; US; 473176473 / 500000000000; 9.46352946E-4; cubic-meter; 1; 1.0; quart
|
||||
volume; fluid; US; 4258588257 / 5000000000000; 8.517176514E-4; cubic-meter; 9 / 5; 1.8; pint
|
||||
volume; fluid; US; 473176473 / 1000000000000; 4.73176473E-4; cubic-meter; 1; 1.0; pint
|
||||
volume; fluid; US; 4258588257 / 10000000000000; 4.258588257E-4; cubic-meter; 9 / 5; 1.8; cup
|
||||
volume; fluid; US; 473176473 / 2000000000000; 2.365882365E-4; cubic-meter; 1; 1.0; cup
|
||||
volume; fluid; US; 4258588257 / 20000000000000; 2.1292941285E-4; cubic-meter; 36 / 5; 7.2; fluid-ounce
|
||||
volume; fluid; US; 473176473 / 16000000000000; 2.95735295625E-5; cubic-meter; 1; 1.0; fluid-ounce
|
||||
volume; fluid; US; 4258588257 / 160000000000000; 2.661617660625E-5; cubic-meter; 9 / 5; 1.8; tablespoon
|
||||
volume; fluid; US; 473176473 / 32000000000000; 1.478676478125E-5; cubic-meter; 1; 1.0; tablespoon
|
||||
volume; fluid; US; 4258588257 / 320000000000000; 1.3308088303125E-5; cubic-meter; 27 / 10; 2.7; teaspoon
|
||||
volume; fluid; US; 157725491 / 32000000000000; 4.92892159375E-6; cubic-meter; 1; 1.0; teaspoon
|
||||
volume; fluid; US; 1419529419 / 320000000000000; 4.436029434375E-6; cubic-meter; 9 / 10; 0.9; teaspoon
|
||||
|
||||
volume; fluid; GB; 5000699 / 1000000000; 0.005000699; cubic-meter; 11 / 10; 1.1; gallon-imperial
|
||||
volume; fluid; GB; 454609 / 100000000; 0.00454609; cubic-meter; 1; 1.0; gallon-imperial
|
||||
volume; fluid; GB; 4091481 / 1000000000; 0.004091481; cubic-meter; 144; 144.0; fluid-ounce-imperial
|
||||
volume; fluid; GB; 454609 / 16000000000; 2.84130625E-5; cubic-meter; 1; 1.0; fluid-ounce-imperial
|
||||
volume; fluid; GB; 4091481 / 160000000000; 2.557175625E-5; cubic-meter; 9 / 10; 0.9; fluid-ounce-imperial
|
||||
|
||||
volume; oil; 001; 109303765263 / 625000000000; 0.1748860244208; cubic-meter; 11 / 10; 1.1; barrel
|
||||
volume; oil; 001; 9936705933 / 62500000000; 0.158987294928; cubic-meter; 1; 1.0; barrel
|
||||
volume; oil; 001; 89430353397 / 625000000000; 0.1430885654352; cubic-meter; 9 / 10; 0.9; barrel
|
||||
|
||||
volume; vehicle; US; 5204941203 / 1250000000000; 0.0041639529624; cubic-meter; 11 / 10; 1.1; gallon
|
||||
volume; vehicle; US; 473176473 / 125000000000; 0.003785411784; cubic-meter; 1; 1.0; gallon
|
||||
volume; vehicle; US; 4258588257 / 1250000000000; 0.0034068706056; cubic-meter; 9 / 10; 0.9; gallon
|
||||
|
||||
volume; vehicle; 001; 11 / 10000; 0.0011; cubic-meter; 11 / 10; 1.1; liter
|
||||
volume; vehicle; 001; 1 / 1000; 0.001; cubic-meter; 1; 1.0; liter
|
||||
volume; vehicle; 001; 9 / 10000; 9.0E-4; cubic-meter; 9 / 10; 0.9; liter
|
||||
|
||||
year-duration; default; 001; 11 / 10; 1.1; year; 11 / 10; 1.1; year
|
||||
year-duration; default; 001; 1; 1.0; year; 1; 1.0; year
|
||||
year-duration; default; 001; 9 / 10; 0.9; year; 54 / 5; 10.8; month
|
||||
year-duration; default; 001; 1 / 12; 0.08333333333333333; year; 1; 1.0; month
|
||||
year-duration; default; 001; 3 / 40; 0.075; year; 9 / 10; 0.9; month
|
||||
|
||||
year-duration; person-age; 001; 13 / 5; 2.6; year; 13 / 5; 2.6; year-person
|
||||
year-duration; person-age; 001; 5 / 2; 2.5; year; 5 / 2; 2.5; year-person
|
||||
year-duration; person-age; 001; 12 / 5; 2.4; year; 2; year-person; 24 / 5; 4.8; month-person
|
||||
year-duration; person-age; 001; 1; 1.0; year; 1; year-person; 0; 0.0; month-person
|
||||
year-duration; person-age; 001; 9 / 10; 0.9; year; 54 / 5; 10.8; month-person
|
||||
year-duration; person-age; 001; 1 / 12; 0.08333333333333333; year; 1; 1.0; month-person
|
||||
year-duration; person-age; 001; 3 / 40; 0.075; year; 9 / 10; 0.9; month-person
|
197
icu4c/source/test/testdata/units/unitsTest.txt
vendored
197
icu4c/source/test/testdata/units/unitsTest.txt
vendored
@ -1,197 +0,0 @@
|
||||
# This file is a copy of common/testData/units/unitsTest.txt from CLDR.
|
||||
# WIP/TODO(hugovdm): determine a good update procedure and document it.
|
||||
#
|
||||
# Test data for unit conversions
|
||||
# Copyright © 1991-2020 Unicode, Inc.
|
||||
# For terms of use, see http://www.unicode.org/copyright.html
|
||||
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
|
||||
# CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)
|
||||
#
|
||||
# Format:
|
||||
# Quantity ; x ; y ; conversion to y (rational) ; test: 1000 x ⟹ y
|
||||
#
|
||||
# Use: convert 1000 x units to the y unit; the result should match the final column,
|
||||
# at the given precision. For example, when the last column is 159.1549,
|
||||
# round to 4 decimal digits before comparing.
|
||||
# Note that certain conversions are approximate, such as degrees to radians
|
||||
#
|
||||
# Generation: Set GENERATE_TESTS in TestUnits.java, and look at TestParseUnit results.
|
||||
|
||||
acceleration ; meter-per-square-second ; meter-per-square-second ; 1 * x ; 1,000.00
|
||||
acceleration ; g-force ; meter-per-square-second ; 9.80665 * x ; 9806.65
|
||||
angle ; arc-second ; revolution ; 0.0000625/81 * x ; 7.716049E-4
|
||||
angle ; arc-minute ; revolution ; 0.00125/27 * x ; 0.0462963
|
||||
angle ; degree ; revolution ; 0.025/9 * x ; 2.777778
|
||||
angle ; radian ; revolution ; 65,501,488/411,557,987 * x ; 159.1549
|
||||
angle ; revolution ; revolution ; 1 * x ; 1,000.00
|
||||
area ; square-centimeter ; square-meter ; 0.0001 * x ; 0.1
|
||||
area ; square-inch ; square-meter ; 0.00064516 * x ; 0.64516
|
||||
area ; square-foot ; square-meter ; 0.09290304 * x ; 92.90304
|
||||
area ; square-yard ; square-meter ; 0.83612736 * x ; 836.1274
|
||||
area ; square-meter ; square-meter ; 1 * x ; 1,000.00
|
||||
area ; dunam ; square-meter ; 1,000 * x ; 1000000.0
|
||||
area ; acre ; square-meter ; 4,046.8564224 * x ; 4046856.0
|
||||
area ; hectare ; square-meter ; 10,000 * x ; 1.0E7
|
||||
area ; square-kilometer ; square-meter ; 1,000,000 * x ; 1.0E9
|
||||
area ; square-mile ; square-meter ; 2,589,988.110336 * x ; 2.589988E9
|
||||
concentration ; millimole-per-liter ; item-per-cubic-meter ; 602,214,076,000,000,000,000,000 * x ; 6.022141E26
|
||||
consumption ; liter-per-100-kilometer ; cubic-meter-per-meter ; 0.00000001 * x ; 1.0E-5
|
||||
consumption ; liter-per-kilometer ; cubic-meter-per-meter ; 0.000001 * x ; 0.001
|
||||
consumption-inverse ; mile-per-gallon-imperial ; meter-per-cubic-meter ; 160,934,400,000/454,609 * x ; 3.540062E8
|
||||
consumption-inverse ; mile-per-gallon ; meter-per-cubic-meter ; 48,000,000,000/112,903 * x ; 4.251437E8
|
||||
digital ; bit ; bit ; 1 * x ; 1,000.00
|
||||
digital ; byte ; bit ; 8 * x ; 8000.0
|
||||
digital ; kilobit ; bit ; 1,000 * x ; 1000000.0
|
||||
digital ; kilobyte ; bit ; 8,000 * x ; 8000000.0
|
||||
digital ; megabit ; bit ; 1,000,000 * x ; 1.0E9
|
||||
digital ; megabyte ; bit ; 8,000,000 * x ; 8.0E9
|
||||
digital ; gigabit ; bit ; 1,000,000,000 * x ; 1.0E12
|
||||
digital ; gigabyte ; bit ; 8,000,000,000 * x ; 8.0E12
|
||||
digital ; terabit ; bit ; 1,000,000,000,000 * x ; 1.0E15
|
||||
digital ; terabyte ; bit ; 8,000,000,000,000 * x ; 8.0E15
|
||||
digital ; petabyte ; bit ; 8,000,000,000,000,000 * x ; 8.0E18
|
||||
duration ; nanosecond ; second ; 0.000000001 * x ; 1.0E-6
|
||||
duration ; microsecond ; second ; 0.000001 * x ; 0.001
|
||||
duration ; millisecond ; second ; 0.001 * x ; 1.0
|
||||
duration ; second ; second ; 1 * x ; 1,000.00
|
||||
duration ; minute ; second ; 60 * x ; 60000.0
|
||||
duration ; hour ; second ; 3,600 * x ; 3600000.0
|
||||
duration ; day ; second ; 86,400 * x ; 8.64E7
|
||||
duration ; day-person ; second ; 86,400 * x ; 8.64E7
|
||||
duration ; week ; second ; 604,800 * x ; 6.048E8
|
||||
duration ; week-person ; second ; 604,800 * x ; 6.048E8
|
||||
electric-current ; milliampere ; ampere ; 0.001 * x ; 1.0
|
||||
electric-current ; ampere ; ampere ; 1 * x ; 1,000.00
|
||||
electric-resistance ; ohm ; kilogram-square-meter-per-cubic-second-square-ampere ; 1 * x ; 1000.0
|
||||
energy ; electronvolt ; kilogram-square-meter-per-square-second ; 0.0000000000000000001602177 * x ; 1.602177E-16
|
||||
energy ; dalton ; kilogram-square-meter-per-square-second ; 0.00000000014924180856 * x ; 1.492418E-7
|
||||
energy ; joule ; kilogram-square-meter-per-square-second ; 1 * x ; 1000.0
|
||||
energy ; newton-meter ; kilogram-square-meter-per-square-second ; 1 * x ; 1000.0
|
||||
energy ; pound-force-foot ; kilogram-square-meter-per-square-second ; 1.3558179483314004 * x ; 1355.818
|
||||
energy ; calorie ; kilogram-square-meter-per-square-second ; 4.184 * x ; 4184.0
|
||||
energy ; kilojoule ; kilogram-square-meter-per-square-second ; 1,000 * x ; 1000000.0
|
||||
energy ; british-thermal-unit ; kilogram-square-meter-per-square-second ; 9,489.1523804/9 * x ; 1054350.0
|
||||
energy ; foodcalorie ; kilogram-square-meter-per-square-second ; 4,184 * x ; 4184000.0
|
||||
energy ; kilocalorie ; kilogram-square-meter-per-square-second ; 4,184 * x ; 4184000.0
|
||||
energy ; kilowatt-hour ; kilogram-square-meter-second-per-cubic-second ; 3,600,000 * x ; 3.6E9
|
||||
energy ; therm-us ; kilogram-square-meter-per-square-second ; 105,480,400 * x ; 1.054804E11
|
||||
force ; newton ; kilogram-meter-per-square-second ; 1 * x ; 1000.0
|
||||
force ; pound-force ; kilogram-meter-per-square-second ; 4.4482216152605 * x ; 4448.222
|
||||
frequency ; hertz ; revolution-per-second ; 1 * x ; 1000.0
|
||||
frequency ; kilohertz ; revolution-per-second ; 1,000 * x ; 1000000.0
|
||||
frequency ; megahertz ; revolution-per-second ; 1,000,000 * x ; 1.0E9
|
||||
frequency ; gigahertz ; revolution-per-second ; 1,000,000,000 * x ; 1.0E12
|
||||
graphics ; dot ; pixel ; 1 * x ; 1000.0
|
||||
graphics ; pixel ; pixel ; 1 * x ; 1,000.00
|
||||
graphics ; megapixel ; pixel ; 1,000,000 * x ; 1.0E9
|
||||
length ; picometer ; meter ; 0.000000000001 * x ; 1.0E-9
|
||||
length ; nanometer ; meter ; 0.000000001 * x ; 1.0E-6
|
||||
length ; micrometer ; meter ; 0.000001 * x ; 0.001
|
||||
length ; point ; meter ; 0.003175/9 * x ; 0.3527778
|
||||
length ; millimeter ; meter ; 0.001 * x ; 1.0
|
||||
length ; centimeter ; meter ; 0.01 * x ; 10.0
|
||||
length ; inch ; meter ; 0.0254 * x ; 25.4
|
||||
length ; decimeter ; meter ; 0.1 * x ; 100.0
|
||||
length ; foot ; meter ; 0.3048 * x ; 304.8
|
||||
length ; yard ; meter ; 0.9144 * x ; 914.4
|
||||
length ; meter ; meter ; 1 * x ; 1,000.00
|
||||
length ; fathom ; meter ; 1.8288 * x ; 1828.8
|
||||
length ; furlong ; meter ; 201.168 * x ; 201168.0
|
||||
length ; kilometer ; meter ; 1,000 * x ; 1000000.0
|
||||
length ; mile ; meter ; 1,609.344 * x ; 1609344.0
|
||||
length ; nautical-mile ; meter ; 1,852 * x ; 1852000.0
|
||||
length ; mile-scandinavian ; meter ; 10,000 * x ; 1.0E7
|
||||
length ; 100-kilometer ; meter ; 100,000 * x ; 1.0E8
|
||||
length ; earth-radius ; meter ; 6,378,100 * x ; 6.3781E9
|
||||
length ; solar-radius ; meter ; 695,700,000 * x ; 6.957E11
|
||||
length ; astronomical-unit ; meter ; 149,597,900,000 * x ; 1.495979E14
|
||||
length ; light-year ; meter ; 9,460,730,000,000,000 * x ; 9.46073E18
|
||||
length ; parsec ; meter ; 30,856,780,000,000,000 * x ; 3.085678E19
|
||||
luminous-flux ; lux ; candela-square-meter-per-square-meter ; 1 * x ; 1000.0
|
||||
luminous-intensity ; candela ; candela ; 1 * x ; 1,000.00
|
||||
mass ; microgram ; kilogram ; 0.000000001 * x ; 1.0E-6
|
||||
mass ; milligram ; kilogram ; 0.000001 * x ; 0.001
|
||||
mass ; carat ; kilogram ; 0.0002 * x ; 0.2
|
||||
mass ; gram ; kilogram ; 0.001 * x ; 1.0
|
||||
mass ; ounce ; kilogram ; 0.028349523125 * x ; 28.34952
|
||||
mass ; ounce-troy ; kilogram ; 0.03110348 * x ; 31.10348
|
||||
mass ; pound ; kilogram ; 0.45359237 * x ; 453.5924
|
||||
mass ; kilogram ; kilogram ; 1 * x ; 1,000.00
|
||||
mass ; stone ; kilogram ; 6.35029318 * x ; 6350.293
|
||||
mass ; ton ; kilogram ; 907.18474 * x ; 907184.7
|
||||
mass ; metric-ton ; kilogram ; 1,000 * x ; 1000000.0
|
||||
mass ; earth-mass ; kilogram ; 5,972,200,000,000,000,000,000,000 * x ; 5.9722E27
|
||||
mass ; solar-mass ; kilogram ; 1,988,470,000,000,000,000,000,000,000,000 * x ; 1.98847E33
|
||||
mass-density ; milligram-per-deciliter ; kilogram-per-cubic-meter ; 0.01 * x ; 10.0
|
||||
portion ; permillion ; portion ; 0.000001 * x ; 0.001
|
||||
portion ; permyriad ; portion ; 0.0001 * x ; 0.1
|
||||
portion ; permille ; portion ; 0.001 * x ; 1.0
|
||||
portion ; percent ; portion ; 0.01 * x ; 10.0
|
||||
portion ; karat ; portion ; 0.125/3 * x ; 41.66667
|
||||
portion ; portion ; portion ; 1 * x ; 1,000.00
|
||||
power ; milliwatt ; kilogram-square-meter-per-cubic-second ; 0.001 * x ; 1.0
|
||||
power ; watt ; kilogram-square-meter-per-cubic-second ; 1 * x ; 1000.0
|
||||
power ; horsepower ; kilogram-square-meter-per-cubic-second ; 745.69987158227022 * x ; 745699.9
|
||||
power ; kilowatt ; kilogram-square-meter-per-cubic-second ; 1,000 * x ; 1000000.0
|
||||
power ; megawatt ; kilogram-square-meter-per-cubic-second ; 1,000,000 * x ; 1.0E9
|
||||
power ; gigawatt ; kilogram-square-meter-per-cubic-second ; 1,000,000,000 * x ; 1.0E12
|
||||
power ; solar-luminosity ; kilogram-square-meter-per-cubic-second ; 382,800,000,000,000,000,000,000,000 * x ; 3.828E29
|
||||
pressure ; pascal ; kilogram-per-meter-square-second ; 1 * x ; 1000.0
|
||||
pressure ; hectopascal ; kilogram-per-meter-square-second ; 100 * x ; 100000.0
|
||||
pressure ; millibar ; kilogram-per-meter-square-second ; 100 * x ; 100000.0
|
||||
pressure ; millimeter-ofhg ; kilogram-meter-per-square-meter-square-second ; 133.322387415 * x ; 133322.4
|
||||
pressure ; kilopascal ; kilogram-per-meter-square-second ; 1,000 * x ; 1000000.0
|
||||
pressure ; inch-ofhg ; kilogram-meter-per-square-meter-square-second ; 3,386.388640341 * x ; 3386389.0
|
||||
pressure ; pound-force-per-square-inch ; kilogram-meter-per-square-meter-square-second ; 111,205,540.3815125/16,129 * x ; 6894757.0
|
||||
pressure ; bar ; kilogram-per-meter-square-second ; 100,000 * x ; 1.0E8
|
||||
pressure ; atmosphere ; kilogram-per-meter-square-second ; 101,325 * x ; 1.01325E8
|
||||
pressure ; megapascal ; kilogram-per-meter-square-second ; 1,000,000 * x ; 1.0E9
|
||||
pressure-per-length ; ofhg ; kilogram-per-square-meter-square-second ; 133,322.387415 * x ; 1.333224E8
|
||||
resolution ; dot-per-inch ; pixel-per-meter ; 5,000/127 * x ; 39370.08
|
||||
resolution ; pixel-per-inch ; pixel-per-meter ; 5,000/127 * x ; 39370.08
|
||||
resolution ; dot-per-centimeter ; pixel-per-meter ; 100 * x ; 100000.0
|
||||
resolution ; pixel-per-centimeter ; pixel-per-meter ; 100 * x ; 100000.0
|
||||
speed ; kilometer-per-hour ; meter-per-second ; 2.5/9 * x ; 277.7778
|
||||
speed ; mile-per-hour ; meter-per-second ; 0.44704 * x ; 447.04
|
||||
speed ; knot ; meter-per-second ; 4.63/9 * x ; 514.4444
|
||||
speed ; meter-per-second ; meter-per-second ; 1 * x ; 1,000.00
|
||||
substance-amount ; item ; item ; 1 * x ; 1,000.00
|
||||
substance-amount ; mole ; item ; 602,214,076,000,000,000,000,000 * x ; 6.022141E26
|
||||
temperature ; fahrenheit ; kelvin ; 5/9 * x - 2,298.35/9 ; 810.9278
|
||||
temperature ; kelvin ; kelvin ; 1 * x ; 1,000.00
|
||||
temperature ; celsius ; kelvin ; 1 * x - 273.15 ; 1273.15
|
||||
typewidth ; em ; em ; 1 * x ; 1,000.00
|
||||
voltage ; volt ; kilogram-square-meter-per-cubic-second-ampere ; 1 * x ; 1000.0
|
||||
volume ; cubic-centimeter ; cubic-meter ; 0.000001 * x ; 0.001
|
||||
volume ; milliliter ; cubic-meter ; 0.000001 * x ; 0.001
|
||||
volume ; teaspoon ; cubic-meter ; 0.00000492892159375 * x ; 0.004928922
|
||||
volume ; centiliter ; cubic-meter ; 0.00001 * x ; 0.01
|
||||
volume ; tablespoon ; cubic-meter ; 0.00001478676478125 * x ; 0.01478676
|
||||
volume ; cubic-inch ; cubic-meter ; 0.000016387064 * x ; 0.01638706
|
||||
volume ; fluid-ounce-imperial ; cubic-meter ; 0.0000284130625 * x ; 0.02841306
|
||||
volume ; fluid-ounce ; cubic-meter ; 0.0000295735295625 * x ; 0.02957353
|
||||
volume ; deciliter ; cubic-meter ; 0.0001 * x ; 0.1
|
||||
volume ; cup ; cubic-meter ; 0.0002365882365 * x ; 0.2365882
|
||||
volume ; cup-metric ; cubic-meter ; 0.00025 * x ; 0.25
|
||||
volume ; pint ; cubic-meter ; 0.000473176473 * x ; 0.4731765
|
||||
volume ; pint-metric ; cubic-meter ; 0.0005 * x ; 0.5
|
||||
volume ; quart ; cubic-meter ; 0.000946352946 * x ; 0.9463529
|
||||
volume ; liter ; cubic-meter ; 0.001 * x ; 1.0
|
||||
volume ; gallon ; cubic-meter ; 0.003785411784 * x ; 3.785412
|
||||
volume ; gallon-imperial ; cubic-meter ; 0.00454609 * x ; 4.54609
|
||||
volume ; cubic-foot ; cubic-meter ; 0.028316846592 * x ; 28.31685
|
||||
volume ; bushel ; cubic-meter ; 0.03523907016688 * x ; 35.23907
|
||||
volume ; hectoliter ; cubic-meter ; 0.1 * x ; 100.0
|
||||
volume ; barrel ; cubic-meter ; 0.158987294928 * x ; 158.9873
|
||||
volume ; cubic-yard ; cubic-meter ; 0.764554857984 * x ; 764.5549
|
||||
volume ; cubic-meter ; cubic-meter ; 1 * x ; 1,000.00
|
||||
volume ; megaliter ; cubic-meter ; 1,000 * x ; 1000000.0
|
||||
volume ; acre-foot ; cubic-meter ; 1,233.48183754752 * x ; 1233482.0
|
||||
volume ; cubic-kilometer ; cubic-meter ; 1,000,000,000 * x ; 1.0E12
|
||||
volume ; cubic-mile ; cubic-meter ; 4,168,181,825.440579584 * x ; 4.168182E12
|
||||
year-duration ; month ; year ; 0.25/3 * x ; 83.33333
|
||||
year-duration ; month-person ; year ; 0.25/3 * x ; 83.33333
|
||||
year-duration ; year ; year ; 1 * x ; 1,000.00
|
||||
year-duration ; year-person ; year ; 1 * x ; 1000.0
|
||||
year-duration ; decade ; year ; 10 * x ; 10000.0
|
||||
year-duration ; century ; year ; 100 * x ; 100000.0
|
Loading…
Reference in New Issue
Block a user