public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-3937] libstdc++: Add C++20 clocks
@ 2022-11-13  1:14 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2022-11-13  1:14 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:1736bf5a61c7364c5da6fa52e5e2bfdbc9507c97

commit r13-3937-g1736bf5a61c7364c5da6fa52e5e2bfdbc9507c97
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 7 17:37:07 2021 +0100

    libstdc++: Add C++20 clocks
    
    Also add the basic types for timezones, without the non-inline
    definitions needed to actually use them.
    
    The get_leap_second_info function currently uses a hardcoded list of
    leap seconds, correct as of the end of 2022. That needs to be replaced
    with a dynamically generated list read from the system tzdata. That will
    be done in a later patch.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/chrono (utc_clock, tai_clock, gps_clock): Define.
            (clock_time_conversion, clock_cast): Define.
            (sys_info, local_info): Define structs for timezone information.
            (nonexistent_local_time, ambiguous_local_time): Define
            exceptions for invalid times.
            (time_zone, time_zone_link, leap_second, zoned_traits, tzdb)
            (tzdb_list): Define classes representing time zones.
            (get_leap_second_info): Define new function returning leap
            second offset for a given time point.
            * testsuite/std/time/clock/gps/1.cc: New test.
            * testsuite/std/time/clock/tai/1.cc: New test.
            * testsuite/std/time/clock/utc/1.cc: New test.

Diff:
---
 libstdc++-v3/include/std/chrono                | 744 ++++++++++++++++++++++++-
 libstdc++-v3/testsuite/std/time/clock/gps/1.cc |  38 ++
 libstdc++-v3/testsuite/std/time/clock/tai/1.cc |  41 ++
 libstdc++-v3/testsuite/std/time/clock/utc/1.cc |  24 +
 4 files changed, 844 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index c0c3a679609..90b73f8198e 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -39,9 +39,15 @@
 #else
 
 #include <bits/chrono.h>
-#if __cplusplus > 201703L
-# include <sstream> // ostringstream
-# include <bits/charconv.h>
+
+#if __cplusplus >= 202002L
+# include <sstream>
+# include <string>
+# include <vector>
+# include <bits/charconv.h> // __to_chars_len, __to_chars_10_impl
+# include <bits/stl_algo.h> // upper_bound TODO: move leap_second_info to .so
+# include <bits/shared_ptr.h>
+# include <bits/unique_ptr.h>
 #endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -102,6 +108,357 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       seconds elapsed;
     };
 
+    template<typename _Duration>
+      leap_second_info
+      get_leap_second_info(const utc_time<_Duration>& __ut);
+
+    /** A clock that measures Universal Coordinated Time (UTC).
+     *
+     * The epoch is 1970-01-01 00:00:00.
+     *
+     * @since C++20
+     */
+    class utc_clock
+    {
+    public:
+      using rep                       = system_clock::rep;
+      using period                    = system_clock::period;
+      using duration                  = chrono::duration<rep, period>;
+      using time_point                = chrono::time_point<utc_clock>;
+      static constexpr bool is_steady = false;
+
+      static time_point
+      now()
+      { return from_sys(system_clock::now()); }
+
+      template<typename _Duration>
+	static sys_time<common_type_t<_Duration, seconds>>
+	to_sys(const utc_time<_Duration>& __t)
+	{
+	  using _CDur = common_type_t<_Duration, seconds>;
+	  const auto __li = chrono::get_leap_second_info(__t);
+	  sys_time<_CDur> __s{__t.time_since_epoch() - seconds{__li.elapsed}};
+	  if (__li.is_leap_second)
+	    __s = chrono::floor<seconds>(__s) + seconds{1} - _CDur{1};
+	  return __s;
+	}
+
+      template<typename _Duration>
+	static utc_time<common_type_t<_Duration, seconds>>
+	from_sys(const sys_time<_Duration>& __t)
+	{
+	  using _CDur = common_type_t<_Duration, seconds>;
+	  utc_time<_Duration> __u(__t.time_since_epoch());
+	  const auto __li = chrono::get_leap_second_info(__u);
+	  return utc_time<_CDur>{__u} + seconds{__li.elapsed};
+	}
+    };
+
+    /** A clock that measures International Atomic Time.
+     *
+     * The epoch is 1958-01-01 00:00:00.
+     *
+     * @since C++20
+     */
+    class tai_clock
+    {
+    public:
+      using rep                       = system_clock::rep;
+      using period                    = system_clock::period;
+      using duration                  = chrono::duration<rep, period>;
+      using time_point                = chrono::time_point<tai_clock>;
+      static constexpr bool is_steady = false; // XXX true for CLOCK_TAI?
+
+      // TODO move into lib, use CLOCK_TAI on linux, add extension point.
+      static time_point
+      now()
+      { return from_utc(utc_clock::now()); }
+
+      template<typename _Duration>
+	static utc_time<common_type_t<_Duration, seconds>>
+	to_utc(const tai_time<_Duration>& __t)
+	{
+	  using _CDur = common_type_t<_Duration, seconds>;
+	  return utc_time<_CDur>{__t.time_since_epoch()} - 378691210s;
+	}
+
+      template<typename _Duration>
+	static tai_time<common_type_t<_Duration, seconds>>
+	from_utc(const utc_time<_Duration>& __t)
+	{
+	  using _CDur = common_type_t<_Duration, seconds>;
+	  return tai_time<_CDur>{__t.time_since_epoch()} + 378691210s;
+	}
+    };
+
+    /** A clock that measures GPS time.
+     *
+     * The epoch is 1980-01-06 00:00:00.
+     *
+     * @since C++20
+     */
+    class gps_clock
+    {
+    public:
+      using rep                       = system_clock::rep;
+      using period                    = system_clock::period;
+      using duration                  = chrono::duration<rep, period>;
+      using time_point                = chrono::time_point<gps_clock>;
+      static constexpr bool is_steady = false; // XXX
+
+      // TODO move into lib, add extension point.
+      static time_point
+      now()
+      { return from_utc(utc_clock::now()); }
+
+      template<typename _Duration>
+	static utc_time<common_type_t<_Duration, seconds>>
+	to_utc(const gps_time<_Duration>& __t)
+	{
+	  using _CDur = common_type_t<_Duration, seconds>;
+	  return utc_time<_CDur>{__t.time_since_epoch()} + 315964809s;
+	}
+
+      template<typename _Duration>
+	static gps_time<common_type_t<_Duration, seconds>>
+	from_utc(const utc_time<_Duration>& __t)
+	{
+	  using _CDur = common_type_t<_Duration, seconds>;
+	  return gps_time<_CDur>{__t.time_since_epoch()} - 315964809s;
+	}
+    };
+
+
+    template<typename _DestClock, typename _SourceClock>
+      struct clock_time_conversion
+      { };
+
+    // Identity conversions
+
+    template<typename _Clock>
+      struct clock_time_conversion<_Clock, _Clock>
+      {
+	template<typename _Duration>
+	  time_point<_Clock, _Duration>
+	  operator()(const time_point<_Clock, _Duration>& __t) const
+	  { return __t; }
+      };
+
+    template<>
+      struct clock_time_conversion<system_clock, system_clock>
+      {
+	template<typename _Duration>
+	  sys_time<_Duration>
+	  operator()(const sys_time<_Duration>& __t) const
+	  { return __t; }
+      };
+
+    template<>
+      struct clock_time_conversion<utc_clock, utc_clock>
+      {
+	template<typename _Duration>
+	  utc_time<_Duration>
+	  operator()(const utc_time<_Duration>& __t) const
+	  { return __t; }
+      };
+
+    // Conversions between system_clock and utc_clock
+
+    template<>
+      struct clock_time_conversion<utc_clock, system_clock>
+      {
+	template<typename _Duration>
+	  utc_time<common_type_t<_Duration, seconds>>
+	  operator()(const sys_time<_Duration>& __t) const
+	  { return utc_clock::from_sys(__t); }
+      };
+
+    template<>
+      struct clock_time_conversion<system_clock, utc_clock>
+      {
+	template<typename _Duration>
+	  sys_time<common_type_t<_Duration, seconds>>
+	  operator()(const utc_time<_Duration>& __t) const
+	  { return utc_clock::to_sys(__t); }
+      };
+
+    template<typename _Tp, typename _Clock>
+      inline constexpr bool __is_time_point_for_v = false;
+
+    template<typename _Clock, typename _Duration>
+      inline constexpr bool
+       __is_time_point_for_v<time_point<_Clock, _Duration>, _Clock> = true;
+
+    // Conversions between system_clock and other clocks
+
+    template<typename _SourceClock>
+      struct clock_time_conversion<system_clock, _SourceClock>
+      {
+	template<typename _Duration, typename _Src = _SourceClock>
+	  auto
+	  operator()(const time_point<_SourceClock, _Duration>& __t) const
+	  -> decltype(_Src::to_sys(__t))
+	  {
+	    using _Ret = decltype(_SourceClock::to_sys(__t));
+	    static_assert(__is_time_point_for_v<_Ret, system_clock>);
+	    return _SourceClock::to_sys(__t);
+	  }
+      };
+
+    template<typename _DestClock>
+      struct clock_time_conversion<_DestClock, system_clock>
+      {
+	template<typename _Duration, typename _Dest = _DestClock>
+	  auto
+	  operator()(const sys_time<_Duration>& __t) const
+	  -> decltype(_Dest::from_sys(__t))
+	  {
+	    using _Ret = decltype(_DestClock::from_sys(__t));
+	    static_assert(__is_time_point_for_v<_Ret, _DestClock>);
+	    return _DestClock::from_sys(__t);
+	  }
+      };
+
+    // Conversions between utc_clock and other clocks
+
+    template<typename _SourceClock>
+      struct clock_time_conversion<utc_clock, _SourceClock>
+      {
+	template<typename _Duration, typename _Src = _SourceClock>
+	  auto
+	  operator()(const time_point<_SourceClock, _Duration>& __t) const
+	  -> decltype(_Src::to_utc(__t))
+	  {
+	    using _Ret = decltype(_SourceClock::to_utc(__t));
+	    static_assert(__is_time_point_for_v<_Ret, utc_clock>);
+	    return _SourceClock::to_utc(__t);
+	  }
+      };
+
+    template<typename _DestClock>
+      struct clock_time_conversion<_DestClock, utc_clock>
+      {
+	template<typename _Duration, typename _Dest = _DestClock>
+	  auto
+	  operator()(const utc_time<_Duration>& __t) const
+	  -> decltype(_Dest::from_utc(__t))
+	  {
+	    using _Ret = decltype(_DestClock::from_utc(__t));
+	    static_assert(__is_time_point_for_v<_Ret, _DestClock>);
+	    return _DestClock::from_utc(__t);
+	  }
+      };
+
+    /// @cond undocumented
+    namespace __detail
+    {
+      template<typename _DestClock, typename _SourceClock, typename _Duration>
+       concept __clock_convs
+	  = requires (const time_point<_SourceClock, _Duration>& __t) {
+	    clock_time_conversion<_DestClock, _SourceClock>{}(__t);
+	  };
+
+      template<typename _DestClock, typename _SourceClock, typename _Duration>
+       concept __clock_convs_sys
+	  = requires (const time_point<_SourceClock, _Duration>& __t) {
+	    clock_time_conversion<_DestClock, system_clock>{}(
+	      clock_time_conversion<system_clock, _SourceClock>{}(__t));
+	  };
+
+      template<typename _DestClock, typename _SourceClock, typename _Duration>
+       concept __clock_convs_utc
+	  = requires (const time_point<_SourceClock, _Duration>& __t) {
+	    clock_time_conversion<_DestClock, utc_clock>{}(
+	      clock_time_conversion<utc_clock, _SourceClock>{}(__t));
+	  };
+
+      template<typename _DestClock, typename _SourceClock, typename _Duration>
+	concept __clock_convs_sys_utc
+	  = requires (const time_point<_SourceClock, _Duration>& __t) {
+	    clock_time_conversion<_DestClock, utc_clock>{}(
+	      clock_time_conversion<utc_clock, system_clock>{}(
+		clock_time_conversion<system_clock, _SourceClock>{}(__t)));
+	  };
+
+      template<typename _DestClock, typename _SourceClock, typename _Duration>
+       concept __clock_convs_utc_sys
+	  = requires (const time_point<_SourceClock, _Duration>& __t) {
+	    clock_time_conversion<_DestClock, system_clock>{}(
+	      clock_time_conversion<system_clock, utc_clock>{}(
+		clock_time_conversion<utc_clock, _SourceClock>{}(__t)));
+	  };
+
+    } // namespace __detail
+    /// @endcond
+
+    /// Convert a time point to a different clock.
+    template<typename _DestClock, typename _SourceClock, typename _Duration>
+      inline auto
+      clock_cast(const time_point<_SourceClock, _Duration>& __t)
+      requires __detail::__clock_convs<_DestClock, _SourceClock, _Duration>
+	|| __detail::__clock_convs_sys<_DestClock, _SourceClock, _Duration>
+	|| __detail::__clock_convs_utc<_DestClock, _SourceClock, _Duration>
+	|| __detail::__clock_convs_sys_utc<_DestClock, _SourceClock, _Duration>
+	|| __detail::__clock_convs_utc_sys<_DestClock, _SourceClock, _Duration>
+      {
+       constexpr bool __direct
+	 = __detail::__clock_convs<_DestClock, _SourceClock, _Duration>;
+       if constexpr (__direct)
+	 {
+	   return clock_time_conversion<_DestClock, _SourceClock>{}(__t);
+	 }
+       else
+	 {
+	   constexpr bool __convert_via_sys_clock
+	     = __detail::__clock_convs_sys<_DestClock, _SourceClock, _Duration>;
+	   constexpr bool __convert_via_utc_clock
+	     = __detail::__clock_convs_utc<_DestClock, _SourceClock, _Duration>;
+	   if constexpr (__convert_via_sys_clock)
+	     {
+	       static_assert(!__convert_via_utc_clock,
+		 "clock_cast requires a unique best conversion, but "
+		 "conversion is possible via system_clock and also via"
+		 "utc_clock");
+	       return clock_time_conversion<_DestClock, system_clock>{}(
+			clock_time_conversion<system_clock, _SourceClock>{}(__t));
+	     }
+	   else if constexpr (__convert_via_utc_clock)
+	     {
+	       return clock_time_conversion<_DestClock, utc_clock>{}(
+			clock_time_conversion<utc_clock, _SourceClock>{}(__t));
+	     }
+	   else
+	     {
+	       constexpr bool __convert_via_sys_and_utc_clocks
+		 = __detail::__clock_convs_sys_utc<_DestClock,
+						   _SourceClock,
+						   _Duration>;
+
+	       if constexpr (__convert_via_sys_and_utc_clocks)
+		 {
+		   constexpr bool __convert_via_utc_and_sys_clocks
+		     = __detail::__clock_convs_utc_sys<_DestClock,
+						       _SourceClock,
+						       _Duration>;
+		   static_assert(!__convert_via_utc_and_sys_clocks,
+		     "clock_cast requires a unique best conversion, but "
+		     "conversion is possible via system_clock followed by "
+		     "utc_clock, and also via utc_clock followed by "
+		     "system_clock");
+		   return clock_time_conversion<_DestClock, utc_clock>{}(
+			    clock_time_conversion<utc_clock, system_clock>{}(
+			      clock_time_conversion<system_clock, _SourceClock>{}(__t)));
+		 }
+	       else
+		 {
+		   return clock_time_conversion<_DestClock, system_clock>{}(
+			    clock_time_conversion<system_clock, utc_clock>{}(
+			      clock_time_conversion<utc_clock, _SourceClock>{}(__t)));
+		 }
+	     }
+	 }
+      }
+
     // CALENDRICAL TYPES
 
     // CLASS DECLARATIONS
@@ -2055,6 +2412,387 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    return __h + 12h;
 	}
     }
+
+    // C++20 [time.zones] Time zones
+
+    struct sys_info
+    {
+      sys_seconds begin;
+      sys_seconds end;
+      seconds offset;
+      minutes save;
+      string abbrev;
+    };
+
+    struct local_info
+    {
+      static constexpr int unique      = 0;
+      static constexpr int nonexistent = 1;
+      static constexpr int ambiguous   = 2;
+
+      int result;
+      sys_info first;
+      sys_info second;
+    };
+
+    class nonexistent_local_time : public runtime_error
+    {
+    public:
+      template<typename _Duration>
+	nonexistent_local_time(const local_time<_Duration>& __tp,
+			       const local_info& __i)
+	: runtime_error(_S_make_what_str(__tp, __i))
+	{ __glibcxx_assert(__i.result == local_info::nonexistent); }
+
+    private:
+      template<typename _Duration> // TODO
+	static string
+	_S_make_what_str(const local_time<_Duration>&, const local_info&);
+    };
+
+    class ambiguous_local_time : public runtime_error
+    {
+    public:
+      template<typename _Duration>
+	ambiguous_local_time(const local_time<_Duration>& __tp,
+			       const local_info& __i)
+	: runtime_error(_S_make_what_str(__tp, __i))
+	{ __glibcxx_assert(__i.result == local_info::nonexistent); }
+
+    private:
+      template<typename _Duration> // TODO
+	static string
+	_S_make_what_str(const local_time<_Duration>&, const local_info&);
+    };
+
+    enum class choose { earliest, latest };
+
+    class time_zone
+    {
+    public:
+      time_zone(time_zone&&) = default;
+      time_zone& operator=(time_zone&&) = default;
+
+      string_view name() const noexcept { return _M_name; }
+
+      template<typename _Duration>
+	sys_info
+	get_info(const sys_time<_Duration>& __st) const;
+
+      template<typename _Duration>
+	local_info
+	get_info(const local_time<_Duration>& __tp) const;
+
+      template<typename _Duration>
+	sys_time<common_type_t<_Duration, seconds>>
+	to_sys(const local_time<_Duration>& __tp) const;
+
+      template<typename _Duration>
+	sys_time<common_type_t<_Duration, seconds>>
+	to_sys(const local_time<_Duration>& __tp, choose __z) const;
+
+      template<typename _Duration>
+	local_time<common_type_t<_Duration, seconds>>
+	to_local(const sys_time<_Duration>& __tp) const;
+
+      friend bool
+      operator==(const time_zone& __x, const time_zone& __y) noexcept
+      { return __x.name() == __y.name(); }
+
+      friend strong_ordering
+      operator<=>(const time_zone& __x, const time_zone& __y) noexcept
+      { return __x.name() <=> __y.name(); }
+
+    private:
+      string _M_name;
+      struct _Impl;
+      unique_ptr<_Impl> _M_impl;
+    };
+
+    struct tzdb;
+    const time_zone* locate_zone(string_view __tz_name);
+    const time_zone* current_zone();
+
+    class time_zone_link
+    {
+    public:
+      time_zone_link(time_zone_link&&) = default;
+      time_zone_link& operator=(time_zone_link&&) = default;
+
+      string_view name() const noexcept { return _M_name; }
+      string_view target() const noexcept { return _M_target; }
+
+      friend bool
+      operator==(const time_zone_link& __x, const time_zone_link& __y) noexcept
+      { return __x.name() == __y.name(); }
+
+      friend strong_ordering
+      operator<=>(const time_zone_link& __x, const time_zone_link& __y) noexcept
+      { return __x.name() <=> __y.name(); }
+
+    private:
+      friend const tzdb& reload_tzdb();
+      // TODO unspecified additional constructors
+      string _M_name;
+      string _M_target;
+    };
+
+    class leap_second
+    {
+    public:
+      leap_second(const leap_second&) = default;
+      leap_second& operator=(const leap_second&) = default;
+
+      constexpr sys_seconds
+      date() const noexcept
+      {
+	if (_M_s >= _M_s.zero()) [[likely]]
+	  return sys_seconds(_M_s);
+	return sys_seconds(-_M_s);
+      }
+
+      constexpr seconds
+      value() const noexcept
+      {
+	if (_M_s >= _M_s.zero()) [[likely]]
+	  return seconds(1);
+	return seconds(-1);
+      }
+
+      // This can be defaulted because the database will never contain two
+      // leap_second objects with the same date but different signs.
+      friend constexpr bool
+      operator==(const leap_second&, const leap_second&) noexcept = default;
+
+      friend constexpr strong_ordering
+      operator<=>(const leap_second& __x, const leap_second& __y) noexcept
+      { return __x.date() <=> __y.date(); }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator==(const leap_second& __x,
+		   const sys_time<_Duration>& __y) noexcept
+	{ return __x.date() == __y; }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator<(const leap_second& __x,
+		  const sys_time<_Duration>& __y) noexcept
+	{ return __x.date() < __y; }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator<(const sys_time<_Duration>& __x,
+		  const leap_second& __y) noexcept
+	{ return __x < __y.date(); }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator>(const leap_second& __x,
+		  const sys_time<_Duration>& __y) noexcept
+	{ return __y < __x.date(); }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator>(const sys_time<_Duration>& __x,
+		  const leap_second& __y) noexcept
+	{ return __y.date() < __x; }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator<=(const leap_second& __x,
+		  const sys_time<_Duration>& __y) noexcept
+	{ return !(__y < __x.date()); }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator<=(const sys_time<_Duration>& __x,
+		  const leap_second& __y) noexcept
+	{ return !(__y.date() < __x); }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator>=(const leap_second& __x,
+		  const sys_time<_Duration>& __y) noexcept
+	{ return !(__x.date() < __y); }
+
+      template<typename _Duration>
+	friend constexpr bool
+	operator>=(const sys_time<_Duration>& __x,
+		  const leap_second& __y) noexcept
+	{ return !(__x < __y.date()); }
+
+      template<three_way_comparable_with<seconds> _Duration>
+	friend constexpr auto
+	operator<=>(const leap_second& __x,
+		   const sys_time<_Duration>& __y) noexcept
+	{ return __x.date() <=> __y; }
+
+    private:
+      explicit leap_second(seconds::rep __s) : _M_s(__s) { }
+
+      friend const tzdb& reload_tzdb();
+      template<typename _Dur>
+	friend leap_second_info
+	get_leap_second_info(const utc_time<_Dur>&);
+
+      seconds _M_s; // == date().time_since_epoch() * value().count()
+    };
+
+    template<class _Tp> struct zoned_traits { };
+
+    template<>
+      struct zoned_traits<const time_zone*>
+      {
+	static const time_zone*
+	default_zone()
+	{ return std::chrono::locate_zone("UTC"); }
+
+	static const time_zone*
+	locate_zone(string_view __name)
+	{ return std::chrono::locate_zone(__name); }
+      };
+
+    struct tzdb
+    {
+      string version;
+      vector<time_zone> zones;
+      vector<time_zone_link> links;
+      vector<leap_second> leap_seconds;
+
+      const time_zone*
+      locate_zone(string_view __tz_name) const;
+
+      const time_zone*
+      current_zone() const;
+
+    private:
+      friend const tzdb& reload_tzdb();
+
+      struct _Rule;
+      vector<_Rule> _M_rules;
+    };
+
+    class tzdb_list
+    {
+      struct _Node;
+    public:
+      tzdb_list(const tzdb_list&) = delete;
+      tzdb_list& operator=(const tzdb_list&) = delete;
+
+      class const_iterator
+      {
+      public:
+	using value_type        = tzdb;
+	using reference         = const tzdb&;
+	using pointer           = const tzdb*;
+	using difference_type   = ptrdiff_t;
+	using iterator_category = forward_iterator_tag;
+
+	constexpr const_iterator() = default;
+	const_iterator(const const_iterator&) = default;
+	const_iterator(const_iterator&&) = default;
+	const_iterator& operator=(const const_iterator&) = default;
+	const_iterator& operator=(const_iterator&&) = default;
+
+	reference operator*() const noexcept;
+	pointer operator->() const noexcept { return &**this; }
+	const_iterator& operator++();
+	const_iterator operator++(int);
+
+	bool operator==(const const_iterator&) const noexcept = default;
+
+      private:
+	explicit const_iterator(const shared_ptr<_Node>&) noexcept;
+
+	shared_ptr<_Node> _M_node;
+	void* _M_reserved = nullptr;
+      };
+
+      // TODO const tzdb& front() const noexcept;
+
+      const_iterator erase_after(const_iterator);
+
+      const_iterator begin() const noexcept;
+      const_iterator end() const noexcept { return {}; }
+      const_iterator cbegin() const noexcept { return begin(); }
+      const_iterator cend() const noexcept { return end(); }
+
+    private:
+      constexpr explicit tzdb_list(nullptr_t);
+
+      friend const tzdb_list& get_tzdb_list();
+      friend const tzdb& get_tzdb();
+      friend const tzdb& reload_tzdb();
+
+      static _Node* _S_head;
+      static shared_ptr<_Node> _S_head_owner;
+    };
+
+    // TODO
+    // const tzdb_list& get_tzdb_list();
+    // const tzdb& get_tzdb();
+
+    // const tzdb& reload_tzdb();
+    // string remove_version();
+
+    template<typename _Duration, typename _TimeZonePtr = const time_zone*>
+      class zoned_time; // TODO
+
+    using zoned_seconds = zoned_time<seconds>;
+
+    template<typename _Duration>
+      leap_second_info
+      get_leap_second_info(const utc_time<_Duration>& __ut)
+      {
+	if constexpr (is_same_v<_Duration, seconds>)
+	  {
+	    // TODO move this function into the library and get leaps from tzdb.
+	    vector<seconds::rep> __leaps
+	    {
+		78796800, // 1 Jul 1972
+		94694400, // 1 Jan 1973
+	       126230400, // 1 Jan 1974
+	       157766400, // 1 Jan 1975
+	       189302400, // 1 Jan 1976
+	       220924800, // 1 Jan 1977
+	       252460800, // 1 Jan 1978
+	       283996800, // 1 Jan 1979
+	       315532800, // 1 Jan 1980
+	       362793600, // 1 Jul 1981
+	       394329600, // 1 Jul 1982
+	       425865600, // 1 Jul 1983
+	       489024000, // 1 Jul 1985
+	       567993600, // 1 Jan 1988
+	       631152000, // 1 Jan 1990
+	       662688000, // 1 Jan 1991
+	       709948800, // 1 Jul 1992
+	       741484800, // 1 Jul 1993
+	       773020800, // 1 Jul 1994
+	       820454400, // 1 Jan 1996
+	       867715200, // 1 Jul 1997
+	       915148800, // 1 Jan 1999
+	      1136073600, // 1 Jan 2006
+	      1230768000, // 1 Jan 2009
+	      1341100800, // 1 Jul 2012
+	      1435708800, // 1 Jul 2015
+	      1483228800, // 1 Jan 2017
+	    };
+
+	    auto __s = __ut.time_since_epoch().count();
+	    auto __pos = std::upper_bound(__leaps.begin(), __leaps.end(), __s);
+	    return {
+	      __pos != __leaps.begin() && __pos[-1] == __s,
+	      seconds{__pos - __leaps.begin()}
+	    };
+	  }
+	else
+	  {
+	    auto __s = chrono::time_point_cast<seconds>(__ut);
+	    return chrono::get_leap_second_info(__s);
+	  }
+      }
+
     /// @} group chrono
 #endif // C++20
   } // namespace chrono
diff --git a/libstdc++-v3/testsuite/std/time/clock/gps/1.cc b/libstdc++-v3/testsuite/std/time/clock/gps/1.cc
new file mode 100644
index 00000000000..9403ee1ecca
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/clock/gps/1.cc
@@ -0,0 +1,38 @@
+// { dg-options "-std=gnu++20" }
+// { dg-do run { target c++20 } }
+
+#include <chrono>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  using namespace std::chrono;
+
+  gps_seconds gps_epoch{0s};
+  utc_seconds gps_as_utc{sys_days{1980y/January/Sunday[1]}.time_since_epoch() + 9s};
+
+  VERIFY( clock_cast<utc_clock>(gps_epoch) == gps_as_utc );
+  VERIFY( gps_epoch == clock_cast<gps_clock>(gps_as_utc) );
+
+  tai_seconds tai_epoch{0s};
+  VERIFY( clock_cast<tai_clock>(clock_cast<gps_clock>(tai_epoch)) == tai_epoch );
+}
+
+void
+test02()
+{
+  using namespace std::chrono;
+
+  sys_days d{2022y/November/12};
+  VERIFY( clock_cast<system_clock>(clock_cast<gps_clock>(d)) == d );
+  gps_seconds t(1234567s);
+  VERIFY( clock_cast<gps_clock>(clock_cast<system_clock>(t)) == t );
+  VERIFY( clock_cast<gps_clock>(clock_cast<utc_clock>(t)) == t );
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/std/time/clock/tai/1.cc b/libstdc++-v3/testsuite/std/time/clock/tai/1.cc
new file mode 100644
index 00000000000..9b36f023c68
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/clock/tai/1.cc
@@ -0,0 +1,41 @@
+// { dg-options "-std=gnu++20" }
+// { dg-do run { target c++20 } }
+
+#include <chrono>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  using namespace std::chrono;
+
+  tai_seconds tai_epoch{0s};
+  utc_seconds tai_as_utc{sys_days{1958y/January/1}.time_since_epoch() - 10s};
+
+  VERIFY( clock_cast<utc_clock>(tai_epoch) == tai_as_utc );
+  VERIFY( tai_epoch == clock_cast<tai_clock>(tai_as_utc) );
+
+  sys_days y2k{2000y/January/1};
+  tai_seconds y2k_as_tai{clock_cast<tai_clock>(y2k)};
+  utc_seconds y2k_as_utc = utc_clock::from_sys(y2k);
+  VERIFY( clock_cast<utc_clock>(y2k_as_tai) == y2k_as_utc );
+  VERIFY( y2k_as_tai == clock_cast<tai_clock>(y2k_as_utc) );
+}
+
+void
+test02()
+{
+  using namespace std::chrono;
+
+  sys_days d{2022y/November/12};
+  VERIFY( clock_cast<system_clock>(clock_cast<tai_clock>(d)) == d );
+  tai_seconds t(1234567s);
+  VERIFY( clock_cast<tai_clock>(clock_cast<system_clock>(t)) == t );
+  VERIFY( clock_cast<tai_clock>(clock_cast<utc_clock>(t)) == t );
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/std/time/clock/utc/1.cc b/libstdc++-v3/testsuite/std/time/clock/utc/1.cc
new file mode 100644
index 00000000000..eef5f3c3a48
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/clock/utc/1.cc
@@ -0,0 +1,24 @@
+// { dg-options "-std=gnu++20" }
+// { dg-do run { target c++20 } }
+
+#include <chrono>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  using namespace std::chrono;
+
+  auto epoch = sys_seconds{sys_days{1970y/January/1}};
+  auto utc_epoch = clock_cast<utc_clock>(epoch);
+  VERIFY( utc_epoch.time_since_epoch() == 0s );
+
+  auto y2k = sys_seconds{sys_days{2000y/January/1}};
+  auto utc_y2k = clock_cast<utc_clock>(y2k);
+  VERIFY( utc_y2k.time_since_epoch() == 946'684'822s );
+}
+
+int main()
+{
+  test01();
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-11-13  1:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-13  1:14 [gcc r13-3937] libstdc++: Add C++20 clocks Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).