forked from HowardHinnant/date
Replace list<TZ_DB> with tzdb_list
* tzdb_list is a singly linked list with an atomic head * push_front() and front() are thread safe.
This commit is contained in:
110
tz.cpp
110
tz.cpp
@@ -96,7 +96,6 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <list>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#if USE_OS_TZDB
|
#if USE_OS_TZDB
|
||||||
# include <queue>
|
# include <queue>
|
||||||
@@ -320,21 +319,54 @@ struct undocumented {explicit undocumented() = default;};
|
|||||||
static_assert(min_year <= max_year, "Configuration error");
|
static_assert(min_year <= max_year, "Configuration error");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static TZ_DB init_tzdb();
|
static std::unique_ptr<TZ_DB> init_tzdb();
|
||||||
|
|
||||||
|
tzdb_list::~tzdb_list()
|
||||||
|
{
|
||||||
|
const TZ_DB* ptr = head_;
|
||||||
|
head_ = nullptr;
|
||||||
|
while (ptr != nullptr)
|
||||||
|
{
|
||||||
|
auto next = ptr->next;
|
||||||
|
delete ptr;
|
||||||
|
ptr = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tzdb_list::tzdb_list(tzdb_list&& x) noexcept
|
||||||
|
: head_{x.head_.exchange(nullptr)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tzdb_list::push_front(TZ_DB* tzdb) noexcept
|
||||||
|
{
|
||||||
|
tzdb->next = head_;
|
||||||
|
head_ = tzdb;
|
||||||
|
}
|
||||||
|
|
||||||
|
tzdb_list::const_iterator
|
||||||
|
tzdb_list::erase_after(const_iterator p) noexcept
|
||||||
|
{
|
||||||
|
auto t = p.p_->next;
|
||||||
|
p.p_->next = p.p_->next->next;
|
||||||
|
delete t;
|
||||||
|
return ++p;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
std::list<TZ_DB>
|
tzdb_list
|
||||||
create_tzdb()
|
create_tzdb()
|
||||||
{
|
{
|
||||||
std::list<TZ_DB> tz_db;
|
tzdb_list tz_db;
|
||||||
tz_db.push_back(init_tzdb());
|
tz_db.push_front(init_tzdb().release());
|
||||||
return tz_db;
|
return tz_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<TZ_DB>&
|
tzdb_list&
|
||||||
get_tzdb_list()
|
get_tzdb_list()
|
||||||
{
|
{
|
||||||
static std::list<TZ_DB> tz_db = create_tzdb();
|
static tzdb_list tz_db = create_tzdb();
|
||||||
return tz_db;
|
return tz_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2493,10 +2525,10 @@ get_version()
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
static
|
static
|
||||||
TZ_DB
|
std::unique_ptr<TZ_DB>
|
||||||
init_tzdb()
|
init_tzdb()
|
||||||
{
|
{
|
||||||
TZ_DB db;
|
std::unique_ptr<TZ_DB> db(new TZ_DB);
|
||||||
|
|
||||||
//Iterate through folders
|
//Iterate through folders
|
||||||
std::queue<std::string> subfolders;
|
std::queue<std::string> subfolders;
|
||||||
@@ -2535,22 +2567,22 @@ init_tzdb()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
db.zones.emplace_back(subname.substr(sizeof(tz_dir)),
|
db->zones.emplace_back(subname.substr(sizeof(tz_dir)),
|
||||||
detail::undocumented{});
|
detail::undocumented{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
}
|
}
|
||||||
db.zones.shrink_to_fit();
|
db->zones.shrink_to_fit();
|
||||||
std::sort(db.zones.begin(), db.zones.end());
|
std::sort(db->zones.begin(), db->zones.end());
|
||||||
# if !MISSING_LEAP_SECONDS
|
# if !MISSING_LEAP_SECONDS
|
||||||
std::ifstream in(tz_dir + std::string(1, folder_delimiter) + "right/UTC",
|
std::ifstream in(tz_dir + std::string(1, folder_delimiter) + "right/UTC",
|
||||||
std::ios_base::binary);
|
std::ios_base::binary);
|
||||||
if (in)
|
if (in)
|
||||||
{
|
{
|
||||||
in.exceptions(std::ios::failbit | std::ios::badbit);
|
in.exceptions(std::ios::failbit | std::ios::badbit);
|
||||||
db.leaps = load_just_leaps(in);
|
db->leaps = load_just_leaps(in);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2559,11 +2591,11 @@ init_tzdb()
|
|||||||
if (!in)
|
if (!in)
|
||||||
throw std::runtime_error("Unable to extract leap second information");
|
throw std::runtime_error("Unable to extract leap second information");
|
||||||
in.exceptions(std::ios::failbit | std::ios::badbit);
|
in.exceptions(std::ios::failbit | std::ios::badbit);
|
||||||
db.leaps = load_just_leaps(in);
|
db->leaps = load_just_leaps(in);
|
||||||
}
|
}
|
||||||
# endif // !MISSING_LEAP_SECONDS
|
# endif // !MISSING_LEAP_SECONDS
|
||||||
# ifdef __APPLE__
|
# ifdef __APPLE__
|
||||||
db.version = get_version();
|
db->version = get_version();
|
||||||
# endif
|
# endif
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
@@ -3200,7 +3232,7 @@ get_version(const std::string& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TZ_DB
|
std::unique_ptr<TZ_DB>
|
||||||
init_tzdb()
|
init_tzdb()
|
||||||
{
|
{
|
||||||
using namespace date;
|
using namespace date;
|
||||||
@@ -3208,7 +3240,7 @@ init_tzdb()
|
|||||||
const std::string path = install + folder_delimiter;
|
const std::string path = install + folder_delimiter;
|
||||||
std::string line;
|
std::string line;
|
||||||
bool continue_zone = false;
|
bool continue_zone = false;
|
||||||
TZ_DB db;
|
std::unique_ptr<TZ_DB> db(new TZ_DB);
|
||||||
|
|
||||||
#if AUTO_DOWNLOAD
|
#if AUTO_DOWNLOAD
|
||||||
if (!file_exists(install))
|
if (!file_exists(install))
|
||||||
@@ -3233,18 +3265,18 @@ init_tzdb()
|
|||||||
msg += "\"";
|
msg += "\"";
|
||||||
throw std::runtime_error(msg);
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
db.version = get_version(path);
|
db->version = get_version(path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
db.version = get_version(path);
|
db->version = get_version(path);
|
||||||
auto rv = remote_version();
|
auto rv = remote_version();
|
||||||
if (!rv.empty() && db.version != rv)
|
if (!rv.empty() && db->version != rv)
|
||||||
{
|
{
|
||||||
if (remote_download(rv))
|
if (remote_download(rv))
|
||||||
{
|
{
|
||||||
remote_install(rv);
|
remote_install(rv);
|
||||||
db.version = get_version(path);
|
db->version = get_version(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3256,7 +3288,7 @@ init_tzdb()
|
|||||||
msg += "\"";
|
msg += "\"";
|
||||||
throw std::runtime_error(msg);
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
db.version = get_version(path);
|
db->version = get_version(path);
|
||||||
#endif // !AUTO_DOWNLOAD
|
#endif // !AUTO_DOWNLOAD
|
||||||
|
|
||||||
CONSTDATA char*const files[] =
|
CONSTDATA char*const files[] =
|
||||||
@@ -3278,27 +3310,27 @@ init_tzdb()
|
|||||||
in >> word;
|
in >> word;
|
||||||
if (word == "Rule")
|
if (word == "Rule")
|
||||||
{
|
{
|
||||||
db.rules.push_back(Rule(line));
|
db->rules.push_back(Rule(line));
|
||||||
continue_zone = false;
|
continue_zone = false;
|
||||||
}
|
}
|
||||||
else if (word == "Link")
|
else if (word == "Link")
|
||||||
{
|
{
|
||||||
db.links.push_back(link(line));
|
db->links.push_back(link(line));
|
||||||
continue_zone = false;
|
continue_zone = false;
|
||||||
}
|
}
|
||||||
else if (word == "Leap")
|
else if (word == "Leap")
|
||||||
{
|
{
|
||||||
db.leaps.push_back(leap(line, detail::undocumented{}));
|
db->leaps.push_back(leap(line, detail::undocumented{}));
|
||||||
continue_zone = false;
|
continue_zone = false;
|
||||||
}
|
}
|
||||||
else if (word == "Zone")
|
else if (word == "Zone")
|
||||||
{
|
{
|
||||||
db.zones.push_back(time_zone(line, detail::undocumented{}));
|
db->zones.push_back(time_zone(line, detail::undocumented{}));
|
||||||
continue_zone = true;
|
continue_zone = true;
|
||||||
}
|
}
|
||||||
else if (line[0] == '\t' && continue_zone)
|
else if (line[0] == '\t' && continue_zone)
|
||||||
{
|
{
|
||||||
db.zones.back().add(line);
|
db->zones.back().add(line);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3307,19 +3339,19 @@ 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());
|
||||||
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();
|
||||||
std::sort(db.leaps.begin(), db.leaps.end());
|
std::sort(db->leaps.begin(), db->leaps.end());
|
||||||
db.leaps.shrink_to_fit();
|
db->leaps.shrink_to_fit();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::string mapping_file = get_install() + folder_delimiter + "windowsZones.xml";
|
std::string mapping_file = get_install() + folder_delimiter + "windowsZones.xml";
|
||||||
db.mappings = load_timezone_mappings_from_xml_file(mapping_file);
|
db->mappings = load_timezone_mappings_from_xml_file(mapping_file);
|
||||||
sort_zone_mappings(db.mappings);
|
sort_zone_mappings(db->mappings);
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
@@ -3333,7 +3365,7 @@ reload_tzdb()
|
|||||||
if (!v.empty() && v == remote_version())
|
if (!v.empty() && v == remote_version())
|
||||||
return get_tzdb_list().front();
|
return get_tzdb_list().front();
|
||||||
#endif // AUTO_DOWNLOAD
|
#endif // AUTO_DOWNLOAD
|
||||||
get_tzdb_list().push_front(init_tzdb());
|
get_tzdb_list().push_front(init_tzdb().release());
|
||||||
return get_tzdb_list().front();
|
return get_tzdb_list().front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
90
tz.h
90
tz.h
@@ -110,10 +110,10 @@ static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <list>
|
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -1144,6 +1144,7 @@ struct TZ_DB
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::vector<detail::timezone_mapping> mappings;
|
std::vector<detail::timezone_mapping> mappings;
|
||||||
#endif
|
#endif
|
||||||
|
TZ_DB* next = nullptr;
|
||||||
|
|
||||||
TZ_DB() = default;
|
TZ_DB() = default;
|
||||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||||
@@ -1183,7 +1184,92 @@ DATE_API std::ostream&
|
|||||||
operator<<(std::ostream& os, const TZ_DB& db);
|
operator<<(std::ostream& os, const TZ_DB& db);
|
||||||
|
|
||||||
DATE_API const TZ_DB& get_tzdb();
|
DATE_API const TZ_DB& get_tzdb();
|
||||||
DATE_API std::list<TZ_DB>& get_tzdb_list();
|
|
||||||
|
class tzdb_list
|
||||||
|
{
|
||||||
|
std::atomic<TZ_DB*> head_{nullptr};
|
||||||
|
|
||||||
|
public:
|
||||||
|
~tzdb_list();
|
||||||
|
tzdb_list() = default;
|
||||||
|
tzdb_list(tzdb_list&& x) noexcept;
|
||||||
|
|
||||||
|
void push_front(TZ_DB* tzdb) noexcept;
|
||||||
|
const TZ_DB& front() const noexcept {return *head_;}
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
const_iterator begin() const noexcept;
|
||||||
|
const_iterator end() const noexcept;
|
||||||
|
|
||||||
|
const_iterator cbegin() const noexcept;
|
||||||
|
const_iterator cend() const noexcept;
|
||||||
|
|
||||||
|
const_iterator erase_after(const_iterator p) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
class tzdb_list::const_iterator
|
||||||
|
{
|
||||||
|
TZ_DB* p_ = nullptr;
|
||||||
|
|
||||||
|
explicit const_iterator(TZ_DB* p) noexcept : p_{p} {}
|
||||||
|
public:
|
||||||
|
const_iterator() = default;
|
||||||
|
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using value_type = TZ_DB;
|
||||||
|
using reference = const value_type&;
|
||||||
|
using pointer = const value_type*;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
|
reference operator*() const noexcept {return *p_;}
|
||||||
|
pointer operator->() const noexcept {return p_;}
|
||||||
|
|
||||||
|
const_iterator& operator++() noexcept {p_ = p_->next; return *this;}
|
||||||
|
const_iterator operator++(int) noexcept {auto t = *this; ++(*this); return t;}
|
||||||
|
|
||||||
|
friend
|
||||||
|
bool
|
||||||
|
operator==(const const_iterator& x, const const_iterator& y) noexcept
|
||||||
|
{return x.p_ == y.p_;}
|
||||||
|
|
||||||
|
friend
|
||||||
|
bool
|
||||||
|
operator!=(const const_iterator& x, const const_iterator& y) noexcept
|
||||||
|
{return !(x == y);}
|
||||||
|
|
||||||
|
friend class tzdb_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
tzdb_list::const_iterator
|
||||||
|
tzdb_list::begin() const noexcept
|
||||||
|
{
|
||||||
|
return const_iterator{head_};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
tzdb_list::const_iterator
|
||||||
|
tzdb_list::end() const noexcept
|
||||||
|
{
|
||||||
|
return const_iterator{nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
tzdb_list::const_iterator
|
||||||
|
tzdb_list::cbegin() const noexcept
|
||||||
|
{
|
||||||
|
return begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
tzdb_list::const_iterator
|
||||||
|
tzdb_list::cend() const noexcept
|
||||||
|
{
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
DATE_API tzdb_list& get_tzdb_list();
|
||||||
|
|
||||||
#if !USE_OS_TZDB
|
#if !USE_OS_TZDB
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user