MeasureUnit.cpp (3305B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "mozilla/intl/MeasureUnit.h" 6 7 #include "unicode/udata.h" 8 #include "unicode/ures.h" 9 #include "unicode/utypes.h" 10 11 namespace mozilla::intl { 12 13 void MeasureUnit::UResourceBundleDeleter::operator()(UResourceBundle* aPtr) { 14 ures_close(aPtr); 15 } 16 17 MeasureUnit::Enumeration::Enumeration(UniqueUResourceBundle aRootLocale, 18 UniqueUResourceBundle aUnits) 19 : mRootLocale(std::move(aRootLocale)), mUnits(std::move(aUnits)) { 20 mUnitsSize = ures_getSize(mUnits.get()); 21 } 22 23 MeasureUnit::Enumeration::Iterator::value_type 24 MeasureUnit::Enumeration::Iterator::operator*() const { 25 // Return an error result after an ICU error has occurred. 26 if (mHasError) { 27 return Err(InternalError{}); 28 } 29 30 // Otherwise return the name of the current measurement unit. 31 const char* unitIdentifier = ures_getKey(mSubtype.get()); 32 MOZ_ASSERT(unitIdentifier); 33 return MakeStringSpan(unitIdentifier); 34 } 35 36 void MeasureUnit::Enumeration::Iterator::advance() { 37 // Reject any attempts to modify this iterator after an error has occurred. 38 if (mHasError) { 39 return; 40 } 41 42 while (true) { 43 // Read the next measurement unit in the types table. 44 if (mTypePos < mTypeSize) { 45 UErrorCode status = U_ZERO_ERROR; 46 UResourceBundle* rawSubtype = 47 ures_getByIndex(mType.get(), mTypePos, nullptr, &status); 48 if (U_FAILURE(status)) { 49 mHasError = true; 50 return; 51 } 52 53 mTypePos += 1; 54 mSubtype.reset(rawSubtype); 55 return; 56 } 57 58 // Read the next measurement unit type in the "units" table. 59 if (mUnitsPos < mEnumeration.mUnitsSize) { 60 UErrorCode status = U_ZERO_ERROR; 61 UResourceBundle* rawType = ures_getByIndex(mEnumeration.mUnits.get(), 62 mUnitsPos, nullptr, &status); 63 if (U_FAILURE(status)) { 64 mHasError = true; 65 return; 66 } 67 68 mUnitsPos += 1; 69 mType.reset(rawType); 70 mTypeSize = ures_getSize(rawType); 71 mTypePos = 0; 72 continue; 73 } 74 75 // All measurement units have been processed. Reset the two |mType*| fields 76 // to zero to match the end-iterator state and then return. 77 MOZ_ASSERT(mUnitsPos == mEnumeration.mUnitsSize); 78 mTypePos = 0; 79 mTypeSize = 0; 80 return; 81 } 82 } 83 84 Result<MeasureUnit::Enumeration, ICUError> 85 MeasureUnit::Enumeration::TryCreate() { 86 // Look up the available measurement units in the resource bundle of the root 87 // locale. 88 89 static const char packageName[] = 90 U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "unit"; 91 static const char rootLocale[] = ""; 92 93 UErrorCode status = U_ZERO_ERROR; 94 UResourceBundle* rawRes = ures_open(packageName, rootLocale, &status); 95 if (U_FAILURE(status)) { 96 return Err(ToICUError(status)); 97 } 98 UniqueUResourceBundle res(rawRes); 99 100 UResourceBundle* rawUnits = 101 ures_getByKey(res.get(), "units", nullptr, &status); 102 if (U_FAILURE(status)) { 103 return Err(ToICUError(status)); 104 } 105 UniqueUResourceBundle units(rawUnits); 106 107 return MeasureUnit::Enumeration(std::move(res), std::move(units)); 108 } 109 110 } // namespace mozilla::intl