Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 57 additions & 14 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -2377,9 +2377,8 @@ namespace chrono {
_NODISCARD sys_info _Get_info(const _Duration& _Dur) const {
using _Internal_duration = duration<__std_tzdb_epoch_milli, milli>;
const auto _Internal_dur = _CHRONO duration_cast<_Internal_duration>(_Dur);
const unique_ptr<__std_tzdb_sys_info, decltype(&__std_tzdb_delete_sys_info)> _Info{
__std_tzdb_get_sys_info(_Name.c_str(), _Name.length(), _Internal_dur.count()),
&__std_tzdb_delete_sys_info};
const unique_ptr<__std_tzdb_sys_info, _Tzdb_deleter<__std_tzdb_sys_info>> _Info{
__std_tzdb_get_sys_info(_Name.c_str(), _Name.length(), _Internal_dur.count())};
if (_Info == nullptr) {
_Xbad_alloc();
} else if (_Info->_Err == __std_tzdb_error::_Win_error) {
Expand Down Expand Up @@ -2550,8 +2549,8 @@ namespace chrono {
// [time.zone.db]

_NODISCARD inline string _Xtzdb_generate_current_zone() {
unique_ptr<__std_tzdb_current_zone_info, decltype(&__std_tzdb_delete_current_zone)> _Info{
__std_tzdb_get_current_zone(), &__std_tzdb_delete_current_zone};
unique_ptr<__std_tzdb_current_zone_info, _Tzdb_deleter<__std_tzdb_current_zone_info>> _Info{
__std_tzdb_get_current_zone()};
if (_Info == nullptr) {
_Xbad_alloc();
} else if (_Info->_Err == __std_tzdb_error::_Win_error) {
Expand Down Expand Up @@ -2599,8 +2598,8 @@ namespace chrono {
};

_NODISCARD inline tuple<string, decltype(tzdb::zones), decltype(tzdb::links)> _Xtzdb_generate_time_zones() {
unique_ptr<__std_tzdb_time_zones_info, decltype(&__std_tzdb_delete_time_zones)> _Info{
__std_tzdb_get_time_zones(), &__std_tzdb_delete_time_zones};
unique_ptr<__std_tzdb_time_zones_info, _Tzdb_deleter<__std_tzdb_time_zones_info>> _Info{
__std_tzdb_get_time_zones()};
if (_Info == nullptr) {
_Xbad_alloc();
} else if (_Info->_Err == __std_tzdb_error::_Win_error) {
Expand Down Expand Up @@ -2666,9 +2665,8 @@ namespace chrono {
(_STD max)(_Current_size, _STD size(_Known_leap_seconds)) - _Pre_2018_count;

size_t _Reg_post_2018_ls_size; // number of post-2018 LSs found in the registry
unique_ptr<__std_tzdb_registry_leap_info[], decltype(&__std_tzdb_delete_reg_leap_seconds)> _Reg_ls_data{
__std_tzdb_get_reg_leap_seconds(_Known_post_2018_ls_size, &_Reg_post_2018_ls_size),
&__std_tzdb_delete_reg_leap_seconds};
unique_ptr<__std_tzdb_registry_leap_info[], _Tzdb_deleter<__std_tzdb_registry_leap_info[]>> _Reg_ls_data{
__std_tzdb_get_reg_leap_seconds(_Known_post_2018_ls_size, &_Reg_post_2018_ls_size)};

if (_Reg_post_2018_ls_size > _Known_post_2018_ls_size && !_Reg_ls_data) {
_Xbad_alloc(); // registry has new data, but failed to allocate storage
Expand Down Expand Up @@ -2700,6 +2698,11 @@ namespace chrono {
return {_STD move(_Leap_sec_info), _All_ls_positive};
}

_NODISCARD inline string _Xtzdb_update_version(const string_view _Version, const size_t _Num_leap_seconds) {
string _Icu_version{_Version.substr(0, _Version.find_last_of('.'))};
return _STD move(_Icu_version) + "." + _STD to_string(_Num_leap_seconds);
}

// TRANSITION: work in progress
// CLASS tzdb_list
class tzdb_list {
Expand All @@ -2713,8 +2716,9 @@ namespace chrono {
tzdb_list& operator=(const tzdb_list&) = delete;

tzdb_list() {
auto [_Version, _Zones, _Links] = _Xtzdb_generate_time_zones();
auto [_Leap_sec, _All_ls_positive] = _Xtzdb_generate_leap_seconds(0);
auto [_Icu_version, _Zones, _Links] = _Xtzdb_generate_time_zones();
auto [_Leap_sec, _All_ls_positive] = _Xtzdb_generate_leap_seconds(0);
auto _Version = _Icu_version + "." + _STD to_string(_Leap_sec.size());
_Tzdb_list.emplace_front(tzdb{
_STD move(_Version), _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive});
}
Expand All @@ -2724,6 +2728,26 @@ namespace chrono {
return _Tzdb_list.front();
}

const_iterator erase_after(const_iterator _Where) noexcept /* strengthened */ {
return _Tzdb_list.erase_after(_Where);
}

_NODISCARD const_iterator begin() const noexcept {
return _Tzdb_list.begin();
}

_NODISCARD const_iterator end() const noexcept {
return _Tzdb_list.end();
}

_NODISCARD const_iterator cbegin() const noexcept {
return _Tzdb_list.cbegin();
}

_NODISCARD const_iterator cend() const noexcept {
return _Tzdb_list.cend();
}

template <class... _ArgsTy>
void _Emplace_front(_ArgsTy&&... _Args) {
_Unique_lock _Lk(_Tzdb_mutex);
Expand All @@ -2743,8 +2767,9 @@ namespace chrono {
_Tzdb.links.begin(), _Tzdb.links.end(), _STD back_inserter(_Links), [](const auto& _Link) {
return time_zone_link{_Link.name(), _Link.target()};
});
_Tzdb_list.emplace_front(
tzdb{_Tzdb.version, _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive});
auto _Version = _Xtzdb_update_version(_Tzdb.version, _Leap_sec.size());
_Tzdb_list.emplace_front(tzdb{
_STD move(_Version), _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive});
}
return _Tzdb_list.front();
}
Expand Down Expand Up @@ -2827,6 +2852,16 @@ namespace chrono {
return _CHRONO get_tzdb_list().front();
}

// FUNCTION locate_zone
_NODISCARD inline const time_zone* locate_zone(string_view _Tz_name) {
return _CHRONO get_tzdb().locate_zone(_Tz_name);
}

// FUNCTION current_zone
_NODISCARD inline const time_zone* current_zone() {
return _CHRONO get_tzdb().current_zone();
}

// FUNCTION reload_tzdb
inline const tzdb& reload_tzdb() {
try {
Expand All @@ -2836,6 +2871,14 @@ namespace chrono {
}
}

// FUNCTION remote_version
_NODISCARD inline string remote_version() {
const auto& _Tzdb = _CHRONO get_tzdb();
const auto& _Version = _Tzdb.version;
const auto [_Leap_sec, _Ignored] = _Xtzdb_generate_leap_seconds(_Tzdb.leap_seconds.size());
return _Leap_sec.empty() ? _Version : _Xtzdb_update_version(_Version, _Leap_sec.size());
}

// [time.zone.zonedtraits]

// STRUCT TEMPLATE zoned_traits
Expand Down
32 changes: 31 additions & 1 deletion stl/inc/xtzdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ void __stdcall __std_tzdb_delete_sys_info(__std_tzdb_sys_info* _Info) noexcept;

__std_tzdb_registry_leap_info* __stdcall __std_tzdb_get_reg_leap_seconds(
size_t _Prev_reg_ls_size, size_t* _Current_reg_ls_size) noexcept;

void __stdcall __std_tzdb_delete_reg_leap_seconds(__std_tzdb_registry_leap_info* _Rlsi) noexcept;

_NODISCARD void* __stdcall __std_calloc_crt(size_t _Count, size_t _Size) noexcept;
Expand All @@ -88,6 +87,37 @@ _END_EXTERN_C

_STD_BEGIN

template <class _Ty>
struct _Tzdb_deleter;

template <>
struct _Tzdb_deleter<__std_tzdb_time_zones_info> {
void operator()(__std_tzdb_time_zones_info* _Info) const noexcept {
__std_tzdb_delete_time_zones(_Info);
}
};

template <>
struct _Tzdb_deleter<__std_tzdb_current_zone_info> {
void operator()(__std_tzdb_current_zone_info* _Info) const noexcept {
__std_tzdb_delete_current_zone(_Info);
}
};

template <>
struct _Tzdb_deleter<__std_tzdb_sys_info> {
void operator()(__std_tzdb_sys_info* _Info) const noexcept {
__std_tzdb_delete_sys_info(_Info);
}
};

template <>
struct _Tzdb_deleter<__std_tzdb_registry_leap_info[]> {
void operator()(__std_tzdb_registry_leap_info* _Info) const noexcept {
__std_tzdb_delete_reg_leap_seconds(_Info);
}
};

template <class _Ty>
class _Crt_allocator {
public:
Expand Down
37 changes: 24 additions & 13 deletions stl/src/tzdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,18 @@ namespace {
return _Fun(en, resultLength, status);
}

struct _UEnumeration_deleter {
void operator()(UEnumeration* _En) const noexcept {
__icu_uenum_close(_En);
}
};

struct _UCalendar_deleter {
void operator()(UCalendar* _Cal) const noexcept {
__icu_ucal_close(_Cal);
}
};

_NODISCARD const char* _Allocate_wide_to_narrow(
const char16_t* const _Input, const int _Input_len, __std_tzdb_error& _Err) noexcept {
const auto _Code_page = __std_fs_code_page();
Expand Down Expand Up @@ -293,16 +305,16 @@ namespace {
return _Get_icu_string_impl(_Icu_fn, 12, _Result_len, _Err);
}

_NODISCARD _STD unique_ptr<UCalendar, decltype(&__icu_ucal_close)> _Get_cal(
_NODISCARD _STD unique_ptr<UCalendar, _UCalendar_deleter> _Get_cal(
const char* _Tz, const size_t _Tz_len, __std_tzdb_error& _Err) noexcept {
const auto _Tz_name = _Allocate_narrow_to_wide(_Tz, static_cast<int>(_Tz_len), _Err);
if (_Tz_name == nullptr) {
return {nullptr, &__icu_ucal_close};
return nullptr;
}

UErrorCode _UErr{U_ZERO_ERROR};
_STD unique_ptr<UCalendar, decltype(&__icu_ucal_close)> _Cal{
__icu_ucal_open(_Tz_name.get(), -1, nullptr, UCalendarType::UCAL_DEFAULT, &_UErr), &__icu_ucal_close};
_STD unique_ptr<UCalendar, _UCalendar_deleter> _Cal{
__icu_ucal_open(_Tz_name.get(), -1, nullptr, UCalendarType::UCAL_DEFAULT, &_UErr)};
if (U_FAILURE(_UErr)) {
_Err = __std_tzdb_error::_Icu_error;
}
Expand Down Expand Up @@ -330,8 +342,8 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe
// _Info == nullptr --> bad_alloc
// _Info->_Err == _Win_error --> failed, call GetLastError()
// _Info->_Err == _Icu_error --> runtime_error interacting with ICU
_STD unique_ptr<__std_tzdb_time_zones_info, decltype(&__std_tzdb_delete_time_zones)> _Info{
new (_STD nothrow) __std_tzdb_time_zones_info{}, &__std_tzdb_delete_time_zones};
_STD unique_ptr<__std_tzdb_time_zones_info, _STD _Tzdb_deleter<__std_tzdb_time_zones_info>> _Info{
new (_STD nothrow) __std_tzdb_time_zones_info{}};
if (_Info == nullptr) {
return nullptr;
}
Expand All @@ -346,9 +358,8 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe
return _Report_error(_Info, __std_tzdb_error::_Icu_error);
}

_STD unique_ptr<UEnumeration, decltype(&__icu_uenum_close)> _Enum{
__icu_ucal_openTimeZoneIDEnumeration(USystemTimeZoneType::UCAL_ZONE_TYPE_ANY, nullptr, nullptr, &_UErr),
&__icu_uenum_close};
_STD unique_ptr<UEnumeration, _UEnumeration_deleter> _Enum{
__icu_ucal_openTimeZoneIDEnumeration(USystemTimeZoneType::UCAL_ZONE_TYPE_ANY, nullptr, nullptr, &_UErr)};
if (U_FAILURE(_UErr)) {
return _Report_error(_Info, __std_tzdb_error::_Icu_error);
}
Expand Down Expand Up @@ -429,8 +440,8 @@ _NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone()
// _Info == nullptr --> bad_alloc
// _Info->_Err == _Win_error --> failed, call GetLastError()
// _Info->_Err == _Icu_error --> runtime_error interacting with ICU
_STD unique_ptr<__std_tzdb_current_zone_info, decltype(&__std_tzdb_delete_current_zone)> _Info{
new (_STD nothrow) __std_tzdb_current_zone_info{}, &__std_tzdb_delete_current_zone};
_STD unique_ptr<__std_tzdb_current_zone_info, _STD _Tzdb_deleter<__std_tzdb_current_zone_info>> _Info{
new (_STD nothrow) __std_tzdb_current_zone_info{}};
if (_Info == nullptr) {
return nullptr;
}
Expand Down Expand Up @@ -466,8 +477,8 @@ _NODISCARD __std_tzdb_sys_info* __stdcall __std_tzdb_get_sys_info(
// _Info == nullptr --> bad_alloc
// _Info->_Err == _Win_error --> failed, call GetLastError()
// _Info->_Err == _Icu_error --> runtime_error interacting with ICU
_STD unique_ptr<__std_tzdb_sys_info, decltype(&__std_tzdb_delete_sys_info)> _Info{
new (_STD nothrow) __std_tzdb_sys_info{}, &__std_tzdb_delete_sys_info};
_STD unique_ptr<__std_tzdb_sys_info, _STD _Tzdb_deleter<__std_tzdb_sys_info>> _Info{
new (_STD nothrow) __std_tzdb_sys_info{}};
if (_Info == nullptr) {
return nullptr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <iostream>
#include <ratio>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>

Expand Down Expand Up @@ -55,17 +56,52 @@ void try_locate_invalid_zone(const tzdb& my_tzdb, string_view name) {
}
}

void timezone_names_test() {
const auto& my_tzdb = get_tzdb();
void timezone_tzdb_list_test() {
const auto& my_tzdb_list = get_tzdb_list();

// only one entry in the list unless leap seconds were to change
assert(&my_tzdb_list.front() == &get_tzdb());
assert(&my_tzdb_list.front() == &reload_tzdb());
assert(++my_tzdb_list.begin() == my_tzdb_list.end());
assert(++my_tzdb_list.cbegin() == my_tzdb_list.cend());
}

void timezone_version_test() {
const auto& my_tzdb = get_tzdb();
assert(my_tzdb.version.empty() == false);

// version should end in .X where X == number of leap seconds
const auto pos = my_tzdb.version.find_last_of('.');
assert(pos != decltype(my_tzdb.version)::npos);
const string leap_seconds{my_tzdb.version, pos + 1};
assert(leap_seconds.empty() == false);
assert(leap_seconds == to_string(my_tzdb.leap_seconds.size()));

// remote version will only differ if leap seconds info changes, will not occur in tests
const auto& reloaded_tzdb = reload_tzdb();
assert(reloaded_tzdb.version.empty() == false);
assert(&reloaded_tzdb == &my_tzdb);

const auto& remote_ver = remote_version();
assert(remote_ver.empty() == false);
assert(remote_ver == my_tzdb.version);
}

void timezone_names_test() {
const auto& my_tzdb = get_tzdb();

test_time_zone_and_link(my_tzdb, "Asia/Thimphu", "Asia/Thimbu");
test_time_zone_and_link(my_tzdb, "America/Tijuana", "America/Ensenada");

const auto current_zone = my_tzdb.current_zone();
assert(current_zone != nullptr);
assert(current_zone->name().empty() == false);
const auto curr_zone = current_zone();
assert(curr_zone != nullptr);
assert(curr_zone->name().empty() == false);
assert(curr_zone == my_tzdb.current_zone());

const auto located_zone = locate_zone("UTC");
assert(located_zone != nullptr);
assert(located_zone->name() == "Etc/UTC");
assert(located_zone == my_tzdb.locate_zone("UTC"));

try_locate_invalid_zone(my_tzdb, "Non/Existent");

Expand Down Expand Up @@ -371,6 +407,8 @@ void timezone_precision_test() {

bool test() {
try {
timezone_tzdb_list_test();
timezone_version_test();
timezone_names_test();
timezone_sys_info_test();
timezone_to_local_test();
Expand Down