224 lines
9.2 KiB
Diff
224 lines
9.2 KiB
Diff
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
index e8b2f34..97b34ac 100644
|
|
--- a/CMakeLists.txt
|
|
+++ b/CMakeLists.txt
|
|
@@ -178,3 +178,5 @@ install(FILES cmake/${PROJECT_NAME}-config.cmake
|
|
)
|
|
|
|
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
|
+
|
|
+SET(CMAKE_CXX_FLAGS "-fno-omit-frame-pointer -O3 -g -gdwarf-4 ${CMAKE_CXX_FLAGS}")
|
|
diff --git a/include/cctz/civil_time_detail.h b/include/cctz/civil_time_detail.h
|
|
index decc5f2..3f7d6c8 100644
|
|
--- a/include/cctz/civil_time_detail.h
|
|
+++ b/include/cctz/civil_time_detail.h
|
|
@@ -186,13 +186,13 @@ CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch,
|
|
CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm,
|
|
diff_t ss) noexcept {
|
|
// Optimization for when (non-constexpr) fields are already normalized.
|
|
- if (0 <= ss && ss < 60) {
|
|
+ if (__builtin_expect(0 <= ss && ss < 60, 1)) {
|
|
const second_t nss = static_cast<second_t>(ss);
|
|
- if (0 <= mm && mm < 60) {
|
|
+ if (__builtin_expect(0 <= mm && mm < 60, 1)) {
|
|
const minute_t nmm = static_cast<minute_t>(mm);
|
|
- if (0 <= hh && hh < 24) {
|
|
+ if (__builtin_expect(0 <= hh && hh < 24, 1)) {
|
|
const hour_t nhh = static_cast<hour_t>(hh);
|
|
- if (1 <= d && d <= 28 && 1 <= m && m <= 12) {
|
|
+ if (__builtin_expect(1 <= d && d <= 28 && 1 <= m && m <= 12, 1)) {
|
|
const day_t nd = static_cast<day_t>(d);
|
|
const month_t nm = static_cast<month_t>(m);
|
|
return fields(y, nm, nd, nhh, nmm, nss);
|
|
diff --git a/include/cctz/time_zone.h b/include/cctz/time_zone.h
|
|
index f97ea26..cdbd6a9 100644
|
|
--- a/include/cctz/time_zone.h
|
|
+++ b/include/cctz/time_zone.h
|
|
@@ -104,6 +104,14 @@ class time_zone {
|
|
return lookup(detail::split_seconds(tp).first);
|
|
}
|
|
|
|
+ // Lookup the UTC offset for a timepoint
|
|
+ // The returned the lookup result doesn't contain valid cs
|
|
+ absolute_lookup lookup_offset(const time_point<seconds> &tp) const;
|
|
+ template <typename D>
|
|
+ absolute_lookup lookup_offset(const time_point<D> &tp) const {
|
|
+ return lookup_offset(detail::split_seconds(tp).first);
|
|
+ }
|
|
+
|
|
// A civil_lookup represents the absolute time(s) (time_point) that
|
|
// correspond to the given civil time (cctz::civil_second) within this
|
|
// time_zone. Usually the given civil time represents a unique instant
|
|
diff --git a/src/cctz_benchmark.cc b/src/cctz_benchmark.cc
|
|
index 179ae50..168cba5 100644
|
|
--- a/src/cctz_benchmark.cc
|
|
+++ b/src/cctz_benchmark.cc
|
|
@@ -797,6 +797,24 @@ void BM_Time_ToCivil_CCTZ(benchmark::State& state) {
|
|
}
|
|
BENCHMARK(BM_Time_ToCivil_CCTZ);
|
|
|
|
+void BM_Time_ToCivil_LookupOffset_Batch1024(benchmark::State &state) {
|
|
+ const cctz::time_zone tz = TestTimeZone();
|
|
+ std::chrono::system_clock::time_point tp =
|
|
+ std::chrono::system_clock::from_time_t(1750656243);
|
|
+ std::chrono::system_clock::time_point tp2 =
|
|
+ std::chrono::system_clock::from_time_t(1750656245);
|
|
+ while (state.KeepRunning()) {
|
|
+ std::swap(tp, tp2);
|
|
+ // benchmark::DoNotOptimize(tz.lookup(tp).cs);
|
|
+
|
|
+ for (int i = 0; i < 1024; i++) {
|
|
+ tp += std::chrono::seconds(1);
|
|
+ benchmark::DoNotOptimize(tz.lookup_offset(tp).cs);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+BENCHMARK(BM_Time_ToCivil_LookupOffset_Batch1024);
|
|
+
|
|
void BM_Time_ToCivil_Libc(benchmark::State& state) {
|
|
// No timezone support, so just use localtime.
|
|
time_t t = 1384569027;
|
|
diff --git a/src/time_zone_if.h b/src/time_zone_if.h
|
|
index f925c6c..01af988 100644
|
|
--- a/src/time_zone_if.h
|
|
+++ b/src/time_zone_if.h
|
|
@@ -36,6 +36,10 @@ class TimeZoneIf {
|
|
|
|
virtual time_zone::absolute_lookup BreakTime(
|
|
const time_point<seconds>& tp) const = 0;
|
|
+ virtual time_zone::absolute_lookup
|
|
+ LookupOffset(const time_point<seconds> &tp) const {
|
|
+ return BreakTime(tp);
|
|
+ }
|
|
virtual time_zone::civil_lookup MakeTime(
|
|
const civil_second& cs) const = 0;
|
|
|
|
diff --git a/src/time_zone_impl.h b/src/time_zone_impl.h
|
|
index 23fcddb..16f26ec 100644
|
|
--- a/src/time_zone_impl.h
|
|
+++ b/src/time_zone_impl.h
|
|
@@ -50,6 +50,10 @@ class time_zone::Impl {
|
|
return zone_->BreakTime(tp);
|
|
}
|
|
|
|
+ time_zone::absolute_lookup LookupOffset(const time_point<seconds> &tp) const {
|
|
+ return zone_->LookupOffset(tp);
|
|
+ }
|
|
+
|
|
// Converts the civil-time components in this time zone into a time_point.
|
|
// That is, the opposite of BreakTime(). The requested civil time may be
|
|
// ambiguous or illegal due to a change of UTC offset.
|
|
diff --git a/src/time_zone_info.cc b/src/time_zone_info.cc
|
|
index eb1cd8a..031c8c4 100644
|
|
--- a/src/time_zone_info.cc
|
|
+++ b/src/time_zone_info.cc
|
|
@@ -751,6 +751,64 @@ time_zone::absolute_lookup TimeZoneInfo::LocalTime(
|
|
tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
|
|
}
|
|
|
|
+time_zone::absolute_lookup
|
|
+TimeZoneInfo::Offset(std::int_fast64_t unix_time,
|
|
+ const TransitionType &tt) const {
|
|
+ return {{}, tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
|
|
+}
|
|
+
|
|
+time_zone::absolute_lookup TimeZoneInfo::Offset(std::int_fast64_t unix_time,
|
|
+ const Transition &tr) const {
|
|
+ const TransitionType &tt = transition_types_[tr.type_index];
|
|
+ // std::int_fast64_t local_unix = unix_time + tt.utc_offset;
|
|
+ return {{}, tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
|
|
+}
|
|
+
|
|
+time_zone::absolute_lookup
|
|
+TimeZoneInfo::LookupOffset(const time_point<seconds> &tp) const {
|
|
+ std::int_fast64_t unix_time = ToUnixSeconds(tp);
|
|
+ const std::size_t timecnt = transitions_.size();
|
|
+ assert(timecnt != 0); // We always add a transition.
|
|
+
|
|
+ const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed);
|
|
+ // This branch is likely to be taken if the hint is valid and the unix_time
|
|
+ // falls within the hinted transition range.
|
|
+ if (0 < hint && hint < timecnt) [[likely]] {
|
|
+ if (transitions_[hint - 1].unix_time <= unix_time) [[likely]] {
|
|
+ if (unix_time < transitions_[hint].unix_time) [[likely]] {
|
|
+ return Offset(unix_time, transitions_[hint - 1]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((unix_time < transitions_[0].unix_time)) {
|
|
+ return Offset(unix_time, transition_types_[default_transition_type_]);
|
|
+ }
|
|
+ if (unix_time >= transitions_.back().unix_time) {
|
|
+ // After the last transition. If we extended the transitions using
|
|
+ // future_spec_, shift back to a supported year using the 400-year
|
|
+ // cycle of calendaric equivalence and then compensate accordingly.
|
|
+ if (extended_) {
|
|
+ const std::int_fast64_t diff =
|
|
+ unix_time - transitions_[timecnt - 1].unix_time;
|
|
+ const year_t shift = diff / kSecsPer400Years + 1;
|
|
+ const auto d = seconds(shift * kSecsPer400Years);
|
|
+ time_zone::absolute_lookup al = BreakTime(tp - d);
|
|
+ al.cs = YearShift(al.cs, shift * 400);
|
|
+ return al;
|
|
+ }
|
|
+ return Offset(unix_time, transitions_[timecnt - 1]);
|
|
+ }
|
|
+
|
|
+ const Transition target = {unix_time, 0, civil_second(), civil_second()};
|
|
+ const Transition *begin = &transitions_[0];
|
|
+ const Transition *tr = std::upper_bound(begin, begin + timecnt, target,
|
|
+ Transition::ByUnixTime());
|
|
+ local_time_hint_.store(static_cast<std::size_t>(tr - begin),
|
|
+ std::memory_order_relaxed);
|
|
+ return Offset(unix_time, *--tr);
|
|
+}
|
|
+
|
|
// BreakTime() translation for a particular transition.
|
|
time_zone::absolute_lookup TimeZoneInfo::LocalTime(
|
|
std::int_fast64_t unix_time, const Transition& tr) const {
|
|
diff --git a/src/time_zone_info.h b/src/time_zone_info.h
|
|
index 4657a2d..dea4431 100644
|
|
--- a/src/time_zone_info.h
|
|
+++ b/src/time_zone_info.h
|
|
@@ -70,6 +70,8 @@ class TimeZoneInfo : public TimeZoneIf {
|
|
// TimeZoneIf implementations.
|
|
time_zone::absolute_lookup BreakTime(
|
|
const time_point<seconds>& tp) const override;
|
|
+ time_zone::absolute_lookup
|
|
+ LookupOffset(const time_point<seconds> &tp) const override;
|
|
time_zone::civil_lookup MakeTime(
|
|
const civil_second& cs) const override;
|
|
bool NextTransition(const time_point<seconds>& tp,
|
|
@@ -103,8 +105,13 @@ class TimeZoneInfo : public TimeZoneIf {
|
|
bool Load(const std::string& name, ZoneInfoSource* zip);
|
|
|
|
// Helpers for BreakTime() and MakeTime().
|
|
+ time_zone::absolute_lookup Offset(std::int_fast64_t unix_time,
|
|
+ const Transition &tr) const;
|
|
+ time_zone::absolute_lookup Offset(std::int_fast64_t unix_time,
|
|
+ const TransitionType &tt) const;
|
|
+
|
|
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
|
|
- const TransitionType& tt) const;
|
|
+ const TransitionType &tt) const;
|
|
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
|
|
const Transition& tr) const;
|
|
time_zone::civil_lookup TimeLocal(const civil_second& cs,
|
|
diff --git a/src/time_zone_lookup.cc b/src/time_zone_lookup.cc
|
|
index 2a38a9b..a97ac2f 100644
|
|
--- a/src/time_zone_lookup.cc
|
|
+++ b/src/time_zone_lookup.cc
|
|
@@ -73,6 +73,11 @@ time_zone::absolute_lookup time_zone::lookup(
|
|
return effective_impl().BreakTime(tp);
|
|
}
|
|
|
|
+time_zone::absolute_lookup
|
|
+time_zone::lookup_offset(const time_point<seconds> &tp) const {
|
|
+ return effective_impl().LookupOffset(tp);
|
|
+}
|
|
+
|
|
time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const {
|
|
return effective_impl().MakeTime(cs);
|
|
}
|