Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/chrono/io/duration_get.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
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_DURATION_GET_HPP | |
9 #define BOOST_CHRONO_IO_DURATION_GET_HPP | |
10 | |
11 #include <boost/chrono/config.hpp> | |
12 #include <string> | |
13 #include <boost/type_traits/is_scalar.hpp> | |
14 #include <boost/utility/enable_if.hpp> | |
15 #include <boost/type_traits/is_signed.hpp> | |
16 #include <boost/mpl/if.hpp> | |
17 #include <boost/math/common_factor_rt.hpp> | |
18 #include <boost/chrono/detail/scan_keyword.hpp> | |
19 #include <boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp> | |
20 | |
21 #include <boost/assert.hpp> | |
22 #include <locale> | |
23 | |
24 /** | |
25 * Duration formatting facet for input. | |
26 */ | |
27 namespace boost | |
28 { | |
29 namespace chrono | |
30 { | |
31 | |
32 namespace detail | |
33 { | |
34 template <class Rep, bool = is_scalar<Rep>::value> | |
35 struct duration_io_intermediate | |
36 { | |
37 typedef Rep type; | |
38 }; | |
39 | |
40 template <class Rep> | |
41 struct duration_io_intermediate<Rep, true> | |
42 { | |
43 typedef typename mpl::if_c<is_floating_point<Rep>::value, long double, typename mpl::if_c< | |
44 is_signed<Rep>::value, long long, unsigned long long>::type>::type type; | |
45 }; | |
46 | |
47 template <typename intermediate_type> | |
48 typename enable_if<is_integral<intermediate_type> , bool>::type reduce(intermediate_type& r, | |
49 unsigned long long& den, std::ios_base::iostate& err) | |
50 { | |
51 typedef typename common_type<intermediate_type, unsigned long long>::type common_type_t; | |
52 | |
53 // Reduce r * num / den | |
54 common_type_t t = math::gcd<common_type_t>(common_type_t(r), common_type_t(den)); | |
55 r /= t; | |
56 den /= t; | |
57 if (den != 1) | |
58 { | |
59 // Conversion to Period is integral and not exact | |
60 err |= std::ios_base::failbit; | |
61 return false; | |
62 } | |
63 return true; | |
64 } | |
65 template <typename intermediate_type> | |
66 typename disable_if<is_integral<intermediate_type> , bool>::type reduce(intermediate_type&, unsigned long long&, | |
67 std::ios_base::iostate&) | |
68 { | |
69 return true; | |
70 } | |
71 | |
72 } | |
73 | |
74 /** | |
75 * @c duration_get is used to parse a character sequence, extracting | |
76 * components of a duration into a class duration. | |
77 * Each get member parses a format as produced by a corresponding format specifier to time_put<>::put. | |
78 * If the sequence being parsed matches the correct format, the | |
79 * corresponding member of the class duration argument are set to the | |
80 * value used to produce the sequence; | |
81 * otherwise either an error is reported or unspecified values are assigned. | |
82 * In other words, user confirmation is required for reliable parsing of | |
83 * user-entered durations, but machine-generated formats can be parsed | |
84 * reliably. This allows parsers to be aggressive about interpreting user | |
85 * variations on standard formats. | |
86 * | |
87 * If the end iterator is reached during parsing of the get() member | |
88 * function, the member sets std::ios_base::eofbit in err. | |
89 */ | |
90 template <class CharT, class InputIterator = std::istreambuf_iterator<CharT> > | |
91 class duration_get: public std::locale::facet | |
92 { | |
93 public: | |
94 /** | |
95 * Type of character the facet is instantiated on. | |
96 */ | |
97 typedef CharT char_type; | |
98 /** | |
99 * Type of character string passed to member functions. | |
100 */ | |
101 typedef std::basic_string<CharT> string_type; | |
102 /** | |
103 * Type of iterator used to scan the character buffer. | |
104 */ | |
105 typedef InputIterator iter_type; | |
106 | |
107 /** | |
108 * Construct a @c duration_get facet. | |
109 * @param refs | |
110 * @Effects Construct a @c duration_get facet. | |
111 * If the @c refs argument is @c 0 then destruction of the object is | |
112 * delegated to the @c locale, or locales, containing it. This allows | |
113 * the user to ignore lifetime management issues. On the other had, | |
114 * if @c refs is @c 1 then the object must be explicitly deleted; | |
115 * the @c locale will not do so. In this case, the object can be | |
116 * maintained across the lifetime of multiple locales. | |
117 */ | |
118 | |
119 explicit duration_get(size_t refs = 0) : | |
120 std::locale::facet(refs) | |
121 { | |
122 } | |
123 | |
124 /** | |
125 * @param s start input stream iterator | |
126 * @param end end input stream iterator | |
127 * @param ios a reference to a ios_base | |
128 * @param err the ios_base state | |
129 * @param d the duration | |
130 * @param pattern begin of the formatting pattern | |
131 * @param pat_end end of the formatting pattern | |
132 * | |
133 * Requires: [pattern,pat_end) shall be a valid range. | |
134 * | |
135 * Effects: The function starts by evaluating err = std::ios_base::goodbit. | |
136 * It then enters a loop, reading zero or more characters from s at | |
137 * each iteration. Unless otherwise specified below, the loop | |
138 * terminates when the first of the following conditions holds: | |
139 * - The expression pattern == pat_end evaluates to true. | |
140 * - The expression err == std::ios_base::goodbit evaluates to false. | |
141 * - The expression s == end evaluates to true, in which case the | |
142 * function evaluates err = std::ios_base::eofbit | std::ios_base::failbit. | |
143 * - The next element of pattern is equal to '%', followed by a conversion | |
144 * specifier character, format. | |
145 * If the number of elements in the range [pattern,pat_end) is not | |
146 * sufficient to unambiguously determine whether the conversion | |
147 * specification is complete and valid, the function evaluates | |
148 * err = std::ios_base::failbit. Otherwise, the function evaluates | |
149 * s = get_value(s, end, ios, err, r) when the conversion specification is 'v' and | |
150 * s = get_value(s, end, ios, err, rt) when the conversion specification is 'u'. | |
151 * If err == std::ios_base::goodbit holds after | |
152 * the evaluation of the expression, the function increments pattern to | |
153 * point just past the end of the conversion specification and continues | |
154 * looping. | |
155 * - The expression isspace(*pattern, ios.getloc()) evaluates to true, in | |
156 * which case the function first increments pattern until | |
157 * pattern == pat_end || !isspace(*pattern, ios.getloc()) evaluates to true, | |
158 * then advances s until s == end || !isspace(*s, ios.getloc()) is true, | |
159 * and finally resumes looping. | |
160 * - The next character read from s matches the element pointed to by | |
161 * pattern in a case-insensitive comparison, in which case the function | |
162 * evaluates ++pattern, ++s and continues looping. Otherwise, the function | |
163 * evaluates err = std::ios_base::failbit. | |
164 * | |
165 * Once r and rt are retrieved, | |
166 * Returns: s | |
167 */ | |
168 template <typename Rep, typename Period> | |
169 iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, | |
170 duration<Rep, Period> &d, const char_type *pattern, const char_type *pat_end) const | |
171 { | |
172 if (std::has_facet<duration_units<CharT> >(ios.getloc())) | |
173 { | |
174 duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(ios.getloc()); | |
175 return get(facet, s, end, ios, err, d, pattern, pat_end); | |
176 } | |
177 else | |
178 { | |
179 duration_units_default<CharT> facet; | |
180 return get(facet, s, end, ios, err, d, pattern, pat_end); | |
181 } | |
182 } | |
183 | |
184 template <typename Rep, typename Period> | |
185 iter_type get(duration_units<CharT> const&facet, iter_type s, iter_type end, std::ios_base& ios, | |
186 std::ios_base::iostate& err, duration<Rep, Period> &d, const char_type *pattern, const char_type *pat_end) const | |
187 { | |
188 | |
189 typedef typename detail::duration_io_intermediate<Rep>::type intermediate_type; | |
190 intermediate_type r; | |
191 rt_ratio rt; | |
192 bool value_found = false, unit_found = false; | |
193 | |
194 const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(ios.getloc()); | |
195 while (pattern != pat_end && err == std::ios_base::goodbit) | |
196 { | |
197 if (s == end) | |
198 { | |
199 err |= std::ios_base::eofbit; | |
200 break; | |
201 } | |
202 if (ct.narrow(*pattern, 0) == '%') | |
203 { | |
204 if (++pattern == pat_end) | |
205 { | |
206 err |= std::ios_base::failbit; | |
207 return s; | |
208 } | |
209 char cmd = ct.narrow(*pattern, 0); | |
210 switch (cmd) | |
211 { | |
212 case 'v': | |
213 { | |
214 if (value_found) | |
215 { | |
216 err |= std::ios_base::failbit; | |
217 return s; | |
218 } | |
219 value_found = true; | |
220 s = get_value(s, end, ios, err, r); | |
221 if (err & (std::ios_base::badbit | std::ios_base::failbit)) | |
222 { | |
223 return s; | |
224 } | |
225 break; | |
226 } | |
227 case 'u': | |
228 { | |
229 if (unit_found) | |
230 { | |
231 err |= std::ios_base::failbit; | |
232 return s; | |
233 } | |
234 unit_found = true; | |
235 s = get_unit(facet, s, end, ios, err, rt); | |
236 if (err & (std::ios_base::badbit | std::ios_base::failbit)) | |
237 { | |
238 return s; | |
239 } | |
240 break; | |
241 } | |
242 default: | |
243 BOOST_ASSERT(false && "Boost::Chrono internal error."); | |
244 break; | |
245 } | |
246 | |
247 ++pattern; | |
248 } | |
249 else if (ct.is(std::ctype_base::space, *pattern)) | |
250 { | |
251 for (++pattern; pattern != pat_end && ct.is(std::ctype_base::space, *pattern); ++pattern) | |
252 ; | |
253 for (; s != end && ct.is(std::ctype_base::space, *s); ++s) | |
254 ; | |
255 } | |
256 else if (ct.toupper(*s) == ct.toupper(*pattern)) | |
257 { | |
258 ++s; | |
259 ++pattern; | |
260 } | |
261 else | |
262 { | |
263 err |= std::ios_base::failbit; | |
264 return s; | |
265 } | |
266 | |
267 } | |
268 | |
269 unsigned long long num = rt.num; | |
270 unsigned long long den = rt.den; | |
271 | |
272 // r should be multiplied by (num/den) / Period | |
273 // Reduce (num/den) / Period to lowest terms | |
274 unsigned long long gcd_n1_n2 = math::gcd<unsigned long long>(num, Period::num); | |
275 unsigned long long gcd_d1_d2 = math::gcd<unsigned long long>(den, Period::den); | |
276 num /= gcd_n1_n2; | |
277 den /= gcd_d1_d2; | |
278 unsigned long long n2 = Period::num / gcd_n1_n2; | |
279 unsigned long long d2 = Period::den / gcd_d1_d2; | |
280 if (num > (std::numeric_limits<unsigned long long>::max)() / d2 || den | |
281 > (std::numeric_limits<unsigned long long>::max)() / n2) | |
282 { | |
283 // (num/den) / Period overflows | |
284 err |= std::ios_base::failbit; | |
285 return s; | |
286 } | |
287 num *= d2; | |
288 den *= n2; | |
289 | |
290 typedef typename common_type<intermediate_type, unsigned long long>::type common_type_t; | |
291 | |
292 // num / den is now factor to multiply by r | |
293 if (!detail::reduce(r, den, err)) return s; | |
294 | |
295 if (chrono::detail::gt(r, ( (duration_values<common_type_t>::max)() / num))) | |
296 { | |
297 // Conversion to Period overflowed | |
298 err |= std::ios_base::failbit; | |
299 return s; | |
300 } | |
301 common_type_t t = r * num; | |
302 t /= den; | |
303 if (t > 0) | |
304 { | |
305 Rep pt = t; | |
306 if ( (duration_values<Rep>::max)() < pt) | |
307 { | |
308 // Conversion to Period overflowed | |
309 err |= std::ios_base::failbit; | |
310 return s; | |
311 } | |
312 } | |
313 // Success! Store it. | |
314 r = Rep(t); | |
315 d = duration<Rep, Period> (r); | |
316 | |
317 return s; | |
318 } | |
319 | |
320 /** | |
321 * | |
322 * @param s start input stream iterator | |
323 * @param end end input stream iterator | |
324 * @param ios a reference to a ios_base | |
325 * @param err the ios_base state | |
326 * @param d the duration | |
327 * Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if | |
328 * @code | |
329 * return get(s, end, ios, err, ios, d, str.data(), str.data() + str.size()); | |
330 * @codeend | |
331 * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name | |
332 */ | |
333 template <typename Rep, typename Period> | |
334 iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, | |
335 duration<Rep, Period> & d) const | |
336 { | |
337 if (std::has_facet<duration_units<CharT> >(ios.getloc())) | |
338 { | |
339 duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(ios.getloc()); | |
340 std::basic_string<CharT> str = facet.get_pattern(); | |
341 return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size()); | |
342 } | |
343 else | |
344 { | |
345 duration_units_default<CharT> facet; | |
346 std::basic_string<CharT> str = facet.get_pattern(); | |
347 return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size()); | |
348 } | |
349 } | |
350 | |
351 /** | |
352 * | |
353 * @param s start input stream iterator | |
354 * @param end end input stream iterator | |
355 * @param ios a reference to a ios_base | |
356 * @param err the ios_base state | |
357 * @param r a reference to the duration representation. | |
358 * @Effects As if | |
359 * @code | |
360 * return std::use_facet<std::num_get<cahr_type, iter_type> >(ios.getloc()).get(s, end, ios, err, r); | |
361 * @endcode | |
362 * | |
363 * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name | |
364 */ | |
365 template <typename Rep> | |
366 iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, Rep& r) const | |
367 { | |
368 return std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r); | |
369 } | |
370 | |
371 /** | |
372 * | |
373 * @param s start input stream iterator | |
374 * @param e end input stream iterator | |
375 * @param ios a reference to a ios_base | |
376 * @param err the ios_base state | |
377 * @param rt a reference to the duration run-time ratio. | |
378 * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name | |
379 */ | |
380 iter_type get_unit(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, rt_ratio &rt) const | |
381 { | |
382 if (std::has_facet<duration_units<CharT> >(is.getloc())) | |
383 { | |
384 return get_unit(std::use_facet<duration_units<CharT> >(is.getloc()), i, e, is, err, rt); | |
385 } | |
386 else | |
387 { | |
388 duration_units_default<CharT> facet; | |
389 return get_unit(facet, i, e, is, err, rt); | |
390 } | |
391 } | |
392 | |
393 | |
394 iter_type get_unit(duration_units<CharT> const &facet, iter_type i, iter_type e, std::ios_base& is, | |
395 std::ios_base::iostate& err, rt_ratio &rt) const | |
396 { | |
397 | |
398 if (*i == '[') | |
399 { | |
400 // parse [N/D]s or [N/D]second or [N/D]seconds format | |
401 ++i; | |
402 i = std::use_facet<std::num_get<CharT, iter_type> >(is.getloc()).get(i, e, is, err, rt.num); | |
403 if ( (err & std::ios_base::failbit) != 0) | |
404 { | |
405 return i; | |
406 } | |
407 | |
408 if (i == e) | |
409 { | |
410 err |= std::ios_base::failbit; | |
411 return i; | |
412 } | |
413 CharT x = *i++; | |
414 if (x != '/') | |
415 { | |
416 err |= std::ios_base::failbit; | |
417 return i; | |
418 } | |
419 i = std::use_facet<std::num_get<CharT, iter_type> >(is.getloc()).get(i, e, is, err, rt.den); | |
420 if ( (err & std::ios_base::failbit) != 0) | |
421 { | |
422 return i; | |
423 } | |
424 if (i == e) | |
425 { | |
426 err |= std::ios_base::failbit; | |
427 return i; | |
428 } | |
429 if (*i != ']') | |
430 { | |
431 err |= std::ios_base::failbit; | |
432 return i; | |
433 } | |
434 ++i; | |
435 if (i == e) | |
436 { | |
437 err |= std::ios_base::failbit; | |
438 return i; | |
439 } | |
440 // parse s or second or seconds | |
441 return do_get_n_d_valid_unit(facet, i, e, is, err); | |
442 } | |
443 else | |
444 { | |
445 return do_get_valid_unit(facet, i, e, is, err, rt); | |
446 } | |
447 } | |
448 | |
449 /** | |
450 * Unique identifier for this type of facet. | |
451 */ | |
452 static std::locale::id id; | |
453 | |
454 /** | |
455 * @Effects Destroy the facet | |
456 */ | |
457 ~duration_get() | |
458 { | |
459 } | |
460 | |
461 protected: | |
462 | |
463 /** | |
464 * Extracts the run-time ratio associated to the duration when it is given in prefix form. | |
465 * | |
466 * This is an extension point of this facet so that we can take in account other periods that can have a useful | |
467 * translation in other contexts, as e.g. days and weeks. | |
468 * | |
469 * @param facet the duration_units facet | |
470 * @param i start input stream iterator. | |
471 * @param e end input stream iterator. | |
472 * @param ios a reference to a ios_base. | |
473 * @param err the ios_base state. | |
474 * @return @c s | |
475 */ | |
476 iter_type do_get_n_d_valid_unit(duration_units<CharT> const &facet, iter_type i, iter_type e, | |
477 std::ios_base&, std::ios_base::iostate& err) const | |
478 { | |
479 // parse SI name, short or long | |
480 | |
481 const string_type* units = facet.get_n_d_valid_units_start(); | |
482 const string_type* units_end = facet.get_n_d_valid_units_end(); | |
483 | |
484 const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end, | |
485 //~ std::use_facet<std::ctype<CharT> >(loc), | |
486 err); | |
487 if (err & (std::ios_base::badbit | std::ios_base::failbit)) | |
488 { | |
489 return i; | |
490 } | |
491 if (!facet.match_n_d_valid_unit(k)) | |
492 { | |
493 err |= std::ios_base::failbit; | |
494 } | |
495 return i; | |
496 } | |
497 | |
498 /** | |
499 * Extracts the run-time ratio associated to the duration when it is given in prefix form. | |
500 * | |
501 * This is an extension point of this facet so that we can take in account other periods that can have a useful | |
502 * translation in other contexts, as e.g. days and weeks. | |
503 * | |
504 * @param facet the duration_units facet | |
505 * @param i start input stream iterator. | |
506 * @param e end input stream iterator. | |
507 * @param ios a reference to a ios_base. | |
508 * @param err the ios_base state. | |
509 * @param rt a reference to the duration run-time ratio. | |
510 * @Effects | |
511 * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name. | |
512 */ | |
513 iter_type do_get_valid_unit(duration_units<CharT> const &facet, iter_type i, iter_type e, | |
514 std::ios_base&, std::ios_base::iostate& err, rt_ratio &rt) const | |
515 { | |
516 // parse SI name, short or long | |
517 | |
518 const string_type* units = facet.get_valid_units_start(); | |
519 const string_type* units_end = facet.get_valid_units_end(); | |
520 | |
521 err = std::ios_base::goodbit; | |
522 const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end, | |
523 //~ std::use_facet<std::ctype<CharT> >(loc), | |
524 err); | |
525 if (err & (std::ios_base::badbit | std::ios_base::failbit)) | |
526 { | |
527 return i; | |
528 } | |
529 if (!facet.match_valid_unit(k, rt)) | |
530 { | |
531 err |= std::ios_base::failbit; | |
532 } | |
533 return i; | |
534 } | |
535 }; | |
536 | |
537 /** | |
538 * Unique identifier for this type of facet. | |
539 */ | |
540 template <class CharT, class InputIterator> | |
541 std::locale::id duration_get<CharT, InputIterator>::id; | |
542 | |
543 } // chrono | |
544 } | |
545 // boost | |
546 | |
547 #endif // header |