<ClInclude Include="uinvchar.h" />
<ClInclude Include="ustr_cnv.h" />
<ClInclude Include="ustr_imp.h" />
- <ClCompile Include="numparse_unisets.h" />
+ <ClInclude Include="numparse_unisets.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="common.rc" />
<ClInclude Include="uinvchar.h" />
<ClInclude Include="ustr_cnv.h" />
<ClInclude Include="ustr_imp.h" />
- <ClCompile Include="numparse_unisets.h" />
+ <ClInclude Include="numparse_unisets.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="common.rc" />
COUNT
};
-// Exported as U_COMMON_API for ucurr.h
-const U_COMMON_API UnicodeSet* get(Key key);
+// Exported as U_COMMON_API for ucurr.cpp
+U_COMMON_API const UnicodeSet* get(Key key);
-Key chooseFrom(UnicodeString str, Key key1);
+// Exported as U_COMMON_API for numparse_decimal.cpp
+U_COMMON_API Key chooseFrom(UnicodeString str, Key key1);
-Key chooseFrom(UnicodeString str, Key key1, Key key2);
+// Exported as U_COMMON_API for numparse_decimal.cpp
+U_COMMON_API Key chooseFrom(UnicodeString str, Key key1, Key key2);
// Unused in C++:
// Key chooseCurrency(UnicodeString str);
using ERoundingMode = icu::DecimalFormat::ERoundingMode;
using EPadPosition = icu::DecimalFormat::EPadPosition;
+// MSVC warns C4805 when comparing bool with UBool
+// TODO: Move this macro into a better place?
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+#define UBOOL_TO_BOOL(b) static_cast<bool>(b)
+#else
+#define UBOOL_TO_BOOL(b) b
+#endif
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) {
fProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status);
fExportedProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status);
- fWarehouse.adoptInsteadAndCheckErrorCode(new DecimalFormatWarehouse(), status);
+ fWarehouse = new DecimalFormatWarehouse();
+ if (fWarehouse == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
if (symbolsToAdopt == nullptr) {
fSymbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status);
} else {
}
void DecimalFormat::setGroupingUsed(UBool enabled) {
- if (enabled == fProperties->groupingUsed) { return; }
+ if (UBOOL_TO_BOOL(enabled) == fProperties->groupingUsed) { return; }
NumberFormat::setGroupingUsed(enabled); // to set field for compatibility
fProperties->groupingUsed = enabled;
touchNoError();
}
void DecimalFormat::setParseIntegerOnly(UBool value) {
- if (value == fProperties->parseIntegerOnly) { return; }
+ if (UBOOL_TO_BOOL(value) == fProperties->parseIntegerOnly) { return; }
NumberFormat::setParseIntegerOnly(value); // to set field for compatibility
fProperties->parseIntegerOnly = value;
touchNoError();
fProperties.adoptInstead(new DecimalFormatProperties(*source.fProperties));
fSymbols.adoptInstead(new DecimalFormatSymbols(*source.fSymbols));
fExportedProperties.adoptInstead(new DecimalFormatProperties());
- fWarehouse.adoptInstead(new DecimalFormatWarehouse());
+ fWarehouse = new DecimalFormatWarehouse();
if (fProperties == nullptr || fSymbols == nullptr || fExportedProperties == nullptr ||
fWarehouse == nullptr) {
return;
}
DecimalFormat::~DecimalFormat() {
- delete fAtomicParser.exchange(nullptr);
- delete fAtomicCurrencyParser.exchange(nullptr);
+ delete fWarehouse->fAtomicParser.exchange(nullptr);
+ delete fWarehouse->fAtomicCurrencyParser.exchange(nullptr);
+ delete fWarehouse;
};
Format* DecimalFormat::clone() const {
}
void DecimalFormat::setSignAlwaysShown(UBool value) {
- if (value == fProperties->signAlwaysShown) { return; }
+ if (UBOOL_TO_BOOL(value) == fProperties->signAlwaysShown) { return; }
fProperties->signAlwaysShown = value;
touchNoError();
}
}
void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
- if (expSignAlways == fProperties->exponentSignAlwaysShown) { return; }
+ if (UBOOL_TO_BOOL(expSignAlways) == fProperties->exponentSignAlwaysShown) { return; }
fProperties->exponentSignAlwaysShown = expSignAlways;
touchNoError();
}
}
void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) {
- if (newValue == fProperties->decimalSeparatorAlwaysShown) { return; }
+ if (UBOOL_TO_BOOL(newValue) == fProperties->decimalSeparatorAlwaysShown) { return; }
fProperties->decimalSeparatorAlwaysShown = newValue;
touchNoError();
}
}
void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) {
- if (newValue == fProperties->decimalPatternMatchRequired) { return; }
+ if (UBOOL_TO_BOOL(newValue) == fProperties->decimalPatternMatchRequired) { return; }
fProperties->decimalPatternMatchRequired = newValue;
touchNoError();
}
}
void DecimalFormat::setParseNoExponent(UBool value) {
- if (value == fProperties->parseNoExponent) { return; }
+ if (UBOOL_TO_BOOL(value) == fProperties->parseNoExponent) { return; }
fProperties->parseNoExponent = value;
touchNoError();
}
}
void DecimalFormat::setParseCaseSensitive(UBool value) {
- if (value == fProperties->parseCaseSensitive) { return; }
+ if (UBOOL_TO_BOOL(value) == fProperties->parseCaseSensitive) { return; }
fProperties->parseCaseSensitive = value;
touchNoError();
}
}
void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) {
- if (value == fProperties->formatFailIfMoreThanMaxDigits) { return; }
+ if (UBOOL_TO_BOOL(value) == fProperties->formatFailIfMoreThanMaxDigits) { return; }
fProperties->formatFailIfMoreThanMaxDigits = value;
touchNoError();
}
setupFastFormat();
// Delete the parsers if they were made previously
- delete fAtomicParser.exchange(nullptr);
- delete fAtomicCurrencyParser.exchange(nullptr);
+ delete fWarehouse->fAtomicParser.exchange(nullptr);
+ delete fWarehouse->fAtomicCurrencyParser.exchange(nullptr);
// In order for the getters to work, we need to populate some fields in NumberFormat.
NumberFormat::setCurrency(fExportedProperties->currency.get(status).getISOCurrency(), status);
if (U_FAILURE(status)) { return nullptr; }
// First try to get the pre-computed parser
- auto* ptr = fAtomicParser.load();
+ auto* ptr = fWarehouse->fAtomicParser.load();
if (ptr != nullptr) {
return ptr;
}
// Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
// atomic if another thread beat us to computing the parser object.
auto* nonConstThis = const_cast<DecimalFormat*>(this);
- if (!nonConstThis->fAtomicParser.compare_exchange_strong(ptr, temp)) {
+ if (!nonConstThis->fWarehouse->fAtomicParser.compare_exchange_strong(ptr, temp)) {
// Another thread beat us to computing the parser
delete temp;
return ptr;
if (U_FAILURE(status)) { return nullptr; }
// First try to get the pre-computed parser
- auto* ptr = fAtomicCurrencyParser.load();
+ auto* ptr = fWarehouse->fAtomicCurrencyParser.load();
if (ptr != nullptr) {
return ptr;
}
// Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
// atomic if another thread beat us to computing the parser object.
auto* nonConstThis = const_cast<DecimalFormat*>(this);
- if (!nonConstThis->fAtomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
+ if (!nonConstThis->fWarehouse->fAtomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
// Another thread beat us to computing the parser
delete temp;
return ptr;
namespace impl {
-class CurrencySymbols : public UMemory {
+// Exported as U_I18N_API for tests
+class U_I18N_API CurrencySymbols : public UMemory {
public:
CurrencySymbols() = default; // default constructor: leaves class in valid but undefined state
result = result * 10 + getDigitPos(magnitude - scale);
}
if (isNegative()) {
- return -result;
+ return static_cast<int64_t>(-result);
}
- return result;
+ return static_cast<int64_t>(result);
}
uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
-#include <unicode/numberformatter.h>
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
-#include <unicode/numberformatter.h>
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
PropertiesAffixPatternProvider propertiesAPP;
CurrencyPluralInfoAffixProvider currencyPluralInfoAPP;
CurrencySymbols currencySymbols;
+
+ // Can't have std::atomic in public header files, so put it here in the warehouse.
+ std::atomic<numparse::impl::NumberParserImpl*> fAtomicParser = {};
+ std::atomic<numparse::impl::NumberParserImpl*> fAtomicCurrencyParser = {};
};
/**
* Wraps a {@link Multiplier} for use in the number formatting pipeline.
*/
-class MultiplierFormatHandler : public MicroPropsGenerator, public UMemory {
+// Exported as U_I18N_API for tests
+class U_I18N_API MultiplierFormatHandler : public MicroPropsGenerator, public UMemory {
public:
void setAndChain(const Scale& multiplier, const MicroPropsGenerator* parent);
/** A very thin C++ wrapper around decNumber.h */
-class DecNum : public UMemory {
+// Exported as U_I18N_API for tests
+class U_I18N_API DecNum : public UMemory {
public:
DecNum(); // leaves object in valid but undefined state
/**
* A warehouse to retain ownership of CodePointMatchers.
*/
-class CodePointMatcherWarehouse : public UMemory {
+// Exported as U_I18N_API for tests
+class U_I18N_API CodePointMatcherWarehouse : public UMemory {
private:
static constexpr int32_t CODE_POINT_STACK_CAPACITY = 5; // Number of entries directly on the stack
static constexpr int32_t CODE_POINT_BATCH_SIZE = 10; // Number of entries per heap allocation
*
* @author sffc
*/
-class AffixTokenMatcherWarehouse : public UMemory {
+// Exported as U_I18N_API for tests
+class U_I18N_API AffixTokenMatcherWarehouse : public UMemory {
public:
AffixTokenMatcherWarehouse() = default; // WARNING: Leaves the object in an unusable state
};
-class AffixPatternMatcher : public ArraySeriesMatcher {
+// Exported as U_I18N_API for tests
+class U_I18N_API AffixPatternMatcher : public ArraySeriesMatcher {
public:
AffixPatternMatcher() = default; // WARNING: Leaves the object in an unusable state
* @author sffc
* @see AnyMatcher
*/
-class SeriesMatcher : public CompositionMatcher {
+// Exported as U_I18N_API for tests
+class U_I18N_API SeriesMatcher : public CompositionMatcher {
public:
bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override;
*
* The object adopts the array, but NOT the matchers contained inside the array.
*/
-class ArraySeriesMatcher : public SeriesMatcher {
+// Exported as U_I18N_API for tests
+class U_I18N_API ArraySeriesMatcher : public SeriesMatcher {
public:
ArraySeriesMatcher(); // WARNING: Leaves the object in an unusable state
U_NAMESPACE_BEGIN namespace numparse {
namespace impl {
-class NumberParserImpl : public MutableMatcherCollection {
+// Exported as U_I18N_API for tests
+class U_I18N_API NumberParserImpl : public MutableMatcherCollection {
public:
virtual ~NumberParserImpl();
}
if (quantity.fitsInLong()) {
- return quantity.toLong();
+ return static_cast<double>(quantity.toLong());
} else {
return quantity.toDouble();
}
};
-class IgnorablesMatcher : public SymbolMatcher {
+// Exported as U_I18N_API for tests
+class U_I18N_API IgnorablesMatcher : public SymbolMatcher {
public:
IgnorablesMatcher() = default; // WARNING: Leaves the object in an unusable state
};
-class MinusSignMatcher : public SymbolMatcher {
+// Exported as U_I18N_API for tests
+class U_I18N_API MinusSignMatcher : public SymbolMatcher {
public:
MinusSignMatcher() = default; // WARNING: Leaves the object in an unusable state
};
-class PercentMatcher : public SymbolMatcher {
+// Exported as U_I18N_API for tests
+class U_I18N_API PercentMatcher : public SymbolMatcher {
public:
PercentMatcher() = default; // WARNING: Leaves the object in an unusable state
};
-class PlusSignMatcher : public SymbolMatcher {
+// Exported as U_I18N_API for tests
+class U_I18N_API PlusSignMatcher : public SymbolMatcher {
public:
PlusSignMatcher() = default; // WARNING: Leaves the object in an unusable state
*
* @author sffc
*/
-class ParsedNumber {
+// Exported as U_I18N_API for tests
+class U_I18N_API ParsedNumber {
public:
/**
*
* @author sffc
*/
-class StringSegment : public UMemory {
+// Exported as U_I18N_API for tests
+class U_I18N_API StringSegment : public UMemory {
public:
StringSegment(const UnicodeString& str, bool ignoreCase);
*
* @author sffc
*/
-class NumberParseMatcher {
+// Exported as U_I18N_API for tests
+class U_I18N_API NumberParseMatcher {
public:
/**
* Matchers can override this method to return true to indicate that they are optional and can be run
// explicit template instantiation. see digitlst.h
// (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::LocalizedNumberFormatter>;
+template class U_I18N_API LocalPointer<number::LocalizedNumberFormatter>;
+template class U_I18N_API LocalPointerBase<number::impl::DecimalFormatProperties>;
+template class U_I18N_API LocalPointer<number::impl::DecimalFormatProperties>;
+template class U_I18N_API LocalPointerBase<DecimalFormatSymbols>;
+template class U_I18N_API LocalPointer<DecimalFormatSymbols>;
template class U_I18N_API EnumSet<UNumberFormatAttribute,
UNUM_MAX_NONBOOLEAN_ATTRIBUTE+1,
UNUM_LIMIT_BOOLEAN_ATTRIBUTE>;
*/
LocalPointer<number::impl::DecimalFormatProperties> fExportedProperties;
- /** A field for a few additional helper object that need ownership. */
- LocalPointer<number::impl::DecimalFormatWarehouse> fWarehouse;
-
- std::atomic<numparse::impl::NumberParserImpl*> fAtomicParser = {};
- std::atomic<numparse::impl::NumberParserImpl*> fAtomicCurrencyParser = {};
+ /**
+ * A field for a few additional helper object that need ownership.
+ * Can't be a LocalPointer because it is an internal class.
+ */
+ number::impl::DecimalFormatWarehouse* fWarehouse;
// Data for fastpath
bool fCanUseFastFormat;
}
value = value * 10 - 0x30 + (int32_t) ch;
}
- int32_t signedValue = neg ? -value : static_cast<int32_t>(value);
+ int32_t signedValue = neg ? static_cast<int32_t>(-value) : static_cast<int32_t>(value);
*static_cast<int32_t *>(intPtr) = signedValue;
}
assertEquals("Should trim, toPlainString", "76.54", dq.toPlainString());
assertEquals("Should trim, toScientificString", "7.654E+1", dq.toScientificString());
assertEquals("Should trim, toLong", 76LL, dq.toLong(true));
- assertEquals("Should trim, toFractionLong", 54L, dq.toFractionLong(false));
+ assertEquals("Should trim, toFractionLong", 54LL, dq.toFractionLong(false));
assertEquals("Should trim, toDouble", 76.54, dq.toDouble());
// To test DecNum output, check the round-trip.
DecNum dn;