1 /*
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
9
10 #ifndef FATAL_INCLUDE_fatal_time_time_h
11 #define FATAL_INCLUDE_fatal_time_time_h
12
13 #include <fatal/type/apply.h>
14 #include <fatal/type/array.h>
15 #include <fatal/type/get.h>
16 #include <fatal/type/list.h>
17 #include <fatal/type/sequence.h>
18 #include <fatal/type/sort.h>
19
20 #include <chrono>
21 #include <ratio>
22 #include <type_traits>
23 #include <utility>
24
25 namespace fatal {
26 namespace time {
27
28 /**
29 * TODO: DOCUMENT
30 *
31 * @author: Marcelo Juchem <marcelo@fb.com>
32 */
33
34 namespace detail {
35
36 template <typename Ratio, char... Suffix>
37 using t_s = pair<Ratio, char_sequence<Suffix...>>;
38
39 } // namespace detail {
40
41 // TODO: MOVE TO MATH
42 using suffixes = list<
43 //detail::t_s<std::yocto, 'y', 's'>,
44 //detail::t_s<std::zepto, 'z', 's'>,
45 detail::t_s<std::atto, 'a', 's'>,
46 detail::t_s<std::femto, 'f', 's'>,
47 detail::t_s<std::pico, 'p', 's'>,
48 detail::t_s<std::nano, 'n', 's'>,
49 detail::t_s<std::micro, 'u', 's'>,
50 detail::t_s<std::milli, 'm', 's'>,
51 detail::t_s<std::centi, 'c', 's'>,
52 detail::t_s<std::deci, 'd', 's'>,
53 detail::t_s<std::chrono::seconds::period, 's'>,
54 detail::t_s<std::deca, 'd', 'a', 's'>,
55 detail::t_s<std::chrono::minutes::period, 'm', 'i', 'n'>,
56 detail::t_s<std::hecto, 'h', 's'>,
57 detail::t_s<std::kilo, 'k', 's'>,
58 detail::t_s<std::chrono::hours::period, 'h'>,
59 detail::t_s<
60 std::ratio_multiply<std::chrono::hours::period, std::ratio<24, 1>>, 'd'
61 >,
62 detail::t_s<
63 std::ratio_multiply<std::chrono::hours::period, std::ratio<24 * 7, 1>>,
64 'w', 'k'
65 >,
66 detail::t_s<std::mega, 'M', 's'>,
67 detail::t_s<std::giga, 'G', 's'>,
68 detail::t_s<std::tera, 'T', 's'>,
69 detail::t_s<std::peta, 'P', 's'>,
70 detail::t_s<std::exa, 'E', 's'>
71 //detail::t_s<std::zetta, 'Z', 's'>,
72 //detail::t_s<std::yotta, 'Y', 's'>
73 >;
74
75 // TODO: DOCUMENT AND TEST
76 template <typename TPeriod>
77 using suffix_t = second<get<suffixes, TPeriod>>;
78
79 // TODO: DOCUMENT AND TEST
80 template <typename T>
suffix()81 inline char const *suffix() {
82 return z_data<suffix_t<typename T::period>>();
83 }
84
85 // TODO: DOCUMENT AND TEST
86 template <typename T>
suffix(T const &)87 inline char const *suffix(T const &) {
88 return suffix<T>();
89 }
90
91 namespace detail {
92
93 template <typename...> struct pretty;
94
95 template <typename T, typename... Args>
96 struct pretty<T, Args...> {
97 template <typename Out, typename P, typename R>
98 static void print(Out &out, std::chrono::duration<R, P> time) {
99 auto const local = std::chrono::duration_cast<
100 std::chrono::duration<R, T>
101 >(time);
102
103 auto const remaining = time - local;
104
105 if (local.count()) {
106 out << local.count() << z_data<suffix_t<T>>();
107
108 if (sizeof...(Args) && remaining.count()) {
109 out << ' ';
110 }
111 }
112
113 pretty<Args...>::print(out, remaining);
114 }
115 };
116
117 template <>
118 struct pretty<> {
119 template <typename Out, typename D>
120 static void print(Out &, D) {}
121 };
122
123 using pretty_print_ratios = list<
124 std::ratio_multiply<std::chrono::hours::period, std::ratio<24 * 7, 1>>,
125 std::ratio_multiply<std::chrono::hours::period, std::ratio<24, 1>>,
126 std::chrono::hours::period,
127 std::chrono::minutes::period,
128 std::chrono::seconds::period,
129 std::chrono::milliseconds::period,
130 std::chrono::microseconds::period,
131 std::chrono::nanoseconds::period
132 >;
133
134 } // namespace detail {
135
136 template <typename Out, typename R, typename P>
137 Out &&pretty_print(Out &&out, std::chrono::duration<R, P> time) {
138 using ratios = reject<
139 typename detail::pretty_print_ratios, curry<applier<std::ratio_greater>, P>
140 >;
141 static_assert(!empty<ratios>::value, "unsupported duration");
142
143 using impl = apply_to<ratios, detail::pretty>;
144 impl::print(out, time);
145
146 return std::forward<Out>(out);
147 }
148
149 } // namespace time {
150 } // namespace fatal {
151
152 #endif // FATAL_INCLUDE_fatal_time_time_h
153