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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ issue. The [bug tag][] and [enhancement tag][] are being populated.

# Goals

We're implementing the latest C++ Working Draft, currently [N4928][], which will eventually become the next C++
We're implementing the latest C++ Working Draft, currently [N4944][], which will eventually become the next C++
International Standard. The terms Working Draft (WD) and Working Paper (WP) are interchangeable; we often
informally refer to these drafts as "the Standard" while being aware of the difference. (There are other relevant
Standards; for example, supporting `/std:c++14` and `/std:c++17` involves understanding how the C++14 and C++17
Expand Down Expand Up @@ -532,7 +532,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
[LWG issues]: https://cplusplus.github.io/LWG/lwg-toc.html
[LWG tag]: https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3ALWG
[Microsoft Open Source Code of Conduct]: https://opensource.microsoft.com/codeofconduct/
[N4928]: https://wg21.link/n4928
[N4944]: https://wg21.link/n4944
[NOTICE.txt]: NOTICE.txt
[Ninja]: https://ninja-build.org
[Pipelines]: https://dev.azure.com/vclibs/STL/_build/latest?definitionId=4&branchName=main
Expand Down
12 changes: 6 additions & 6 deletions stl/inc/__msvc_chrono.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,10 +695,10 @@ namespace chrono {
} // namespace chrono

template <class _Rep, class _Period>
_NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept(
is_arithmetic_v<_Rep>) {
// Convert duration to xtime, maximum 10 days from now, returns whether clamping occurred.
// If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where
_NODISCARD bool _To_timespec64_sys_10_day_clamped(
_timespec64& _Ts64, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept(is_arithmetic_v<_Rep>) {
// Convert duration to _timespec64 representing system time, maximum 10 days from now, returns whether clamping
// occurred. If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where
// the other side of the DLL boundary overflows int32_t milliseconds.
// Every function calling this one is TRANSITION, ABI
constexpr _CHRONO nanoseconds _Ten_days{_CHRONO hours{24} * 10};
Expand All @@ -712,9 +712,9 @@ _NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duratio
}

const auto _Whole_seconds = _CHRONO duration_cast<_CHRONO seconds>(_Tx0);
_Xt.sec = _Whole_seconds.count();
_Ts64.tv_sec = _Whole_seconds.count();
_Tx0 -= _Whole_seconds;
_Xt.nsec = static_cast<long>(_Tx0.count());
_Ts64.tv_nsec = static_cast<long>(_Tx0.count());
return _Clamped;
}

Expand Down
10 changes: 10 additions & 0 deletions stl/inc/__msvc_tzdb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ struct __std_tzdb_sys_info {
const char* _Abbrev;
};

enum class __std_tzdb_sys_info_type : char {
// TRANSITION, ABI: In order to be compatible with existing object files which do not know about
// `__std_tzdb_sys_info_type`, the type is passed in the after-end byte of a string passed with its length to
// `__std_tzdb_get_sys_info`. Since older object files always pass the `.c_str()` of a `std::string`
// to that function, the after-end byte will always be '\0'.
_Full = '\0',
_Offset_only,
_Offset_and_range,
};

_NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noexcept;
void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) noexcept;

Expand Down
147 changes: 81 additions & 66 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -1750,70 +1750,12 @@ namespace chrono {

template <class _Duration>
_NODISCARD sys_info get_info(const sys_time<_Duration>& _Sys) const {
return _Get_info(_Sys.time_since_epoch());
return _Get_info(_Sys.time_since_epoch(), __std_tzdb_sys_info_type::_Full);
}

template <class _Duration>
_NODISCARD local_info get_info(const local_time<_Duration>& _Local) const {
local_info _Info{};
const auto _Time_since_ep = _Local.time_since_epoch();
_Info.first = _Get_info(_Time_since_ep);

const sys_seconds _Local_sys{_CHRONO duration_cast<sys_seconds::duration>(_Time_since_ep)};
const auto _Curr_sys = _Local_sys - _Info.first.offset;
if (_Info.first.begin != _Min_seconds && _Curr_sys < _Info.first.begin + days{1}) {
// get previous transition information
_Info.second = get_info(_Info.first.begin - seconds{1});

const auto _Transition = _Info.first.begin;
const auto _Prev_sys = _Local_sys - _Info.second.offset;
if (_Curr_sys >= _Transition) {
if (_Prev_sys < _Transition) {
_Info.result = local_info::ambiguous;
_STD swap(_Info.first, _Info.second);
} else {
_Info.result = local_info::unique;
_Info.second = {};
}
} else {
if (_Prev_sys >= _Transition) {
_Info.result = local_info::nonexistent;
_STD swap(_Info.first, _Info.second);
} else {
_Info.result = local_info::unique;
_Info.first = _STD move(_Info.second);
_Info.second = {};
}
}
} else if (_Info.first.end != _Max_seconds && _Curr_sys > _Info.first.end - days{1}) {
// get next transition information
_Info.second = get_info(_Info.first.end + seconds{1});

const auto _Transition = _Info.first.end;
const auto _Next_sys = _Local_sys - _Info.second.offset;
if (_Curr_sys < _Transition) {
if (_Next_sys >= _Transition) {
_Info.result = local_info::ambiguous;
} else {
_Info.result = local_info::unique;
_Info.second = {};
}
} else {
if (_Next_sys < _Transition) {
_Info.result = local_info::nonexistent;
} else {
_Info.result = local_info::unique;
_Info.first = _STD move(_Info.second);
_Info.second = {};
}
}
} else {
// local time is contained inside of first transition boundaries by at least 1 day
_Info.result = local_info::unique;
_Info.second = {};
}

return _Info;
return _Get_local_info(_Local, __std_tzdb_sys_info_type::_Full);
}

template <class _Duration>
Expand All @@ -1831,7 +1773,7 @@ namespace chrono {
template <class _Duration>
_NODISCARD sys_time<common_type_t<_Duration, seconds>> to_sys(
const local_time<_Duration>& _Local, const choose _Choose) const {
const auto _Info = get_info(_Local);
const auto _Info = _Get_local_info(_Local, __std_tzdb_sys_info_type::_Offset_and_range);
if (_Info.result == local_info::nonexistent) {
return _Info.first.end;
}
Expand All @@ -1844,7 +1786,7 @@ namespace chrono {

template <class _Duration>
_NODISCARD local_time<common_type_t<_Duration, seconds>> to_local(const sys_time<_Duration>& _Sys) const {
const auto _Info = get_info(_Sys);
const auto _Info = _Get_info(_Sys.time_since_epoch(), __std_tzdb_sys_info_type::_Offset_only);
return local_time<common_type_t<_Duration, seconds>>{_Sys.time_since_epoch() + _Info.offset};
}

Expand All @@ -1853,11 +1795,20 @@ namespace chrono {

private:
template <class _Duration>
_NODISCARD sys_info _Get_info(const _Duration& _Dur) const {
_NODISCARD sys_info _Get_info(const _Duration& _Dur, __std_tzdb_sys_info_type _Type) const {
using _Internal_duration = duration<__std_tzdb_epoch_milli, milli>;
const auto _Internal_dur = _CHRONO duration_cast<_Internal_duration>(_Dur);

// TRANSITION, vNext
// Because the signature of __std_tzdb_get_sys_info cannot be changed, _Type is encoded in the
// time zone name. In vNext, this should be a dedicated argument.
const string _Tz_arg = _Name + static_cast<char>(_Type);

const auto _Tz_len = _Name.length();

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())};
__std_tzdb_get_sys_info(_Tz_arg.c_str(), _Tz_len, _Internal_dur.count())};

if (_Info == nullptr) {
_Xbad_alloc();
} else if (_Info->_Err == __std_tzdb_error::_Win_error) {
Expand All @@ -1882,7 +1833,71 @@ namespace chrono {
.end = _End,
.offset = _CHRONO duration_cast<seconds>(_Internal_duration{_Info->_Offset}),
.save = _CHRONO duration_cast<minutes>(_Internal_duration{_Info->_Save}),
.abbrev = _Info->_Abbrev};
.abbrev = _Info->_Abbrev ? _Info->_Abbrev : ""};
}

template <class _Duration>
_NODISCARD local_info _Get_local_info(
const local_time<_Duration>& _Local, __std_tzdb_sys_info_type _Type) const {
local_info _Info{};
const auto _Time_since_ep = _Local.time_since_epoch();
_Info.first = _Get_info(_Time_since_ep, _Type);

const sys_seconds _Local_sys{_CHRONO duration_cast<sys_seconds::duration>(_Time_since_ep)};
const auto _Curr_sys = _Local_sys - _Info.first.offset;
if (_Info.first.begin != _Min_seconds && _Curr_sys < _Info.first.begin + days{1}) {
// get previous transition information
_Info.second = _Get_info((_Info.first.begin - seconds{1}).time_since_epoch(), _Type);

const auto _Transition = _Info.first.begin;
const auto _Prev_sys = _Local_sys - _Info.second.offset;
if (_Curr_sys >= _Transition) {
if (_Prev_sys < _Transition) {
_Info.result = local_info::ambiguous;
_STD swap(_Info.first, _Info.second);
} else {
_Info.result = local_info::unique;
_Info.second = {};
}
} else {
if (_Prev_sys >= _Transition) {
_Info.result = local_info::nonexistent;
_STD swap(_Info.first, _Info.second);
} else {
_Info.result = local_info::unique;
_Info.first = _STD move(_Info.second);
_Info.second = {};
}
}
} else if (_Info.first.end != _Max_seconds && _Curr_sys > _Info.first.end - days{1}) {
// get next transition information
_Info.second = _Get_info((_Info.first.end + seconds{1}).time_since_epoch(), _Type);

const auto _Transition = _Info.first.end;
const auto _Next_sys = _Local_sys - _Info.second.offset;
if (_Curr_sys < _Transition) {
if (_Next_sys >= _Transition) {
_Info.result = local_info::ambiguous;
} else {
_Info.result = local_info::unique;
_Info.second = {};
}
} else {
if (_Next_sys < _Transition) {
_Info.result = local_info::nonexistent;
} else {
_Info.result = local_info::unique;
_Info.first = _STD move(_Info.second);
_Info.second = {};
}
}
} else {
// local time is contained inside of first transition boundaries by at least 1 day
_Info.result = local_info::unique;
_Info.second = {};
}

return _Info;
}

string _Name;
Expand Down Expand Up @@ -2955,7 +2970,7 @@ namespace chrono {
void_t<decltype(_Conv1{}(_Conv2{}(_Conv3{}(_STD declval<_Tp>()))))>> = true;

template <class _DestClock, class _SourceClock, class _Duration>
_NODISCARD _CONSTEVAL _Clock_cast_strategy _Choose_clock_cast() noexcept {
_NODISCARD consteval _Clock_cast_strategy _Choose_clock_cast() noexcept {
using _Tp = const time_point<_SourceClock, _Duration>&;

if constexpr (is_invocable_v<clock_time_conversion<_DestClock, _SourceClock>, _Tp>) {
Expand Down
12 changes: 6 additions & 6 deletions stl/inc/compare
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ namespace _Strong_order {
enum class _St { _None, _Adl, _Floating, _Three };

template <class _Ty1, class _Ty2>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
if constexpr (!same_as<decay_t<_Ty1>, decay_t<_Ty2>>) {
return {_St::_None};
} else if constexpr (_Has_ADL<_Ty1, _Ty2>) {
Expand Down Expand Up @@ -497,7 +497,7 @@ namespace _Weak_order {
enum class _St { _None, _Adl, _Floating, _Three, _Strong };

template <class _Ty1, class _Ty2>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
if constexpr (!same_as<decay_t<_Ty1>, decay_t<_Ty2>>) {
return {_St::_None};
} else if constexpr (_Has_ADL<_Ty1, _Ty2>) {
Expand Down Expand Up @@ -626,7 +626,7 @@ namespace _Partial_order {
enum class _St { _None, _Adl, _Three, _Weak, _Strong };

template <class _Ty1, class _Ty2>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
if constexpr (!same_as<decay_t<_Ty1>, decay_t<_Ty2>>) {
return {_St::_None};
} else if constexpr (_Has_ADL<_Ty1, _Ty2>) {
Expand Down Expand Up @@ -695,7 +695,7 @@ namespace _Compare_strong_order_fallback {
enum class _St { _None, _Strong, _Fallback };

template <class _Ty1, class _Ty2>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
if constexpr (!same_as<decay_t<_Ty1>, decay_t<_Ty2>>) {
return {_St::_None};
} else if constexpr (_Can_strong_order<_Ty1, _Ty2>) {
Expand Down Expand Up @@ -745,7 +745,7 @@ namespace _Compare_weak_order_fallback {
enum class _St { _None, _Weak, _Fallback };

template <class _Ty1, class _Ty2>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
if constexpr (!same_as<decay_t<_Ty1>, decay_t<_Ty2>>) {
return {_St::_None};
} else if constexpr (_Can_weak_order<_Ty1, _Ty2>) {
Expand Down Expand Up @@ -802,7 +802,7 @@ namespace _Compare_partial_order_fallback {
enum class _St { _None, _Partial, _Fallback };

template <class _Ty1, class _Ty2>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
_NODISCARD static consteval _Choice_t<_St> _Choose() noexcept {
if constexpr (!same_as<decay_t<_Ty1>, decay_t<_Ty2>>) {
return {_St::_None};
} else if constexpr (_Can_partial_order<_Ty1, _Ty2>) {
Expand Down
33 changes: 9 additions & 24 deletions stl/inc/condition_variable
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ public:
}

// TRANSITION, ABI: The standard says that we should use a steady clock,
// but unfortunately our ABI speaks struct xtime, which is relative to the system clock.
_CSTD xtime _Tgt;
const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Rel_time);
const cv_status _Result = _Wait_until(_Lck, &_Tgt);
// but unfortunately our ABI relies on the system clock.
_timespec64 _Tgt;
const bool _Clamped = _To_timespec64_sys_10_day_clamped(_Tgt, _Rel_time);
const cv_status _Result = _Wait_until_sys_time(_Lck, &_Tgt);
if (_Clamped) {
return cv_status::no_timeout;
}
Expand All @@ -139,22 +139,6 @@ public:
return wait_until(_Lck, _To_absolute_time(_Rel_time), _STD move(_Pred));
}

template <class _Lock>
cv_status wait_until(_Lock& _Lck, const xtime* const _Abs_time) { // wait for signal with timeout
return _Wait_until(_Lck, _Abs_time);
}

template <class _Lock, class _Predicate>
bool wait_until(_Lock& _Lck, const xtime* const _Abs_time, _Predicate _Pred) {
// wait for signal with timeout and check predicate
while (!_Pred()) {
if (_Wait_until(_Lck, _Abs_time) == cv_status::timeout) {
return _Pred();
}
}
return true;
}

#if _HAS_CXX20
private:
struct _Cv_any_notify_all {
Expand Down Expand Up @@ -221,9 +205,9 @@ public:

const auto _Rel_time = _Abs_time - _Now;
// TRANSITION, ABI: The standard says that we should use a steady clock,
// but unfortunately our ABI speaks struct xtime, which is relative to the system clock.
_CSTD xtime _Tgt;
(void) _To_xtime_10_day_clamped(_Tgt, _Rel_time);
// but unfortunately our ABI relies on the system clock.
_timespec64 _Tgt;
(void) _To_timespec64_sys_10_day_clamped(_Tgt, _Rel_time);
(void) _Cnd_timedwait(_Mycnd(), _Myptr->_Mymtx(), &_Tgt);
_Guard_unlocks_before_locking_outer.unlock();
} // relock
Expand All @@ -247,7 +231,8 @@ private:
}

template <class _Lock>
cv_status _Wait_until(_Lock& _Lck, const xtime* const _Abs_time) { // wait for signal with timeout
cv_status _Wait_until_sys_time(_Lock& _Lck, const _timespec64* const _Abs_time) {
// wait for signal with timeout
const shared_ptr<mutex> _Ptr = _Myptr; // for immunity to *this destruction
unique_lock<mutex> _Guard{*_Ptr};
_Unlock_guard<_Lock> _Unlock_outer{_Lck};
Expand Down
Loading