From: Hugo van der Merwe <17109322+hugovdm@users.noreply.github.com> Date: Thu, 19 Mar 2020 12:03:15 +0000 (+0100) Subject: Merge branch 'units_router' into younies_units_router_resources X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d65e7374aa9392c58cb04144705c87039a14f3a9;p=icu Merge branch 'units_router' into younies_units_router_resources --- d65e7374aa9392c58cb04144705c87039a14f3a9 diff --cc icu4c/source/i18n/unitsrouter.cpp index 89376c72de1,826f75aba4a..a4506be8b9e --- a/icu4c/source/i18n/unitsrouter.cpp +++ b/icu4c/source/i18n/unitsrouter.cpp @@@ -5,12 -5,10 +5,14 @@@ #if !UCONFIG_NO_FORMATTING + #include + #include "cmemory.h" +#include "cstring.h" +#include "number_decimalquantity.h" +#include "resource.h" #include "unitsrouter.h" +#include "uresimp.h" U_NAMESPACE_BEGIN @@@ -197,122 -44,17 +199,121 @@@ void putUnitPref(UResourceBundle *usage } // 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 convertUnitsBundle; + // 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", convertUnitsBundle.getAlias(), &status); + ures_getAllItemsWithFallback(convertUnitsBundle.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: + StackUResourceBundle stackBundle; + 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); + + // Load ConversionRateInfo for each of the units in unitPreferences. + // + // WIP/FIXME: this currently adds plenty of duplicates. hugovdm will soon + // adapt the code to skip dupes (or add conversion info for units with SI + // prefixes?) + for (int32_t i = 0; i < unitPreferences.length(); i++) { + UnitPreference *up = unitPreferences[i]; + MeasureUnit prefUnitBase = MeasureUnit::forIdentifier(up->unit.data(), status) + .withSIPrefix(UMEASURE_SI_PREFIX_ONE, status); + ures_getAllItemsWithFallback(convertUnitsBundle.getAlias(), prefUnitBase.getIdentifier(), convertSink, status); + } +} + +} // namespace hugovdm_wip + UnitsRouter::UnitsRouter(MeasureUnit inputUnit, StringPiece locale, StringPiece usage, UErrorCode &status) { - StringPiece unitCategory = extractUnitCategory(inputUnit); - MaybeStackVector preferences = extractUnitPreferences(locale, usage, unitCategory); + // 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 = preferences.length(); i < n; ++i) { - const auto &preference = *preferences[i]; - MeasureUnit complexTargetUnit = MeasureUnit::forIdentifier(preference.identifier, 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: + // TODO(younies): Find a way to emplaceBack `ConverterPreference` // converterPreferences_.emplaceBack( - // ConverterPreference(inputUnit, complexTargetUnit, preference.geq, status)); - // std::move(ConverterPreference(inputUnit, complexTargetUnit, preference.limit, status))); ++ // std::move(ConverterPreference(inputUnit, complexTargetUnit, preference.geq, status))); } } @@@ -333,4 -74,4 +333,4 @@@ MaybeStackVector UnitsRouter:: U_NAMESPACE_END --#endif /* #if !UCONFIG_NO_FORMATTING */ ++#endif /* #if !UCONFIG_NO_FORMATTING */