diff --git a/tz.cpp b/tz.cpp index 6c0e3d8..39bae30 100644 --- a/tz.cpp +++ b/tz.cpp @@ -1249,6 +1249,9 @@ Zone::zonelet::zonelet(const zonelet& i) } Zone::Zone(const std::string& s) +#if LAZY_INIT + : adjusted_(new std::once_flag{}) +#endif { try { @@ -1566,24 +1569,22 @@ Zone::adjust_infos(const std::vector& rules) const zonelet* prev_zonelet = nullptr; for (auto& z : zonelets_) { + std::pair eqr{}; + std::istringstream in; + in.exceptions(std::ios::failbit | std::ios::badbit); // Classify info as rule-based, has save, or neither if (!z.u.rule_.empty()) { // Find out if this zonelet has a rule or a save - auto i = std::lower_bound(rules.begin(), rules.end(), z.u.rule_, - [](const Rule& r, const std::string& nm) - { - return r.name() < nm; - }); - if (i == rules.end() || i->name() != z.u.rule_) + eqr = std::equal_range(rules.data(), rules.data() + rules.size(), z.u.rule_); + if (eqr.first == eqr.second) { // The rule doesn't exist. Assume this is a save try { using namespace std::chrono; using string = std::string; - std::istringstream in(z.u.rule_); - in.exceptions(std::ios::failbit | std::ios::badbit); + in.str(z.u.rule_); auto tmp = duration_cast(parse_signed_time(in)); #if !defined(_MSC_VER) || (_MSC_VER >= 1900) z.u.rule_.~string(); @@ -1608,13 +1609,6 @@ Zone::adjust_infos(const std::vector& rules) z.tag_ = zonelet::is_empty; } - std::pair eqr{}; - if (z.tag_ == zonelet::has_rule) - { - eqr = std::equal_range(rules.data(), rules.data() + rules.size(), z.u.rule_); - assert(eqr.first != eqr.second); - } - minutes final_save{0}; if (z.tag_ == zonelet::has_save) { @@ -1750,6 +1744,12 @@ Zone::get_info(std::chrono::system_clock::time_point tp, tz timezone) const " is out of range:[" + std::to_string(static_cast(min_year)) + ", " + std::to_string(static_cast(max_year)) + "]"); auto tps = floor(tp); +#if LAZY_INIT + std::call_once(*adjusted_, [this]() + { + const_cast(this)->adjust_infos(get_tzdb().rules); + }); +#endif auto i = std::upper_bound(zonelets_.begin(), zonelets_.end(), tps, [timezone](second_point t, const zonelet& zl) { @@ -1803,6 +1803,12 @@ operator<<(std::ostream& os, const Zone& z) detail::save_stream _(os); os.fill(' '); os.flags(std::ios::dec | std::ios::left); +#if LAZY_INIT + std::call_once(*z.adjusted_, [&z]() + { + const_cast(z).adjust_infos(get_tzdb().rules); + }); +#endif os.width(35); os << z.name_; std::string indent; @@ -1909,9 +1915,8 @@ init_tzdb() std::ifstream infile(path + "Makefile"); while (infile) { - std::string version; - infile >> version; - if (version == "VERSION=") + infile >> line; + if (line == "VERSION=") { infile >> db.version; break; @@ -1966,8 +1971,10 @@ init_tzdb() std::sort(db.rules.begin(), db.rules.end()); Rule::split_overlaps(db.rules); std::sort(db.zones.begin(), db.zones.end()); +#if !LAZY_INIT for (auto& z : db.zones) z.adjust_infos(db.rules); +#endif db.zones.shrink_to_fit(); std::sort(db.links.begin(), db.links.end()); db.links.shrink_to_fit(); diff --git a/tz.h b/tz.h index 5412775..0533179 100644 --- a/tz.h +++ b/tz.h @@ -50,6 +50,10 @@ Technically any OS may use the mapping process but currently only Windows does u #endif #endif +#ifndef LAZY_INIT +# define LAZY_INIT 1 +#endif + #include "date.h" #include @@ -200,6 +204,9 @@ private: std::string name_; std::vector zonelets_; +#if LAZY_INIT + std::unique_ptr adjusted_; +#endif public: #if !defined(_MSC_VER) || (_MSC_VER >= 1900) @@ -207,15 +214,20 @@ public: Zone& operator=(Zone&&) = default; #else // defined(_MSC_VER) || (_MSC_VER >= 1900) Zone(Zone&& src) - : - name_(std::move(src.name_)), - zonelets_(std::move(src.zonelets_)) + : name_(std::move(src.name_)) + , zonelets_(std::move(src.zonelets_)) +#if LAZY_INIT + , adjusted_(std::move(src.adjusted_)) +#endif {} Zone& operator=(Zone&& src) { name_ = std::move(src.name_); zonelets_ = std::move(src.zonelets_); +#if LAZY_INIT + adjusted_ = std::move(src.adjusted_); +#endif return *this; } #endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)