[libcxx-commits] [libcxx] [libcxx] Implement C++20 std::chrono::is_clock, std::chrono::is_clock_v (PR #160607)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Sep 25 18:04:21 PDT 2025
================
@@ -0,0 +1,242 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+#include <chrono>
+#include <ratio>
+
+struct EmptyStruct {};
+
+// Test structs missing required members
+struct MissingRep {
+ using period = std::ratio<1>;
+ using duration = std::chrono::seconds;
+ using time_point = std::chrono::time_point<MissingRep>;
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+struct MissingPeriod {
+ using rep = long;
+ using duration = std::chrono::seconds;
+ using time_point = std::chrono::time_point<MissingPeriod>;
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+struct MissingDuration {
+ using rep = long;
+ using time_point = long;
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+struct MissingTimePoint {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::seconds;
+ static constexpr bool is_steady = false;
+ static std::chrono::time_point<MissingTimePoint> now();
+};
+
+struct MissingIsSteady {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::seconds;
+ using time_point = std::chrono::time_point<MissingIsSteady>;
+ static time_point now();
+};
+
+struct MissingNow {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::seconds;
+ using time_point = std::chrono::time_point<MissingNow>;
+ static constexpr bool is_steady = false;
+};
+
+// Valid clock types
+struct ValidSteadyClock {
+ using rep = long long;
+ using period = std::nano;
+ using duration = std::chrono::nanoseconds;
+ using time_point = std::chrono::time_point<ValidSteadyClock>;
+ static constexpr bool is_steady = true;
+ static time_point now();
+};
+
+struct ValidSystemClock {
+ using rep = long long;
+ using period = std::micro;
+ using duration = std::chrono::microseconds;
+ using time_point = std::chrono::time_point<ValidSystemClock>;
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+// Test clocks with invalid is_steady type
+struct WrongIsSteadyType {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::seconds;
+ using time_point = std::chrono::time_point<WrongIsSteadyType>;
+ static bool is_steady; // Not const bool
+ static time_point now();
+};
+
+struct WrongIsSteadyNonBool {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::seconds;
+ using time_point = std::chrono::time_point<WrongIsSteadyNonBool>;
+ static constexpr int is_steady = 1; // Not bool
+ static time_point now();
+};
+
+// Test clocks with invalid now() return type
+struct WrongNowReturnType {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::seconds;
+ using time_point = std::chrono::time_point<WrongNowReturnType>;
+ static constexpr bool is_steady = false;
+ static int now(); // Wrong return type
+};
+
+// Test clocks with invalid period type
+struct WrongPeriodType {
+ using rep = long;
+ using period = int; // Not a ratio
+ using duration = std::chrono::seconds;
+ using time_point = std::chrono::time_point<WrongPeriodType>;
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+// Test clocks with invalid rep type (neither arithmetic nor numeric_limits specialized)
+struct InvalidRepType {
+ using rep = EmptyStruct; // Not arithmetic, no numeric_limits specialization
+ using period = std::ratio<1>;
+ using duration = std::chrono::duration<EmptyStruct>;
+ using time_point = std::chrono::time_point<InvalidRepType, duration>;
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+// Test clocks with wrong duration type
+struct WrongDurationType {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::milliseconds; // Should be duration<long, ratio<1>>
+ using time_point = std::chrono::time_point<WrongDurationType>;
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+// Test clocks with wrong time_point type
+struct WrongTimePointType {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::duration<long, std::ratio<1>>;
+ using time_point = int; // Not a time_point
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+struct WrongTimePointClock {
+ using rep = long;
+ using period = std::ratio<1>;
+ using duration = std::chrono::duration<long, std::ratio<1>>;
+ using time_point = std::chrono::time_point<ValidSystemClock>; // Wrong clock type
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+// Valid clock with time_point that has matching duration instead of matching clock
+struct ValidClockWithDurationMatch {
+ using rep = int;
+ using period = std::milli;
+ using duration = std::chrono::duration<int, std::milli>;
+ using time_point = std::chrono::time_point<ValidSystemClock, duration>; // Valid: matches duration
+ static constexpr bool is_steady = false;
+ static time_point now();
+};
+
+int main(int, char**) {
+ // Test both is_clock and is_clock_v
+ static_assert(std::chrono::is_clock<std::chrono::system_clock>::value);
+ static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
+
+ // Test standard clock types
+ static_assert(std::chrono::is_clock_v<std::chrono::system_clock>);
+#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK
+ static_assert(std::chrono::is_clock_v<std::chrono::steady_clock>);
+#endif
+ static_assert(std::chrono::is_clock_v<std::chrono::high_resolution_clock>);
+
+ // Test non-clock types
+ static_assert(!std::chrono::is_clock_v<EmptyStruct>);
+ static_assert(!std::chrono::is_clock_v<int>);
+ static_assert(!std::chrono::is_clock_v<void>);
+ static_assert(!std::chrono::is_clock_v<std::chrono::system_clock::time_point>);
+#ifdef _LIBCPP_HAS_MONOTONIC_CLOCK
+ static_assert(!std::chrono::is_clock_v<std::chrono::steady_clock::time_point>);
+#endif
+ static_assert(!std::chrono::is_clock_v<std::chrono::seconds>);
+ static_assert(!std::chrono::is_clock_v<std::chrono::milliseconds>);
+
+ // Test structs missing required members
+ static_assert(!std::chrono::is_clock_v<MissingRep>);
+ static_assert(!std::chrono::is_clock_v<MissingPeriod>);
+ static_assert(!std::chrono::is_clock_v<MissingDuration>);
+ static_assert(!std::chrono::is_clock_v<MissingTimePoint>);
+ static_assert(!std::chrono::is_clock_v<MissingIsSteady>);
+ static_assert(!std::chrono::is_clock_v<MissingNow>);
+
+ // Test valid custom clocks
+ static_assert(std::chrono::is_clock_v<ValidSteadyClock>);
+ static_assert(std::chrono::is_clock_v<ValidSystemClock>);
+ static_assert(std::chrono::is_clock_v<ValidClockWithDurationMatch>);
+
+ // Test clocks with invalid is_steady type
+ static_assert(!std::chrono::is_clock_v<WrongIsSteadyType>); // is_steady not const bool
----------------
frederick-vs-ja wrote:
I think it's better to write stricter-than-standard checks as `LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<...>)`, because other implementations may use this test file and they may implement `is_clock_v` in some more relaxed or different way.
https://github.com/llvm/llvm-project/pull/160607
More information about the libcxx-commits
mailing list