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
#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<UnitPreference> extractUnitPreferences(StringPiece locale, StringPiece usage,
+// StringPiece category) {
+// MaybeStackVector<UnitPreference> 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<ConversionRateInfo> &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<ConversionRateInfo> &outVector;
};
-MaybeStackVector<UnitPreference> extractUnitPreferences(StringPiece locale, StringPiece usage,
- StringPiece category) {
- MaybeStackVector<UnitPreference> result;
+class UnitPreferencesSink : public ResourceSink {
+ public:
+ explicit UnitPreferencesSink(MaybeStackVector<UnitPreference> &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<UnitPreference> &outVector;
+};
-StringPiece extractUnitCategory(MeasureUnit unit) {
- StringPiece result;
+void putUnitPref(UResourceBundle *usageData, MaybeStackVector<UnitPreference> &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<ConversionRateInfo> &conversionInfo,
+ MaybeStackVector<UnitPreference> &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<UnitPreference> 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<UnitPreference> preferences = extractUnitPreferences(locale, usage, unitCategory);
+ const char *region = "001"; // FIXME extract from locale.
+ CharString category;
+ MeasureUnit baseUnit;
+ MaybeStackVector<ConversionRateInfo> conversionInfo;
+ MaybeStackVector<UnitPreference> 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));
}
}
return converterPreference.converter.convert(quantity, status);
}
}
+ // FIXME: return <...>;
}
U_NAMESPACE_END
#ifndef __UNITSROUTER_H__
#define __UNITSROUTER_H__
+#include "charstr.h" // CharString
#include "cmemory.h"
#include "complexunitsconverter.h"
#include "unicode/errorcode.h"
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<ConversionRateInfo> &conversionInfo,
+ MaybeStackVector<UnitPreference> &unitPreferences, UErrorCode &status);
+
+} // namespace hugo_wip
+
#endif //__UNITSROUTER_H__
#endif /* #if !UCONFIG_NO_FORMATTING */
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)
#include "unicode/unistr.h"
#include "unicode/unum.h"
#include "unitconverter.h"
+#include "unitsrouter.h"
#include "uparse.h"
#include <iostream>
};
using icu::number::impl::DecimalQuantity;
+using namespace ::hugovdm_wip;
class UnitsTest : public IntlTest {
public:
MeasureUnit baseUnit;
MaybeStackVector<ConversionRateInfo> conversionInfo;
MaybeStackVector<UnitPreference> 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;
}
+++ /dev/null
-#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<ConversionRateInfo> &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<ConversionRateInfo> &outVector;
-};
-
-class UnitPreferencesSink : public ResourceSink {
- public:
- explicit UnitPreferencesSink(MaybeStackVector<UnitPreference> &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<UnitPreference> &outVector;
-};
-
-void putUnitPref(UResourceBundle *usageData,
- MaybeStackVector<UnitPreference> &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<ConversionRateInfo> &conversionInfo,
- MaybeStackVector<UnitPreference> &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);
-}
+++ /dev/null
-#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<ConversionRateInfo> &conversionInfo,
- MaybeStackVector<UnitPreference> &unitPreferences, UErrorCode &status);
-
-#endif // WIP_UNITS_RESOURCE_LOADER_H