• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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      * Compare this SingleUnitImpl to another SingleUnitImpl for the sake of
37      * sorting and coalescing.
38      *
39      * Takes the sign of dimensionality into account, but not the absolute
40      * value: per-meter is not considered the same as meter, but meter is
41      * considered the same as square-meter.
42      *
43      * The dimensionless unit generally does not get compared, but if it did, it
44      * would sort before other units by virtue of index being < 0 and
45      * dimensionality not being negative.
46      */
compareToSingleUnitImpl47     int32_t compareTo(const SingleUnitImpl& other) const {
48         if (dimensionality < 0 && other.dimensionality > 0) {
49             // Positive dimensions first
50             return 1;
51         }
52         if (dimensionality > 0 && other.dimensionality < 0) {
53             return -1;
54         }
55         if (index < other.index) {
56             return -1;
57         }
58         if (index > other.index) {
59             return 1;
60         }
61         if (siPrefix < other.siPrefix) {
62             return -1;
63         }
64         if (siPrefix > other.siPrefix) {
65             return 1;
66         }
67         return 0;
68     }
69 
70     /**
71      * Return whether this SingleUnitImpl is compatible with another for the purpose of coalescing.
72      *
73      * Units with the same base unit and SI prefix should match, except that they must also have
74      * the same dimensionality sign, such that we don't merge numerator and denominator.
75      */
isCompatibleWithSingleUnitImpl76     bool isCompatibleWith(const SingleUnitImpl& other) const {
77         return (compareTo(other) == 0);
78     }
79 
80     /**
81      * Returns true if this unit is the "dimensionless base unit", as produced
82      * by the MeasureUnit() default constructor. (This does not include the
83      * likes of concentrations or angles.)
84      */
isDimensionlessSingleUnitImpl85     bool isDimensionless() const {
86         return index == -1;
87     }
88 
89     /**
90      * Simple unit index, unique for every simple unit, -1 for the dimensionless
91      * unit. This is an index into a string list in measunit_extra.cpp.
92      *
93      * The default value is -1, meaning the dimensionless unit:
94      * isDimensionless() will return true, until index is changed.
95      */
96     int32_t index = -1;
97 
98     /**
99      * SI prefix.
100      *
101      * This is ignored for the dimensionless unit.
102      */
103     UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE;
104 
105     /**
106      * Dimensionality.
107      *
108      * This is meaningless for the dimensionless unit.
109      */
110     int32_t dimensionality = 1;
111 };
112 
113 
114 /**
115  * Internal representation of measurement units. Capable of representing all complexities of units,
116  * including mixed and compound units.
117  */
118 struct MeasureUnitImpl : public UMemory {
119     /** Extract the MeasureUnitImpl from a MeasureUnit. */
getMeasureUnitImpl120     static inline const MeasureUnitImpl* get(const MeasureUnit& measureUnit) {
121         return measureUnit.fImpl;
122     }
123 
124     /**
125      * Parse a unit identifier into a MeasureUnitImpl.
126      *
127      * @param identifier The unit identifier string.
128      * @param status Set if the identifier string is not valid.
129      * @return A newly parsed value object. Behaviour of this unit is
130      * unspecified if an error is returned via status.
131      */
132     static MeasureUnitImpl forIdentifier(StringPiece identifier, UErrorCode& status);
133 
134     /**
135      * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present.
136      *
137      * @param measureUnit The source MeasureUnit.
138      * @param memory A place to write the new MeasureUnitImpl if parsing is required.
139      * @param status Set if an error occurs.
140      * @return A reference to either measureUnit.fImpl or memory.
141      */
142     static const MeasureUnitImpl& forMeasureUnit(
143         const MeasureUnit& measureUnit, MeasureUnitImpl& memory, UErrorCode& status);
144 
145     /**
146      * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present.
147      *
148      * @param measureUnit The source MeasureUnit.
149      * @param status Set if an error occurs.
150      * @return A value object, either newly parsed or copied from measureUnit.
151      */
152     static MeasureUnitImpl forMeasureUnitMaybeCopy(
153         const MeasureUnit& measureUnit, UErrorCode& status);
154 
155     /**
156      * Used for currency units.
157      */
forCurrencyCodeMeasureUnitImpl158     static inline MeasureUnitImpl forCurrencyCode(StringPiece currencyCode) {
159         MeasureUnitImpl result;
160         UErrorCode localStatus = U_ZERO_ERROR;
161         result.identifier.append(currencyCode, localStatus);
162         // localStatus is not expected to fail since currencyCode should be 3 chars long
163         return result;
164     }
165 
166     /** Transform this MeasureUnitImpl into a MeasureUnit, simplifying if possible. */
167     MeasureUnit build(UErrorCode& status) &&;
168 
169     /**
170      * Create a copy of this MeasureUnitImpl. Don't use copy constructor to make this explicit.
171      */
copyMeasureUnitImpl172     inline MeasureUnitImpl copy(UErrorCode& status) const {
173         MeasureUnitImpl result;
174         result.complexity = complexity;
175         result.units.appendAll(units, status);
176         result.identifier.append(identifier, status);
177         return result;
178     }
179 
180     /** Mutates this MeasureUnitImpl to take the reciprocal. */
181     void takeReciprocal(UErrorCode& status);
182 
183     /**
184      * Mutates this MeasureUnitImpl to append a single unit.
185      *
186      * @return true if a new item was added. If unit is the dimensionless unit,
187      * it is never added: the return value will always be false.
188      */
189     bool append(const SingleUnitImpl& singleUnit, UErrorCode& status);
190 
191     /** The complexity, either SINGLE, COMPOUND, or MIXED. */
192     UMeasureUnitComplexity complexity = UMEASURE_UNIT_SINGLE;
193 
194     /**
195      * The list of simple units. These may be summed or multiplied, based on the
196      * value of the complexity field.
197      *
198      * The "dimensionless" unit (SingleUnitImpl default constructor) must not be
199      * added to this list.
200      */
201     MaybeStackVector<SingleUnitImpl> units;
202 
203     /**
204      * The full unit identifier.  Owned by the MeasureUnitImpl.  Empty if not computed.
205      */
206     CharString identifier;
207 };
208 
209 
210 U_NAMESPACE_END
211 
212 #endif /* #if !UCONFIG_NO_FORMATTING */
213 #endif //__MEASUNIT_IMPL_H__
214