From: Hugo van der Merwe <17109322+hugovdm@users.noreply.github.com> Date: Wed, 18 Mar 2020 17:34:38 +0000 (+0100) Subject: Move wip_units_resource_loader.* code into unitsrouter.* X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4bf58cf0a743eaa2df417d88388eebb0537a3b76;p=icu Move wip_units_resource_loader.* code into unitsrouter.* --- diff --git a/icu4c/source/i18n/Makefile.in b/icu4c/source/i18n/Makefile.in index 827f2c207ba..0df439b7e90 100644 --- a/icu4c/source/i18n/Makefile.in +++ b/icu4c/source/i18n/Makefile.in @@ -115,7 +115,7 @@ numparse_affixes.o numparse_compositions.o numparse_validators.o \ numrange_fluent.o numrange_impl.o \ erarules.o \ formattedvalue.o formattedval_iterimpl.o formattedval_sbimpl.o formatted_string_builder.o \ -unitconverter.o +unitconverter.o unitsrouter.o ## Header files to install HEADERS = $(srcdir)/unicode/*.h diff --git a/icu4c/source/i18n/unitsrouter.cpp b/icu4c/source/i18n/unitsrouter.cpp index 9da50ef0647..50aab0dda14 100644 --- a/icu4c/source/i18n/unitsrouter.cpp +++ b/icu4c/source/i18n/unitsrouter.cpp @@ -6,52 +6,303 @@ #if !UCONFIG_NO_FORMATTING #include "cmemory.h" +#include "cstring.h" +#include "number_decimalquantity.h" +#include "resource.h" #include "unitsrouter.h" +#include "uresimp.h" U_NAMESPACE_BEGIN namespace { /* Internal Data */ -// Preference of a single unit. -struct UnitPreference { - StringPiece identifier; - - // Represents the limit of the largest unit in the identifier that the quantity must be greater than - // or equal. - // e.g. geq: 0.3 for a unit "foot-and-inch" - double limit; +// // Preference of a single unit. +// struct UnitPreference { +// StringPiece identifier; + +// // Represents the limit of the largest unit in the identifier that the quantity must be greater than +// // or equal. +// // e.g. geq: 0.3 for a unit "foot-and-inch" +// double limit; +// }; + +// MaybeStackVector extractUnitPreferences(StringPiece locale, StringPiece usage, +// StringPiece category) { +// MaybeStackVector result; + +// // TODO(hugovdm): extract from the database all the UnitPreference for the `locale`, `category` and +// // `usage` in order. + +// return result; +// } + +// StringPiece extractUnitCategory(MeasureUnit unit) { +// StringPiece result; + +// // TODO(hugovdm): extract the category of a unit from their MeasureUnits. + +// return result; +// } + +using namespace ::hugovdm_wip; +using icu::number::impl::DecimalQuantity; + +class ConvertUnitsSink : public ResourceSink { + public: + explicit ConvertUnitsSink(MaybeStackVector &out) : outVector(out) {} + + // WIP: look into noFallback + void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) { + ResourceTable conversionRateTable = value.getTable(status); + if (U_FAILURE(status)) { + // fprintf(stderr, "%s: getTable failed\n", u_errorName(status)); + return; + } + + ConversionRateInfo *cr = outVector.emplaceBack(); + if (!cr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + + int32_t length = uprv_strlen(key); + cr->source.append(key, length, status); + if (U_FAILURE(status)) { + // fprintf(stderr, "%s: source.append failed\n", u_errorName(status)); + return; + } + for (int32_t i = 0; conversionRateTable.getKeyAndValue(i, key, value); ++i) { + if (uprv_strcmp(key, "factor") == 0) { + int32_t length; + const UChar *f = value.getString(length, status); + cr->factor.appendInvariantChars(f, length, status); + cr->factorUChar = f; + } else if (uprv_strcmp(key, "offset") == 0) { + int32_t length; + const UChar *o = value.getString(length, status); + cr->offset.appendInvariantChars(o, length, status); + cr->offsetUChar = o; + } else if (uprv_strcmp(key, "target") == 0) { + int32_t length; + const UChar *t = value.getString(length, status); + cr->target.appendInvariantChars(t, length, status); + cr->targetUChar = t; + } + } + } + + private: + MaybeStackVector &outVector; }; -MaybeStackVector extractUnitPreferences(StringPiece locale, StringPiece usage, - StringPiece category) { - MaybeStackVector result; +class UnitPreferencesSink : public ResourceSink { + public: + explicit UnitPreferencesSink(MaybeStackVector &out) : outVector(out) {} - // TODO(hugovdm): extract from the database all the UnitPreference for the `locale`, `category` and - // `usage` in order. + // WIP: look into noFallback + void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) { + if (U_FAILURE(status)) { return; } + int32_t prefLen; + ResourceArray unitPrefs = value.getArray(status); + if (U_FAILURE(status)) { return; } + prefLen = unitPrefs.getSize(); + for (int32_t i = 0; unitPrefs.getValue(i, value); i++) { + UnitPreference *up = outVector.emplaceBack(); + if (!up) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + ResourceTable unitPref = value.getTable(status); + if (U_FAILURE(status)) { return; } + for (int32_t i = 0; unitPref.getKeyAndValue(i, key, value); ++i) { + if (uprv_strcmp(key, "unit") == 0) { + int32_t length; + const UChar *u = value.getString(length, status); + up->unit.appendInvariantChars(u, length, status); + } else if (uprv_strcmp(key, "geq") == 0) { + int32_t length; + const UChar *g = value.getString(length, status); + CharString geq; + geq.appendInvariantChars(g, length, status); + DecimalQuantity dq; + dq.setToDecNumber(geq.data(), status); + up->geq = dq.toDouble(); + } else if (uprv_strcmp(key, "skeleton") == 0) { + int32_t length; + const UChar *s = value.getString(length, status); + up->skeleton.appendInvariantChars(s, length, status); + } + } + } + } - return result; -} + private: + MaybeStackVector &outVector; +}; -StringPiece extractUnitCategory(MeasureUnit unit) { - StringPiece result; +void putUnitPref(UResourceBundle *usageData, MaybeStackVector &outVector, + UErrorCode &status) { + if (U_FAILURE(status)) { return; } - // TODO(hugovdm): extract the category of a unit from their MeasureUnits. + UResourceBundle *prefBundle = NULL; + int32_t numPrefs = ures_getSize(usageData); + for (int32_t i = 0; i < numPrefs; i++) { + prefBundle = ures_getByIndex(usageData, i, prefBundle, &status); + if (U_FAILURE(status)) { + // fprintf(stderr, "failed getting index %d/%d: %s\n", i, numPrefs, u_errorName(status)); + status = U_ZERO_ERROR; + break; + } + int32_t len; + const UChar *unitIdent = ures_getStringByKey(prefBundle, "unit", &len, &status); + if (U_FAILURE(status)) { + // fprintf(stderr, "open unit failed: %s\n", u_errorName(status)); + break; + } - return result; + UnitPreference *up = outVector.emplaceBack(); + if (!up) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + up->unit.appendInvariantChars(unitIdent, len, status); + if (U_FAILURE(status)) { + // fprintf(stderr, "failed appending unitIdent: %s\n", u_errorName(status)); + status = U_ZERO_ERROR; + break; + } + const UChar *geq = ures_getStringByKey(prefBundle, "geq", &len, &status); + if (U_SUCCESS(status)) { + CharString cGeq; + cGeq.appendInvariantChars(geq, len, status); + DecimalQuantity dq; + dq.setToDecNumber(StringPiece(cGeq.data()), status); + // fprintf(stderr, "status: %s, geq: %s, dq.toDouble(): %f\n", u_errorName(status), + // cGeq.data(), + // dq.toDouble()); + up->geq = dq.toDouble(); + } else if (status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + } + if (U_FAILURE(status)) { + // fprintf(stderr, "failed appending geq: %s\n", u_errorName(status)); + break; + } + const UChar *skel = ures_getStringByKey(prefBundle, "skeleton", &len, &status); + if (U_SUCCESS(status)) { + up->skeleton.appendInvariantChars(skel, len, status); + } else if (status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + } + } + ures_close(prefBundle); } } // namespace +namespace hugovdm_wip { + +/** + * Fetches required data FIXME. + * + * @param inputUnit the unit for which input is expected. (NOTE/WIP: If this is + * known to be a base unit already, we could strip some logic here.) + */ +void getUnitsData(const char *outputRegion, const char *usage, const MeasureUnit &inputUnit, + CharString &category, MeasureUnit &baseUnit, + MaybeStackVector &conversionInfo, + MaybeStackVector &unitPreferences, UErrorCode &status) { + // One can also use a StackUResourceBundle as a fill-in. + LocalUResourceBundlePointer unitsBundle(ures_openDirect(NULL, "units", &status)); + if (U_FAILURE(status)) { + // fprintf(stderr, "%s: ures_openDirect %s\n", u_errorName(status), "units"); + return; + } + + MeasureUnit inputBase = inputUnit.withSIPrefix(UMEASURE_SI_PREFIX_ONE, status); + if (uprv_strcmp(inputBase.getIdentifier(), "gram") == 0) { inputBase = MeasureUnit::getKilogram(); } + // if (U_FAILURE(status)) fprintf(stderr, "failed getting inputBase: %s\n", u_errorName(status)); + + StackUResourceBundle stackBundle; + // CharString has initial capacity 40. Key appending only gets slow when we + // go beyond. TODO(hugovdm): look at how often this might happen though? + // Each append could be a re-allocation. + CharString key; + // key.append("convertUnits/", status); + key.append(inputBase.getIdentifier(), status); + ConvertUnitsSink convertSink(conversionInfo); + ures_getByKey(unitsBundle.getAlias(), "convertUnits", stackBundle.getAlias(), &status); + ures_getAllItemsWithFallback(stackBundle.getAlias(), key.data(), convertSink, status); + const CharString &baseIdentifier = conversionInfo[0]->target; + baseUnit = MeasureUnit::forIdentifier(baseIdentifier.data(), status); + + // key.clear(); + // key.append("unitQuantities/", status); + // key.append(baseIdentifier, status); + // ures_findSubResource(unitsBundle.getAlias(), key.data(), fillIn, &status); + // Now we still need to convert to string. + LocalUResourceBundlePointer unitQuantities( + ures_getByKey(unitsBundle.getAlias(), "unitQuantities", NULL, &status)); + int32_t categoryLength; + const UChar *uCategory = + ures_getStringByKey(unitQuantities.getAlias(), baseIdentifier.data(), &categoryLength, &status); + category.appendInvariantChars(uCategory, categoryLength, status); + + // We load the region-specific unit preferences into stackBundle, reusing it + // for fill-in every step of the way: + ures_getByKey(unitsBundle.getAlias(), "unitPreferenceData", stackBundle.getAlias(), &status); + ures_getByKey(stackBundle.getAlias(), category.data(), stackBundle.getAlias(), &status); + if (U_FAILURE(status)) { return; } + ures_getByKey(stackBundle.getAlias(), usage, stackBundle.getAlias(), &status); + if (status == U_MISSING_RESOURCE_ERROR) { + // Requested usage does not exist, use "default". + status = U_ZERO_ERROR; + ures_getByKey(stackBundle.getAlias(), "default", stackBundle.getAlias(), &status); + } + // if (U_FAILURE(status)) fprintf(stderr, "failed getting usage %s: %s\n", usage, + // u_errorName(status)); + ures_getByKey(stackBundle.getAlias(), outputRegion, stackBundle.getAlias(), &status); + if (status == U_MISSING_RESOURCE_ERROR) { + // Requested region does not exist, use "001". + status = U_ZERO_ERROR; + ures_getByKey(stackBundle.getAlias(), "001", stackBundle.getAlias(), &status); + } + // if (U_FAILURE(status)) fprintf(stderr, "failed getting region %s: %s\n", outputRegion, + // u_errorName(status)); + putUnitPref(stackBundle.getAlias(), unitPreferences, status); + // if (U_FAILURE(status)) fprintf(stderr, "putUnitPref failed: %s\n", u_errorName(status)); + + // An alterantive for the above "We load ..." block, I don't think this is neater: + // key.clear(); + // key.append("unitPreferenceData/", status); + // key.append(category, status).append("/", status); + // key.append(usage, status).append("/", status); // FIXME: fall back to "default" + // key.append(outputRegion, status); // FIXME: fall back to "001" + // UnitPreferencesSink prefsSink(unitPreferences); + // ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), prefsSink, status); +} + +} // namespace hugovdm_wip + UnitsRouter::UnitsRouter(MeasureUnit inputUnit, StringPiece locale, StringPiece usage, UErrorCode &status) { - StringPiece unitCategory = extractUnitCategory(inputUnit); - MaybeStackVector preferences = extractUnitPreferences(locale, usage, unitCategory); - - for (int i = 0, n = preferences.length(); i < n; ++i) { - const auto &preference = *preferences[i]; - MeasureUnit complexTargetUnit = MeasureUnit::forIdentifier(preference.identifier, status); - converterPreferences_.emplaceBack( - ConverterPreference(inputUnit, complexTargetUnit, preference.limit, status)); + // StringPiece unitCategory = extractUnitCategory(inputUnit); + // MaybeStackVector preferences = extractUnitPreferences(locale, usage, unitCategory); + const char *region = "001"; // FIXME extract from locale. + CharString category; + MeasureUnit baseUnit; + MaybeStackVector conversionInfo; + MaybeStackVector unitPreferences; + getUnitsData(region, usage.data(), inputUnit, category, baseUnit, conversionInfo, unitPreferences, + status); + + for (int i = 0, n = unitPreferences.length(); i < n; ++i) { + const auto &preference = *unitPreferences[i]; + MeasureUnit complexTargetUnit = MeasureUnit::forIdentifier(preference.unit.data(), status); + // This fails to compile - it tries to copy a ConverterPreference + // instance but converter member has no copy-constructor: + // converterPreferences_.emplaceBack( + // ConverterPreference(inputUnit, complexTargetUnit, preference.geq, status)); } } @@ -67,6 +318,7 @@ MaybeStackVector UnitsRouter::route(double quantity, UErrorCode &status return converterPreference.converter.convert(quantity, status); } } + // FIXME: return <...>; } U_NAMESPACE_END diff --git a/icu4c/source/i18n/unitsrouter.h b/icu4c/source/i18n/unitsrouter.h index 4fb9e9cdb89..98a9029b6dc 100644 --- a/icu4c/source/i18n/unitsrouter.h +++ b/icu4c/source/i18n/unitsrouter.h @@ -7,6 +7,7 @@ #ifndef __UNITSROUTER_H__ #define __UNITSROUTER_H__ +#include "charstr.h" // CharString #include "cmemory.h" #include "complexunitsconverter.h" #include "unicode/errorcode.h" @@ -36,6 +37,44 @@ class U_I18N_API UnitsRouter { U_NAMESPACE_END +namespace hugovdm_wip { +// This namespace contains code from hugovdm that hasn't been reviewed by sffc +// yet. It still needs thorough review and a "final resting place". + +using icu::CharString; +using icu::MaybeStackVector; +using icu::MeasureUnit; + +struct ConversionRateInfo { + CharString source; + CharString target; + CharString factor; + CharString offset; + + const UChar *factorUChar; + const UChar *offsetUChar; + // WIP: This is a UChar* so that it can point at the resource. We could + // convert it to a CharString and own it ourselves, or if we can trust + // another owner's lifetime management we can make it a char*. + const UChar *targetUChar; + + bool reciprocal = false; +}; + +struct UnitPreference { + UnitPreference() : geq(0) {} + CharString unit; + double geq; + CharString skeleton; +}; + +void getUnitsData(const char *outputRegion, const char *usage, const MeasureUnit &inputUnit, + CharString &category, MeasureUnit &baseUnit, + MaybeStackVector &conversionInfo, + MaybeStackVector &unitPreferences, UErrorCode &status); + +} // namespace hugo_wip + #endif //__UNITSROUTER_H__ #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/Makefile.in b/icu4c/source/test/intltest/Makefile.in index 63487318a64..594d491f6f7 100644 --- a/icu4c/source/test/intltest/Makefile.in +++ b/icu4c/source/test/intltest/Makefile.in @@ -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 \ -unitstest.o wip_units_resource_loader.o +unitstest.o DEPS = $(OBJECTS:.o=.d) diff --git a/icu4c/source/test/intltest/unitstest.cpp b/icu4c/source/test/intltest/unitstest.cpp index e46f2de4d92..b2da82d107d 100644 --- a/icu4c/source/test/intltest/unitstest.cpp +++ b/icu4c/source/test/intltest/unitstest.cpp @@ -14,6 +14,7 @@ #include "unicode/unistr.h" #include "unicode/unum.h" #include "unitconverter.h" +#include "unitsrouter.h" #include "uparse.h" #include @@ -25,6 +26,7 @@ struct UnitConversionTestCase { }; using icu::number::impl::DecimalQuantity; +using namespace ::hugovdm_wip; class UnitsTest : public IntlTest { public: @@ -806,8 +808,8 @@ void UnitsTest::testGetUnitsData() { MeasureUnit baseUnit; MaybeStackVector conversionInfo; MaybeStackVector unitPreferences; - getUnitsData(t.outputRegion, t.usage, inputUnit, category, baseUnit, conversionInfo, - unitPreferences, status); + hugovdm_wip::getUnitsData(t.outputRegion, t.usage, inputUnit, category, baseUnit, conversionInfo, + unitPreferences, status); if (status.errIfFailureAndReset("getUnitsData(\"%s\", \"%s\", \"%s\", ...)", t.outputRegion, t.usage, t.inputUnit)) { continue; } diff --git a/icu4c/source/test/intltest/wip_units_resource_loader.cpp b/icu4c/source/test/intltest/wip_units_resource_loader.cpp deleted file mode 100644 index 256c3367ce3..00000000000 --- a/icu4c/source/test/intltest/wip_units_resource_loader.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "wip_units_resource_loader.h" -#include "cstring.h" // uprv_strcmp -#include "cmemory.h" // MaybeStackVector -#include "number_decimalquantity.h" // DecimalQuantity -#include "uresimp.h" // ures_getAllItemsWithFallback - -using namespace icu; -using icu::number::impl::DecimalQuantity; - -namespace { - -// Resources. It should be migrated to a permanent location with updated API, -// once we know what that will look like and where that will be. - -class ConvertUnitsSink : public ResourceSink { - public: - explicit ConvertUnitsSink(MaybeStackVector &out) : outVector(out) {} - - // WIP: look into noFallback - void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) { - ResourceTable conversionRateTable = value.getTable(status); - if (U_FAILURE(status)) { - // fprintf(stderr, "%s: getTable failed\n", u_errorName(status)); - return; - } - - ConversionRateInfo *cr = outVector.emplaceBack(); - if (!cr) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - - int32_t length = uprv_strlen(key); - cr->source.append(key, length, status); - if (U_FAILURE(status)) { - // fprintf(stderr, "%s: source.append failed\n", u_errorName(status)); - return; - } - for (int32_t i = 0; conversionRateTable.getKeyAndValue(i, key, value); ++i) { - if (uprv_strcmp(key, "factor") == 0) { - int32_t length; - const UChar *f = value.getString(length, status); - cr->factor.appendInvariantChars(f, length, status); - cr->factorUChar = f; - } else if (uprv_strcmp(key, "offset") == 0) { - int32_t length; - const UChar *o = value.getString(length, status); - cr->offset.appendInvariantChars(o, length, status); - cr->offsetUChar = o; - } else if (uprv_strcmp(key, "target") == 0) { - int32_t length; - const UChar *t = value.getString(length, status); - cr->target.appendInvariantChars(t, length, status); - cr->targetUChar = t; - } - } - } - private: - MaybeStackVector &outVector; -}; - -class UnitPreferencesSink : public ResourceSink { - public: - explicit UnitPreferencesSink(MaybeStackVector &out) : outVector(out) {} - - // WIP: look into noFallback - void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) { - if (U_FAILURE(status)) { return; } - int32_t prefLen; - ResourceArray unitPrefs = value.getArray(status); - if (U_FAILURE(status)) { return; } - prefLen = unitPrefs.getSize(); - for (int32_t i = 0; unitPrefs.getValue(i, value); i++) { - UnitPreference *up = outVector.emplaceBack(); - if (!up) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - ResourceTable unitPref = value.getTable(status); - if (U_FAILURE(status)) { return; } - for (int32_t i = 0; unitPref.getKeyAndValue(i, key, value); ++i) { - if (uprv_strcmp(key, "unit") == 0) { - int32_t length; - const UChar *u = value.getString(length, status); - up->unit.appendInvariantChars(u, length, status); - } else if (uprv_strcmp(key, "geq") == 0) { - int32_t length; - const UChar *g = value.getString(length, status); - CharString geq; - geq.appendInvariantChars(g, length, status); - DecimalQuantity dq; - dq.setToDecNumber(geq.data(), status); - up->geq = dq.toDouble(); - } else if (uprv_strcmp(key, "skeleton") == 0) { - int32_t length; - const UChar *s = value.getString(length, status); - up->skeleton.appendInvariantChars(s, length, status); - } - } - } - } - private: - MaybeStackVector &outVector; -}; - -void putUnitPref(UResourceBundle *usageData, - MaybeStackVector &outVector, UErrorCode &status) { - if (U_FAILURE(status)) { return; } - - UResourceBundle *prefBundle = NULL; - int32_t numPrefs = ures_getSize(usageData); - for (int32_t i = 0; i < numPrefs; i++) { - prefBundle = ures_getByIndex(usageData, i, prefBundle, &status); - if (U_FAILURE(status)) { - // fprintf(stderr, "failed getting index %d/%d: %s\n", i, numPrefs, u_errorName(status)); - status = U_ZERO_ERROR; - break; - } - int32_t len; - const UChar *unitIdent = ures_getStringByKey(prefBundle, "unit", &len, &status); - if (U_FAILURE(status)) { - // fprintf(stderr, "open unit failed: %s\n", u_errorName(status)); - break; - } - - UnitPreference *up = outVector.emplaceBack(); - if (!up) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - up->unit.appendInvariantChars(unitIdent, len, status); - if (U_FAILURE(status)) { - // fprintf(stderr, "failed appending unitIdent: %s\n", u_errorName(status)); - status = U_ZERO_ERROR; - break; - } - const UChar *geq = ures_getStringByKey(prefBundle, "geq", &len, &status); - if (U_SUCCESS(status)) { - CharString cGeq; - cGeq.appendInvariantChars(geq, len, status); - DecimalQuantity dq; - dq.setToDecNumber(StringPiece(cGeq.data()), status); - // fprintf(stderr, "status: %s, geq: %s, dq.toDouble(): %f\n", u_errorName(status), cGeq.data(), - // dq.toDouble()); - up->geq = dq.toDouble(); - } else if (status == U_MISSING_RESOURCE_ERROR) { - status = U_ZERO_ERROR; - } - if (U_FAILURE(status)) { - // fprintf(stderr, "failed appending geq: %s\n", u_errorName(status)); - break; - } - const UChar *skel = ures_getStringByKey(prefBundle, "skeleton", &len, &status); - if (U_SUCCESS(status)) { - up->skeleton.appendInvariantChars(skel, len, status); - } else if (status == U_MISSING_RESOURCE_ERROR) { - status = U_ZERO_ERROR; - } - } - ures_close(prefBundle); -} - -} // namespace - -/** - * Fetches required data FIXME. - * - * @param inputUnit the unit for which input is expected. (NOTE/WIP: If this is - * known to be a base unit already, we could strip some logic here.) - */ -void getUnitsData(const char *outputRegion, const char *usage, const MeasureUnit &inputUnit, - CharString &category, MeasureUnit &baseUnit, - MaybeStackVector &conversionInfo, - MaybeStackVector &unitPreferences, UErrorCode &status) { - // One can also use a StackUResourceBundle as a fill-in. - LocalUResourceBundlePointer unitsBundle(ures_openDirect(NULL, "units", &status)); - if (U_FAILURE(status)) { - // fprintf(stderr, "%s: ures_openDirect %s\n", u_errorName(status), "units"); - return; - } - - MeasureUnit inputBase = inputUnit.withSIPrefix(UMEASURE_SI_PREFIX_ONE, status); - if (uprv_strcmp(inputBase.getIdentifier(), "gram") == 0) { inputBase = MeasureUnit::getKilogram(); } - // if (U_FAILURE(status)) fprintf(stderr, "failed getting inputBase: %s\n", u_errorName(status)); - - StackUResourceBundle stackBundle; - // CharString has initial capacity 40. Key appending only gets slow when we - // go beyond. TODO(hugovdm): look at how often this might happen though? - // Each append could be a re-allocation. - CharString key; - // key.append("convertUnits/", status); - key.append(inputBase.getIdentifier(), status); - ConvertUnitsSink convertSink(conversionInfo); - ures_getByKey(unitsBundle.getAlias(), "convertUnits", stackBundle.getAlias(), &status); - ures_getAllItemsWithFallback(stackBundle.getAlias(), key.data(), convertSink, status); - const CharString &baseIdentifier = conversionInfo[0]->target; - baseUnit = MeasureUnit::forIdentifier(baseIdentifier.data(), status); - - // key.clear(); - // key.append("unitQuantities/", status); - // key.append(baseIdentifier, status); - // ures_findSubResource(unitsBundle.getAlias(), key.data(), fillIn, &status); - // Now we still need to convert to string. - LocalUResourceBundlePointer unitQuantities( - ures_getByKey(unitsBundle.getAlias(), "unitQuantities", NULL, &status)); - int32_t categoryLength; - const UChar *uCategory = - ures_getStringByKey(unitQuantities.getAlias(), baseIdentifier.data(), &categoryLength, &status); - category.appendInvariantChars(uCategory, categoryLength, status); - - // We load the region-specific unit preferences into stackBundle, reusing it - // for fill-in every step of the way: - ures_getByKey(unitsBundle.getAlias(), "unitPreferenceData", stackBundle.getAlias(), &status); - ures_getByKey(stackBundle.getAlias(), category.data(), stackBundle.getAlias(), &status); - if (U_FAILURE(status)) { return; } - ures_getByKey(stackBundle.getAlias(), usage, stackBundle.getAlias(), &status); - if (status == U_MISSING_RESOURCE_ERROR) { - // Requested usage does not exist, use "default". - status = U_ZERO_ERROR; - ures_getByKey(stackBundle.getAlias(), "default", stackBundle.getAlias(), &status); - } - // if (U_FAILURE(status)) fprintf(stderr, "failed getting usage %s: %s\n", usage, u_errorName(status)); - ures_getByKey(stackBundle.getAlias(), outputRegion, stackBundle.getAlias(), &status); - if (status == U_MISSING_RESOURCE_ERROR) { - // Requested region does not exist, use "001". - status = U_ZERO_ERROR; - ures_getByKey(stackBundle.getAlias(), "001", stackBundle.getAlias(), &status); - } - // if (U_FAILURE(status)) fprintf(stderr, "failed getting region %s: %s\n", outputRegion, u_errorName(status)); - putUnitPref(stackBundle.getAlias(), unitPreferences, status); - // if (U_FAILURE(status)) fprintf(stderr, "putUnitPref failed: %s\n", u_errorName(status)); - - // An alterantive for the above "We load ..." block, I don't think this is neater: - // key.clear(); - // key.append("unitPreferenceData/", status); - // key.append(category, status).append("/", status); - // key.append(usage, status).append("/", status); // FIXME: fall back to "default" - // key.append(outputRegion, status); // FIXME: fall back to "001" - // UnitPreferencesSink prefsSink(unitPreferences); - // ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), prefsSink, status); -} diff --git a/icu4c/source/test/intltest/wip_units_resource_loader.h b/icu4c/source/test/intltest/wip_units_resource_loader.h deleted file mode 100644 index 36f923c5acf..00000000000 --- a/icu4c/source/test/intltest/wip_units_resource_loader.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef WIP_UNITS_RESOURCE_LOADER_H -#define WIP_UNITS_RESOURCE_LOADER_H - -#include "charstr.h" // CharString -#include "unicode/measunit.h" // MeasureUnit - -using icu::CharString; -using icu::MaybeStackVector; -using icu::MeasureUnit; - -struct ConversionRateInfo { - CharString source; - CharString target; - CharString factor; - CharString offset; - - const UChar *factorUChar; - const UChar *offsetUChar; - // WIP: This is a UChar* so that it can point at the resource. We could - // convert it to a CharString and own it ourselves, or if we can trust - // another owner's lifetime management we can make it a char*. - const UChar *targetUChar; - - bool reciprocal = false; -}; - -struct UnitPreference { - UnitPreference() : geq(0) {} - CharString unit; - double geq; - CharString skeleton; -}; - -void getUnitsData(const char *outputRegion, const char *usage, const MeasureUnit &inputUnit, - CharString &category, MeasureUnit &baseUnit, - MaybeStackVector &conversionInfo, - MaybeStackVector &unitPreferences, UErrorCode &status); - -#endif // WIP_UNITS_RESOURCE_LOADER_H