Skip to content

Commit fde236b

Browse files
committed
Implement hh_mm_ss from P1466R3. Reviewed as https://reviews.llvm.org/D65365.
llvm-svn: 368299
1 parent ba4bda6 commit fde236b

File tree

16 files changed

+896
-6
lines changed

16 files changed

+896
-6
lines changed

libcxx/include/chrono

Lines changed: 114 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -612,13 +612,43 @@ constexpr year_month_weekday_last
612612
constexpr year_month_weekday_last
613613
operator/(const month_weekday_last& mwdl, int y) noexcept;
614614
615-
// 25.9, class template time_of_day // C++20
616-
template<class Duration> class time_of_day;
615+
// 26.9, class template hh_mm_ss
616+
template <class Duration>
617+
class hh_mm_ss
618+
{
619+
bool is_neg; // exposition only
620+
chrono::hours h; // exposition only
621+
chrono::minutes m; // exposition only
622+
chrono::seconds s; // exposition only
623+
precision ss; // exposition only
624+
625+
public:
626+
static unsigned constexpr fractional_width = see below;
627+
using precision = see below;
628+
629+
constexpr hh_mm_ss() noexcept : hh_mm_ss{Duration::zero()} {}
630+
constexpr explicit hh_mm_ss(Duration d) noexcept;
631+
632+
constexpr bool is_negative() const noexcept;
633+
constexpr chrono::hours hours() const noexcept;
634+
constexpr chrono::minutes minutes() const noexcept;
635+
constexpr chrono::seconds seconds() const noexcept;
636+
constexpr precision subseconds() const noexcept;
637+
638+
constexpr explicit operator precision() const noexcept;
639+
constexpr precision to_duration() const noexcept;
640+
};
641+
642+
template <class charT, class traits, class Duration>
643+
basic_ostream<charT, traits>&
644+
operator<<(basic_ostream<charT, traits>& os, hh_mm_ss<Duration> const& hms);
645+
646+
// 26.10, 12/24 hour functions
647+
constexpr bool is_am(hours const& h) noexcept;
648+
constexpr bool is_pm(hours const& h) noexcept;
649+
constexpr hours make12(const hours& h) noexcept;
650+
constexpr hours make24(const hours& h, bool is_pm) noexcept;
617651
618-
template<> class time_of_day<hours>;
619-
template<> class time_of_day<minutes>;
620-
template<> class time_of_day<seconds>;
621-
template<class Rep, class Period> class time_of_day<duration<Rep, Period>>;
622652
623653
// 25.10.2, time zone database // C++20
624654
struct tzdb;
@@ -2716,6 +2746,84 @@ inline constexpr year_month_weekday_last& year_month_weekday_last::operator-=(co
27162746
inline constexpr year_month_weekday_last& year_month_weekday_last::operator+=(const years& __dy) noexcept { *this = *this + __dy; return *this; }
27172747
inline constexpr year_month_weekday_last& year_month_weekday_last::operator-=(const years& __dy) noexcept { *this = *this - __dy; return *this; }
27182748

2749+
2750+
template <class _Duration>
2751+
class hh_mm_ss
2752+
{
2753+
private:
2754+
static_assert(__is_duration<_Duration>::value, "template parameter of hh_mm_ss must be a std::chrono::duration");
2755+
using __CommonType = common_type_t<_Duration, chrono::seconds>;
2756+
2757+
static constexpr uint64_t __pow10(unsigned __exp)
2758+
{
2759+
uint64_t __ret = 1;
2760+
for (unsigned __i = 0; __i < __exp; ++__i)
2761+
__ret *= 10U;
2762+
return __ret;
2763+
}
2764+
2765+
static constexpr unsigned __width(uint64_t __n, uint64_t __d = 10, unsigned __w = 0)
2766+
{
2767+
if (__n >= 2 && __d != 0 && __w < 19)
2768+
return 1 + __width(__n, __d % __n * 10, __w+1);
2769+
return 0;
2770+
}
2771+
2772+
public:
2773+
static unsigned constexpr fractional_width = __width(__CommonType::period::den) < 19 ?
2774+
__width(__CommonType::period::den) : 6u;
2775+
using precision = duration<typename __CommonType::rep, ratio<1, __pow10(fractional_width)>>;
2776+
2777+
constexpr hh_mm_ss() noexcept : hh_mm_ss{_Duration::zero()} {}
2778+
2779+
constexpr explicit hh_mm_ss(_Duration __d) noexcept :
2780+
__is_neg(__d < _Duration(0)),
2781+
__h(duration_cast<chrono::hours> (abs(__d))),
2782+
__m(duration_cast<chrono::minutes>(abs(__d) - hours())),
2783+
__s(duration_cast<chrono::seconds>(abs(__d) - hours() - minutes())),
2784+
__f(duration_cast<precision> (abs(__d) - hours() - minutes() - seconds()))
2785+
{}
2786+
2787+
constexpr bool is_negative() const noexcept { return __is_neg; }
2788+
constexpr chrono::hours hours() const noexcept { return __h; }
2789+
constexpr chrono::minutes minutes() const noexcept { return __m; }
2790+
constexpr chrono::seconds seconds() const noexcept { return __s; }
2791+
constexpr precision subseconds() const noexcept { return __f; }
2792+
2793+
constexpr precision to_duration() const noexcept
2794+
{
2795+
auto __dur = __h + __m + __s + __f;
2796+
return __is_neg ? -__dur : __dur;
2797+
}
2798+
2799+
constexpr explicit operator precision() const noexcept { return to_duration(); }
2800+
2801+
private:
2802+
bool __is_neg;
2803+
chrono::hours __h;
2804+
chrono::minutes __m;
2805+
chrono::seconds __s;
2806+
precision __f;
2807+
};
2808+
2809+
constexpr bool is_am(const hours& __h) noexcept { return __h >= hours( 0) && __h < hours(12); }
2810+
constexpr bool is_pm(const hours& __h) noexcept { return __h >= hours(12) && __h < hours(24); }
2811+
2812+
constexpr hours make12(const hours& __h) noexcept
2813+
{
2814+
if (__h == hours( 0)) return hours(12);
2815+
else if (__h <= hours(12)) return __h;
2816+
else return __h - hours(12);
2817+
}
2818+
2819+
constexpr hours make24(const hours& __h, bool __is_pm) noexcept
2820+
{
2821+
if (__is_pm)
2822+
return __h == hours(12) ? __h : __h + hours(12);
2823+
else
2824+
return __h == hours(12) ? hours(0) : __h;
2825+
}
2826+
27192827
#endif // _LIBCPP_STD_VER > 17
27202828
} // chrono
27212829

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
9+
// <chrono>
10+
11+
// template <class Duration> class hh_mm_ss;
12+
// If Duration is not an instance of duration, the program is ill-formed.
13+
14+
#include <chrono>
15+
#include <string>
16+
#include <cassert>
17+
#include "test_macros.h"
18+
19+
struct A {};
20+
21+
int main(int, char**)
22+
{
23+
std::chrono::hh_mm_ss<void> h0; // expected-error-re@chrono:* {{static_assert failed {{.*}} "template parameter of hh_mm_ss must be a std::chrono::duration"}}
24+
std::chrono::hh_mm_ss<int> h1; // expected-error-re@chrono:* {{static_assert failed {{.*}} "template parameter of hh_mm_ss must be a std::chrono::duration"}}
25+
std::chrono::hh_mm_ss<std::string> h2; // expected-error-re@chrono:* {{static_assert failed {{.*}} "template parameter of hh_mm_ss must be a std::chrono::duration"}}
26+
std::chrono::hh_mm_ss<A> h3; // expected-error-re@chrono:* {{static_assert failed {{.*}} "template parameter of hh_mm_ss must be a std::chrono::duration"}}
27+
28+
return 0;
29+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
9+
// <chrono>
10+
11+
// constexpr bool is_am(const hours& h) noexcept;
12+
// Returns: 0h <= h && h <= 11h.
13+
14+
#include <chrono>
15+
#include <cassert>
16+
17+
#include "test_macros.h"
18+
19+
int main(int, char**)
20+
{
21+
using hours = std::chrono::hours;
22+
ASSERT_SAME_TYPE(bool, decltype(std::chrono::is_am(std::declval<hours>())));
23+
ASSERT_NOEXCEPT( std::chrono::is_am(std::declval<hours>()));
24+
25+
static_assert( std::chrono::is_am(hours( 0)), "");
26+
static_assert( std::chrono::is_am(hours(11)), "");
27+
static_assert(!std::chrono::is_am(hours(12)), "");
28+
static_assert(!std::chrono::is_am(hours(23)), "");
29+
30+
for (int i = 0; i < 12; ++i)
31+
assert( std::chrono::is_am(hours(i)));
32+
for (int i = 12; i < 24; ++i)
33+
assert(!std::chrono::is_am(hours(i)));
34+
35+
return 0;
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
9+
// <chrono>
10+
11+
// constexpr bool is_pm(const hours& h) noexcept;
12+
// Returns: 12h <= h && h <= 23
13+
14+
#include <chrono>
15+
#include <cassert>
16+
17+
#include "test_macros.h"
18+
19+
int main(int, char**)
20+
{
21+
using hours = std::chrono::hours;
22+
ASSERT_SAME_TYPE(bool, decltype(std::chrono::is_pm(std::declval<hours>())));
23+
ASSERT_NOEXCEPT( std::chrono::is_pm(std::declval<hours>()));
24+
25+
static_assert(!std::chrono::is_pm(hours( 0)), "");
26+
static_assert(!std::chrono::is_pm(hours(11)), "");
27+
static_assert( std::chrono::is_pm(hours(12)), "");
28+
static_assert( std::chrono::is_pm(hours(23)), "");
29+
30+
for (int i = 0; i < 12; ++i)
31+
assert(!std::chrono::is_pm(hours(i)));
32+
for (int i = 12; i < 24; ++i)
33+
assert( std::chrono::is_pm(hours(i)));
34+
35+
return 0;
36+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
9+
// <chrono>
10+
11+
// constexpr hours make12(const hours& h) noexcept;
12+
// Returns: The 12-hour equivalent of h in the range [1h, 12h].
13+
// If h is not in the range [0h, 23h], the value returned is unspecified.
14+
15+
#include <chrono>
16+
#include <cassert>
17+
18+
#include "test_macros.h"
19+
20+
int main(int, char**)
21+
{
22+
using hours = std::chrono::hours;
23+
ASSERT_SAME_TYPE(hours, decltype(std::chrono::make12(std::declval<hours>())));
24+
ASSERT_NOEXCEPT( std::chrono::make12(std::declval<hours>()));
25+
26+
static_assert( std::chrono::make12(hours( 0)) == hours(12), "");
27+
static_assert( std::chrono::make12(hours(11)) == hours(11), "");
28+
static_assert( std::chrono::make12(hours(12)) == hours(12), "");
29+
static_assert( std::chrono::make12(hours(23)) == hours(11), "");
30+
31+
assert( std::chrono::make12(hours(0)) == hours(12));
32+
for (int i = 1; i < 13; ++i)
33+
assert( std::chrono::make12(hours(i)) == hours(i));
34+
for (int i = 13; i < 24; ++i)
35+
assert( std::chrono::make12(hours(i)) == hours(i-12));
36+
37+
return 0;
38+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
9+
// <chrono>
10+
11+
// constexpr hours make24(const hours& h, bool is_pm) noexcept;
12+
// Returns: If is_pm is false, returns the 24-hour equivalent of h in the range [0h, 11h],
13+
// assuming h represents an ante meridiem hour.
14+
// Else returns the 24-hour equivalent of h in the range [12h, 23h],
15+
// assuming h represents a post meridiem hour.
16+
// If h is not in the range [1h, 12h], the value returned is unspecified.
17+
18+
#include <chrono>
19+
#include <cassert>
20+
21+
#include "test_macros.h"
22+
23+
int main(int, char**)
24+
{
25+
using hours = std::chrono::hours;
26+
ASSERT_SAME_TYPE(hours, decltype(std::chrono::make24(std::declval<hours>(), false)));
27+
ASSERT_NOEXCEPT( std::chrono::make24(std::declval<hours>(), false));
28+
29+
static_assert( std::chrono::make24(hours( 1), false) == hours( 1), "");
30+
static_assert( std::chrono::make24(hours(11), false) == hours(11), "");
31+
static_assert( std::chrono::make24(hours(12), false) == hours( 0), "");
32+
static_assert( std::chrono::make24(hours( 1), true) == hours(13), "");
33+
static_assert( std::chrono::make24(hours(11), true) == hours(23), "");
34+
static_assert( std::chrono::make24(hours(12), true) == hours(12), "");
35+
36+
for (int i = 1; i < 11; ++i)
37+
{
38+
assert((std::chrono::make24(hours(i), false)) == hours(i));
39+
assert((std::chrono::make24(hours(i), true)) == hours(12+i));
40+
}
41+
assert((std::chrono::make24(hours(12), false)) == hours( 0));
42+
assert((std::chrono::make24(hours(12), true)) == hours(12));
43+
44+
return 0;
45+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
9+
// <chrono>
10+
11+
// template <class Duration>
12+
// class hh_mm_ss
13+
//
14+
// constexpr chrono::hours hours() const noexcept;
15+
16+
// Test values
17+
// duration hours minutes seconds fractional
18+
// 5000s 1 23 20 0
19+
// 5000 minutes 83 20 0 0
20+
// 123456789ms 34 17 36 789ms
21+
// 123456789us 0 2 3 456789us
22+
// 123456789ns 0 0 0 123456789ns
23+
// 1000mfn 0 20 9 0.6 (6000/10000)
24+
// 10000mfn 3 21 36 0
25+
26+
27+
#include <chrono>
28+
#include <cassert>
29+
30+
#include "test_macros.h"
31+
32+
template <typename Duration>
33+
constexpr long check_hours(Duration d)
34+
{
35+
using HMS = std::chrono::hh_mm_ss<Duration>;
36+
ASSERT_SAME_TYPE(std::chrono::hours, decltype(std::declval<HMS>().hours()));
37+
ASSERT_NOEXCEPT( std::declval<HMS>().hours());
38+
return HMS(d).hours().count();
39+
}
40+
41+
int main(int, char**)
42+
{
43+
using microfortnights = std::chrono::duration<int, std::ratio<756, 625>>;
44+
45+
static_assert( check_hours(std::chrono::minutes( 1)) == 0, "");
46+
static_assert( check_hours(std::chrono::minutes(-1)) == 0, "");
47+
48+
assert( check_hours(std::chrono::seconds( 5000)) == 1);
49+
assert( check_hours(std::chrono::seconds(-5000)) == 1);
50+
assert( check_hours(std::chrono::minutes( 5000)) == 83);
51+
assert( check_hours(std::chrono::minutes(-5000)) == 83);
52+
assert( check_hours(std::chrono::hours( 11)) == 11);
53+
assert( check_hours(std::chrono::hours(-11)) == 11);
54+
55+
assert( check_hours(std::chrono::milliseconds( 123456789LL)) == 34);
56+
assert( check_hours(std::chrono::milliseconds(-123456789LL)) == 34);
57+
assert( check_hours(std::chrono::microseconds( 123456789LL)) == 0);
58+
assert( check_hours(std::chrono::microseconds(-123456789LL)) == 0);
59+
assert( check_hours(std::chrono::nanoseconds( 123456789LL)) == 0);
60+
assert( check_hours(std::chrono::nanoseconds(-123456789LL)) == 0);
61+
62+
assert( check_hours(microfortnights( 1000)) == 0);
63+
assert( check_hours(microfortnights( -1000)) == 0);
64+
assert( check_hours(microfortnights( 10000)) == 3);
65+
assert( check_hours(microfortnights(-10000)) == 3);
66+
67+
return 0;
68+
}

0 commit comments

Comments
 (0)