diff --git a/icu4c/source/common/unicode/localpointer.h b/icu4c/source/common/unicode/localpointer.h index cf6782a0078..c69efbd5700 100644 --- a/icu4c/source/common/unicode/localpointer.h +++ b/icu4c/source/common/unicode/localpointer.h @@ -378,7 +378,7 @@ public: * @param p simple pointer to an array of T objects that is adopted * @stable ICU 4.4 */ - explicit LocalArray(T *p=nullptr) : LocalPointerBase(p), fLength(p==nullptr?0:-1) {} + explicit LocalArray(T *p=nullptr) : LocalPointerBase(p), fLength(0) {} /** * Constructor takes ownership and reports an error if nullptr. * @@ -397,6 +397,18 @@ public: errorCode=U_MEMORY_ALLOCATION_ERROR; } } + +private: + /** Constructor for withLengthAndCheckErrorCode() */ + LocalArray(T *p, int32_t length, UErrorCode &errorCode) : LocalArray(p) { + if (p != nullptr) { + fLength = length; + } else if (U_SUCCESS(errorCode)) { + errorCode=U_MEMORY_ALLOCATION_ERROR; + } + } + +public: /** * Move constructor, leaves src with isNull(). * @param src source smart pointer @@ -410,13 +422,15 @@ public: /** * Construct a LocalArray with a specified length. * - * @param p Pointer to the array to adopt. - * @param length The length of the array. - * @return A LocalArray with a length field. + * @param p simple pointer to an array of T objects that is adopted + * @param length number of valid objects in the array, accesible via length() + * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR + * if p==nullptr and no other failure code had been set + * * @draft ICU 67 */ - static LocalArray withLength(T *p, int32_t length) { - return LocalArray(p, length); + static LocalArray withLengthAndCheckErrorCode(T *p, int32_t length, UErrorCode& status) { + return LocalArray(p, length, status); } #endif // U_HIDE_DRAFT_API @@ -454,6 +468,7 @@ public: LocalPointerBase::ptr=src.ptr; src.ptr=nullptr; fLength=src.fLength; + src.fLength=0; return *this; } @@ -468,7 +483,7 @@ public: */ LocalArray &operator=(std::unique_ptr &&p) U_NOEXCEPT { adoptInstead(p.release()); - fLength=-1; + fLength=0; return *this; } #endif /* U_HIDE_DRAFT_API */ @@ -504,7 +519,7 @@ public: void adoptInstead(T *p) { delete[] LocalPointerBase::ptr; LocalPointerBase::ptr=p; - fLength=-1; + fLength=0; } /** * Deletes the array it owns, @@ -531,7 +546,7 @@ public: } else { delete[] p; } - fLength=-1; + fLength=0; } /** * Array item access (writable). @@ -564,14 +579,14 @@ public: * The length of the array contained in the LocalArray. The size must be * provided when the LocalArray is constructed. * - * @return The length of the array, or -1 if unknown. + * @return The length of the array, or 0 if unknown. * @draft ICU 67 */ int32_t length() const { return fLength; } #endif // U_HIDE_DRAFT_API private: - int32_t fLength = -1; + int32_t fLength = 0; LocalArray(T *p, int32_t length) : LocalArray(p) { fLength = length; diff --git a/icu4c/source/i18n/measunit_impl.h b/icu4c/source/i18n/measunit_impl.h index 631a47fa979..ffcd0581ce1 100644 --- a/icu4c/source/i18n/measunit_impl.h +++ b/icu4c/source/i18n/measunit_impl.h @@ -64,7 +64,7 @@ struct TempSingleUnit : public UMemory { /** SI prefix. **/ UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE; - /** Dimentionality. **/ + /** Dimensionality. **/ int32_t dimensionality = 1; }; diff --git a/icu4c/source/i18n/number_skeletons.cpp b/icu4c/source/i18n/number_skeletons.cpp index 99e5241e70e..a202bdf14e8 100644 --- a/icu4c/source/i18n/number_skeletons.cpp +++ b/icu4c/source/i18n/number_skeletons.cpp @@ -30,16 +30,6 @@ using namespace icu::number; using namespace icu::number::impl; using namespace icu::number::impl::skeleton; -#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER) -// Ignore MSVC warning 4661. This is generated for NumberFormatterSettings<>::toSkeleton() as this method -// is defined elsewhere (in number_skeletons.cpp). The compiler is warning that the explicit template instantiation -// inside this single translation unit (CPP file) is incomplete, and thus it isn't sure if the template class is -// fully defined. However, since each translation unit explicitly instantiates all the necessary template classes, -// they will all be passed to the linker, and the linker will still find and export all the class members. -#pragma warning(push) -#pragma warning(disable: 4661) -#endif - namespace { icu::UInitOnce gNumberSkeletonsInitOnce = U_INITONCE_INITIALIZER; @@ -1699,6 +1689,16 @@ bool GeneratorHelpers::scale(const MacroProps& macros, UnicodeString& sb, UError // Definitions of public API methods (put here for dependency disentanglement) +#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER) +// Ignore MSVC warning 4661. This is generated for NumberFormatterSettings<>::toSkeleton() as this method +// is defined elsewhere (in number_skeletons.cpp). The compiler is warning that the explicit template instantiation +// inside this single translation unit (CPP file) is incomplete, and thus it isn't sure if the template class is +// fully defined. However, since each translation unit explicitly instantiates all the necessary template classes, +// they will all be passed to the linker, and the linker will still find and export all the class members. +#pragma warning(push) +#pragma warning(disable: 4661) +#endif + template UnicodeString NumberFormatterSettings::toSkeleton(UErrorCode& status) const { if (U_FAILURE(status)) { diff --git a/icu4c/source/i18n/unicode/measunit.h b/icu4c/source/i18n/unicode/measunit.h index 46ff78da32b..34522ebe1e9 100644 --- a/icu4c/source/i18n/unicode/measunit.h +++ b/icu4c/source/i18n/unicode/measunit.h @@ -40,8 +40,8 @@ struct MeasureUnitImpl; * square-kilometer, kilojoule, one-per-second. * - COMPOUND: A unit composed of the product of multiple single units. Examples: * meter-per-second, kilowatt-hour, kilogram-meter-per-square-second. - * - SEQUENCE: A unit composed of the sum of multiple compound units. Examples: foot+inch, - * hour+minute+second, hectare+square-meter. + * - SEQUENCE: A unit composed of the sum of multiple single units. Examples: foot+inch, + * hour+minute+second, degree+arcminute+arcsecond. * * The complexity determines which operations are available. For example, you cannot set the power * or SI prefix of a compound unit. @@ -135,91 +135,91 @@ typedef enum UMeasureSIPrefix { UMEASURE_SI_PREFIX_KILO = 3, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: hecto, 10^2. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_HECTO = 2, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: deka, 10^1. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_DEKA = 1, /** - * SI prefix: FIXME, 10^FIXME. + * The absence of an SI prefix. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_ONE = 0, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: deci, 10^-1. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_DECI = -1, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: centi, 10^-2. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_CENTI = -2, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: milli, 10^-3. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_MILLI = -3, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: micro, 10^-6. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_MICRO = -6, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: nano, 10^-9. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_NANO = -9, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: pico, 10^-12. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_PICO = -12, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: femto, 10^-15. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_FEMTO = -15, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: atto, 10^-18. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_ATTO = -18, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: zepto, 10^-21. * * @draft ICU 67 */ UMEASURE_SI_PREFIX_ZEPTO = -21, /** - * SI prefix: FIXME, 10^FIXME. + * SI prefix: yocto, 10^-24. * * @draft ICU 67 */ diff --git a/icu4c/source/test/intltest/measfmttest.cpp b/icu4c/source/test/intltest/measfmttest.cpp index d784abe0d03..639bc6fe22f 100644 --- a/icu4c/source/test/intltest/measfmttest.cpp +++ b/icu4c/source/test/intltest/measfmttest.cpp @@ -3401,6 +3401,22 @@ void MeasureFormatTest::TestCompoundUnitOperations() { assertTrue("one equality", one2 == one3); assertTrue("one-per-one equality", onePerOne == onePerSquareKiloOne); assertTrue("kilometer equality", kilometer == kilometer2); + + // Test out-of-range powers + MeasureUnit power15 = MeasureUnit::forIdentifier("p15-kilometer", status); + verifySingleUnit(power15, UMEASURE_SI_PREFIX_KILO, 15, "p15-kilometer"); + status.errIfFailureAndReset(); + MeasureUnit power16a = MeasureUnit::forIdentifier("p16-kilometer", status); + status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR); + MeasureUnit power16b = power15.product(kilometer, status); + status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR); + MeasureUnit powerN15 = MeasureUnit::forIdentifier("one-per-p15-kilometer", status); + verifySingleUnit(powerN15, UMEASURE_SI_PREFIX_KILO, -15, "one-per-p15-kilometer"); + status.errIfFailureAndReset(); + MeasureUnit powerN16a = MeasureUnit::forIdentifier("one-per-p16-kilometer", status); + status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR); + MeasureUnit powerN16b = powerN15.product(overQuarticKilometer1, status); + status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR); } void MeasureFormatTest::TestIdentifiers() {