LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) {
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
- // No additional fields to assign (let call count and compiled formatter reset to defaults)
+ // Reset to default values.
+ clear();
return *this;
}
// Formatter is compiled
lnfMoveHelper(static_cast<LNF&&>(src));
} else {
- // Reset to default values.
- auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
- umtx_storeRelease(*callCount, 0);
- fCompiled = nullptr;
+ clear();
}
return *this;
}
+void LocalizedNumberFormatter::clear() {
+ // Reset to default values.
+ auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
+ umtx_storeRelease(*callCount, 0);
+ delete fCompiled;
+ fCompiled = nullptr;
+}
+
void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) {
// Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled().
// Don't copy the call count directly because doing so requires a loadAcquire/storeRelease.
// The bits themselves appear to be platform-dependent, so copying them might not be safe.
auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
umtx_storeRelease(*callCount, INT32_MIN);
+ delete fCompiled;
fCompiled = src.fCompiled;
// Reset the source object to leave it in a safe state.
auto* srcCallCount = reinterpret_cast<u_atomic_int32_t*>(src.fUnsafeCallCount);
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_NOEXCEPT
: NFS<LNF>(std::move(src)) {
- // No additional fields to assign
+ // Steal the compiled formatter
+ LNF&& _src = static_cast<LNF&&>(src);
+ fImpl = _src.fImpl;
+ _src.fImpl = nullptr;
}
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
- // No additional fields to assign
+ // Do not steal; just clear
+ delete fImpl;
+ fImpl = nullptr;
return *this;
}
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
- // No additional fields to assign
+ // Steal the compiled formatter
+ delete fImpl;
+ fImpl = src.fImpl;
+ src.fImpl = nullptr;
return *this;
}
assertTrue("[constructor] Source should be reset after move", l1.getCompiled() == nullptr);
// Reset l1 and l2 to check for macro-props copying for behavior testing
+ // Make the test more interesting: also warm them up with a compiled formatter.
l1 = NumberFormatter::withLocale("en");
+ l1.formatInt(1, status);
+ l1.formatInt(1, status);
+ l1.formatInt(1, status);
l2 = NumberFormatter::withLocale("en");
+ l2.formatInt(1, status);
+ l2.formatInt(1, status);
+ l2.formatInt(1, status);
// Copy assignment
l1 = l3;
TESTCASE_AUTO(testIdentity);
TESTCASE_AUTO(testDifferentFormatters);
TESTCASE_AUTO(testPlurals);
+ TESTCASE_AUTO(testCopyMove);
TESTCASE_AUTO_END;
}
}
}
+void NumberRangeFormatterTest::testCopyMove() {
+ IcuTestErrorCode status(*this, "testCopyMove");
+
+ // Default constructors
+ LocalizedNumberRangeFormatter l1;
+ assertEquals("Initial behavior", u"1–5", l1.formatFormattableRange(1, 5, status).toString(status));
+ if (status.errDataIfFailureAndReset()) { return; }
+
+ // Setup
+ l1 = NumberRangeFormatter::withLocale("fr-FR")
+ .numberFormatterBoth(NumberFormatter::with().unit(USD));
+ assertEquals("Currency behavior", u"1,00–5,00 $US", l1.formatFormattableRange(1, 5, status).toString(status));
+
+ // Copy constructor
+ LocalizedNumberRangeFormatter l2 = l1;
+ assertEquals("Copy constructor", u"1,00–5,00 $US", l2.formatFormattableRange(1, 5, status).toString(status));
+
+ // Move constructor
+ LocalizedNumberRangeFormatter l3 = std::move(l1);
+ assertEquals("Move constructor", u"1,00–5,00 $US", l3.formatFormattableRange(1, 5, status).toString(status));
+
+ // Reset objects for assignment tests
+ l1 = NumberRangeFormatter::withLocale("en-us");
+ l2 = NumberRangeFormatter::withLocale("en-us");
+ assertEquals("Rest behavior, l1", u"1–5", l1.formatFormattableRange(1, 5, status).toString(status));
+ assertEquals("Rest behavior, l2", u"1–5", l2.formatFormattableRange(1, 5, status).toString(status));
+
+ // Copy assignment
+ l1 = l3;
+ assertEquals("Copy constructor", u"1,00–5,00 $US", l1.formatFormattableRange(1, 5, status).toString(status));
+
+ // Move assignment
+ l2 = std::move(l3);
+ assertEquals("Copy constructor", u"1,00–5,00 $US", l2.formatFormattableRange(1, 5, status).toString(status));
+
+ // FormattedNumberRange
+ FormattedNumberRange result = l1.formatFormattableRange(1, 5, status);
+ assertEquals("FormattedNumberRange move constructor", u"1,00–5,00 $US", result.toString(status));
+ result = l1.formatFormattableRange(3, 6, status);
+ assertEquals("FormattedNumberRange move assignment", u"3,00–6,00 $US", result.toString(status));
+}
+
void NumberRangeFormatterTest::assertFormatRange(
const char16_t* message,
const UnlocalizedNumberRangeFormatter& f,