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