Skip to content
Open
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
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ set(files
__chrono/gps_clock.h
__chrono/hh_mm_ss.h
__chrono/high_resolution_clock.h
__chrono/is_clock.h
__chrono/leap_second.h
__chrono/literals.h
__chrono/local_info.h
Expand Down
73 changes: 73 additions & 0 deletions libcxx/include/__chrono/is_clock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___CHRONO_IS_CLOCK_H
#define _LIBCPP___CHRONO_IS_CLOCK_H

#include <__config>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_arithmetic.h>
#include <__type_traits/is_same.h>
#include <ratio>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER >= 20

_LIBCPP_BEGIN_NAMESPACE_STD

namespace chrono {

template <class _Rep, class _Period>
class duration;

template <class _Clock, class _Duration>
class time_point;

// Helper to check that _Tp::time_point has the form time_point<_, typename _Tp::duration>.
template <class _TimePoint, class _ClockType>
constexpr bool __is_valid_clock_time_point_v = false;

template <class _TimePointClock, class _ClockType>
constexpr bool __is_valid_clock_time_point_v<time_point<_TimePointClock, typename _ClockType::duration>, _ClockType> =
true;

// Check if a clock satisfies the Cpp17Clock requirements as defined in [time.clock.req]
template <class _Tp>
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires {
typename _Tp::rep;
requires is_arithmetic_v<typename _Tp::rep>;

typename _Tp::period;
requires __is_ratio_v<typename _Tp::period>;

typename _Tp::duration;
requires _IsSame<typename _Tp::duration, duration<typename _Tp::rep, typename _Tp::period>>::value;

typename _Tp::time_point;
requires __is_valid_clock_time_point_v<typename _Tp::time_point, _Tp>;

_Tp::is_steady;
requires _IsSame<decltype(_Tp::is_steady), const bool>::value;

_Tp::now();
requires _IsSame<decltype(_Tp::now()), typename _Tp::time_point>::value;
};

template <class _Tp>
struct _LIBCPP_NO_SPECIALIZATIONS is_clock : bool_constant<is_clock_v<_Tp>> {};

} // namespace chrono

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER
#endif // _LIBCPP___CHRONO_IS_CLOCK_H
4 changes: 4 additions & 0 deletions libcxx/include/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ template <class ToDuration, class Rep, class Period>
template <class ToDuration, class Rep, class Period>
constexpr ToDuration round(const duration<Rep, Period>& d); // C++17

template <class T> struct is_clock; // C++20
template <class T> inline constexpr bool is_clock_v = is_clock<T>::value; // C++20

// duration I/O
template<class charT, class traits, class Rep, class Period> // C++20
basic_ostream<charT, traits>&
Expand Down Expand Up @@ -1057,6 +1060,7 @@ constexpr chrono::year operator ""y(unsigned lo
# include <__chrono/day.h>
# include <__chrono/exception.h>
# include <__chrono/hh_mm_ss.h>
# include <__chrono/is_clock.h>
# include <__chrono/literals.h>
# include <__chrono/local_info.h>
# include <__chrono/month.h>
Expand Down
4 changes: 4 additions & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,10 @@ module std [system] {
header "__chrono/high_resolution_clock.h"
export *
}
module is_clock {
header "__chrono/is_clock.h"
export std_core.type_traits.integral_constant
}
module leap_second {
header "__chrono/leap_second.h"
}
Expand Down
4 changes: 2 additions & 2 deletions libcxx/modules/std/chrono.inc
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export namespace std {

using std::chrono::duration_values;

// using std::chrono::is_clock;
// using std::chrono::is_clock_v;
using std::chrono::is_clock;
using std::chrono::is_clock_v;

// [time.duration.nonmember], duration arithmetic
using std::chrono::operator+;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
//===----------------------------------------------------------------------===//
//
// 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>

#include "test_macros.h"

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();
};

// 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>);
#if _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>);
#if _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>);

// cv-qualified and reference types
static_assert(std::chrono::is_clock_v<const std::chrono::system_clock>);
static_assert(std::chrono::is_clock_v<volatile std::chrono::system_clock>);
static_assert(std::chrono::is_clock_v<const volatile std::chrono::system_clock>);
static_assert(!std::chrono::is_clock_v<std::chrono::system_clock&>);
static_assert(!std::chrono::is_clock_v<std::chrono::system_clock&&>);
static_assert(!std::chrono::is_clock_v<const std::chrono::system_clock&>);

// array and pointer types
static_assert(!std::chrono::is_clock_v<std::chrono::system_clock[]>);
static_assert(!std::chrono::is_clock_v<std::chrono::system_clock[10]>);
static_assert(!std::chrono::is_clock_v<std::chrono::system_clock*>);
static_assert(!std::chrono::is_clock_v<std::chrono::system_clock* const>);

// The Standard defined a minimum set of checks and allowed implementation to perform stricter checks. The following
// static asserts are implementation specific and a conforming standard library implementation doesn't have to produce
// the same outcome.

// Test clocks with invalid is_steady type
LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongIsSteadyType>); // is_steady not const bool
LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongIsSteadyNonBool>); // is_steady not bool type

// Test clocks with invalid now() return type
LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongNowReturnType>); // now() doesn't return time_point

// Test clocks with invalid period type
LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongPeriodType>); // period is not a ratio

// Test clocks with invalid rep type
LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<InvalidRepType>); // rep is not arithmetic and no numeric_limits

// Test clocks with wrong duration type
LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongDurationType>); // duration doesn't match duration<rep, period>

// Test clocks with wrong time_point type
LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongTimePointType>); // time_point is not a time_point
LIBCPP_STATIC_ASSERT(!std::chrono::is_clock_v<WrongTimePointClock>); // time_point has wrong clock and wrong duration
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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>

#if !__has_warning("-Winvalid-specializations")
// expected-no-diagnostics
#else

namespace std::chrono {
// try adding specializations to is_clock
template <>
struct is_clock<int> : std::false_type {}; // expected-error@*:* {{'is_clock' cannot be specialized}}

template <>
constexpr bool is_clock_v<float> = false; // expected-error@*:* {{'is_clock_v' cannot be specialized}}

} // namespace std::chrono

#endif
Loading