-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++][TZDB] Fixes parsing interleaved rules. #84808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Typically the rules in the database are contiguous, but that is not a requirement. This fixes the case when they are not.
@llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante) ChangesTypically the rules in the database are contiguous, but that is not a requirement. This fixes the case when they are not. Full diff: https://github.com/llvm/llvm-project/pull/84808.diff 2 Files Affected:
diff --git a/libcxx/src/tzdb.cpp b/libcxx/src/tzdb.cpp
index 2bb801e48694ee..49985b870d8525 100644
--- a/libcxx/src/tzdb.cpp
+++ b/libcxx/src/tzdb.cpp
@@ -511,14 +511,33 @@ static string __parse_version(istream& __input) {
return chrono::__parse_string(__input);
}
+[[nodiscard]]
+static __tz::__rule& __create_entry(__tz::__rules_storage_type& __rules, const string& __name) {
+ auto __result = [&]() -> __tz::__rule& {
+ auto& __rule = __rules.emplace_back(__name, vector<__tz::__rule>{});
+ return __rule.second.emplace_back();
+ };
+
+ if (__rules.empty())
+ return __result();
+
+ // Typically rules are in contiguous order in the database.
+ // But there are exceptions. For example, NZ and Chatham are interleaved.
+ if (__rules.back().first == __name)
+ return __rules.back().second.emplace_back();
+
+ if (auto __it = ranges::find(__rules, __name, [](const auto& __r) { return __r.first; });
+ __it != ranges::end(__rules))
+ return __it->second.emplace_back();
+
+ return __result();
+}
+
static void __parse_rule(tzdb& __tzdb, __tz::__rules_storage_type& __rules, istream& __input) {
chrono::__skip_mandatory_whitespace(__input);
string __name = chrono::__parse_string(__input);
- if (__rules.empty() || __rules.back().first != __name)
- __rules.emplace_back(__name, vector<__tz::__rule>{});
-
- __tz::__rule& __rule = __rules.back().second.emplace_back();
+ __tz::__rule& __rule = __create_entry(__rules, __name);
chrono::__skip_mandatory_whitespace(__input);
__rule.__from = chrono::__parse_year(__input);
diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.db/rules.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.db/rules.pass.cpp
index 5ae2ed1e91ebe5..4814f4aad87fbc 100644
--- a/libcxx/test/libcxx/time/time.zone/time.zone.db/rules.pass.cpp
+++ b/libcxx/test/libcxx/time/time.zone/time.zone.db/rules.pass.cpp
@@ -550,6 +550,29 @@ R a 0 1 - Ja Su>=31 1w 2s abc
assert(result.rules[0].second[2].__letters == "abc");
}
+static void test_mixed_order() {
+ // This is a part of the real database. The interesting part is that the
+ // rules NZ and Chatham are interleaved. Make sure the parse algorithm
+ // handles this correctly.
+ parse_result result{
+ R"(
+# Since 1957 Chatham has been 45 minutes ahead of NZ, but until 2018a
+# there was no documented single notation for the date and time of this
+# transition. Duplicate the Rule lines for now, to give the 2018a change
+# time to percolate out.
+Rule NZ 1974 only - Nov Sun>=1 2:00s 1:00 D
+Rule Chatham 1974 only - Nov Sun>=1 2:45s 1:00 -
+Rule NZ 1975 only - Feb lastSun 2:00s 0 S
+Rule Chatham 1975 only - Feb lastSun 2:45s 0 -
+Rule NZ 1975 1988 - Oct lastSun 2:00s 1:00 D
+Rule Chatham 1975 1988 - Oct lastSun 2:45s 1:00 -
+)"};
+
+ assert(result.rules.size() == 2);
+ assert(result.rules[0].second.size() == 3);
+ assert(result.rules[1].second.size() == 3);
+}
+
int main(int, const char**) {
test_invalid();
test_name();
@@ -560,6 +583,7 @@ int main(int, const char**) {
test_at();
test_save();
test_letter();
+ test_mixed_order();
return 0;
}
|
You can test this locally with the following command:git-clang-format --diff a066f71e70b9cbfdc2f2eb41e7c4d8372d216a6e eac58f6cacea5639b8a938b9d603203a275449ff -- libcxx/src/tzdb.cpp libcxx/test/libcxx/time/time.zone/time.zone.db/rules.pass.cpp View the diff from clang-format here.diff --git a/libcxx/src/tzdb.cpp b/libcxx/src/tzdb.cpp
index 0307f754ca..c2b477fd19 100644
--- a/libcxx/src/tzdb.cpp
+++ b/libcxx/src/tzdb.cpp
@@ -511,8 +511,7 @@ static string __parse_version(istream& __input) {
return chrono::__parse_string(__input);
}
-[[nodiscard]]
-static __tz::__rule& __create_entry(__tz::__rules_storage_type& __rules, const string& __name) {
+[[nodiscard]] static __tz::__rule& __create_entry(__tz::__rules_storage_type& __rules, const string& __name) {
auto __result = [&]() -> __tz::__rule& {
auto& __rule = __rules.emplace_back(__name, vector<__tz::__rule>{});
return __rule.second.emplace_back();
|
ldionne
approved these changes
Mar 12, 2024
Co-authored-by: Louis Dionne <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Typically the rules in the database are contiguous, but that is not a requirement. This fixes the case when they are not.