blob: c01765e2cea6c6c0f3dacdd24407fc272cce18cf [file] [log] [blame]
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
#ifndef __NUMBER_TYPES_H__
#define __NUMBER_TYPES_H__
#include <cstdint>
#include "unicode/decimfmt.h"
#include "unicode/unum.h"
#include "unicode/numsys.h"
#include "unicode/numberformatter.h"
#include "unicode/utf16.h"
#include "uassert.h"
#include "unicode/platform.h"
U_NAMESPACE_BEGIN
namespace number {
namespace impl {
// Typedef several enums for brevity and for easier comparison to Java.
typedef UNumberFormatFields Field;
typedef UNumberFormatRoundingMode RoundingMode;
typedef UNumberFormatPadPosition PadPosition;
typedef UNumberCompactStyle CompactStyle;
// ICU4J Equivalent: RoundingUtils.MAX_INT_FRAC_SIG
static constexpr int32_t kMaxIntFracSig = 999;
// ICU4J Equivalent: RoundingUtils.DEFAULT_ROUNDING_MODE
static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN;
// ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING
static constexpr char16_t kFallbackPaddingString[] = u" ";
// ICU4J Equivalent: NumberFormatterImpl.DEFAULT_CURRENCY
static constexpr char16_t kDefaultCurrency[] = u"XXX";
// Forward declarations:
class Modifier;
class MutablePatternModifier;
class DecimalQuantity;
class NumberStringBuilder;
struct MicroProps;
enum AffixPatternType {
// Represents a literal character; the value is stored in the code point field.
TYPE_CODEPOINT = 0,
// Represents a minus sign symbol '-'.
TYPE_MINUS_SIGN = -1,
// Represents a plus sign symbol '+'.
TYPE_PLUS_SIGN = -2,
// Represents a percent sign symbol '%'.
TYPE_PERCENT = -3,
// Represents a permille sign symbol '‰'.
TYPE_PERMILLE = -4,
// Represents a single currency symbol '¤'.
TYPE_CURRENCY_SINGLE = -5,
// Represents a double currency symbol '¤¤'.
TYPE_CURRENCY_DOUBLE = -6,
// Represents a triple currency symbol '¤¤¤'.
TYPE_CURRENCY_TRIPLE = -7,
// Represents a quadruple currency symbol '¤¤¤¤'.
TYPE_CURRENCY_QUAD = -8,
// Represents a quintuple currency symbol '¤¤¤¤¤'.
TYPE_CURRENCY_QUINT = -9,
// Represents a sequence of six or more currency symbols.
TYPE_CURRENCY_OVERFLOW = -15
};
enum CompactType {
TYPE_DECIMAL,
TYPE_CURRENCY
};
// TODO: Should this be moved somewhere else, maybe where other ICU classes can use it?
// Exported as U_I18N_API because it is a base class for other exported types
class U_I18N_API CharSequence {
public:
virtual ~CharSequence() = default;
virtual int32_t length() const = 0;
virtual char16_t charAt(int32_t index) const = 0;
virtual UChar32 codePointAt(int32_t index) const {
// Default implementation; can be overridden with a more efficient version
char16_t leading = charAt(index);
if (U16_IS_LEAD(leading) && length() > index + 1) {
char16_t trailing = charAt(index + 1);
return U16_GET_SUPPLEMENTARY(leading, trailing);
} else {
return leading;
}
}
virtual UnicodeString toUnicodeString() const = 0;
};
class U_I18N_API AffixPatternProvider {
public:
static const int32_t AFFIX_PLURAL_MASK = 0xff;
static const int32_t AFFIX_PREFIX = 0x100;
static const int32_t AFFIX_NEGATIVE_SUBPATTERN = 0x200;
static const int32_t AFFIX_PADDING = 0x400;
virtual ~AffixPatternProvider() = default;
virtual char16_t charAt(int flags, int i) const = 0;
virtual int length(int flags) const = 0;
virtual bool hasCurrencySign() const = 0;
virtual bool positiveHasPlusSign() const = 0;
virtual bool hasNegativeSubpattern() const = 0;
virtual bool negativeHasMinusSign() const = 0;
virtual bool containsSymbolType(AffixPatternType, UErrorCode &) const = 0;
/**
* True if the pattern has a number placeholder like "0" or "#,##0.00"; false if the pattern does not
* have one. This is used in cases like compact notation, where the pattern replaces the entire
* number instead of rendering the number.
*/
virtual bool hasBody() const = 0;
};
/**
* A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string
* builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else,
* like a {@link com.ibm.icu.text.SimpleFormatter} pattern.
*
* A Modifier is usually immutable, except in cases such as {@link MurkyModifier}, which are mutable for performance
* reasons.
*
* Exported as U_I18N_API because it is a base class for other exported types
*/
class U_I18N_API Modifier {
public:
virtual ~Modifier() = default;
/**
* Apply this Modifier to the string builder.
*
* @param output
* The string builder to which to apply this modifier.
* @param leftIndex
* The left index of the string within the builder. Equal to 0 when only one number is being formatted.
* @param rightIndex
* The right index of the string within the string builder. Equal to length when only one number is being
* formatted.
* @return The number of characters (UTF-16 code units) that were added to the string builder.
*/
virtual int32_t
apply(NumberStringBuilder &output, int leftIndex, int rightIndex, UErrorCode &status) const = 0;
/**
* Gets the length of the prefix. This information can be used in combination with {@link #apply} to extract the
* prefix and suffix strings.
*
* @return The number of characters (UTF-16 code units) in the prefix.
*/
virtual int32_t getPrefixLength(UErrorCode& status) const = 0;
/**
* Returns the number of code points in the modifier, prefix plus suffix.
*/
virtual int32_t getCodePointCount(UErrorCode &status) const = 0;
/**
* Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed
* to bubble up. With regard to padding, strong modifiers are considered to be on the inside of the prefix and
* suffix.
*
* @return Whether the modifier is strong.
*/
virtual bool isStrong() const = 0;
};
/**
* This interface is used when all number formatting settings, including the locale, are known, except for the quantity
* itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the
* quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output.
*
* <p>
* In other words, this interface is used for the parts of number processing that are <em>quantity-dependent</em>.
*
* <p>
* In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of MicroPropsGenerators
* are linked together, and each one is responsible for manipulating a certain quantity-dependent part of the
* MicroProps. At the tail of the linked list is a base instance of {@link MicroProps} with properties that are not
* quantity-dependent. Each element in the linked list calls {@link #processQuantity} on its "parent", then does its
* work, and then returns the result.
*
* Exported as U_I18N_API because it is a base class for other exported types
*
*/
class U_I18N_API MicroPropsGenerator {
public:
virtual ~MicroPropsGenerator() = default;
/**
* Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}.
*
* @param quantity
* The quantity for consideration and optional mutation.
* @param micros
* The MicroProps instance to populate.
* @return A MicroProps instance resolved for the quantity.
*/
virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros, UErrorCode& status) const = 0;
};
/**
* An interface used by compact notation and scientific notation to choose a multiplier while rounding.
*/
class MultiplierProducer {
public:
virtual ~MultiplierProducer() = default;
/**
* Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a magnitude of 5
* (e.g., 100,000) should return a multiplier of -3, since the number is displayed in thousands.
*
* @param magnitude
* The power of ten of the input number.
* @return The shift in powers of ten.
*/
virtual int32_t getMultiplier(int32_t magnitude) const = 0;
};
// Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties
template<typename T>
class U_I18N_API NullableValue {
public:
NullableValue() : fNull(true) {}
NullableValue(const NullableValue<T> &other) = default;
explicit NullableValue(const T &other) {
fValue = other;
fNull = false;
}
NullableValue<T> &operator=(const NullableValue<T> &other) = default;
NullableValue<T> &operator=(const T &other) {
fValue = other;
fNull = false;
return *this;
}
bool operator==(const NullableValue &other) const {
// "fValue == other.fValue" returns UBool, not bool (causes compiler warnings)
return fNull ? other.fNull : (other.fNull ? false : static_cast<bool>(fValue == other.fValue));
}
void nullify() {
// TODO: It might be nice to call the destructor here.
fNull = true;
}
bool isNull() const {
return fNull;
}
T get(UErrorCode &status) const {
if (fNull) {
status = U_UNDEFINED_VARIABLE;
}
return fValue;
}
private:
bool fNull;
T fValue;
};
} // namespace impl
} // namespace number
U_NAMESPACE_END
#endif //__NUMBER_TYPES_H__
#endif /* #if !UCONFIG_NO_FORMATTING */