1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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
|