[libcxx-commits] [libcxx] [libc++][chrono] Loads tzdata.zi in tzdb. (PR #74928)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 30 09:29:40 PST 2024


================
@@ -96,6 +121,369 @@ static void __matches(istream& __input, string_view __expected) {
   }
 }
 
+[[nodiscard]] static int64_t __parse_integral(istream& __input, bool __leading_zero_allowed) {
+  int64_t __result = __input.get();
+  if (__leading_zero_allowed) {
+    if (__result < '0' || __result > '9')
+      std::__throw_runtime_error("corrupt tzdb: expected a digit");
+  } else {
+    if (__result < '1' || __result > '9')
+      std::__throw_runtime_error("corrupt tzdb: expected a non-zero digit");
+  }
+  __result -= '0';
+  while (true) {
+    if (__input.peek() < '0' || __input.peek() > '9')
+      return __result;
+
+    // In order to avoid possible overflows we limit the accepted range.
+    // Most values parsed are expected to be very small:
+    // - 8784 hours in a year
+    // - 31 days in a month
+    // - year no real maximum, these values are expected to be less than
+    //   the range of the year type.
+    //
+    // However the leapseconds use a seconds after epoch value. Using an
+    // int would run into an overflow in 2038. By using a 64-bit value
+    // the range is large enough for the bilions of years. Limiting that
+    // range slightly to make the code easier is not an issue.
+    if (__result > (std::numeric_limits<int64_t>::max() / 16))
+      std::__throw_runtime_error("corrupt tzdb: integral too large");
+
+    __result *= 10;
+    __result += __input.get() - '0';
+  }
+}
+
+//===----------------------------------------------------------------------===//
+//                          Calendar
+//===----------------------------------------------------------------------===//
+
+[[nodiscard]] static day __parse_day(istream& __input) {
+  unsigned __result = chrono::__parse_integral(__input, false);
+  if (__result > 31)
+    std::__throw_runtime_error("corrupt tzdb day: value too large");
+  return day{__result};
+}
+
+[[nodiscard]] static weekday __parse_weekday(istream& __input) {
+  // TZDB allows the shortest unique name.
+  switch (std::tolower(__input.get())) {
+  case 'f':
+    chrono::__skip(__input, "riday");
+    return Friday;
+
+  case 'm':
+    chrono::__skip(__input, "onday");
+    return Monday;
+
+  case 's':
+    switch (std::tolower(__input.get())) {
+    case 'a':
+      chrono::__skip(__input, "turday");
+      return Saturday;
+
+    case 'u':
+      chrono::__skip(__input, "unday");
----------------
ldionne wrote:

```suggestion
      chrono::__skip(__input, "nday");
```

Maybe a test too?

https://github.com/llvm/llvm-project/pull/74928


More information about the libcxx-commits mailing list