[54/59] Refactor __tzfile_compute to avoid two gotos

Message ID 20250105055750.1668721-55-eggert@cs.ucla.edu (mailing list archive)
State New
Headers
Series time: sync mktime from Gnulib |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent

Commit Message

Paul Eggert Jan. 5, 2025, 5:57 a.m. UTC
  * 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(-)
  

Patch

diff --git a/time/tzfile.c b/time/tzfile.c
index cde8d74b6f..0ee70fd356 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -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];
     }