measunit_impl.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // © 2020 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. #ifndef __MEASUNIT_IMPL_H__
  4. #define __MEASUNIT_IMPL_H__
  5. #include "unicode/utypes.h"
  6. #if !UCONFIG_NO_FORMATTING
  7. #include "unicode/measunit.h"
  8. #include "cmemory.h"
  9. #include "charstr.h"
  10. U_NAMESPACE_BEGIN
  11. static const char16_t kDefaultCurrency[] = u"XXX";
  12. static const char kDefaultCurrency8[] = "XXX";
  13. /**
  14. * A struct representing a single unit (optional SI prefix and dimensionality).
  15. */
  16. struct SingleUnitImpl : public UMemory {
  17. /**
  18. * Gets a single unit from the MeasureUnit. If there are multiple single units, sets an error
  19. * code and returns the base dimensionless unit. Parses if necessary.
  20. */
  21. static SingleUnitImpl forMeasureUnit(const MeasureUnit& measureUnit, UErrorCode& status);
  22. /** Transform this SingleUnitImpl into a MeasureUnit, simplifying if possible. */
  23. MeasureUnit build(UErrorCode& status) const;
  24. /**
  25. * Compare this SingleUnitImpl to another SingleUnitImpl for the sake of
  26. * sorting and coalescing.
  27. *
  28. * Takes the sign of dimensionality into account, but not the absolute
  29. * value: per-meter is not considered the same as meter, but meter is
  30. * considered the same as square-meter.
  31. *
  32. * The dimensionless unit generally does not get compared, but if it did, it
  33. * would sort before other units by virtue of index being < 0 and
  34. * dimensionality not being negative.
  35. */
  36. int32_t compareTo(const SingleUnitImpl& other) const {
  37. if (dimensionality < 0 && other.dimensionality > 0) {
  38. // Positive dimensions first
  39. return 1;
  40. }
  41. if (dimensionality > 0 && other.dimensionality < 0) {
  42. return -1;
  43. }
  44. if (index < other.index) {
  45. return -1;
  46. }
  47. if (index > other.index) {
  48. return 1;
  49. }
  50. if (siPrefix < other.siPrefix) {
  51. return -1;
  52. }
  53. if (siPrefix > other.siPrefix) {
  54. return 1;
  55. }
  56. return 0;
  57. }
  58. /**
  59. * Return whether this SingleUnitImpl is compatible with another for the purpose of coalescing.
  60. *
  61. * Units with the same base unit and SI prefix should match, except that they must also have
  62. * the same dimensionality sign, such that we don't merge numerator and denominator.
  63. */
  64. bool isCompatibleWith(const SingleUnitImpl& other) const {
  65. return (compareTo(other) == 0);
  66. }
  67. /**
  68. * Returns true if this unit is the "dimensionless base unit", as produced
  69. * by the MeasureUnit() default constructor. (This does not include the
  70. * likes of concentrations or angles.)
  71. */
  72. bool isDimensionless() const {
  73. return index == -1;
  74. }
  75. /**
  76. * Simple unit index, unique for every simple unit, -1 for the dimensionless
  77. * unit. This is an index into a string list in measunit_extra.cpp.
  78. *
  79. * The default value is -1, meaning the dimensionless unit:
  80. * isDimensionless() will return true, until index is changed.
  81. */
  82. int32_t index = -1;
  83. /**
  84. * SI prefix.
  85. *
  86. * This is ignored for the dimensionless unit.
  87. */
  88. UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE;
  89. /**
  90. * Dimensionality.
  91. *
  92. * This is meaningless for the dimensionless unit.
  93. */
  94. int32_t dimensionality = 1;
  95. };
  96. /**
  97. * Internal representation of measurement units. Capable of representing all complexities of units,
  98. * including mixed and compound units.
  99. */
  100. struct MeasureUnitImpl : public UMemory {
  101. /** Extract the MeasureUnitImpl from a MeasureUnit. */
  102. static inline const MeasureUnitImpl* get(const MeasureUnit& measureUnit) {
  103. return measureUnit.fImpl;
  104. }
  105. /**
  106. * Parse a unit identifier into a MeasureUnitImpl.
  107. *
  108. * @param identifier The unit identifier string.
  109. * @param status Set if the identifier string is not valid.
  110. * @return A newly parsed value object. Behaviour of this unit is
  111. * unspecified if an error is returned via status.
  112. */
  113. static MeasureUnitImpl forIdentifier(StringPiece identifier, UErrorCode& status);
  114. /**
  115. * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present.
  116. *
  117. * @param measureUnit The source MeasureUnit.
  118. * @param memory A place to write the new MeasureUnitImpl if parsing is required.
  119. * @param status Set if an error occurs.
  120. * @return A reference to either measureUnit.fImpl or memory.
  121. */
  122. static const MeasureUnitImpl& forMeasureUnit(
  123. const MeasureUnit& measureUnit, MeasureUnitImpl& memory, UErrorCode& status);
  124. /**
  125. * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present.
  126. *
  127. * @param measureUnit The source MeasureUnit.
  128. * @param status Set if an error occurs.
  129. * @return A value object, either newly parsed or copied from measureUnit.
  130. */
  131. static MeasureUnitImpl forMeasureUnitMaybeCopy(
  132. const MeasureUnit& measureUnit, UErrorCode& status);
  133. /**
  134. * Used for currency units.
  135. */
  136. static inline MeasureUnitImpl forCurrencyCode(StringPiece currencyCode) {
  137. MeasureUnitImpl result;
  138. UErrorCode localStatus = U_ZERO_ERROR;
  139. result.identifier.append(currencyCode, localStatus);
  140. // localStatus is not expected to fail since currencyCode should be 3 chars long
  141. return result;
  142. }
  143. /** Transform this MeasureUnitImpl into a MeasureUnit, simplifying if possible. */
  144. MeasureUnit build(UErrorCode& status) &&;
  145. /**
  146. * Create a copy of this MeasureUnitImpl. Don't use copy constructor to make this explicit.
  147. */
  148. inline MeasureUnitImpl copy(UErrorCode& status) const {
  149. MeasureUnitImpl result;
  150. result.complexity = complexity;
  151. result.units.appendAll(units, status);
  152. result.identifier.append(identifier, status);
  153. return result;
  154. }
  155. /** Mutates this MeasureUnitImpl to take the reciprocal. */
  156. void takeReciprocal(UErrorCode& status);
  157. /**
  158. * Mutates this MeasureUnitImpl to append a single unit.
  159. *
  160. * @return true if a new item was added. If unit is the dimensionless unit,
  161. * it is never added: the return value will always be false.
  162. */
  163. bool append(const SingleUnitImpl& singleUnit, UErrorCode& status);
  164. /** The complexity, either SINGLE, COMPOUND, or MIXED. */
  165. UMeasureUnitComplexity complexity = UMEASURE_UNIT_SINGLE;
  166. /**
  167. * The list of simple units. These may be summed or multiplied, based on the
  168. * value of the complexity field.
  169. *
  170. * The "dimensionless" unit (SingleUnitImpl default constructor) must not be
  171. * added to this list.
  172. */
  173. MaybeStackVector<SingleUnitImpl> units;
  174. /**
  175. * The full unit identifier. Owned by the MeasureUnitImpl. Empty if not computed.
  176. */
  177. CharString identifier;
  178. };
  179. U_NAMESPACE_END
  180. #endif /* #if !UCONFIG_NO_FORMATTING */
  181. #endif //__MEASUNIT_IMPL_H__