Modifier::~Modifier() = default;
+ModifierStore::~ModifierStore() = default;
+
+AdoptingModifierStore::~AdoptingModifierStore() {
+ for (const Modifier *mod : mods) {
+ delete mod;
+ }
+}
+
int32_t ConstantAffixModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex,
UErrorCode &status) const {
return false;
}
-bool ConstantAffixModifier::operator==(const Modifier& other) const {
+void ConstantAffixModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not currently used.
+ U_ASSERT(false);
+}
+
+bool ConstantAffixModifier::semanticallyEquivalent(const Modifier& other) const {
auto* _other = dynamic_cast<const ConstantAffixModifier*>(&other);
if (_other == nullptr) {
return false;
return false;
}
-bool SimpleModifier::operator==(const Modifier& other) const {
+void SimpleModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not currently used.
+ U_ASSERT(false);
+}
+
+bool SimpleModifier::semanticallyEquivalent(const Modifier& other) const {
auto* _other = dynamic_cast<const SimpleModifier*>(&other);
if (_other == nullptr) {
return false;
return fPrefix.containsField(field) || fSuffix.containsField(field);
}
-bool ConstantMultiFieldModifier::operator==(const Modifier& other) const {
+void ConstantMultiFieldModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not currently used.
+ U_ASSERT(false);
+}
+
+bool ConstantMultiFieldModifier::semanticallyEquivalent(const Modifier& other) const {
auto* _other = dynamic_cast<const ConstantMultiFieldModifier*>(&other);
if (_other == nullptr) {
return false;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
- bool operator==(const Modifier& other) const U_OVERRIDE;
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
private:
UnicodeString fPrefix;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
- bool operator==(const Modifier& other) const U_OVERRIDE;
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
/**
* TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
- bool operator==(const Modifier& other) const U_OVERRIDE;
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
protected:
// NOTE: In Java, these are stored as array pointers. In C++, the NumberStringBuilder is stored by
return false;
}
- bool operator==(const Modifier& other) const U_OVERRIDE {
+ void getParameters(Parameters& output) const U_OVERRIDE {
+ output.obj = nullptr;
+ }
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE {
return other.getCodePointCount() == 0;
}
};
/**
- * A ParameterizedModifier by itself is NOT a Modifier. Rather, it wraps a data structure containing two or more
- * Modifiers and returns the modifier appropriate for the current situation.
+ * This implementation of ModifierStore adopts Modifer pointers.
*/
-class U_I18N_API ParameterizedModifier : public UMemory {
+class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory {
public:
- // NOTE: mods is zero-initialized (to nullptr)
- ParameterizedModifier() : mods() {
- }
+ virtual ~AdoptingModifierStore();
- // No copying!
- ParameterizedModifier(const ParameterizedModifier &other) = delete;
+ static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER;
- ~ParameterizedModifier() {
- for (const Modifier *mod : mods) {
- delete mod;
- }
- }
+ AdoptingModifierStore() = default;
- void adoptPositiveNegativeModifiers(
- const Modifier *positive, const Modifier *zero, const Modifier *negative) {
- mods[2] = positive;
- mods[1] = zero;
- mods[0] = negative;
- }
+ // No copying!
+ AdoptingModifierStore(const AdoptingModifierStore &other) = delete;
- /** The modifier is ADOPTED. */
- void adoptSignPluralModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) {
+ /**
+ * Sets the Modifier with the specified signum and plural form.
+ */
+ void adoptModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) {
mods[getModIndex(signum, plural)] = mod;
}
+ /**
+ * Sets the Modifier with the specified signum.
+ * The modifier will apply to all plural forms.
+ */
+ void adoptModifierWithoutPlural(int8_t signum, const Modifier *mod) {
+ mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod;
+ }
+
/** Returns a reference to the modifier; no ownership change. */
- const Modifier *getModifier(int8_t signum) const {
- return mods[signum + 1];
+ const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const U_OVERRIDE {
+ const Modifier* modifier = mods[getModIndex(signum, plural)];
+ if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) {
+ modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
+ }
+ return modifier;
}
/** Returns a reference to the modifier; no ownership change. */
- const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const {
- return mods[getModIndex(signum, plural)];
+ const Modifier *getModifierWithoutPlural(int8_t signum) const {
+ return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
}
private:
- const Modifier *mods[3 * StandardPlural::COUNT];
+ // NOTE: mods is zero-initialized (to nullptr)
+ const Modifier *mods[3 * StandardPlural::COUNT] = {};
inline static int32_t getModIndex(int8_t signum, StandardPlural::Form plural) {
+ U_ASSERT(signum >= -1 && signum <= 1);
+ U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
return static_cast<int32_t>(plural) * 3 + (signum + 1);
}
};
StandardPlural::Form::MANY,
StandardPlural::Form::OTHER};
- auto pm = new ParameterizedModifier();
+ auto pm = new AdoptingModifierStore();
if (pm == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return nullptr;
// Slower path when we require the plural keyword.
for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) {
setNumberProperties(1, plural);
- pm->adoptSignPluralModifier(1, plural, createConstantModifier(status));
+ pm->adoptModifier(1, plural, createConstantModifier(status));
setNumberProperties(0, plural);
- pm->adoptSignPluralModifier(0, plural, createConstantModifier(status));
+ pm->adoptModifier(0, plural, createConstantModifier(status));
setNumberProperties(-1, plural);
- pm->adoptSignPluralModifier(-1, plural, createConstantModifier(status));
+ pm->adoptModifier(-1, plural, createConstantModifier(status));
}
if (U_FAILURE(status)) {
delete pm;
} else {
// Faster path when plural keyword is not needed.
setNumberProperties(1, StandardPlural::Form::COUNT);
- Modifier* positive = createConstantModifier(status);
+ pm->adoptModifierWithoutPlural(1, createConstantModifier(status));
setNumberProperties(0, StandardPlural::Form::COUNT);
- Modifier* zero = createConstantModifier(status);
+ pm->adoptModifierWithoutPlural(0, createConstantModifier(status));
setNumberProperties(-1, StandardPlural::Form::COUNT);
- Modifier* negative = createConstantModifier(status);
- pm->adoptPositiveNegativeModifiers(positive, zero, negative);
+ pm->adoptModifierWithoutPlural(-1, createConstantModifier(status));
if (U_FAILURE(status)) {
delete pm;
return nullptr;
}
}
-ImmutablePatternModifier::ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules,
+ImmutablePatternModifier::ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules,
const MicroPropsGenerator* parent)
: pm(pm), rules(rules), parent(parent) {}
void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity& quantity) const {
if (rules == nullptr) {
- micros.modMiddle = pm->getModifier(quantity.signum());
+ micros.modMiddle = pm->getModifierWithoutPlural(quantity.signum());
} else {
// TODO: Fix this. Avoid the copy.
DecimalQuantity copy(quantity);
const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlural::Form plural) const {
if (rules == nullptr) {
- return pm->getModifier(signum);
+ return pm->getModifierWithoutPlural(signum);
} else {
return pm->getModifier(signum, plural);
}
return false;
}
-bool MutablePatternModifier::operator==(const Modifier& other) const {
+void MutablePatternModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not currently used.
+ U_ASSERT(false);
+}
+
+bool MutablePatternModifier::semanticallyEquivalent(const Modifier& other) const {
(void)other;
// This method is not currently used.
U_ASSERT(false);
U_NAMESPACE_BEGIN
// Export an explicit template instantiation of the LocalPointer that is used as a
-// data member of ParameterizedModifier.
+// data member of AdoptingModifierStore.
// (When building DLLs for Windows this is required.)
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
#pragma warning(suppress: 4661)
-template class U_I18N_API LocalPointerBase<number::impl::ParameterizedModifier>;
-template class U_I18N_API LocalPointer<number::impl::ParameterizedModifier>;
+template class U_I18N_API LocalPointerBase<number::impl::AdoptingModifierStore>;
+template class U_I18N_API LocalPointer<number::impl::AdoptingModifierStore>;
#endif
namespace number {
const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const;
private:
- ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules,
+ ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules,
const MicroPropsGenerator* parent);
- const LocalPointer<ParameterizedModifier> pm;
+ const LocalPointer<AdoptingModifierStore> pm;
const PluralRules* rules;
const MicroPropsGenerator* parent;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
- bool operator==(const Modifier& other) const U_OVERRIDE;
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
/**
* Returns the string that substitutes a given symbol type in a pattern.
return false;
}
-bool ScientificModifier::operator==(const Modifier& other) const {
+void ScientificModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not used for inner modifiers.
+ U_ASSERT(false);
+}
+
+bool ScientificModifier::semanticallyEquivalent(const Modifier& other) const {
auto* _other = dynamic_cast<const ScientificModifier*>(&other);
if (_other == nullptr) {
return false;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
- bool operator==(const Modifier& other) const U_OVERRIDE;
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
private:
int32_t fExponent;
#include "uassert.h"
#include "unicode/platform.h"
#include "unicode/uniset.h"
+#include "standardplural.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
class MutablePatternModifier;
class DecimalQuantity;
class NumberStringBuilder;
+class ModifierStore;
struct MicroProps;
* 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
+ * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance
* reasons.
*
* Exported as U_I18N_API because it is a base class for other exported types
virtual bool containsField(UNumberFormatFields field) const = 0;
/**
- * Returns whether the affixes owned by this modifier are equal to the ones owned by the given modifier.
+ * A fill-in for getParameters(). obj will always be set; if non-null, the other
+ * two fields are also safe to read.
*/
- virtual bool operator==(const Modifier& other) const = 0;
+ struct Parameters {
+ const ModifierStore* obj = nullptr;
+ int8_t signum;
+ StandardPlural::Form plural;
+ };
+
+ /**
+ * Gets a set of "parameters" for this Modifier.
+ */
+ virtual void getParameters(Parameters& output) const = 0;
+
+ /**
+ * Returns whether this Modifier is *semantically equivalent* to the other Modifier;
+ * in many cases, this is the same as equal, but parameters should be ignored.
+ */
+ virtual bool semanticallyEquivalent(const Modifier& other) const = 0;
};
+
+/**
+ * This is *not* a modifier; rather, it is an object that can return modifiers
+ * based on given parameters.
+ *
+ * Exported as U_I18N_API because it is a base class for other exported types.
+ */
+class U_I18N_API ModifierStore {
+ public:
+ virtual ~ModifierStore();
+
+ /**
+ * Returns a Modifier with the given parameters (best-effort).
+ */
+ virtual const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) 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
// TODO: Write this as MicroProps operator==() ?
// TODO: Avoid the redundancy of these equality operations with the
// ones in formatRange?
- if (!(*micros1.modInner == *micros2.modInner)
- || !(*micros1.modMiddle == *micros2.modMiddle)
- || !(*micros1.modOuter == *micros2.modOuter)) {
+ if (!micros1.modInner->semanticallyEquivalent(*micros2.modInner)
+ || !micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle)
+ || !micros1.modOuter->semanticallyEquivalent(*micros2.modOuter)) {
formatRange(data, micros1, micros2, status);
data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL;
return;
case UNUM_RANGE_COLLAPSE_UNIT:
{
// OUTER MODIFIER
- collapseOuter = *micros1.modOuter == *micros2.modOuter;
+ collapseOuter = micros1.modOuter->semanticallyEquivalent(*micros2.modOuter);
if (!collapseOuter) {
// Never collapse inner mods if outer mods are not collapsable
}
// MIDDLE MODIFIER
- collapseMiddle = *micros1.modMiddle == *micros2.modMiddle;
+ collapseMiddle = micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle);
if (!collapseMiddle) {
// Never collapse inner mods if outer mods are not collapsable
}
// INNER MODIFIER
- collapseInner = *micros1.modInner == *micros2.modInner;
+ collapseInner = micros1.modInner->semanticallyEquivalent(*micros2.modInner);
// All done checking for collapsability.
break;