1 // © 2017 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #include "unicode/utypes.h" 5 6 #if !UCONFIG_NO_FORMATTING 7 #ifndef __NUMBER_MICROPROPS_H__ 8 #define __NUMBER_MICROPROPS_H__ 9 10 // TODO: minimize includes 11 #include "unicode/numberformatter.h" 12 #include "number_types.h" 13 #include "number_decimalquantity.h" 14 #include "number_scientific.h" 15 #include "number_patternstring.h" 16 #include "number_modifiers.h" 17 #include "number_multiplier.h" 18 #include "number_roundingutils.h" 19 #include "decNumber.h" 20 #include "charstr.h" 21 #include "util.h" 22 23 U_NAMESPACE_BEGIN 24 namespace number::impl { 25 26 /** 27 * A copyable container for the integer values of mixed unit measurements. 28 * 29 * If memory allocation fails during copying, no values are copied and status is 30 * set to U_MEMORY_ALLOCATION_ERROR. 31 */ 32 class IntMeasures : public MaybeStackArray<int64_t, 2> { 33 public: 34 /** 35 * Default constructor initializes with internal T[stackCapacity] buffer. 36 * 37 * Stack Capacity: most mixed units are expected to consist of two or three 38 * subunits, so one or two integer measures should be enough. 39 */ IntMeasures()40 IntMeasures() : MaybeStackArray<int64_t, 2>() {} 41 42 /** 43 * Copy constructor. 44 * 45 * If memory allocation fails during copying, no values are copied and 46 * status is set to U_MEMORY_ALLOCATION_ERROR. 47 */ IntMeasures(const IntMeasures & other)48 IntMeasures(const IntMeasures &other) : MaybeStackArray<int64_t, 2>() { 49 this->operator=(other); 50 } 51 52 // Assignment operator 53 IntMeasures &operator=(const IntMeasures &rhs) { 54 if (this == &rhs) { 55 return *this; 56 } 57 copyFrom(rhs, status); 58 return *this; 59 } 60 61 /** Move constructor */ 62 IntMeasures(IntMeasures &&src) = default; 63 64 /** Move assignment */ 65 IntMeasures &operator=(IntMeasures &&src) = default; 66 67 UErrorCode status = U_ZERO_ERROR; 68 }; 69 70 struct SimpleMicroProps : public UMemory { 71 Grouper grouping; 72 bool useCurrency = false; 73 UNumberDecimalSeparatorDisplay decimal = UNUM_DECIMAL_SEPARATOR_AUTO; 74 75 // Currency symbol to be used as the decimal separator 76 UnicodeString currencyAsDecimal = ICU_Utility::makeBogusString(); 77 78 // Note: This struct has no direct ownership of the following pointer. 79 const DecimalFormatSymbols* symbols = nullptr; 80 }; 81 82 /** 83 * MicroProps is the first MicroPropsGenerator that should be should be called, 84 * producing an initialized MicroProps instance that will be passed on and 85 * modified throughout the rest of the chain of MicroPropsGenerator instances. 86 */ 87 struct MicroProps : public MicroPropsGenerator { 88 SimpleMicroProps simple; 89 90 // NOTE: All of these fields are properly initialized in NumberFormatterImpl. 91 RoundingImpl rounder; 92 Padder padding; 93 IntegerWidth integerWidth; 94 UNumberSignDisplay sign; 95 char nsName[9]; 96 97 // No ownership: must point at a string which will outlive MicroProps 98 // instances, e.g. a string with static storage duration, or just a string 99 // that will never be deallocated or modified. 100 const char *gender; 101 102 // Note: This struct has no direct ownership of the following pointers. 103 104 // Pointers to Modifiers provided by the number formatting pipeline (when 105 // the value is known): 106 107 // A Modifier provided by LongNameHandler, used for currency long names and 108 // units. If there is no LongNameHandler needed, this should be an 109 // EmptyModifier. (This is typically the third modifier applied.) 110 const Modifier* modOuter; 111 // A Modifier for short currencies and compact notation. (This is typically 112 // the second modifier applied.) 113 const Modifier* modMiddle = nullptr; 114 // A Modifier provided by ScientificHandler, used for scientific notation. 115 // This is typically the first modifier applied. 116 const Modifier* modInner; 117 118 // The following "helper" fields may optionally be used during the MicroPropsGenerator. 119 // They live here to retain memory. 120 struct { 121 // The ScientificModifier for which ScientificHandler is responsible. 122 // ScientificHandler::processQuantity() modifies this Modifier. 123 ScientificModifier scientificModifier; 124 // EmptyModifier used for modOuter 125 EmptyModifier emptyWeakModifier{false}; 126 // EmptyModifier used for modInner 127 EmptyModifier emptyStrongModifier{true}; 128 MultiplierFormatHandler multiplier; 129 // A Modifier used for Mixed Units. When formatting mixed units, 130 // LongNameHandler assigns this Modifier. 131 SimpleModifier mixedUnitModifier; 132 } helpers; 133 134 // The MeasureUnit with which the output is represented. May also have 135 // UMEASURE_UNIT_MIXED complexity, in which case mixedMeasures comes into 136 // play. 137 MeasureUnit outputUnit; 138 139 // Contains all the values of each unit in mixed units. For quantity (which is the floating value of 140 // the smallest unit in the mixed unit), the value stores in `quantity`. 141 // NOTE: the value of quantity in `mixedMeasures` will be left unset. 142 IntMeasures mixedMeasures; 143 144 // Points to quantity position, -1 if the position is not set yet. 145 int32_t indexOfQuantity = -1; 146 147 // Number of mixedMeasures that have been populated 148 int32_t mixedMeasuresCount = 0; 149 150 MicroProps() = default; 151 152 MicroProps(const MicroProps& other) = default; 153 154 MicroProps& operator=(const MicroProps& other) = default; 155 156 /** 157 * As MicroProps is the "base instance", this implementation of 158 * MicroPropsGenerator::processQuantity() just ensures that the output 159 * `micros` is correctly initialized. 160 * 161 * For the "safe" invocation of this function, micros must not be *this, 162 * such that a copy of the base instance is made. For the "unsafe" path, 163 * this function can be used only once, because the base MicroProps instance 164 * will be modified and thus not be available for re-use. 165 * 166 * @param quantity The quantity for consideration and optional mutation. 167 * @param micros The MicroProps instance to populate. If this parameter is 168 * not already `*this`, it will be overwritten with a copy of `*this`. 169 */ processQuantityMicroProps170 void processQuantity(DecimalQuantity &quantity, MicroProps µs, 171 UErrorCode &status) const override { 172 (void) quantity; 173 (void) status; 174 if (this == µs) { 175 // Unsafe path: no need to perform a copy. 176 U_ASSERT(!exhausted); 177 micros.exhausted = true; 178 U_ASSERT(exhausted); 179 } else { 180 // Safe path: copy self into the output micros. 181 U_ASSERT(!exhausted); 182 micros = *this; 183 } 184 } 185 186 private: 187 // Internal fields: 188 bool exhausted = false; 189 }; 190 191 } // namespace number::impl 192 U_NAMESPACE_END 193 194 #endif // __NUMBER_MICROPROPS_H__ 195 196 #endif /* #if !UCONFIG_NO_FORMATTING */ 197