* time/tzfile.c (first_transition_after): New function.
(__tzfile_compute): Use it to avoid the need for two gotos.
---
time/tzfile.c | 129 +++++++++++++++++++++++++++-----------------------
1 file changed, 69 insertions(+), 60 deletions(-)
@@ -574,6 +574,70 @@ __tzfile_read (const char *file)
return false;
}
+/* Find index of first transition after TIMER.
+ If there are no transitions after TIMER, return the number of transitions.
+ TIMER must not be less than the first transition (if any). */
+
+static tzidx
+first_transition_after (__time64_t timer)
+{
+ if (timecnt == 0 || timer >= transitions[timecnt - 1])
+ return timecnt;
+
+ tzidx lo = 0;
+ tzidx hi = timecnt - 1;
+
+ /* Find the last transition on or before TIMER.
+ Assume that DST is changing twice a year and guess
+ initial search spot from it. Half of a gregorian year
+ has on average 365.2425 * 86400 / 2 = 15778476 seconds.
+ Although i's value can be wrong if overflow occurs,
+ this is harmless because it is just a guess. */
+
+ __time64_t tdiff;
+ tzidx i;
+ ckd_sub (&tdiff, transitions[timecnt - 1], timer);
+ ckd_add (&i, tdiff / 15778476, 0);
+ if (i < timecnt)
+ {
+ i = timecnt - 1 - i;
+ if (timer < transitions[i])
+ {
+ if (i < 10 || timer >= transitions[i - 10])
+ {
+ /* Linear search. */
+ while (timer < transitions[i - 1])
+ --i;
+ return i;
+ }
+ hi = i - 10;
+ }
+ else
+ {
+ if (timecnt - i <= 10 || timer < transitions[i + 10])
+ {
+ /* Linear search. */
+ while (timer >= transitions[i])
+ ++i;
+ return i;
+ }
+ lo = i + 10;
+ }
+ }
+
+ /* Binary search. */
+ /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
+ while (lo + 1 < hi)
+ {
+ i = (lo >> 1) + (hi >> 1) + (lo & hi & 1);
+ if (timer < transitions[i])
+ hi = i;
+ else
+ lo = i;
+ }
+ return hi;
+}
+
void
__tzfile_compute (__time64_t timer, int use_localtime,
int *leap_correct, bool *leap_hit,
@@ -615,10 +679,12 @@ __tzfile_compute (__time64_t timer, int use_localtime,
}
else
{
- if (timecnt == 0 || timer >= transitions[timecnt - 1])
+ i = first_transition_after (timer);
+ if (i == timecnt)
{
- /* TIMER is after the last transition. Use the TZ string if
- it is present and we can convert to the broken down structure. */
+ /* TIMER is after the last transition, or there are no transitions
+ and a TZ string is present. Use the TZ string if it is present
+ and if we can convert to the broken down structure. */
if (__glibc_likely (tzspec != NULL)
&& __glibc_likely (__offtime (timer, 0, 0, tp) != NULL))
{
@@ -626,64 +692,7 @@ __tzfile_compute (__time64_t timer, int use_localtime,
__tz_compute (timer, tp);
return;
}
-
- i = timecnt;
- }
- else
- {
- /* Find the first transition after TIMER, and
- then pick the type of the transition before it. */
- tzidx lo = 0;
- tzidx hi = timecnt - 1;
- /* Assume that DST is changing twice a year and guess
- initial search spot from it. Half of a gregorian year
- has on average 365.2425 * 86400 / 2 = 15778476 seconds.
- Although i's value can be wrong if overflow occurs,
- this is harmless because it is just a guess. */
- __time64_t tdiff;
- ckd_sub (&tdiff, transitions[timecnt - 1], timer);
- ckd_add (&i, tdiff / 15778476, 0);
- if (i < timecnt)
- {
- i = timecnt - 1 - i;
- if (timer < transitions[i])
- {
- if (i < 10 || timer >= transitions[i - 10])
- {
- /* Linear search. */
- while (timer < transitions[i - 1])
- --i;
- goto found;
- }
- hi = i - 10;
- }
- else
- {
- if (timecnt - i <= 10 || timer < transitions[i + 10])
- {
- /* Linear search. */
- while (timer >= transitions[i])
- ++i;
- goto found;
- }
- lo = i + 10;
- }
- }
-
- /* Binary search. */
- /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
- while (lo + 1 < hi)
- {
- i = (lo >> 1) + (hi >> 1) + (lo & hi & 1);
- if (timer < transitions[i])
- hi = i;
- else
- lo = i;
- }
- i = hi;
}
-
- found:
ti = type_idxs[i - 1];
}