From 0563859d8cf7c0d3dfea3b576adca25667d77c17 Mon Sep 17 00:00:00 2001 From: Frank Tang Date: Wed, 28 Feb 2024 21:43:54 +0000 Subject: [PATCH] ICU-22679 Optimize calendar code for edge cases See #2853 --- icu4c/source/i18n/islamcal.cpp | 46 +++++++++++++++------------------- icu4c/source/i18n/islamcal.h | 5 ---- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/icu4c/source/i18n/islamcal.cpp b/icu4c/source/i18n/islamcal.cpp index f71cbdc821f..15ac84407bd 100644 --- a/icu4c/source/i18n/islamcal.cpp +++ b/icu4c/source/i18n/islamcal.cpp @@ -192,15 +192,6 @@ static const int UMALQURA_MONTHLENGTH[] = { 0x06AA, 0x0AD6, 0x055D, 0x029D }; -int32_t getUmalqura_MonthLength(int32_t y, int32_t m) { - int32_t mask = (int32_t) (0x01 << (11 - m)); // set mask for bit corresponding to month - if((UMALQURA_MONTHLENGTH[y] & mask) == 0 ) - return 29; - else - return 30; - -} - //------------------------------------------------------------------------- // Constructors... //------------------------------------------------------------------------- @@ -311,8 +302,7 @@ static const int8_t umAlQuraYrStartEstimateFix[] = { /** * Determine whether a year is a leap year in the Islamic civil calendar */ -UBool IslamicCalendar::civilLeapYear(int32_t year) -{ +inline bool civilLeapYear(int32_t year) { return (14 + 11 * year) % 30 < 11; } @@ -877,7 +867,8 @@ int32_t IslamicUmalquraCalendar::handleGetMonthLength(int32_t extendedYear, int3 } return length; } - return getUmalqura_MonthLength(extendedYear - UMALQURA_YEAR_START, month); + int32_t mask = (int32_t) (0x01 << (11 - month)); // set mask for bit corresponding to month + return ((UMALQURA_MONTHLENGTH[extendedYear - UMALQURA_YEAR_START] & mask) == 0) ? 29 : 30; } /** @@ -926,28 +917,31 @@ void IslamicUmalquraCalendar::handleComputeFields(int32_t julianDay, UErrorCode month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 ); month = month < 11 ? month : 11; } else { - int y =UMALQURA_YEAR_START-1, m =0; - long d = 1; + // Estimate a value y which is closer to but not greater than the year. + // It is the inverse function of the logic inside + // IslamicUmalquraCalendar::yearStart(). + year = ((double(days) - (460322.05 + 0.5)) / 354.36720) + + UMALQURA_YEAR_START - 1; + month = 0; + int32_t d = 1; + // need a slight correction to some while (d > 0) { - y++; - d = days - yearStart(y) +1; - if (d == handleGetYearLength(y)) { - m=11; + d = days - yearStart(++year) + 1; + int32_t yearLength = handleGetYearLength(year); + if (d == yearLength) { + month = 11; break; } - if (d < handleGetYearLength(y)){ - int monthLen = handleGetMonthLength(y, m); - m=0; - while(d > monthLen){ + if (d < yearLength){ + int32_t monthLen = handleGetMonthLength(year, month); + for (month = 0; + d > monthLen; + monthLen = handleGetMonthLength(year, ++month)) { d -= monthLen; - m++; - monthLen = handleGetMonthLength(y, m); } break; } } - year = y; - month = m; } dayOfMonth = (days - monthStart(year, month)) + 1; diff --git a/icu4c/source/i18n/islamcal.h b/icu4c/source/i18n/islamcal.h index 196f3454c99..2cbd07f46ad 100644 --- a/icu4c/source/i18n/islamcal.h +++ b/icu4c/source/i18n/islamcal.h @@ -197,11 +197,6 @@ class U_I18N_API IslamicCalendar : public Calendar { virtual IslamicCalendar* clone() const override; protected: - /** - * Determine whether a year is a leap year in the Islamic civil calendar - */ - static UBool civilLeapYear(int32_t year); - /** * Return the day # on which the given year starts. Days are counted * from the Hijri epoch, origin 0.