Renaming and refactoring
authorShane F. Carr <shane@unicode.org>
Thu, 16 Jan 2020 21:17:46 +0000 (22:17 +0100)
committerShane F. Carr <shane@unicode.org>
Fri, 17 Jan 2020 16:14:19 +0000 (17:14 +0100)
icu4c/source/i18n/measunit_extra.cpp
icu4c/source/i18n/unicode/measunit.h
icu4c/source/test/intltest/measfmttest.cpp

index 090cb803ac023144e6c2191ff9ef022c6df11ee0..e39d6dab6974addb3a2adcf8b947710a6a0f8738 100644 (file)
@@ -87,7 +87,7 @@ const struct SIPrefixStrings {
     { "yocto", UMEASURE_SI_PREFIX_YOCTO },
 };
 
-// FIXME: Get this list from data
+// TODO(ICU-20920): Get this list from data
 const char16_t* const gSimpleUnits[] = {
     u"one", // note: expected to be index 0
     u"100kilometer",
@@ -308,7 +308,7 @@ private:
     int32_t fMatch;
 };
 
-struct PowerUnit {
+struct SingleUnit {
     int8_t power = 1;
     UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE;
     int32_t simpleUnitIndex = 0;
@@ -357,13 +357,13 @@ struct PowerUnit {
 
 class CompoundUnit {
 public:
-    typedef MaybeStackVector<PowerUnit, 3> PowerUnitList;
+    typedef MaybeStackVector<SingleUnit, 3> SingleUnitList;
 
-    void append(PowerUnit&& powerUnit, UErrorCode& status) {
-        if (powerUnit.power >= 0) {
-            appendImpl(numerator, std::move(powerUnit), status);
+    void append(SingleUnit&& singleUnit, UErrorCode& status) {
+        if (singleUnit.power >= 0) {
+            appendImpl(numerator, std::move(singleUnit), status);
         } else {
-            appendImpl(denominator, std::move(powerUnit), status);
+            appendImpl(denominator, std::move(singleUnit), status);
         }
     }
 
@@ -373,7 +373,7 @@ public:
         denominator = std::move(temp);
     }
 
-    void appendTo(CharString& builder, UErrorCode& status) {
+    void appendTo(CharString& builder, UErrorCode& status) const {
         if (numerator.length() == 0) {
             builder.append("one", status);
         } else {
@@ -385,19 +385,23 @@ public:
         }
     }
 
-    const PowerUnitList& getNumeratorUnits() {
+    const SingleUnitList& getNumeratorUnits() const {
         return numerator;
     }
 
-    const PowerUnitList& getDenominatorUnits() {
+    const SingleUnitList& getDenominatorUnits() const {
         return denominator;
     }
 
+    bool isSingle() const {
+        return numerator.length() + denominator.length() == 1;
+    }
+
 private:
-    PowerUnitList numerator;
-    PowerUnitList denominator;
+    SingleUnitList numerator;
+    SingleUnitList denominator;
 
-    void appendToImpl(const PowerUnitList& unitList, int32_t len, CharString& builder, UErrorCode& status) {
+    void appendToImpl(const SingleUnitList& unitList, int32_t len, CharString& builder, UErrorCode& status) const {
         bool first = true;
         for (int32_t i = 0; i < len; i++) {
             if (first) {
@@ -409,23 +413,23 @@ private:
         }
     }
 
-    void appendImpl(PowerUnitList& unitList, PowerUnit&& powerUnit, UErrorCode& status) {
+    void appendImpl(SingleUnitList& unitList, SingleUnit&& singleUnit, UErrorCode& status) {
         // Check that the same simple unit doesn't already exist
         for (int32_t i = 0; i < unitList.length(); i++) {
-            PowerUnit* candidate = unitList[i];
-            if (candidate->simpleUnitIndex == powerUnit.simpleUnitIndex
-                    && candidate->siPrefix == powerUnit.siPrefix) {
-                candidate->power += powerUnit.power;
+            SingleUnit* candidate = unitList[i];
+            if (candidate->simpleUnitIndex == singleUnit.simpleUnitIndex
+                    && candidate->siPrefix == singleUnit.siPrefix) {
+                candidate->power += singleUnit.power;
                 return;
             }
         }
         // Add a new unit
-        PowerUnit* destination = unitList.emplaceBack();
+        SingleUnit* destination = unitList.emplaceBack();
         if (!destination) {
             status = U_MEMORY_ALLOCATION_ERROR;
             return;
         }
-        *destination = std::move(powerUnit);
+        *destination = std::move(singleUnit);
     }
 };
 
@@ -446,10 +450,10 @@ public:
         return fIndex < fSource.length();
     }
 
-    PowerUnit getOnlyPowerUnit(UErrorCode& status) {
+    SingleUnit getOnlySingleUnit(UErrorCode& status) {
         bool sawPlus;
-        PowerUnit retval;
-        nextPowerUnit(retval, sawPlus, status);
+        SingleUnit retval;
+        nextSingleUnit(retval, sawPlus, status);
         if (U_FAILURE(status)) {
             return retval;
         }
@@ -468,13 +472,13 @@ public:
         }
         while (hasNext()) {
             int32_t previ = fIndex;
-            PowerUnit powerUnit;
-            nextPowerUnit(powerUnit, sawPlus, status);
+            SingleUnit singleUnit;
+            nextSingleUnit(singleUnit, sawPlus, status);
             if (sawPlus) {
                 fIndex = previ;
                 break;
             }
-            result.append(std::move(powerUnit), status);
+            result.append(std::move(singleUnit), status);
         }
         return;
     }
@@ -537,7 +541,7 @@ private:
         return Token(match);
     }
 
-    void nextPowerUnit(PowerUnit& result, bool& sawPlus, UErrorCode& status) {
+    void nextSingleUnit(SingleUnit& result, bool& sawPlus, UErrorCode& status) {
         sawPlus = false;
         if (U_FAILURE(status)) {
             return;
@@ -607,7 +611,7 @@ private:
 
                 case Token::TYPE_ONE:
                     // Skip "one" and go to the next unit
-                    return nextPowerUnit(result, sawPlus, status);
+                    return nextSingleUnit(result, sawPlus, status);
 
                 case Token::TYPE_SIMPLE_UNIT:
                     result.simpleUnitIndex = token.getSimpleUnitIndex();
@@ -654,42 +658,61 @@ MeasureUnit MeasureUnit::forIdentifier(const char* identifier, UErrorCode& statu
     return MeasureUnit(builder.cloneData(status));
 }
 
+UMeasureUnitComplexity MeasureUnit::getComplexity(UErrorCode& status) const {
+    const char* id = getIdentifier();
+    UnitIdentifierParser parser = UnitIdentifierParser::from(id, status);
+    if (U_FAILURE(status)) {
+        // Unrecoverable error
+        return UMEASURE_UNIT_SINGLE;
+    }
+
+    CompoundUnit compoundUnit;
+    parser.nextCompoundUnit(compoundUnit, status);
+    if (compoundUnit.isSingle()) {
+        return UMEASURE_UNIT_SINGLE;
+    } else if (parser.hasNext()) {
+        return UMEASURE_UNIT_SEQUENCE;
+    } else {
+        return UMEASURE_UNIT_COMPOUND;
+    }
+}
+
 UMeasureSIPrefix MeasureUnit::getSIPrefix(UErrorCode& status) const {
     const char* id = getIdentifier();
-    return UnitIdentifierParser::from(id, status).getOnlyPowerUnit(status).siPrefix;
+    return UnitIdentifierParser::from(id, status).getOnlySingleUnit(status).siPrefix;
 }
 
 MeasureUnit MeasureUnit::withSIPrefix(UMeasureSIPrefix prefix, UErrorCode& status) const {
     const char* id = getIdentifier();
-    PowerUnit powerUnit = UnitIdentifierParser::from(id, status).getOnlyPowerUnit(status);
+    SingleUnit singleUnit = UnitIdentifierParser::from(id, status).getOnlySingleUnit(status);
     if (U_FAILURE(status)) {
         return *this;
     }
 
-    powerUnit.siPrefix = prefix;
+    singleUnit.siPrefix = prefix;
     CharString builder;
-    powerUnit.appendTo(builder, status);
+    singleUnit.appendTo(builder, status);
     return MeasureUnit(builder.cloneData(status));
 }
 
 int8_t MeasureUnit::getPower(UErrorCode& status) const {
     const char* id = getIdentifier();
-    return UnitIdentifierParser::from(id, status).getOnlyPowerUnit(status).power;
+    return UnitIdentifierParser::from(id, status).getOnlySingleUnit(status).power;
 }
 
 MeasureUnit MeasureUnit::withPower(int8_t power, UErrorCode& status) const {
     const char* id = getIdentifier();
-    PowerUnit powerUnit = UnitIdentifierParser::from(id, status).getOnlyPowerUnit(status);
+    SingleUnit singleUnit = UnitIdentifierParser::from(id, status).getOnlySingleUnit(status);
     if (U_FAILURE(status)) {
         return *this;
     }
 
     CharString builder;
-    powerUnit.power = power;
+    singleUnit.power = power;
     if (power < 0) {
         builder.append("one-per-", status);
     }
-    powerUnit.appendTo(builder, status);
+    singleUnit.appendTo(builder, status);
     return MeasureUnit(builder.cloneData(status));
 }
 
@@ -729,15 +752,15 @@ MeasureUnit MeasureUnit::product(const MeasureUnit& other, UErrorCode& status) c
     return MeasureUnit(builder.cloneData(status));
 }
 
-LocalArray<MeasureUnit> MeasureUnit::getSimpleUnits(UErrorCode& status) const {
+LocalArray<MeasureUnit> MeasureUnit::getSingleUnits(UErrorCode& status) const {
     const char* id = getIdentifier();
     CompoundUnit compoundUnit = UnitIdentifierParser::from(id, status).getOnlyCompoundUnit(status);
     if (U_FAILURE(status)) {
         return LocalArray<MeasureUnit>::withLength(nullptr, 0);
     }
 
-    const CompoundUnit::PowerUnitList& numerator = compoundUnit.getNumeratorUnits();
-    const CompoundUnit::PowerUnitList& denominator = compoundUnit.getDenominatorUnits();
+    const CompoundUnit::SingleUnitList& numerator = compoundUnit.getNumeratorUnits();
+    const CompoundUnit::SingleUnitList& denominator = compoundUnit.getDenominatorUnits();
     int32_t count = numerator.length() + denominator.length();
     MeasureUnit* arr = new MeasureUnit[count];
 
index c9947d3edff7a64b5c582efa853fc8a01c7406f7..cdf760fdbdb58ae5bf4cb27ad380c80410434b0a 100644 (file)
@@ -31,6 +31,44 @@ U_NAMESPACE_BEGIN
 
 class StringEnumeration;
 
+/**
+ * Enumeration for unit complexity. There are three levels:
+ * 
+ * - SINGLE: A single unit, optionally with a power and/or SI prefix. Examples: hectare,
+ *           square-kilometer, kilojoule, one-per-second.
+ * - COMPOUND: A unit composed of the product of multiple single units. Examples:
+ *             meter-per-second, kilowatt-hour, kilogram-meter-per-square-second.
+ * - SEQUENCE: A unit composed of the sum of multiple compound units. Examples: foot+inch,
+ *             hour+minute+second, hectare+square-meter.
+ *
+ * The complexity determines which operations are available. For example, you cannot set the power
+ * or SI prefix of a compound unit.
+ *
+ * @draft ICU 67
+ */
+enum UMeasureUnitComplexity {
+    /**
+     * A single unit, like kilojoule.
+     *
+     * @draft ICU 67
+     */
+    UMEASURE_UNIT_SINGLE,
+
+    /**
+     * A compound unit, like meter-per-second.
+     * 
+     * @draft ICU 67
+     */
+    UMEASURE_UNIT_COMPOUND,
+
+    /**
+     * A sequence unit, like hour+minute.
+     *
+     * @draft ICU 67
+     */
+    UMEASURE_UNIT_SEQUENCE
+};
+
 /**
  * Enumeration for SI prefixes, such as "kilo".
  *
@@ -297,60 +335,74 @@ class U_I18N_API MeasureUnit: public UObject {
     const char* getIdentifier() const;
 
     /**
-     * Creates a MeasureUnit which is this MeasureUnit augmented with the specified SI prefix.
+     * Compute the complexity of the unit. See UMeasureUnitComplexity for more information.
+     *
+     * @param status Set if an error occurs.
+     * @return The unit complexity.
+     * @draft ICU 67
+     */
+    UMeasureUnitComplexity getComplexity(UErrorCode& status) const;
+
+    /**
+     * Creates a MeasureUnit which is this SINGLE unit augmented with the specified SI prefix.
      * For example, UMEASURE_SI_PREFIX_KILO for "kilo".
      *
      * There is sufficient locale data to format all standard SI prefixes.
      *
-     * This method only works if the MeasureUnit is composed of only one simple unit. An error
-     * will be set if called on a MeasureUnit containing multiple units.
+     * NOTE: Only works on SINGLE units. If this is a COMPOUND or SEQUENCE unit, an error will
+     * occur. For more information, see UMeasureUnitComplexity.
      *
      * @param prefix The SI prefix, from UMeasureSIPrefix.
-     * @param status ICU error code
-     * @return A new MeasureUnit.
+     * @param status Set if this is not a SINGLE unit or if another error occurs.
+     * @return A new SINGLE unit.
      */
     MeasureUnit withSIPrefix(UMeasureSIPrefix prefix, UErrorCode& status) const;
 
     /**
-     * Gets the current SI prefix of this MeasureUnit. For example, if the unit has the SI prefix
+     * Gets the current SI prefix of this SINGLE unit. For example, if the unit has the SI prefix
      * "kilo", then UMEASURE_SI_PREFIX_KILO is returned.
      *
-     * If the MeasureUnit is composed of multiple simple units, the SI prefix of the first simple
-     * unit is returned. For example, from "centimeter-kilogram-per-second", the SI prefix
-     * UMEASURE_SI_PREFIX_CENTI will be returned.
+     * NOTE: Only works on SINGLE units. If this is a COMPOUND or SEQUENCE unit, an error will
+     * occur. For more information, see UMeasureUnitComplexity.
      *
-     * @return The SI prefix of the first simple unit, from UMeasureSIPrefix.
+     * @param status Set if this is not a SINGLE unit or if another error occurs.
+     * @return The SI prefix of this SINGLE unit, from UMeasureSIPrefix.
      */
     UMeasureSIPrefix getSIPrefix(UErrorCode& status) const;
 
     /**
-     * Creates a MeasureUnit which is this MeasureUnit augmented with the specified power. For
+     * Creates a MeasureUnit which is this SINGLE unit augmented with the specified power. For
      * example, if power is 2, the unit will be squared.
      *
-     * This method only works if the MeasureUnit is composed of only one simple unit. An error
-     * will be set if called on a MeasureUnit containing multiple units.
+     * NOTE: Only works on SINGLE units. If this is a COMPOUND or SEQUENCE unit, an error will
+     * occur. For more information, see UMeasureUnitComplexity.
      *
      * @param power The power.
-     * @param status ICU error code
-     * @return A new MeasureUnit.
+     * @param status Set if this is not a SINGLE unit or if another error occurs.
+     * @return A new SINGLE unit.
      */
     MeasureUnit withPower(int8_t power, UErrorCode& status) const;
 
     /**
      * Gets the power of this MeasureUnit. For example, if the unit is square, then 2 is returned.
      *
-     * If the MeasureUnit is composed of multiple simple units, the power of the first simple unit
-     * is returned. For example, from "cubic-meter-per-square-second", 3 is returned.
+     * NOTE: Only works on SINGLE units. If this is a COMPOUND or SEQUENCE unit, an error will
+     * occur. For more information, see UMeasureUnitComplexity.
      *
-     * @return The power of the first simple unit.
+     * @param status Set if this is not a SINGLE unit or if another error occurs.
+     * @return The power of this simple unit.
      */
     int8_t getPower(UErrorCode& status) const;
 
     /**
-     * Gets the reciprocal of the unit, with the numerator and denominator flipped.
+     * Gets the reciprocal of this MeasureUnit, with the numerator and denominator flipped.
      *
      * For example, if the receiver is "meter-per-second", the unit "second-per-meter" is returned.
      *
+     * NOTE: Only works on SINGLE and COMPOUND units. If this is a SEQUENCE unit, an error will
+     * occur. For more information, see UMeasureUnitComplexity.
+     *
+     * @param status Set if this is a SEQUENCE unit or if another error occurs.
      * @return The reciprocal of the target unit.
      */
     MeasureUnit reciprocal(UErrorCode& status) const;
@@ -364,88 +416,42 @@ class U_I18N_API MeasureUnit: public UObject {
      * For example, if the receiver is "kilowatt" and the argument is "hour-per-day", then the
      * unit "kilowatt-hour-per-day" is returned.
      *
+     * NOTE: Only works on SINGLE and COMPOUND units. If either unit (receivee and argument) is a
+     * SEQUENCE unit, an error will occur. For more information, see UMeasureUnitComplexity.
+     *
+     * @param status Set if this or other is a SEQUENCE unit or if another error occurs.
      * @return The product of the target unit with the provided unit.
      */
     MeasureUnit product(const MeasureUnit& other, UErrorCode& status) const;
 
     /**
-     * Gets the number of constituent simple units.
-     *
-     * For example, if the receiver is "meter-per-square-second", then 2 is returned, since there
-     * are two simple units: "meter" and "second".
-     *
-     * @return The number of constituent units.
-     */
-    size_t getSimpleUnitCount(UErrorCode& status) const;
-
-    LocalArray<MeasureUnit> getSimpleUnits(UErrorCode& status) const;
-
-    LocalArray<MeasureUnit> getSequenceUnits(UErrorCode& status) const;
-
-    /**
-     * Gets the constituent unit at the given index.
-     * 
-     * For example, to loop over all simple units:
-     * 
-     * <pre>
-     * MeasureUnit unit(u"meter-per-square-second");
-     * for (size_t i = 0; i < unit.getSimpleUnitCount(); i++) {
-     *     std::cout << unit.simpleUnitAt(i).toString() << std::endl;
-     * }
-     * </pre>
-     * 
-     * Expected output: meter, one-per-square-second
-     * 
-     * @param index Zero-based index. If out of range, the dimensionless unit is returned.
-     * @return The constituent simple unit at the specified position.
-     */
-    MeasureUnit simpleUnitAt(size_t index, UErrorCode& status) const;
-
-    /**
-     * Composes this unit with a super unit.
-     * 
-     * A super unit, used for formatting only, should be a larger unit sharing the same dimension.
-     * For example, if the current unit is "inch", a super unit could be "foot", in order to
-     * render 71 inches as "5 feet, 11 inches". If the super unit is invalid, an error will occur
-     * during formatting.
+     * Gets the list of single units contained within a compound unit.
      *
-     * A unit can have multiple super units; for example, "second" could have both "minute" and
-     * "hour" as super units.
-     * 
-     * Super units are ignored and left untouched in most other methods, such as withSIPrefix,
-     * withPower, and reciprocal.
+     * For example, given "meter-kilogram-per-second", three units will be returned: "meter",
+     * "kilogram", and "one-per-second".
      *
-     * @param other The super unit to compose with the target unit.
-     * @return The composition of the given super unit with this unit.
-     */
-    MeasureUnit withSuperUnit(const MeasureUnit& other, UErrorCode& status) const;
-
-    /**
-     * Gets the number of super units in the receiver.
+     * If this is a SINGLE unit, an array of length 1 will be returned.
      *
-     * For example, "foot+inch" has one super unit.
+     * NOTE: Only works on SINGLE and COMPOUND units. If this is a SEQUENCE unit, an error will
+     * occur. For more information, see UMeasureUnitComplexity.
      *
-     * @return The number of super units.
+     * @param status Set if this is a SEQUENCE unit or if another error occurs.
+     * @return An array of single units, owned by the caller.
      */
-    size_t getSuperUnitCount(UErrorCode& status) const;
+    LocalArray<MeasureUnit> getSingleUnits(UErrorCode& status) const;
 
     /**
-     * Gets the super unit at the given index.
+     * Gets the list of compound units contained within a sequence unit.
      *
-     * For example, to loop over all super units:
-     *
-     * <pre>
-     * MeasureUnit unit(u"hour+minute+second");
-     * for (size_t i = 0; i < unit.getSuperUnitCount(); i++) {
-     *     std::cout << unit.superUnitAt(i).toCoreUnitIdentifier() << std::endl;
-     * }
-     * </pre>
+     * For example, given "hour+minute+second", three units will be returned: "hour", "minute",
+     * and "second".
      *
-     * Expected output: hour, minute
+     * If this is a SINGLE or COMPOUND unit, an array of length 1 will be returned.
      *
-     * @return The super unit at the specified position.
+     * @param status Set of an error occurs.
+     * @return An array of compound units, owned by the caller.
      */
-    MeasureUnit superUnitAt(size_t index, UErrorCode& status) const;
+    LocalArray<MeasureUnit> getCompoundUnits(UErrorCode& status) const;
 
     /**
      * getAvailable gets all of the available units.
index 5af03b77e646fbcd8774f3551cb2a56843324fb3..b15ca5b01280f720e438b0cdd3a86f5fa190def2 100644 (file)
@@ -139,7 +139,7 @@ private:
         NumberFormat::EAlignmentFields field,
         int32_t start,
         int32_t end);
-    void verifyPowerUnit(
+    void verifySingleUnit(
         const MeasureUnit& unit,
         UMeasureSIPrefix siPrefix,
         int8_t power,
@@ -3239,11 +3239,11 @@ void MeasureFormatTest::TestCompoundUnitOperations() {
     MeasureUnit centimeter2 = meter.withSIPrefix(UMEASURE_SI_PREFIX_CENTI, status);
     MeasureUnit cubicDecimeter = cubicMeter.withSIPrefix(UMEASURE_SI_PREFIX_DECI, status);
 
-    verifyPowerUnit(kilometer, UMEASURE_SI_PREFIX_KILO, 1, "kilometer");
-    verifyPowerUnit(meter, UMEASURE_SI_PREFIX_ONE, 1, "meter");
-    verifyPowerUnit(centimeter1, UMEASURE_SI_PREFIX_CENTI, 1, "centimeter");
-    verifyPowerUnit(centimeter2, UMEASURE_SI_PREFIX_CENTI, 1, "centimeter");
-    verifyPowerUnit(cubicDecimeter, UMEASURE_SI_PREFIX_DECI, 3, "cubic-decimeter");
+    verifySingleUnit(kilometer, UMEASURE_SI_PREFIX_KILO, 1, "kilometer");
+    verifySingleUnit(meter, UMEASURE_SI_PREFIX_ONE, 1, "meter");
+    verifySingleUnit(centimeter1, UMEASURE_SI_PREFIX_CENTI, 1, "centimeter");
+    verifySingleUnit(centimeter2, UMEASURE_SI_PREFIX_CENTI, 1, "centimeter");
+    verifySingleUnit(cubicDecimeter, UMEASURE_SI_PREFIX_DECI, 3, "cubic-decimeter");
 
     assertTrue("centimeter equality", centimeter1 == centimeter2);
     assertTrue("kilometer inequality", centimeter1 != kilometer);
@@ -3253,10 +3253,10 @@ void MeasureFormatTest::TestCompoundUnitOperations() {
     MeasureUnit quarticKilometer = kilometer.withPower(4, status);
     MeasureUnit overQuarticKilometer1 = kilometer.withPower(-4, status);
 
-    verifyPowerUnit(squareMeter, UMEASURE_SI_PREFIX_ONE, 2, "square-meter");
-    verifyPowerUnit(overCubicCentimeter, UMEASURE_SI_PREFIX_CENTI, -3, "one-per-cubic-centimeter");
-    verifyPowerUnit(quarticKilometer, UMEASURE_SI_PREFIX_KILO, 4, "p4-kilometer");
-    verifyPowerUnit(overQuarticKilometer1, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
+    verifySingleUnit(squareMeter, UMEASURE_SI_PREFIX_ONE, 2, "square-meter");
+    verifySingleUnit(overCubicCentimeter, UMEASURE_SI_PREFIX_CENTI, -3, "one-per-cubic-centimeter");
+    verifySingleUnit(quarticKilometer, UMEASURE_SI_PREFIX_KILO, 4, "p4-kilometer");
+    verifySingleUnit(overQuarticKilometer1, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
 
     assertTrue("power inequality", quarticKilometer != overQuarticKilometer1);
 
@@ -3266,8 +3266,8 @@ void MeasureFormatTest::TestCompoundUnitOperations() {
         .product(kilometer, status)
         .reciprocal(status);
 
-    verifyPowerUnit(overQuarticKilometer2, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
-    verifyPowerUnit(overQuarticKilometer3, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
+    verifySingleUnit(overQuarticKilometer2, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
+    verifySingleUnit(overQuarticKilometer3, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
 
     assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer2);
     assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer3);
@@ -3281,7 +3281,7 @@ void MeasureFormatTest::TestCompoundUnitOperations() {
     MeasureUnit secondCentimeter = kiloSquareSecond.product(meter.withSIPrefix(UMEASURE_SI_PREFIX_CENTI, status), status);
     MeasureUnit secondCentimeterPerKilometer = secondCentimeter.product(kilometer.reciprocal(status), status);
 
-    verifyPowerUnit(kiloSquareSecond, UMEASURE_SI_PREFIX_KILO, 2, "square-kilosecond");
+    verifySingleUnit(kiloSquareSecond, UMEASURE_SI_PREFIX_KILO, 2, "square-kilosecond");
     const char* meterSecondSub[] = {"meter", "square-kilosecond"};
     verifyCompoundUnit(meterSecond, "meter-square-kilosecond",
         meterSecondSub, UPRV_LENGTHOF(meterSecondSub));
@@ -3387,12 +3387,12 @@ void MeasureFormatTest::verifyFormat(
     }
 }
 
-void MeasureFormatTest::verifyPowerUnit(
+void MeasureFormatTest::verifySingleUnit(
         const MeasureUnit& unit,
         UMeasureSIPrefix siPrefix,
         int8_t power,
         const char* identifier) {
-    IcuTestErrorCode status(*this, "verifyPowerUnit");
+    IcuTestErrorCode status(*this, "verifySingleUnit");
     UnicodeString uid(identifier, -1, US_INV);
     assertEquals(uid + ": SI prefix",
         siPrefix,
@@ -3409,6 +3409,10 @@ void MeasureFormatTest::verifyPowerUnit(
     assertTrue(uid + ": Constructor",
         unit == MeasureUnit::forIdentifier(identifier, status));
     status.errIfFailureAndReset("%s: Constructor", identifier);
+    assertEquals(uid + ": Complexity",
+        UMEASURE_UNIT_SINGLE,
+        unit.getComplexity(status));
+    status.errIfFailureAndReset("%s: Complexity", identifier);
 }
 
 void MeasureFormatTest::verifyCompoundUnit(
@@ -3425,14 +3429,21 @@ void MeasureFormatTest::verifyCompoundUnit(
     assertTrue(uid + ": Constructor",
         unit == MeasureUnit::forIdentifier(identifier, status));
     status.errIfFailureAndReset("%s: Constructor", identifier);
+    assertEquals(uid + ": Complexity",
+        UMEASURE_UNIT_COMPOUND,
+        unit.getComplexity(status));
+    status.errIfFailureAndReset("%s: Complexity", identifier);
 
-    LocalArray<MeasureUnit> subUnits = unit.getSimpleUnits(status);
+    LocalArray<MeasureUnit> subUnits = unit.getSingleUnits(status);
     assertEquals(uid + ": Length", subIdentifierCount, subUnits.length());
     for (int32_t i = 0;; i++) {
         if (i >= subIdentifierCount || i >= subUnits.length()) break;
         assertEquals(uid + ": Sub-unit #" + Int64ToUnicodeString(i),
             subIdentifiers[i],
             subUnits[i].getIdentifier());
+        assertEquals(uid + ": Sub-unit Complexity",
+            UMEASURE_UNIT_SINGLE,
+            subUnits[i].getComplexity(status));
     }
 }