1 // © 2020 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #ifndef __MEASUNIT_IMPL_H__ 5 #define __MEASUNIT_IMPL_H__ 6 7 #include "unicode/utypes.h" 8 9 #if !UCONFIG_NO_FORMATTING 10 11 #include "unicode/measunit.h" 12 #include "cmemory.h" 13 #include "charstr.h" 14 15 U_NAMESPACE_BEGIN 16 17 18 static const char16_t kDefaultCurrency[] = u"XXX"; 19 static const char kDefaultCurrency8[] = "XXX"; 20 21 22 /** 23 * A struct representing a single unit (optional SI prefix and dimensionality). 24 */ 25 struct U_I18N_API SingleUnitImpl : public UMemory { 26 /** 27 * Gets a single unit from the MeasureUnit. If there are multiple single units, sets an error 28 * code and returns the base dimensionless unit. Parses if necessary. 29 */ 30 static SingleUnitImpl forMeasureUnit(const MeasureUnit& measureUnit, UErrorCode& status); 31 32 /** Transform this SingleUnitImpl into a MeasureUnit, simplifying if possible. */ 33 MeasureUnit build(UErrorCode& status) const; 34 35 /** 36 * Returns the "simple unit ID", without SI or dimensionality prefix: this 37 * instance may represent a square-kilometer, but only "meter" will be 38 * returned. 39 * 40 * The returned pointer points at memory that exists for the duration of the 41 * program's running. 42 */ 43 const char *getSimpleUnitID() const; 44 45 /** 46 * Compare this SingleUnitImpl to another SingleUnitImpl for the sake of 47 * sorting and coalescing. 48 * 49 * Takes the sign of dimensionality into account, but not the absolute 50 * value: per-meter is not considered the same as meter, but meter is 51 * considered the same as square-meter. 52 * 53 * The dimensionless unit generally does not get compared, but if it did, it 54 * would sort before other units by virtue of index being < 0 and 55 * dimensionality not being negative. 56 */ compareToSingleUnitImpl57 int32_t compareTo(const SingleUnitImpl& other) const { 58 if (dimensionality < 0 && other.dimensionality > 0) { 59 // Positive dimensions first 60 return 1; 61 } 62 if (dimensionality > 0 && other.dimensionality < 0) { 63 return -1; 64 } 65 if (index < other.index) { 66 return -1; 67 } 68 if (index > other.index) { 69 return 1; 70 } 71 if (siPrefix < other.siPrefix) { 72 return -1; 73 } 74 if (siPrefix > other.siPrefix) { 75 return 1; 76 } 77 return 0; 78 } 79 80 /** 81 * Return whether this SingleUnitImpl is compatible with another for the purpose of coalescing. 82 * 83 * Units with the same base unit and SI prefix should match, except that they must also have 84 * the same dimensionality sign, such that we don't merge numerator and denominator. 85 */ isCompatibleWithSingleUnitImpl86 bool isCompatibleWith(const SingleUnitImpl& other) const { 87 return (compareTo(other) == 0); 88 } 89 90 /** 91 * Returns true if this unit is the "dimensionless base unit", as produced 92 * by the MeasureUnit() default constructor. (This does not include the 93 * likes of concentrations or angles.) 94 */ isDimensionlessSingleUnitImpl95 bool isDimensionless() const { 96 return index == -1; 97 } 98 99 /** 100 * Simple unit index, unique for every simple unit, -1 for the dimensionless 101 * unit. This is an index into a string list in measunit_extra.cpp. 102 * 103 * The default value is -1, meaning the dimensionless unit: 104 * isDimensionless() will return true, until index is changed. 105 */ 106 int32_t index = -1; 107 108 /** 109 * SI prefix. 110 * 111 * This is ignored for the dimensionless unit. 112 */ 113 UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE; 114 115 /** 116 * Dimensionality. 117 * 118 * This is meaningless for the dimensionless unit. 119 */ 120 int32_t dimensionality = 1; 121 }; 122 123 // Export explicit template instantiations of MaybeStackArray, MemoryPool and 124 // MaybeStackVector. This is required when building DLLs for Windows. (See 125 // datefmt.h, collationiterator.h, erarules.h and others for similar examples.) 126 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN 127 template class U_I18N_API MaybeStackArray<SingleUnitImpl*, 8>; 128 template class U_I18N_API MemoryPool<SingleUnitImpl, 8>; 129 template class U_I18N_API MaybeStackVector<SingleUnitImpl, 8>; 130 #endif 131 132 /** 133 * Internal representation of measurement units. Capable of representing all complexities of units, 134 * including mixed and compound units. 135 */ 136 struct U_I18N_API MeasureUnitImpl : public UMemory { 137 MeasureUnitImpl() = default; 138 MeasureUnitImpl(MeasureUnitImpl &&other) = default; 139 MeasureUnitImpl(const MeasureUnitImpl &other, UErrorCode &status); 140 MeasureUnitImpl(const SingleUnitImpl &singleUnit, UErrorCode &status); 141 142 MeasureUnitImpl &operator=(MeasureUnitImpl &&other) noexcept = default; 143 144 /** Extract the MeasureUnitImpl from a MeasureUnit. */ getMeasureUnitImpl145 static inline const MeasureUnitImpl* get(const MeasureUnit& measureUnit) { 146 return measureUnit.fImpl; 147 } 148 149 /** 150 * Parse a unit identifier into a MeasureUnitImpl. 151 * 152 * @param identifier The unit identifier string. 153 * @param status Set if the identifier string is not valid. 154 * @return A newly parsed value object. Behaviour of this unit is 155 * unspecified if an error is returned via status. 156 */ 157 static MeasureUnitImpl forIdentifier(StringPiece identifier, UErrorCode& status); 158 159 /** 160 * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present. 161 * 162 * @param measureUnit The source MeasureUnit. 163 * @param memory A place to write the new MeasureUnitImpl if parsing is required. 164 * @param status Set if an error occurs. 165 * @return A reference to either measureUnit.fImpl or memory. 166 */ 167 static const MeasureUnitImpl& forMeasureUnit( 168 const MeasureUnit& measureUnit, MeasureUnitImpl& memory, UErrorCode& status); 169 170 /** 171 * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present. 172 * 173 * @param measureUnit The source MeasureUnit. 174 * @param status Set if an error occurs. 175 * @return A value object, either newly parsed or copied from measureUnit. 176 */ 177 static MeasureUnitImpl forMeasureUnitMaybeCopy( 178 const MeasureUnit& measureUnit, UErrorCode& status); 179 180 /** 181 * Used for currency units. 182 */ forCurrencyCodeMeasureUnitImpl183 static inline MeasureUnitImpl forCurrencyCode(StringPiece currencyCode) { 184 MeasureUnitImpl result; 185 UErrorCode localStatus = U_ZERO_ERROR; 186 result.identifier.append(currencyCode, localStatus); 187 // localStatus is not expected to fail since currencyCode should be 3 chars long 188 return result; 189 } 190 191 /** Transform this MeasureUnitImpl into a MeasureUnit, simplifying if possible. */ 192 MeasureUnit build(UErrorCode& status) &&; 193 194 /** 195 * Create a copy of this MeasureUnitImpl. Don't use copy constructor to make this explicit. 196 */ 197 MeasureUnitImpl copy(UErrorCode& status) const; 198 199 /** 200 * Extracts the list of all the individual units inside the `MeasureUnitImpl`. 201 * For example: 202 * - if the `MeasureUnitImpl` is `foot-per-hour` 203 * it will return a list of 1 {`foot-per-hour`} 204 * - if the `MeasureUnitImpl` is `foot-and-inch` 205 * it will return a list of 2 { `foot`, `inch`} 206 */ 207 MaybeStackVector<MeasureUnitImpl> extractIndividualUnits(UErrorCode &status) const; 208 209 /** Mutates this MeasureUnitImpl to take the reciprocal. */ 210 void takeReciprocal(UErrorCode& status); 211 212 /** 213 * Mutates this MeasureUnitImpl to append a single unit. 214 * 215 * @return true if a new item was added. If unit is the dimensionless unit, 216 * it is never added: the return value will always be false. 217 */ 218 bool append(const SingleUnitImpl& singleUnit, UErrorCode& status); 219 220 /** The complexity, either SINGLE, COMPOUND, or MIXED. */ 221 UMeasureUnitComplexity complexity = UMEASURE_UNIT_SINGLE; 222 223 /** 224 * The list of simple units. These may be summed or multiplied, based on the 225 * value of the complexity field. 226 * 227 * The "dimensionless" unit (SingleUnitImpl default constructor) must not be 228 * added to this list. 229 */ 230 MaybeStackVector<SingleUnitImpl> units; 231 232 /** 233 * The full unit identifier. Owned by the MeasureUnitImpl. Empty if not computed. 234 */ 235 CharString identifier; 236 }; 237 238 U_NAMESPACE_END 239 240 #endif /* #if !UCONFIG_NO_FORMATTING */ 241 #endif //__MEASUNIT_IMPL_H__ 242