summaryrefslogtreecommitdiffstats
path: root/intl/components/src/MeasureUnit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'intl/components/src/MeasureUnit.cpp')
-rw-r--r--intl/components/src/MeasureUnit.cpp110
1 files changed, 110 insertions, 0 deletions
diff --git a/intl/components/src/MeasureUnit.cpp b/intl/components/src/MeasureUnit.cpp
new file mode 100644
index 0000000000..3b932c9168
--- /dev/null
+++ b/intl/components/src/MeasureUnit.cpp
@@ -0,0 +1,110 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/intl/MeasureUnit.h"
+
+#include "unicode/udata.h"
+#include "unicode/ures.h"
+#include "unicode/utypes.h"
+
+namespace mozilla::intl {
+
+void MeasureUnit::UResourceBundleDeleter::operator()(UResourceBundle* aPtr) {
+ ures_close(aPtr);
+}
+
+MeasureUnit::Enumeration::Enumeration(UniqueUResourceBundle aRootLocale,
+ UniqueUResourceBundle aUnits)
+ : mRootLocale(std::move(aRootLocale)), mUnits(std::move(aUnits)) {
+ mUnitsSize = ures_getSize(mUnits.get());
+}
+
+MeasureUnit::Enumeration::Iterator::value_type
+MeasureUnit::Enumeration::Iterator::operator*() const {
+ // Return an error result after an ICU error has occurred.
+ if (mHasError) {
+ return Err(InternalError{});
+ }
+
+ // Otherwise return the name of the current measurement unit.
+ const char* unitIdentifier = ures_getKey(mSubtype.get());
+ MOZ_ASSERT(unitIdentifier);
+ return MakeStringSpan(unitIdentifier);
+}
+
+void MeasureUnit::Enumeration::Iterator::advance() {
+ // Reject any attempts to modify this iterator after an error has occurred.
+ if (mHasError) {
+ return;
+ }
+
+ while (true) {
+ // Read the next measurement unit in the types table.
+ if (mTypePos < mTypeSize) {
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle* rawSubtype =
+ ures_getByIndex(mType.get(), mTypePos, nullptr, &status);
+ if (U_FAILURE(status)) {
+ mHasError = true;
+ return;
+ }
+
+ mTypePos += 1;
+ mSubtype.reset(rawSubtype);
+ return;
+ }
+
+ // Read the next measurement unit type in the "units" table.
+ if (mUnitsPos < mEnumeration.mUnitsSize) {
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle* rawType = ures_getByIndex(mEnumeration.mUnits.get(),
+ mUnitsPos, nullptr, &status);
+ if (U_FAILURE(status)) {
+ mHasError = true;
+ return;
+ }
+
+ mUnitsPos += 1;
+ mType.reset(rawType);
+ mTypeSize = ures_getSize(rawType);
+ mTypePos = 0;
+ continue;
+ }
+
+ // All measurement units have been processed. Reset the two |mType*| fields
+ // to zero to match the end-iterator state and then return.
+ MOZ_ASSERT(mUnitsPos == mEnumeration.mUnitsSize);
+ mTypePos = 0;
+ mTypeSize = 0;
+ return;
+ }
+}
+
+Result<MeasureUnit::Enumeration, ICUError>
+MeasureUnit::Enumeration::TryCreate() {
+ // Look up the available measurement units in the resource bundle of the root
+ // locale.
+
+ static const char packageName[] =
+ U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "unit";
+ static const char rootLocale[] = "";
+
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle* rawRes = ures_open(packageName, rootLocale, &status);
+ if (U_FAILURE(status)) {
+ return Err(ToICUError(status));
+ }
+ UniqueUResourceBundle res(rawRes);
+
+ UResourceBundle* rawUnits =
+ ures_getByKey(res.get(), "units", nullptr, &status);
+ if (U_FAILURE(status)) {
+ return Err(ToICUError(status));
+ }
+ UniqueUResourceBundle units(rawUnits);
+
+ return MeasureUnit::Enumeration(std::move(res), std::move(units));
+}
+
+} // namespace mozilla::intl