Skip to content

Commit dde4623

Browse files
<chrono>: Avoid unnecessary use of concepts (#1787)
1 parent 3017b91 commit dde4623

File tree

2 files changed

+137
-91
lines changed
  • stl/inc
  • tests/std/tests/P0355R7_calendars_and_time_zones_time_zones

2 files changed

+137
-91
lines changed

stl/inc/chrono

Lines changed: 134 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ namespace chrono {
212212
using rep = typename _Duration::rep;
213213
using period = typename _Duration::period;
214214

215-
static_assert(_Is_duration_v<_Duration>, "duration must be an instance of std::duration");
215+
static_assert(_Is_duration_v<_Duration>,
216+
"N4885 [time.point.general]/1 mandates Duration to be a specialization of chrono::duration.");
216217

217218
constexpr time_point() = default;
218219

@@ -2128,8 +2129,11 @@ namespace chrono {
21282129
}
21292130

21302131
template <class _Duration>
2131-
requires _Is_duration_v<_Duration> class hh_mm_ss {
2132+
class hh_mm_ss {
21322133
public:
2134+
static_assert(_Is_duration_v<_Duration>,
2135+
"N4885 [time.hms.overview]/2 mandates Duration to be a specialization of chrono::duration.");
2136+
21332137
static constexpr unsigned int fractional_width = [] {
21342138
auto _Num = _Duration::period::num;
21352139
constexpr auto _Den = _Duration::period::den;
@@ -2907,19 +2911,19 @@ namespace chrono {
29072911
class zoned_time {
29082912
private:
29092913
static_assert(_Is_duration_v<_Duration>,
2910-
"N4878 [time.zone.zonedtime.overview]/2 requires Duration to be a specialization of chrono::duration.");
2914+
"N4885 [time.zone.zonedtime.overview]/2 mandates Duration to be a specialization of chrono::duration.");
29112915

29122916
using _Traits = zoned_traits<_TimeZonePtr>;
29132917

29142918
public:
29152919
using duration = common_type_t<_Duration, seconds>;
29162920

2917-
template <class _Traits2 = _Traits, class = decltype(_Traits2::default_zone())>
2921+
template <class _Traits2 = _Traits, class = void_t<decltype(_Traits2::default_zone())>>
29182922
zoned_time() : _Zone{_Traits::default_zone()} {}
29192923
zoned_time(const zoned_time&) = default;
29202924
zoned_time& operator=(const zoned_time&) = default;
29212925

2922-
template <class _Traits2 = _Traits, class = decltype(_Traits2::default_zone())>
2926+
template <class _Traits2 = _Traits, class = void_t<decltype(_Traits2::default_zone())>>
29232927
zoned_time(const sys_time<_Duration>& _Sys) : _Zone{_Traits::default_zone()}, _Tp{_Sys} {}
29242928

29252929
explicit zoned_time(_TimeZonePtr _Tz) noexcept /* strengthened */ : _Zone{_STD move(_Tz)} {}
@@ -3405,131 +3409,174 @@ namespace chrono {
34053409

34063410
// [time.clock.cast.sys]
34073411

3408-
// TRANSITION, GH-395 workaround, is_same_v -> same_as
3409-
template <class _Ty, class _Clock>
3410-
concept _Is_time_point = requires {
3411-
typename _Ty::duration;
3412-
requires is_same_v<time_point<_Clock, typename _Ty::duration>, _Ty>;
3413-
};
3412+
template <class _TimePoint, class _Clock>
3413+
inline constexpr bool _Is_time_point_for_clock = false;
34143414

34153415
template <class _Clock, class _Duration>
3416-
concept _Convertible_to_sys_time =
3417-
is_same_v<_Clock, system_clock> || requires(const time_point<_Clock, _Duration>& _Time) {
3418-
{ _Clock::to_sys(_Time) }
3419-
->_Is_time_point<system_clock>;
3420-
};
3421-
3422-
template <class _Clock, class _Duration>
3423-
concept _Convertible_from_sys_time = is_same_v<_Clock, system_clock> || requires(const sys_time<_Duration>& _Time) {
3424-
{ _Clock::from_sys(_Time) }
3425-
->_Is_time_point<_Clock>;
3426-
};
3416+
inline constexpr bool _Is_time_point_for_clock<time_point<_Clock, _Duration>, _Clock> = true;
34273417

34283418
template <class _SourceClock>
34293419
struct clock_time_conversion<system_clock, _SourceClock> {
3430-
template <class _Duration>
3420+
template <class _Duration, class _SourceClock2 = _SourceClock,
3421+
class =
3422+
void_t<decltype(_SourceClock2::to_sys(_STD declval<const time_point<_SourceClock2, _Duration>&>()))>>
34313423
_NODISCARD auto operator()(const time_point<_SourceClock, _Duration>& _Time) const
3432-
noexcept(noexcept(_SourceClock::to_sys(_Time))) /* strengthened */
3433-
requires _Convertible_to_sys_time<_SourceClock, _Duration> {
3424+
noexcept(noexcept(_SourceClock::to_sys(_Time))) /* strengthened */ {
3425+
static_assert(_Is_time_point_for_clock<decltype(_SourceClock::to_sys(_Time)), system_clock>,
3426+
"N4885 [time.clock.cast.sys]/2: Mandates: SourceClock::to_sys(t) returns a sys_time<Duration>");
34343427
return _SourceClock::to_sys(_Time);
34353428
}
34363429
};
34373430

34383431
template <class _DestClock>
34393432
struct clock_time_conversion<_DestClock, system_clock> {
3440-
template <class _Duration>
3433+
template <class _Duration, class _DestClock2 = _DestClock,
3434+
class = void_t<decltype(_DestClock2::from_sys(_STD declval<const sys_time<_Duration>&>()))>>
34413435
_NODISCARD auto operator()(const sys_time<_Duration>& _Time) const
3442-
noexcept(noexcept(_DestClock::from_sys(_Time))) /* strengthened */
3443-
requires _Convertible_from_sys_time<_DestClock, _Duration> {
3436+
noexcept(noexcept(_DestClock::from_sys(_Time))) /* strengthened */ {
3437+
static_assert(_Is_time_point_for_clock<decltype(_DestClock::from_sys(_Time)), _DestClock>,
3438+
"N4885 [time.clock.cast.sys]/5: Mandates: DestClock::from_sys(t) returns a "
3439+
"time_point<DestClock, Duration>");
34443440
return _DestClock::from_sys(_Time);
34453441
}
34463442
};
34473443

34483444
// [time.clock.cast.utc]
34493445

3450-
template <class _Clock, class _Duration>
3451-
concept _Convertible_to_utc_time =
3452-
is_same_v<_Clock,
3453-
utc_clock> || is_same_v<_Clock, system_clock> || requires(const time_point<_Clock, _Duration>& _Time) {
3454-
{ _Clock::to_utc(_Time) }
3455-
->_Is_time_point<utc_clock>;
3456-
};
3457-
3458-
template <class _Clock, class _Duration>
3459-
concept _Convertible_from_utc_time =
3460-
is_same_v<_Clock, utc_clock> || is_same_v<_Clock, system_clock> || requires(const utc_time<_Duration>& _Time) {
3461-
{ _Clock::from_utc(_Time) }
3462-
->_Is_time_point<_Clock>;
3463-
};
3464-
34653446
template <class _SourceClock>
34663447
struct clock_time_conversion<utc_clock, _SourceClock> {
3467-
template <class _Duration>
3448+
template <class _Duration, class _SourceClock2 = _SourceClock,
3449+
class =
3450+
void_t<decltype(_SourceClock2::to_utc(_STD declval<const time_point<_SourceClock2, _Duration>&>()))>>
34683451
_NODISCARD auto operator()(const time_point<_SourceClock, _Duration>& _Time) const
3469-
noexcept(noexcept(_SourceClock::to_utc(_Time))) /* strengthened */
3470-
requires _Convertible_to_utc_time<_SourceClock, _Duration> {
3452+
noexcept(noexcept(_SourceClock::to_utc(_Time))) /* strengthened */ {
3453+
static_assert(_Is_time_point_for_clock<decltype(_SourceClock::to_utc(_Time)), utc_clock>,
3454+
"N4885 [time.clock.cast.utc]/2: Mandates: SourceClock::to_utc(t) returns a utc_time<Duration>");
34713455
return _SourceClock::to_utc(_Time);
34723456
}
34733457
};
34743458

34753459
template <class _DestClock>
34763460
struct clock_time_conversion<_DestClock, utc_clock> {
3477-
template <class _Duration>
3461+
template <class _Duration, class _DestClock2 = _DestClock,
3462+
class = void_t<decltype(_DestClock2::from_utc(_STD declval<const utc_time<_Duration>&>()))>>
34783463
_NODISCARD auto operator()(const utc_time<_Duration>& _Time) const
3479-
noexcept(noexcept(_DestClock::from_utc(_Time))) /* strengthened */
3480-
requires _Convertible_from_utc_time<_DestClock, _Duration> {
3464+
noexcept(noexcept(_DestClock::from_utc(_Time))) /* strengthened */ {
3465+
static_assert(_Is_time_point_for_clock<decltype(_DestClock::from_utc(_Time)), _DestClock>,
3466+
"N4885 [time.clock.cast.utc]/5: Mandates: DestClock::from_utc(t) returns a "
3467+
"time_point<DestClock, Duration>");
34813468
return _DestClock::from_utc(_Time);
34823469
}
34833470
};
34843471

34853472
// [time.clock.cast.fn]
34863473

3487-
// FUNCTION TEMPLATE clock_cast
3474+
enum class _Clock_cast_strategy {
3475+
_Direct,
3476+
_Via_sys,
3477+
_Via_utc,
3478+
_Via_utc_from_sys,
3479+
_Via_sys_from_utc,
3480+
_Two_step_ambiguous,
3481+
_Three_step_ambiguous,
3482+
_None,
3483+
};
3484+
3485+
template <class _Conv1, class _Conv2, class _Tp, class = void>
3486+
inline constexpr bool _Has_two_step_conversion = false;
3487+
3488+
template <class _Conv1, class _Conv2, class _Tp>
3489+
inline constexpr bool
3490+
_Has_two_step_conversion<_Conv1, _Conv2, _Tp, void_t<decltype(_Conv1{}(_Conv2{}(_STD declval<_Tp>())))>> = true;
3491+
3492+
template <class _Conv1, class _Conv2, class _Conv3, class _Tp, class = void>
3493+
inline constexpr bool _Has_three_step_conversion = false;
3494+
3495+
template <class _Conv1, class _Conv2, class _Conv3, class _Tp>
3496+
inline constexpr bool _Has_three_step_conversion<_Conv1, _Conv2, _Conv3, _Tp,
3497+
void_t<decltype(_Conv1{}(_Conv2{}(_Conv3{}(_STD declval<_Tp>()))))>> = true;
3498+
3499+
template <class _DestClock, class _SourceClock, class _Duration>
3500+
_NODISCARD _CONSTEVAL _Clock_cast_strategy _Choose_clock_cast() noexcept {
3501+
using _Tp = const time_point<_SourceClock, _Duration>&;
3502+
3503+
if constexpr (is_invocable_v<clock_time_conversion<_DestClock, _SourceClock>, _Tp>) {
3504+
return _Clock_cast_strategy::_Direct;
3505+
} else {
3506+
constexpr bool _Has_sys = _Has_two_step_conversion< //
3507+
clock_time_conversion<_DestClock, system_clock>, //
3508+
clock_time_conversion<system_clock, _SourceClock>, _Tp>;
3509+
3510+
constexpr bool _Has_utc = _Has_two_step_conversion< //
3511+
clock_time_conversion<_DestClock, utc_clock>, //
3512+
clock_time_conversion<utc_clock, _SourceClock>, _Tp>;
3513+
3514+
if constexpr (_Has_sys && _Has_utc) {
3515+
return _Clock_cast_strategy::_Two_step_ambiguous;
3516+
} else if constexpr (_Has_sys) {
3517+
return _Clock_cast_strategy::_Via_sys;
3518+
} else if constexpr (_Has_utc) {
3519+
return _Clock_cast_strategy::_Via_utc;
3520+
} else {
3521+
constexpr bool _Has_utc_from_sys = _Has_three_step_conversion< //
3522+
clock_time_conversion<_DestClock, utc_clock>, //
3523+
clock_time_conversion<utc_clock, system_clock>, //
3524+
clock_time_conversion<system_clock, _SourceClock>, _Tp>;
3525+
3526+
constexpr bool _Has_sys_from_utc = _Has_three_step_conversion< //
3527+
clock_time_conversion<_DestClock, system_clock>, //
3528+
clock_time_conversion<system_clock, utc_clock>, //
3529+
clock_time_conversion<utc_clock, _SourceClock>, _Tp>;
3530+
3531+
if constexpr (_Has_utc_from_sys && _Has_sys_from_utc) {
3532+
return _Clock_cast_strategy::_Three_step_ambiguous;
3533+
} else if constexpr (_Has_utc_from_sys) {
3534+
return _Clock_cast_strategy::_Via_utc_from_sys;
3535+
} else if constexpr (_Has_sys_from_utc) {
3536+
return _Clock_cast_strategy::_Via_sys_from_utc;
3537+
} else {
3538+
return _Clock_cast_strategy::_None;
3539+
}
3540+
}
3541+
}
3542+
}
3543+
34883544
template <class _DestClock, class _SourceClock, class _Duration>
3545+
inline constexpr auto _Clock_cast_choice = _Choose_clock_cast<_DestClock, _SourceClock, _Duration>();
3546+
3547+
// FUNCTION TEMPLATE clock_cast
3548+
template <class _DestClock, class _SourceClock, class _Duration,
3549+
enable_if_t<_Clock_cast_choice<_DestClock, _SourceClock, _Duration> != _Clock_cast_strategy::_None, int> = 0>
34893550
_NODISCARD auto clock_cast(const time_point<_SourceClock, _Duration>& _Time) {
3490-
constexpr bool _Has_direct_conversion =
3491-
is_invocable_v<clock_time_conversion<_DestClock, _SourceClock>, decltype(_Time)>;
3492-
3493-
constexpr bool _Utc_from_src = _Convertible_to_utc_time<_SourceClock, _Duration>;
3494-
constexpr bool _Sys_from_src = _Convertible_to_sys_time<_SourceClock, _Duration>;
3495-
constexpr bool _Dest_from_utc = _Convertible_from_utc_time<_DestClock, _Duration>;
3496-
constexpr bool _Dest_from_sys = _Convertible_from_sys_time<_DestClock, _Duration>;
3497-
3498-
constexpr bool _Has_utc_conversion = _Dest_from_utc && _Utc_from_src;
3499-
constexpr bool _Has_sys_conversion = _Dest_from_sys && _Sys_from_src;
3500-
static_assert(_Has_direct_conversion || !(_Has_utc_conversion && _Has_sys_conversion),
3501-
"A two-step clock time conversion is required to be unique, either through utc_clock or system_clock, but "
3502-
"not both (N4878 [time.clock.cast.fn]/2.)");
3503-
3504-
constexpr bool _Has_sys_utc_conversion = _Dest_from_sys && _Utc_from_src;
3505-
constexpr bool _Has_utc_sys_conversion = _Dest_from_utc && _Sys_from_src;
3506-
static_assert(_Has_direct_conversion || _Has_utc_conversion || _Has_sys_conversion
3507-
|| !(_Has_utc_sys_conversion && _Has_sys_utc_conversion),
3508-
"A three-step clock time conversion is required to be unique, either utc-to-system or system-to-utc, but "
3509-
"not both (N4878 [time.clock.cast.fn]/2).");
3551+
constexpr auto _Strat = _Clock_cast_choice<_DestClock, _SourceClock, _Duration>;
35103552

3511-
// clang-format off
3512-
if constexpr (_Has_direct_conversion) {
3553+
if constexpr (_Strat == _Clock_cast_strategy::_Direct) {
35133554
return clock_time_conversion<_DestClock, _SourceClock>{}(_Time);
3514-
} else if constexpr (_Has_utc_conversion) {
3515-
return clock_time_conversion<_DestClock, utc_clock>{}(
3516-
clock_time_conversion<utc_clock, _SourceClock>{}(_Time));
3517-
} else if constexpr (_Has_sys_conversion) {
3555+
} else if constexpr (_Strat == _Clock_cast_strategy::_Via_sys) {
35183556
return clock_time_conversion<_DestClock, system_clock>{}(
3519-
clock_time_conversion<system_clock, _SourceClock>{}(_Time));
3520-
} else if constexpr (_Has_sys_utc_conversion) {
3521-
return clock_time_conversion<_DestClock, system_clock>{}(
3522-
clock_time_conversion<system_clock, utc_clock>{}(
3523-
clock_time_conversion<utc_clock, _SourceClock>{}(_Time)));
3524-
} else if constexpr (_Has_utc_sys_conversion) {
3557+
clock_time_conversion<system_clock, _SourceClock>{}(_Time));
3558+
} else if constexpr (_Strat == _Clock_cast_strategy::_Via_utc) {
35253559
return clock_time_conversion<_DestClock, utc_clock>{}(
3526-
clock_time_conversion<utc_clock, system_clock>{}(
3527-
clock_time_conversion<system_clock, _SourceClock>{}(_Time)));
3560+
clock_time_conversion<utc_clock, _SourceClock>{}(_Time));
3561+
} else if constexpr (_Strat == _Clock_cast_strategy::_Via_utc_from_sys) {
3562+
return clock_time_conversion<_DestClock, utc_clock>{}( //
3563+
clock_time_conversion<utc_clock, system_clock>{}(
3564+
clock_time_conversion<system_clock, _SourceClock>{}(_Time)));
3565+
} else if constexpr (_Strat == _Clock_cast_strategy::_Via_sys_from_utc) {
3566+
return clock_time_conversion<_DestClock, system_clock>{}( //
3567+
clock_time_conversion<system_clock, utc_clock>{}(
3568+
clock_time_conversion<utc_clock, _SourceClock>{}(_Time)));
3569+
} else if constexpr (_Strat == _Clock_cast_strategy::_Two_step_ambiguous) {
3570+
static_assert(_Always_false<_Duration>,
3571+
"A two-step clock time conversion is required to be unique, "
3572+
"either through utc_clock or system_clock, but not both (N4878 [time.clock.cast.fn]/2).");
3573+
} else if constexpr (_Strat == _Clock_cast_strategy::_Three_step_ambiguous) {
3574+
static_assert(_Always_false<_Duration>,
3575+
"A three-step clock time conversion is required to be unique, "
3576+
"either utc-to-system or system-to-utc, but not both (N4878 [time.clock.cast.fn]/2).");
35283577
} else {
3529-
static_assert(_Always_false<_Duration>, "No clock time conversion exists from source clock type to "
3530-
"destination clock type (N4878 [time.clock.cast.fn]/1).");
3578+
static_assert(_Always_false<_Duration>, "should be unreachable");
35313579
}
3532-
// clang-format on
35333580
}
35343581

35353582
// [time.parse]

tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,13 @@ void timezone_names_test() {
147147
}
148148

149149
// See GH-1786. These may change over time and might have to be removed from this test.
150-
151-
// these are some examples in which the ICU.dll and IANA database diverge in what they consider a zone or a link
150+
// These are some examples in which the ICU.dll and IANA database diverge in what they consider a zone or a link.
152151
assert(_Locate_zone_impl(my_tzdb.links, "Atlantic/Faroe") != nullptr); // is a time_zone in IANA
153152
assert(_Locate_zone_impl(my_tzdb.zones, "Africa/Addis_Ababa") != nullptr); // is a time_zone_link in IANA
154153
assert(_Locate_zone_impl(my_tzdb.links, "PST") != nullptr); // time_zone_link does not exist in IANA
155-
assert(_Locate_zone_impl(my_tzdb.links, "Africa/Asmara") != nullptr); // matches IANA but target is wrong
154+
assert(_Locate_zone_impl(my_tzdb.links, "Africa/Asmara") != nullptr); // matches IANA but target is different
156155
assert(_Locate_zone_impl(my_tzdb.links, "Africa/Asmara")->target() == "Africa/Asmera"); // target == Africa/Nairobi
157-
assert(_Locate_zone_impl(my_tzdb.zones, "America/Nuuk") == nullptr); // does not exist in ICU (very rare)
156+
assert(_Locate_zone_impl(my_tzdb.zones, "America/Nuuk") == nullptr); // added in ICU 68, update test when it arrives
158157
}
159158

160159
void validate_timezone_transitions(const time_zone* tz, const Transition& transition) {

0 commit comments

Comments
 (0)