Skip to content

Commit 1e11c1a

Browse files
committed
ICU-23264 Add isAvailable method to MeasureUnit for efficient unit validation
This new method checks if a specific unit is available for a given type and subtype, improving performance by avoiding the need to retrieve all available units. Updated parseMeasureUnitOption to utilize this method for better error handling when validating measure units.
1 parent aa17de1 commit 1e11c1a

File tree

3 files changed

+43
-18
lines changed

3 files changed

+43
-18
lines changed

icu4c/source/i18n/measunit.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2729,6 +2729,28 @@ StringEnumeration* MeasureUnit::getAvailableTypes(UErrorCode &errorCode) {
27292729
return result;
27302730
}
27312731

2732+
bool MeasureUnit::isAvailable(const char *type, const char *subtype, MeasureUnit &result) {
2733+
if (type == nullptr || subtype == nullptr) {
2734+
return false;
2735+
}
2736+
2737+
// Find the type index using binary search
2738+
int32_t typeIdx = binarySearch(gTypes, 0, UPRV_LENGTHOF(gTypes), type);
2739+
if (typeIdx == -1) {
2740+
return false; // Type not found
2741+
}
2742+
2743+
// Find the subtype within the type's range using binary search
2744+
int32_t subtypeIdx = binarySearch(gSubTypes, gOffsets[typeIdx], gOffsets[typeIdx + 1], subtype);
2745+
if (subtypeIdx == -1) {
2746+
return false; // Subtype not found
2747+
}
2748+
2749+
// Create the MeasureUnit and return it
2750+
result.setTo(typeIdx, subtypeIdx - gOffsets[typeIdx]);
2751+
return true;
2752+
}
2753+
27322754
bool MeasureUnit::findBySubType(StringPiece subType, MeasureUnit* output) {
27332755
// Sanity checking kCurrencyOffset and final entry in gOffsets
27342756
U_ASSERT(uprv_strcmp(gTypes[kCurrencyOffset], "currency") == 0);

icu4c/source/i18n/number_skeletons.cpp

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,25 +1072,12 @@ void blueprint_helpers::parseMeasureUnitOption(const StringSegment& segment, Mac
10721072
CharString subType;
10731073
SKELETON_UCHAR_TO_CHAR(subType, stemString, firstHyphen + 1, stemString.length(), status);
10741074

1075-
// Note: the largest type as of this writing (Aug 2020) is "volume", which has 33 units.
1076-
static constexpr int32_t CAPACITY = 40;
1077-
MeasureUnit units[CAPACITY];
1078-
UErrorCode localStatus = U_ZERO_ERROR;
1079-
int32_t numUnits = MeasureUnit::getAvailable(type.data(), units, CAPACITY, localStatus);
1080-
if (U_FAILURE(localStatus)) {
1081-
// More than 30 units in this type?
1082-
status = U_INTERNAL_PROGRAM_ERROR;
1075+
MeasureUnit unit;
1076+
if (MeasureUnit::isAvailable(type.data(), subType.data(), unit)) {
1077+
macros.unit = unit;
10831078
return;
1084-
}
1085-
for (int32_t i = 0; i < numUnits; i++) {
1086-
auto& unit = units[i];
1087-
if (uprv_strcmp(subType.data(), unit.getSubtype()) == 0) {
1088-
macros.unit = unit;
1089-
return;
1090-
}
1091-
}
1092-
1093-
// throw new SkeletonSyntaxException("Unknown measure unit", segment);
1079+
}
1080+
10941081
status = U_NUMBER_SKELETON_SYNTAX_ERROR;
10951082
}
10961083

icu4c/source/i18n/unicode/measunit.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,22 @@ class U_I18N_API MeasureUnit: public UObject {
720720
*/
721721
static StringEnumeration* getAvailableTypes(UErrorCode &errorCode);
722722

723+
#ifndef U_HIDE_INTERNAL_API
724+
/**
725+
* Check if a specific unit is available for the given type and subtype.
726+
*
727+
* <p> Note: This is more efficient than calling getAvailable() when you only need
728+
* to validate and retrieve a single unit.
729+
*
730+
* @param type the unit type (e.g., "length", "mass", "volume")
731+
* @param subtype the unit subtype (e.g., "meter", "kilogram", "liter")
732+
* @param result if the unit is found, this will be set to the MeasureUnit
733+
* @return true if the unit exists, false otherwise
734+
* @internal
735+
*/
736+
static bool isAvailable(const char *type, const char *subtype, MeasureUnit &result);
737+
#endif /* U_HIDE_INTERNAL_API */
738+
723739
/**
724740
* Return the class ID for this class. This is useful only for comparing to
725741
* a return value from getDynamicClassID(). For example:

0 commit comments

Comments
 (0)