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