]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // (C) Copyright Howard Hinnant |
2 | // (C) Copyright 2011 Vicente J. Botet Escriba | |
3 | // Use, modification and distribution are subject to the Boost Software License, | |
4 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
5 | // http://www.boost.org/LICENSE_1_0.txt). | |
6 | // | |
7 | ||
8 | #ifndef BOOST_CHRONO_IO_TIME_POINT_GET_HPP | |
9 | #define BOOST_CHRONO_IO_TIME_POINT_GET_HPP | |
10 | ||
11 | #include <boost/chrono/config.hpp> | |
12 | #include <boost/chrono/detail/scan_keyword.hpp> | |
13 | #include <boost/chrono/io/time_point_units.hpp> | |
14 | #include <boost/chrono/io/duration_get.hpp> | |
15 | #include <boost/assert.hpp> | |
16 | #include <locale> | |
17 | #include <string> | |
18 | ||
19 | /** | |
20 | * Duration formatting facet for input. | |
21 | */ | |
22 | namespace boost | |
23 | { | |
24 | namespace chrono | |
25 | { | |
26 | ||
27 | template <class CharT, class InputIterator = std::istreambuf_iterator<CharT> > | |
28 | class time_point_get: public std::locale::facet | |
29 | { | |
30 | public: | |
31 | /** | |
32 | * Type of character the facet is instantiated on. | |
33 | */ | |
34 | typedef CharT char_type; | |
35 | /** | |
36 | * Type of iterator used to scan the character buffer. | |
37 | */ | |
38 | typedef InputIterator iter_type; | |
39 | ||
40 | /** | |
41 | * Construct a @c time_point_get facet. | |
42 | * @param refs | |
43 | * @Effects Construct a @c time_point_get facet. | |
44 | * If the @c refs argument is @c 0 then destruction of the object is | |
45 | * delegated to the @c locale, or locales, containing it. This allows | |
46 | * the user to ignore lifetime management issues. On the other had, | |
47 | * if @c refs is @c 1 then the object must be explicitly deleted; | |
48 | * the @c locale will not do so. In this case, the object can be | |
49 | * maintained across the lifetime of multiple locales. | |
50 | */ | |
51 | ||
52 | explicit time_point_get(size_t refs = 0) : | |
53 | std::locale::facet(refs) | |
54 | { | |
55 | } | |
56 | ||
57 | /** | |
58 | * @param s start input stream iterator | |
59 | * @param end end input stream iterator | |
60 | * @param ios a reference to a ios_base | |
61 | * @param err the ios_base state | |
62 | * @param d the duration | |
63 | * @param pattern begin of the formatting pattern | |
64 | * @param pat_end end of the formatting pattern | |
65 | * | |
66 | * Requires: [pattern,pat_end) shall be a valid range. | |
67 | * | |
68 | * Effects: The function starts by evaluating err = std::ios_base::goodbit. | |
69 | * It then enters a loop, reading zero or more characters from s at | |
70 | * each iteration. Unless otherwise specified below, the loop | |
71 | * terminates when the first of the following conditions holds: | |
72 | * - The expression pattern == pat_end evaluates to true. | |
73 | * - The expression err == std::ios_base::goodbit evaluates to false. | |
74 | * - The expression s == end evaluates to true, in which case the | |
75 | * function evaluates err = std::ios_base::eofbit | std::ios_base::failbit. | |
76 | * - The next element of pattern is equal to '%', followed by a conversion | |
77 | * specifier character, the functions @c get_duration or @c get_epoch are called depending on | |
78 | * whether the format is @c 'd' or @c 'e'. | |
79 | * If the number of elements in the range [pattern,pat_end) is not | |
80 | * sufficient to unambiguously determine whether the conversion | |
81 | * specification is complete and valid, the function evaluates | |
82 | * err = std::ios_base::failbit. Otherwise, the function evaluates | |
83 | * s = do_get(s, end, ios, err, d). If err == std::ios_base::goodbit holds after | |
84 | * the evaluation of the expression, the function increments pattern to | |
85 | * point just past the end of the conversion specification and continues | |
86 | * looping. | |
87 | * - The expression isspace(*pattern, ios.getloc()) evaluates to true, in | |
88 | * which case the function first increments pattern until | |
89 | * pattern == pat_end || !isspace(*pattern, ios.getloc()) evaluates to true, | |
90 | * then advances s until s == end || !isspace(*s, ios.getloc()) is true, | |
91 | * and finally resumes looping. | |
92 | * - The next character read from s matches the element pointed to by | |
93 | * pattern in a case-insensitive comparison, in which case the function | |
94 | * evaluates ++pattern, ++s and continues looping. Otherwise, the function | |
95 | * evaluates err = std::ios_base::failbit. | |
96 | * | |
97 | * Returns: s | |
98 | */ | |
99 | ||
100 | template <class Clock, class Duration> | |
101 | iter_type get(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, | |
102 | time_point<Clock, Duration> &tp, const char_type *pattern, const char_type *pat_end) const | |
103 | { | |
104 | if (std::has_facet<time_point_units<CharT> >(is.getloc())) | |
105 | { | |
106 | time_point_units<CharT> const &facet = std::use_facet<time_point_units<CharT> >(is.getloc()); | |
107 | return get(facet, i, e, is, err, tp, pattern, pat_end); | |
108 | } | |
109 | else | |
110 | { | |
111 | time_point_units_default<CharT> facet; | |
112 | return get(facet, i, e, is, err, tp, pattern, pat_end); | |
113 | } | |
114 | } | |
115 | ||
116 | template <class Clock, class Duration> | |
117 | iter_type get(time_point_units<CharT> const &facet, iter_type s, iter_type end, std::ios_base& ios, | |
118 | std::ios_base::iostate& err, time_point<Clock, Duration> &tp, const char_type *pattern, | |
119 | const char_type *pat_end) const | |
120 | { | |
121 | ||
122 | Duration d; | |
123 | bool duration_found = false, epoch_found = false; | |
124 | ||
125 | const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(ios.getloc()); | |
126 | err = std::ios_base::goodbit; | |
127 | while (pattern != pat_end && err == std::ios_base::goodbit) | |
128 | { | |
129 | if (s == end) | |
130 | { | |
131 | err |= std::ios_base::eofbit; | |
132 | break; | |
133 | } | |
134 | if (ct.narrow(*pattern, 0) == '%') | |
135 | { | |
136 | if (++pattern == pat_end) | |
137 | { | |
138 | err |= std::ios_base::failbit; | |
139 | return s; | |
140 | } | |
141 | char cmd = ct.narrow(*pattern, 0); | |
142 | switch (cmd) | |
143 | { | |
144 | case 'd': | |
145 | { | |
146 | if (duration_found) | |
147 | { | |
148 | err |= std::ios_base::failbit; | |
149 | return s; | |
150 | } | |
151 | duration_found = true; | |
152 | s = get_duration(s, end, ios, err, d); | |
153 | if (err & (std::ios_base::badbit | std::ios_base::failbit)) | |
154 | { | |
155 | return s; | |
156 | } | |
157 | break; | |
158 | } | |
159 | case 'e': | |
160 | { | |
161 | if (epoch_found) | |
162 | { | |
163 | err |= std::ios_base::failbit; | |
164 | return s; | |
165 | } | |
166 | epoch_found = true; | |
167 | s = get_epoch<Clock> (facet, s, end, ios, err); | |
168 | if (err & (std::ios_base::badbit | std::ios_base::failbit)) | |
169 | { | |
170 | return s; | |
171 | } | |
172 | break; | |
173 | } | |
174 | default: | |
175 | BOOST_ASSERT(false && "Boost::Chrono internal error."); | |
176 | break; | |
177 | } | |
178 | ||
179 | ++pattern; | |
180 | } | |
181 | else if (ct.is(std::ctype_base::space, *pattern)) | |
182 | { | |
183 | for (++pattern; pattern != pat_end && ct.is(std::ctype_base::space, *pattern); ++pattern) | |
184 | ; | |
185 | for (; s != end && ct.is(std::ctype_base::space, *s); ++s) | |
186 | ; | |
187 | } | |
188 | else if (ct.toupper(*s) == ct.toupper(*pattern)) | |
189 | { | |
190 | ++s; | |
191 | ++pattern; | |
192 | } | |
193 | else | |
194 | { | |
195 | err |= std::ios_base::failbit; | |
196 | } | |
197 | } | |
198 | ||
199 | // Success! Store it. | |
200 | tp = time_point<Clock, Duration> (d); | |
201 | return s; | |
202 | } | |
203 | ||
204 | /** | |
205 | * | |
206 | * @param s an input stream iterator | |
207 | * @param ios a reference to a ios_base | |
208 | * @param d the duration | |
209 | * Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if | |
210 | * @code | |
211 | * return get(s, end, ios, err, ios, d, str.data(), str.data() + str.size()); | |
212 | * @codeend | |
213 | * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name | |
214 | */ | |
215 | template <class Clock, class Duration> | |
216 | iter_type get(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, | |
217 | time_point<Clock, Duration> &tp) const | |
218 | { | |
219 | if (std::has_facet<time_point_units<CharT> >(is.getloc())) | |
220 | { | |
221 | time_point_units<CharT> const &facet = std::use_facet<time_point_units<CharT> >(is.getloc()); | |
222 | std::basic_string<CharT> str = facet.get_pattern(); | |
223 | return get(facet, i, e, is, err, tp, str.data(), str.data() + str.size()); | |
224 | } | |
225 | else | |
226 | { | |
227 | time_point_units_default<CharT> facet; | |
228 | std::basic_string<CharT> str = facet.get_pattern(); | |
229 | return get(facet, i, e, is, err, tp, str.data(), str.data() + str.size()); | |
230 | } | |
231 | } | |
232 | ||
233 | /** | |
234 | * As if | |
235 | * @code | |
236 | * return facet.get(s, end, ios, err, d); | |
237 | * @endcode | |
238 | * where @c facet is either the @c duration_get facet associated to the @c ios or an instance of the default @c duration_get facet. | |
239 | * | |
240 | * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid duration. | |
241 | */ | |
242 | template <typename Rep, typename Period> | |
243 | iter_type get_duration(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, | |
244 | duration<Rep, Period>& d) const | |
245 | { | |
246 | if (std::has_facet<duration_get<CharT> >(is.getloc())) | |
247 | { | |
248 | duration_get<CharT> const &facet = std::use_facet<duration_get<CharT> >(is.getloc()); | |
249 | return get_duration(facet, i, e, is, err, d); | |
250 | } | |
251 | else | |
252 | { | |
253 | duration_get<CharT> facet; | |
254 | return get_duration(facet, i, e, is, err, d); | |
255 | } | |
256 | } | |
257 | ||
258 | template <typename Rep, typename Period> | |
259 | iter_type get_duration(duration_get<CharT> const& facet, iter_type s, iter_type end, std::ios_base& ios, | |
260 | std::ios_base::iostate& err, duration<Rep, Period>& d) const | |
261 | { | |
262 | return facet.get(s, end, ios, err, d); | |
263 | } | |
264 | ||
265 | /** | |
266 | * | |
267 | * @Effects Let @c facet be the @c time_point_units facet associated to @c is or a new instance of the default @c time_point_units_default facet. | |
268 | * Let @c epoch be the epoch string associated to the Clock using this facet. | |
269 | * Scans @c i to match @c epoch or @c e is reached. | |
270 | * | |
271 | * If not match before the @c e is reached @c std::ios_base::failbit is set in @c err. | |
272 | * If @c e is reached @c std::ios_base::failbit is set in @c err. | |
273 | * | |
274 | * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid epoch. | |
275 | */ | |
276 | template <class Clock> | |
277 | iter_type get_epoch(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err) const | |
278 | { | |
279 | if (std::has_facet<time_point_units<CharT> >(is.getloc())) | |
280 | { | |
281 | time_point_units<CharT> const &facet = std::use_facet<time_point_units<CharT> >(is.getloc()); | |
282 | return get_epoch<Clock>(facet, i, e, is, err); | |
283 | } | |
284 | else | |
285 | { | |
286 | time_point_units_default<CharT> facet; | |
287 | return get_epoch<Clock>(facet, i, e, is, err); | |
288 | } | |
289 | } | |
290 | ||
291 | template <class Clock> | |
292 | iter_type get_epoch(time_point_units<CharT> const &facet, iter_type i, iter_type e, std::ios_base&, | |
293 | std::ios_base::iostate& err) const | |
294 | { | |
295 | const std::basic_string<CharT> epoch = facet.template get_epoch<Clock> (); | |
296 | std::ptrdiff_t k = chrono_detail::scan_keyword(i, e, &epoch, &epoch + 1, | |
297 | //~ std::use_facet<std::ctype<CharT> >(ios.getloc()), | |
298 | err) - &epoch; | |
299 | if (k == 1) | |
300 | { | |
301 | err |= std::ios_base::failbit; | |
302 | return i; | |
303 | } | |
304 | return i; | |
305 | } | |
306 | ||
307 | /** | |
308 | * Unique identifier for this type of facet. | |
309 | */ | |
310 | static std::locale::id id; | |
311 | ||
312 | /** | |
313 | * @Effects Destroy the facet | |
314 | */ | |
315 | ~time_point_get() | |
316 | { | |
317 | } | |
318 | }; | |
319 | ||
320 | /** | |
321 | * Unique identifier for this type of facet. | |
322 | */ | |
323 | template <class CharT, class InputIterator> | |
324 | std::locale::id time_point_get<CharT, InputIterator>::id; | |
325 | ||
326 | } // chrono | |
327 | } | |
328 | // boost | |
329 | ||
330 | #endif // header |