1 //===----------------------------------------------------------------------===////
3 // The LLVM Compiler Infrastructure
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===////
10 #ifndef FILESYSTEM_TIME_HELPER_H
11 #define FILESYSTEM_TIME_HELPER_H
13 #include "experimental/__config"
20 #if !defined(UTIME_OMIT)
21 #include <sys/time.h> // for ::utimes as used in __last_write_time
24 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
26 namespace time_detail { namespace {
28 using namespace chrono;
30 template <class FileTimeT,
31 bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
32 struct fs_time_util_base {
33 static constexpr auto max_seconds =
34 duration_cast<seconds>(FileTimeT::duration::max()).count();
36 static constexpr auto max_nsec =
37 duration_cast<nanoseconds>(FileTimeT::duration::max() -
41 static constexpr auto min_seconds =
42 duration_cast<seconds>(FileTimeT::duration::min()).count();
44 static constexpr auto min_nsec_timespec =
45 duration_cast<nanoseconds>(
46 (FileTimeT::duration::min() - seconds(min_seconds)) + seconds(1))
49 // Static assert that these values properly round trip.
50 static_assert((seconds(min_seconds) +
51 duration_cast<microseconds>(nanoseconds(min_nsec_timespec))) -
52 duration_cast<microseconds>(seconds(1)) ==
53 FileTimeT::duration::min(),
57 template <class FileTimeT>
58 struct fs_time_util_base<FileTimeT, true> {
59 static const long long max_seconds;
60 static const long long max_nsec;
61 static const long long min_seconds;
62 static const long long min_nsec_timespec;
65 template <class FileTimeT>
66 const long long fs_time_util_base<FileTimeT, true>::max_seconds =
67 duration_cast<seconds>(FileTimeT::duration::max()).count();
69 template <class FileTimeT>
70 const long long fs_time_util_base<FileTimeT, true>::max_nsec =
71 duration_cast<nanoseconds>(FileTimeT::duration::max() -
75 template <class FileTimeT>
76 const long long fs_time_util_base<FileTimeT, true>::min_seconds =
77 duration_cast<seconds>(FileTimeT::duration::min()).count();
79 template <class FileTimeT>
80 const long long fs_time_util_base<FileTimeT, true>::min_nsec_timespec =
81 duration_cast<nanoseconds>((FileTimeT::duration::min() -
82 seconds(min_seconds)) +
86 template <class FileTimeT, class TimeT, class TimeSpecT>
87 struct fs_time_util : fs_time_util_base<FileTimeT> {
88 using Base = fs_time_util_base<FileTimeT>;
90 using Base::max_seconds;
91 using Base::min_nsec_timespec;
92 using Base::min_seconds;
95 template <class CType, class ChronoType>
96 static bool checked_set(CType* out, ChronoType time) {
97 using Lim = numeric_limits<CType>;
98 if (time > Lim::max() || time < Lim::min())
100 *out = static_cast<CType>(time);
104 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
105 if (tm.tv_sec >= 0) {
106 return (tm.tv_sec < max_seconds) ||
107 (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
108 } else if (tm.tv_sec == (min_seconds - 1)) {
109 return tm.tv_nsec >= min_nsec_timespec;
111 return (tm.tv_sec >= min_seconds);
115 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
116 auto secs = duration_cast<seconds>(tm.time_since_epoch());
117 auto nsecs = duration_cast<nanoseconds>(tm.time_since_epoch() - secs);
118 if (nsecs.count() < 0) {
119 secs = secs + seconds(1);
120 nsecs = nsecs + seconds(1);
122 using TLim = numeric_limits<TimeT>;
123 if (secs.count() >= 0)
124 return secs.count() <= TLim::max();
125 return secs.count() >= TLim::min();
128 static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
129 convert_timespec(TimeSpecT tm) {
130 auto adj_msec = duration_cast<microseconds>(nanoseconds(tm.tv_nsec));
131 if (tm.tv_sec >= 0) {
132 auto Dur = seconds(tm.tv_sec) + microseconds(adj_msec);
133 return FileTimeT(Dur);
134 } else if (duration_cast<microseconds>(nanoseconds(tm.tv_nsec)).count() ==
136 return FileTimeT(seconds(tm.tv_sec));
137 } else { // tm.tv_sec < 0
139 duration_cast<microseconds>(seconds(1) - nanoseconds(tm.tv_nsec));
140 auto Dur = seconds(tm.tv_sec + 1) - adj_subsec;
141 return FileTimeT(Dur);
145 template <class SubSecDurT, class SubSecT>
146 static bool set_times_checked(TimeT* sec_out, SubSecT* subsec_out,
148 using namespace chrono;
149 auto dur = tp.time_since_epoch();
150 auto sec_dur = duration_cast<seconds>(dur);
151 auto subsec_dur = duration_cast<SubSecDurT>(dur - sec_dur);
152 // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
153 if (subsec_dur.count() < 0) {
154 if (sec_dur.count() > min_seconds) {
155 sec_dur -= seconds(1);
156 subsec_dur += seconds(1);
158 subsec_dur = SubSecDurT::zero();
161 return checked_set(sec_out, sec_dur.count()) &&
162 checked_set(subsec_out, subsec_dur.count());
167 } // end namespace time_detail
169 using time_detail::fs_time_util;
171 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
173 #endif // FILESYSTEM_TIME_HELPER_H