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