return std::move(impl).build(status);
}
+
+/**
+ * Returns the sign of the dimensionality.
+ *
+ * NOTE:
+ * it returns `0` when the dimensionality is zero.
+ */
+int32_t dimensionSign(int32_t dimension) {
+ if (dimension == 0) return 0;
+ if (dimension > 0) return 1;
+ return -1;
+}
+
+/**
+ * Searches the `simplifiedUnits` for a unit with the same base identifier in the `newUnit`, for example
+ * `meter` and `meter` or `millimeter` and `centimeter`.
+ * After finding a match, the matched unit in simplified unit will be merged with the `newUnit` and
+ * `true` will be returned. Otherwise, `false` will be returned.
+ */
+bool findAndSet(MaybeStackVector<MeasureUnit> &simplifiedUnits, const MeasureUnit &newUnit,
+ UErrorCode &status) {
+ for (int i = 0, n = simplifiedUnits.length(); i < n; i++) {
+ auto simplifiedUnitImpl = SingleUnitImpl::forMeasureUnit(*simplifiedUnits[i], status);
+ auto newUnitImpl = SingleUnitImpl::forMeasureUnit(newUnit, status);
+ if (simplifiedUnitImpl.identifier == newUnitImpl.identifier) {
+ int32_t newDimensionality = simplifiedUnitImpl.dimensionality + newUnitImpl.dimensionality;
+ UMeasureSIPrefix newSIprefix = static_cast<UMeasureSIPrefix>(
+ simplifiedUnitImpl.siPrefix * dimensionSign(simplifiedUnitImpl.dimensionality) +
+ newUnitImpl.siPrefix * dimensionSign(newUnitImpl.dimensionality));
+
+ auto &simplifiedUnit = *simplifiedUnits[i];
+ simplifiedUnit = simplifiedUnit.withDimensionality(newDimensionality, status);
+ simplifiedUnit = simplifiedUnit.withSIPrefix(newSIprefix ,status);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+MeasureUnit MeasureUnit::simplify(UErrorCode &status) const {
+ MeasureUnit result;
+ if (this->getComplexity(status) == UMeasureUnitComplexity::UMEASURE_UNIT_MIXED) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return result;
+ }
+
+ int32_t outCount;
+ auto singleUnits = this->splitToSingleUnits(outCount, status);
+
+ MaybeStackVector<MeasureUnit> simplifiedUnits;
+ for (int i = 0 ; i < outCount ; ++i) {
+ if (findAndSet(simplifiedUnits,singleUnits[i] , status )) { continue;}
+
+ simplifiedUnits.emplaceBackAndConfirm(status, singleUnits[i]);
+ }
+
+ for (int i = 0 , n = simplifiedUnits.length() ; i < n ; ++i) {
+ result = result.product(*simplifiedUnits[i] , status);
+ }
+
+ return result;
+}
+
LocalArray<MeasureUnit> MeasureUnit::splitToSingleUnits(int32_t& outCount, UErrorCode& status) const {
MeasureUnitImpl temp;
const MeasureUnitImpl& impl = MeasureUnitImpl::forMeasureUnit(*this, temp, status);
* 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
+ * NOTE: Only works on SINGLE and COMPOUND units. If either unit (receiver and argument) is a
* MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
*
* @param other The MeasureUnit to multiply with the target.
* @draft ICU 67
*/
MeasureUnit product(const MeasureUnit& other, UErrorCode& status) const;
+
+ /**
+ * Extracts a simplified version of the unit (i.e. no repetition in the internal units). For example,
+ * "square-meter-per-meter" will be "meter".
+ *
+ * NOTE: Only works on SINGLE and COMPOUND units. If the current unit is a
+ * MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
+ *
+ * @param status Set if this is a MIXED unit or if another error occurs.
+ * @return a simplified version of the current unit.
+ * @draft ICU 67
+ */
+ MeasureUnit simplify( UErrorCode& status) const;
+
#endif // U_HIDE_DRAFT_API
#ifndef U_HIDE_INTERNAL_API