Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speculatively implement LWG-4139 [time.zone.leap] recursive constraint in <=> #4902

Merged
merged 3 commits into from
Aug 25, 2024
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
116 changes: 63 additions & 53 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -1944,65 +1944,75 @@ namespace chrono {
return _Elapsed_offset;
}

private:
sys_seconds _Date;
bool _Is_positive;
seconds _Elapsed_offset;
};
_NODISCARD friend constexpr bool operator==(const leap_second& _Left, const leap_second& _Right) noexcept {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change requested: I don't think we need a comment here to indicated speculative implementation of LWG-4139, despite that this is a fairly big change and that LWG hasn't yet signed off on a proposed resolution. LWG has demonstrated approval of the "make leap_second's operators hidden friends" approach, and both libc++ and libstdc++implement it, so I have no doubt this will be the eventual resolution of the issue.

return _Left.date() == _Right.date();
}
template <class _Duration>
_NODISCARD friend constexpr bool operator==(
const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return _Left.date() == _Right;
}

_EXPORT_STD _NODISCARD constexpr bool operator==(const leap_second& _Left, const leap_second& _Right) noexcept {
return _Left.date() == _Right.date();
}
_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator==(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return _Left.date() == _Right;
}
template <class _Duration>
_NODISCARD friend constexpr bool operator<(
const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return _Left.date() < _Right;
}
template <class _Duration>
_NODISCARD friend constexpr bool operator<(
const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
return _Left < _Right.date();
}

_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator<(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return _Left.date() < _Right;
}
_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator<(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
return _Left < _Right.date();
}
template <class _Duration>
_NODISCARD friend constexpr bool operator>(
const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return _Right < _Left.date();
}
template <class _Duration>
_NODISCARD friend constexpr bool operator>(
const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
return _Right.date() < _Left;
}

_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator>(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return _Right < _Left.date();
}
_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator>(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
return _Right.date() < _Left;
}
template <class _Duration>
_NODISCARD friend constexpr bool operator<=(
const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return !(_Right < _Left.date());
}
template <class _Duration>
_NODISCARD friend constexpr bool operator<=(
const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
return !(_Right.date() < _Left);
}

_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator<=(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return !(_Right < _Left.date());
}
_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator<=(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
return !(_Right.date() < _Left);
}
template <class _Duration>
_NODISCARD friend constexpr bool operator>=(
const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return !(_Left.date() < _Right);
}
template <class _Duration>
_NODISCARD friend constexpr bool operator>=(
const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
return !(_Left < _Right.date());
}

_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator>=(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return !(_Left.date() < _Right);
}
_EXPORT_STD template <class _Duration>
_NODISCARD constexpr bool operator>=(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
return !(_Left < _Right.date());
}
template <class _Duration>
requires three_way_comparable_with<sys_seconds, sys_time<_Duration>>
_NODISCARD friend constexpr auto operator<=>(
const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return _Left.date() <=> _Right;
}
_NODISCARD friend constexpr strong_ordering operator<=>(
const leap_second& _Left, const leap_second& _Right) noexcept {
return _Left.date() <=> _Right.date();
}

_EXPORT_STD template <class _Duration>
requires three_way_comparable_with<sys_seconds, sys_time<_Duration>>
_NODISCARD constexpr auto operator<=>(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
return _Left.date() <=> _Right;
}
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(
const leap_second& _Left, const leap_second& _Right) noexcept {
return _Left.date() <=> _Right.date();
}
private:
sys_seconds _Date;
bool _Is_positive;
seconds _Elapsed_offset;
};

// [time.zone.link]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
#include <cmath>
#include <compare>
#include <filesystem>
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>

#include <is_permissive.hpp>
#include <timezone_data.hpp>

using namespace std;
Expand Down Expand Up @@ -475,6 +477,63 @@ void test() {
}
}

// LWG-4139 "[time.zone.leap] recursive constraint in <=>"
namespace lwg_4139 {
struct conv_to_leap_second : local_t {
operator leap_second() const noexcept;
};

static_assert(equality_comparable<conv_to_leap_second> == is_permissive);
static_assert(equality_comparable_with<conv_to_leap_second, leap_second> == is_permissive);
static_assert(totally_ordered<conv_to_leap_second> == is_permissive);
static_assert(totally_ordered_with<conv_to_leap_second, leap_second> == is_permissive);
static_assert(three_way_comparable<conv_to_leap_second> == is_permissive);
static_assert(three_way_comparable_with<conv_to_leap_second, leap_second> == is_permissive);

using ref_leap_second = reference_wrapper<leap_second>;

static_assert(equality_comparable<ref_leap_second>);
static_assert(equality_comparable_with<ref_leap_second, leap_second>);
static_assert(totally_ordered<ref_leap_second>);
static_assert(totally_ordered_with<ref_leap_second, leap_second>);
static_assert(three_way_comparable<ref_leap_second>);
static_assert(three_way_comparable_with<ref_leap_second, leap_second>);

template <class T, class U>
concept can_equality_compare_with = requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
t == u;
t != u;
u == t;
u != t;
};

template <class T, class U>
concept can_relation_compare_with = requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
t < u;
t > u;
t <= u;
t >= u;
u < t;
u > t;
u <= t;
u >= t;
};

template <class T, class U>
concept can_three_way_compare_with = requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
t <=> u;
u <=> t;
};

static_assert(!can_equality_compare_with<conv_to_leap_second, sys_seconds>);
static_assert(!can_relation_compare_with<conv_to_leap_second, sys_seconds>);
static_assert(!can_three_way_compare_with<conv_to_leap_second, sys_seconds>);

static_assert(can_equality_compare_with<ref_leap_second, sys_seconds>);
static_assert(can_relation_compare_with<ref_leap_second, sys_seconds>);
static_assert(can_three_way_compare_with<ref_leap_second, sys_seconds>);
} // namespace lwg_4139

int main() {
run_tz_test([] { test(); });
}