blob: 3cc2cd0476f75a83da451f9469c021696bf3ff40 [file] [log] [blame]
Victor Changd8aa9d52021-01-05 23:49:57 +00001// © 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
15U_NAMESPACE_BEGIN
16
17
18static const char16_t kDefaultCurrency[] = u"XXX";
19static const char kDefaultCurrency8[] = "XXX";
20
21
22/**
23 * A struct representing a single unit (optional SI prefix and dimensionality).
24 */
Victor Changce4bf3c2021-01-19 16:34:24 +000025struct U_I18N_API SingleUnitImpl : public UMemory {
Victor Changd8aa9d52021-01-05 23:49:57 +000026 /**
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 /**
Victor Changce4bf3c2021-01-19 16:34:24 +000036 * 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 /**
Victor Changd8aa9d52021-01-05 23:49:57 +000046 * 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 */
57 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 */
86 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 */
95 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
Victor Changce4bf3c2021-01-19 16:34:24 +0000123// 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
127template class U_I18N_API MaybeStackArray<SingleUnitImpl*, 8>;
128template class U_I18N_API MemoryPool<SingleUnitImpl, 8>;
129template class U_I18N_API MaybeStackVector<SingleUnitImpl, 8>;
130#endif
Victor Changd8aa9d52021-01-05 23:49:57 +0000131
132/**
133 * Internal representation of measurement units. Capable of representing all complexities of units,
134 * including mixed and compound units.
135 */
Victor Changce4bf3c2021-01-19 16:34:24 +0000136struct 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
Victor Changd8aa9d52021-01-05 23:49:57 +0000144 /** Extract the MeasureUnitImpl from a MeasureUnit. */
145 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 */
183 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 */
Victor Changce4bf3c2021-01-19 16:34:24 +0000197 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;
Victor Changd8aa9d52021-01-05 23:49:57 +0000208
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
Victor Changd8aa9d52021-01-05 23:49:57 +0000238U_NAMESPACE_END
239
240#endif /* #if !UCONFIG_NO_FORMATTING */
241#endif //__MEASUNIT_IMPL_H__