Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/units/io.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 // Boost.Units - A C++ library for zero-overhead dimensional analysis and | |
2 // unit/quantity manipulation and conversion | |
3 // | |
4 // Copyright (C) 2003-2008 Matthias Christian Schabel | |
5 // Copyright (C) 2007-2010 Steven Watanabe | |
6 // | |
7 // Distributed under the Boost Software License, Version 1.0. (See | |
8 // accompanying file LICENSE_1_0.txt or copy at | |
9 // http://www.boost.org/LICENSE_1_0.txt) | |
10 | |
11 #ifndef BOOST_UNITS_IO_HPP | |
12 #define BOOST_UNITS_IO_HPP | |
13 | |
14 /// \file | |
15 /// \brief Stream input and output for rationals, units and quantities. | |
16 /// \details Functions and manipulators for output and input of units and quantities. | |
17 /// symbol and name format, and engineering and binary autoprefix. | |
18 /// Serialization output is also supported. | |
19 | |
20 #include <cassert> | |
21 #include <cmath> | |
22 #include <string> | |
23 #include <iosfwd> | |
24 #include <ios> | |
25 #include <sstream> | |
26 | |
27 #include <boost/serialization/nvp.hpp> | |
28 | |
29 #include <boost/units/units_fwd.hpp> | |
30 #include <boost/units/heterogeneous_system.hpp> | |
31 #include <boost/units/make_scaled_unit.hpp> | |
32 #include <boost/units/quantity.hpp> | |
33 #include <boost/units/scale.hpp> | |
34 #include <boost/units/static_rational.hpp> | |
35 #include <boost/units/unit.hpp> | |
36 #include <boost/units/detail/utility.hpp> | |
37 | |
38 namespace boost { | |
39 | |
40 namespace serialization { | |
41 | |
42 /// Boost Serialization library support for units. | |
43 template<class Archive,class System,class Dim> | |
44 inline void serialize(Archive& ar,boost::units::unit<Dim,System>&,const unsigned int /*version*/) | |
45 { } | |
46 | |
47 /// Boost Serialization library support for quantities. | |
48 template<class Archive,class Unit,class Y> | |
49 inline void serialize(Archive& ar,boost::units::quantity<Unit,Y>& q,const unsigned int /*version*/) | |
50 { | |
51 ar & boost::serialization::make_nvp("value", units::quantity_cast<Y&>(q)); | |
52 } | |
53 | |
54 } // namespace serialization | |
55 | |
56 namespace units { | |
57 | |
58 // get string representation of arbitrary type. | |
59 template<class T> std::string to_string(const T& t) | |
60 { | |
61 std::stringstream sstr; | |
62 | |
63 sstr << t; | |
64 | |
65 return sstr.str(); | |
66 } | |
67 | |
68 /// get string representation of integral-valued @c static_rational. | |
69 template<integer_type N> std::string to_string(const static_rational<N>&) | |
70 { | |
71 return to_string(N); | |
72 } | |
73 | |
74 /// get string representation of @c static_rational. | |
75 template<integer_type N, integer_type D> std::string to_string(const static_rational<N,D>&) | |
76 { | |
77 return '(' + to_string(N) + '/' + to_string(D) + ')'; | |
78 } | |
79 | |
80 /// Write @c static_rational to @c std::basic_ostream. | |
81 template<class Char, class Traits, integer_type N, integer_type D> | |
82 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,const static_rational<N,D>& r) | |
83 { | |
84 os << to_string(r); | |
85 return os; | |
86 } | |
87 | |
88 /// traits template for unit names. | |
89 template<class BaseUnit> | |
90 struct base_unit_info | |
91 { | |
92 /// INTERNAL ONLY | |
93 typedef void base_unit_info_primary_template; | |
94 /// The full name of the unit (returns BaseUnit::name() by default) | |
95 static std::string name() | |
96 { | |
97 return(BaseUnit::name()); | |
98 } | |
99 /// The symbol for the base unit (Returns BaseUnit::symbol() by default) | |
100 static std::string symbol() | |
101 { | |
102 return(BaseUnit::symbol()); /// \returns BaseUnit::symbol(), for example "m" | |
103 } | |
104 }; | |
105 | |
106 /// \enum format_mode format of output of units, for example "m" or "meter". | |
107 enum format_mode | |
108 { | |
109 symbol_fmt = 0, /// default - reduces unit names to known symbols for both base and derived units. | |
110 name_fmt = 1, /// output full unit names for base and derived units, for example "meter". | |
111 raw_fmt = 2, /// output only symbols for base units (but not derived units), for example "m". | |
112 typename_fmt = 3, /// output demangled typenames (useful only for diagnosis). | |
113 fmt_mask = 3 /// Bits used for format. | |
114 }; | |
115 | |
116 /// \enum autoprefix_mode automatic scaling and prefix (controlled by value of quantity) a, if any, | |
117 enum autoprefix_mode | |
118 { | |
119 autoprefix_none = 0, /// No automatic prefix. | |
120 autoprefix_engineering = 4, /// Scale and prefix with 10^3 multiples, 1234.5 m output as 1.2345 km. | |
121 autoprefix_binary = 8, /// Scale and prefix with 2^10 (1024) multiples, 1024 as 1 kb. | |
122 autoprefix_mask = 12 /// Bits used for autoprefix. | |
123 }; | |
124 | |
125 namespace detail { | |
126 | |
127 template<bool> | |
128 struct xalloc_key_holder | |
129 { | |
130 static int value; | |
131 static bool initialized; | |
132 }; | |
133 | |
134 template<bool b> | |
135 int xalloc_key_holder<b>::value = 0; | |
136 | |
137 template<bool b> | |
138 bool xalloc_key_holder<b>::initialized = 0; | |
139 | |
140 struct xalloc_key_initializer_t | |
141 { | |
142 xalloc_key_initializer_t() | |
143 { | |
144 if (!xalloc_key_holder<true>::initialized) | |
145 { | |
146 xalloc_key_holder<true>::value = std::ios_base::xalloc(); | |
147 xalloc_key_holder<true>::initialized = true; | |
148 } | |
149 } | |
150 }; | |
151 | |
152 namespace /**/ { | |
153 | |
154 xalloc_key_initializer_t xalloc_key_initializer; | |
155 | |
156 } // namespace | |
157 | |
158 } // namespace detail | |
159 | |
160 /// returns flags controlling output. | |
161 inline long get_flags(std::ios_base& ios, long mask) | |
162 { | |
163 return(ios.iword(detail::xalloc_key_holder<true>::value) & mask); | |
164 } | |
165 | |
166 /// Set new flags controlling output format. | |
167 inline void set_flags(std::ios_base& ios, long new_flags, long mask) | |
168 { | |
169 assert((~mask & new_flags) == 0); | |
170 long& flags = ios.iword(detail::xalloc_key_holder<true>::value); | |
171 flags = (flags & ~mask) | new_flags; | |
172 } | |
173 | |
174 /// returns flags controlling output format. | |
175 inline format_mode get_format(std::ios_base& ios) | |
176 { | |
177 return(static_cast<format_mode>((get_flags)(ios, fmt_mask))); | |
178 } | |
179 | |
180 /// Set new flags controlling output format. | |
181 inline void set_format(std::ios_base& ios, format_mode new_mode) | |
182 { | |
183 (set_flags)(ios, new_mode, fmt_mask); | |
184 } | |
185 | |
186 /// Set new flags for type_name output format. | |
187 inline std::ios_base& typename_format(std::ios_base& ios) | |
188 { | |
189 (set_format)(ios, typename_fmt); | |
190 return(ios); | |
191 } | |
192 | |
193 /// set new flag for raw format output, for example "m". | |
194 inline std::ios_base& raw_format(std::ios_base& ios) | |
195 { | |
196 (set_format)(ios, raw_fmt); | |
197 return(ios); | |
198 } | |
199 | |
200 /// set new format flag for symbol output, for example "m". | |
201 inline std::ios_base& symbol_format(std::ios_base& ios) | |
202 { | |
203 (set_format)(ios, symbol_fmt); | |
204 return(ios); | |
205 } | |
206 | |
207 /// set new format for name output, for example "meter". | |
208 inline std::ios_base& name_format(std::ios_base& ios) | |
209 { | |
210 (set_format)(ios, name_fmt); | |
211 return(ios); | |
212 } | |
213 | |
214 /// get autoprefix flags for output. | |
215 inline autoprefix_mode get_autoprefix(std::ios_base& ios) | |
216 { | |
217 return static_cast<autoprefix_mode>((get_flags)(ios, autoprefix_mask)); | |
218 } | |
219 | |
220 /// Get format for output. | |
221 inline void set_autoprefix(std::ios_base& ios, autoprefix_mode new_mode) | |
222 { | |
223 (set_flags)(ios, new_mode, autoprefix_mask); | |
224 } | |
225 | |
226 /// Clear autoprefix flags. | |
227 inline std::ios_base& no_prefix(std::ios_base& ios) | |
228 { | |
229 (set_autoprefix)(ios, autoprefix_none); | |
230 return ios; | |
231 } | |
232 | |
233 /// Set flag for engineering prefix, so 1234.5 m displays as "1.2345 km". | |
234 inline std::ios_base& engineering_prefix(std::ios_base& ios) | |
235 { | |
236 (set_autoprefix)(ios, autoprefix_engineering); | |
237 return ios; | |
238 } | |
239 | |
240 /// Set flag for binary prefix, so 1024 byte displays as "1 Kib". | |
241 inline std::ios_base& binary_prefix(std::ios_base& ios) | |
242 { | |
243 (set_autoprefix)(ios, autoprefix_binary); | |
244 return ios; | |
245 } | |
246 | |
247 namespace detail { | |
248 | |
249 /// \return exponent string like "^1/2". | |
250 template<integer_type N, integer_type D> | |
251 inline std::string exponent_string(const static_rational<N,D>& r) | |
252 { | |
253 return '^' + to_string(r); | |
254 } | |
255 | |
256 /// \return empty exponent string for integer rational like 2. | |
257 template<> | |
258 inline std::string exponent_string(const static_rational<1>&) | |
259 { | |
260 return ""; | |
261 } | |
262 | |
263 template<class T> | |
264 inline std::string base_unit_symbol_string(const T&) | |
265 { | |
266 return base_unit_info<typename T::tag_type>::symbol() + exponent_string(typename T::value_type()); | |
267 } | |
268 | |
269 template<class T> | |
270 inline std::string base_unit_name_string(const T&) | |
271 { | |
272 return base_unit_info<typename T::tag_type>::name() + exponent_string(typename T::value_type()); | |
273 } | |
274 | |
275 // stringify with symbols. | |
276 template<int N> | |
277 struct symbol_string_impl | |
278 { | |
279 template<class Begin> | |
280 struct apply | |
281 { | |
282 typedef typename symbol_string_impl<N-1>::template apply<typename Begin::next> next; | |
283 static void value(std::string& str) | |
284 { | |
285 str += base_unit_symbol_string(typename Begin::item()) + ' '; | |
286 next::value(str); | |
287 } | |
288 }; | |
289 }; | |
290 | |
291 template<> | |
292 struct symbol_string_impl<1> | |
293 { | |
294 template<class Begin> | |
295 struct apply | |
296 { | |
297 static void value(std::string& str) | |
298 { | |
299 str += base_unit_symbol_string(typename Begin::item()); | |
300 }; | |
301 }; | |
302 }; | |
303 | |
304 template<> | |
305 struct symbol_string_impl<0> | |
306 { | |
307 template<class Begin> | |
308 struct apply | |
309 { | |
310 static void value(std::string& str) | |
311 { | |
312 // better shorthand for dimensionless? | |
313 str += "dimensionless"; | |
314 } | |
315 }; | |
316 }; | |
317 | |
318 template<int N> | |
319 struct scale_symbol_string_impl | |
320 { | |
321 template<class Begin> | |
322 struct apply | |
323 { | |
324 static void value(std::string& str) | |
325 { | |
326 str += Begin::item::symbol(); | |
327 scale_symbol_string_impl<N - 1>::template apply<typename Begin::next>::value(str); | |
328 } | |
329 }; | |
330 }; | |
331 | |
332 template<> | |
333 struct scale_symbol_string_impl<0> | |
334 { | |
335 template<class Begin> | |
336 struct apply | |
337 { | |
338 static void value(std::string&) { } | |
339 }; | |
340 }; | |
341 | |
342 // stringify with names. | |
343 template<int N> | |
344 struct name_string_impl | |
345 { | |
346 template<class Begin> | |
347 struct apply | |
348 { | |
349 typedef typename name_string_impl<N-1>::template apply<typename Begin::next> next; | |
350 static void value(std::string& str) | |
351 { | |
352 str += base_unit_name_string(typename Begin::item()) + ' '; | |
353 next::value(str); | |
354 } | |
355 }; | |
356 }; | |
357 | |
358 template<> | |
359 struct name_string_impl<1> | |
360 { | |
361 template<class Begin> | |
362 struct apply | |
363 { | |
364 static void value(std::string& str) | |
365 { | |
366 str += base_unit_name_string(typename Begin::item()); | |
367 }; | |
368 }; | |
369 }; | |
370 | |
371 template<> | |
372 struct name_string_impl<0> | |
373 { | |
374 template<class Begin> | |
375 struct apply | |
376 { | |
377 static void value(std::string& str) | |
378 { | |
379 str += "dimensionless"; | |
380 } | |
381 }; | |
382 }; | |
383 | |
384 template<int N> | |
385 struct scale_name_string_impl | |
386 { | |
387 template<class Begin> | |
388 struct apply | |
389 { | |
390 static void value(std::string& str) | |
391 { | |
392 str += Begin::item::name(); | |
393 scale_name_string_impl<N - 1>::template apply<typename Begin::next>::value(str); | |
394 } | |
395 }; | |
396 }; | |
397 | |
398 template<> | |
399 struct scale_name_string_impl<0> | |
400 { | |
401 template<class Begin> | |
402 struct apply | |
403 { | |
404 static void value(std::string&) { } | |
405 }; | |
406 }; | |
407 | |
408 } // namespace detail | |
409 | |
410 namespace detail { | |
411 | |
412 // These two overloads of symbol_string and name_string will | |
413 // will pick up homogeneous_systems. They simply call the | |
414 // appropriate function with a heterogeneous_system. | |
415 template<class Dimension,class System, class SubFormatter> | |
416 inline std::string | |
417 to_string_impl(const unit<Dimension,System>&, SubFormatter f) | |
418 { | |
419 return f(typename reduce_unit<unit<Dimension, System> >::type()); | |
420 } | |
421 | |
422 /// INTERNAL ONLY | |
423 // this overload picks up heterogeneous units that are not scaled. | |
424 template<class Dimension,class Units, class Subformatter> | |
425 inline std::string | |
426 to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >&, Subformatter f) | |
427 { | |
428 std::string str; | |
429 f.template append_units_to<Units>(str); | |
430 return(str); | |
431 } | |
432 | |
433 // This overload is a special case for heterogeneous_system which | |
434 // is really unitless | |
435 /// INTERNAL ONLY | |
436 template<class Subformatter> | |
437 inline std::string | |
438 to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, dimensionless_type> > >&, Subformatter) | |
439 { | |
440 return("dimensionless"); | |
441 } | |
442 | |
443 // this overload deals with heterogeneous_systems which are unitless | |
444 // but scaled. | |
445 /// INTERNAL ONLY | |
446 template<class Scale, class Subformatter> | |
447 inline std::string | |
448 to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, Scale> > >&, Subformatter f) | |
449 { | |
450 std::string str; | |
451 f.template append_scale_to<Scale>(str); | |
452 return(str); | |
453 } | |
454 | |
455 // this overload deals with scaled units. | |
456 /// INTERNAL ONLY | |
457 template<class Dimension,class Units,class Scale, class Subformatter> | |
458 inline std::string | |
459 to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f) | |
460 { | |
461 std::string str; | |
462 | |
463 f.template append_scale_to<Scale>(str); | |
464 | |
465 std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()); | |
466 | |
467 if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >())) | |
468 { | |
469 str += "("; | |
470 str += without_scale; | |
471 str += ")"; | |
472 } | |
473 else | |
474 { | |
475 str += without_scale; | |
476 } | |
477 | |
478 return(str); | |
479 } | |
480 | |
481 // This overload catches scaled units that have a single base unit | |
482 // raised to the first power. It causes si::nano * si::meters to not | |
483 // put parentheses around the meters. i.e. nm rather than n(m) | |
484 /// INTERNAL ONLY | |
485 template<class Dimension,class Unit,class Scale, class Subformatter> | |
486 inline std::string | |
487 to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f) | |
488 { | |
489 std::string str; | |
490 | |
491 f.template append_scale_to<Scale>(str); | |
492 str += f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >()); | |
493 | |
494 return(str); | |
495 } | |
496 | |
497 // This overload is necessary to disambiguate. | |
498 // it catches units that are unscaled and have a single | |
499 // base unit raised to the first power. It is treated the | |
500 // same as any other unscaled unit. | |
501 /// INTERNAL ONLY | |
502 template<class Dimension,class Unit,class Subformatter> | |
503 inline std::string | |
504 to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, dimensionless_type> > >&, Subformatter f) | |
505 { | |
506 std::string str; | |
507 f.template append_units_to<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type> >(str); | |
508 return(str); | |
509 } | |
510 | |
511 // This overload catches scaled units that have a single scaled base unit | |
512 // raised to the first power. It moves that scaling on the base unit | |
513 // to the unit level scaling and recurses. By doing this we make sure that | |
514 // si::milli * si::kilograms will print g rather than mkg. | |
515 // | |
516 // This transformation will not be applied if base_unit_info is specialized | |
517 // for the scaled base unit. | |
518 // | |
519 /// INTERNAL ONLY | |
520 template<class Dimension,class Unit,class UnitScale, class Scale, class Subformatter> | |
521 inline std::string | |
522 to_string_impl( | |
523 const unit< | |
524 Dimension, | |
525 heterogeneous_system< | |
526 heterogeneous_system_impl< | |
527 list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>, | |
528 Dimension, | |
529 Scale | |
530 > | |
531 > | |
532 >&, | |
533 Subformatter f, | |
534 typename base_unit_info<scaled_base_unit<Unit, UnitScale> >::base_unit_info_primary_template* = 0) | |
535 { | |
536 return(f( | |
537 unit< | |
538 Dimension, | |
539 heterogeneous_system< | |
540 heterogeneous_system_impl< | |
541 list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, | |
542 Dimension, | |
543 typename mpl::times<Scale, list<scale_list_dim<UnitScale>, dimensionless_type> >::type | |
544 > | |
545 > | |
546 >())); | |
547 } | |
548 | |
549 // this overload disambuguates between the overload for an unscaled unit | |
550 // and the overload for a scaled base unit raised to the first power. | |
551 /// INTERNAL ONLY | |
552 template<class Dimension,class Unit,class UnitScale,class Subformatter> | |
553 inline std::string | |
554 to_string_impl( | |
555 const unit< | |
556 Dimension, | |
557 heterogeneous_system< | |
558 heterogeneous_system_impl< | |
559 list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>, | |
560 Dimension, | |
561 dimensionless_type | |
562 > | |
563 > | |
564 >&, | |
565 Subformatter f, | |
566 typename base_unit_info<scaled_base_unit<Unit, UnitScale> >::base_unit_info_primary_template* = 0) | |
567 { | |
568 std::string str; | |
569 f.template append_units_to<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type> >(str); | |
570 return(str); | |
571 } | |
572 | |
573 struct format_raw_symbol_impl { | |
574 template<class Units> | |
575 void append_units_to(std::string& str) { | |
576 detail::symbol_string_impl<Units::size::value>::template apply<Units>::value(str); | |
577 } | |
578 template<class Scale> | |
579 void append_scale_to(std::string& str) { | |
580 detail::scale_symbol_string_impl<Scale::size::value>::template apply<Scale>::value(str); | |
581 } | |
582 template<class Unit> | |
583 std::string operator()(const Unit& u) { | |
584 return(to_string_impl(u, *this)); | |
585 } | |
586 template<class Unit> | |
587 bool is_default_string(const std::string&, const Unit&) { | |
588 return(true); | |
589 } | |
590 }; | |
591 | |
592 struct format_symbol_impl : format_raw_symbol_impl { | |
593 template<class Unit> | |
594 std::string operator()(const Unit& u) { | |
595 return(symbol_string(u)); | |
596 } | |
597 template<class Unit> | |
598 bool is_default_string(const std::string& str, const Unit& u) { | |
599 return(str == to_string_impl(u, format_raw_symbol_impl())); | |
600 } | |
601 }; | |
602 | |
603 struct format_raw_name_impl { | |
604 template<class Units> | |
605 void append_units_to(std::string& str) { | |
606 detail::name_string_impl<(Units::size::value)>::template apply<Units>::value(str); | |
607 } | |
608 template<class Scale> | |
609 void append_scale_to(std::string& str) { | |
610 detail::scale_name_string_impl<Scale::size::value>::template apply<Scale>::value(str); | |
611 } | |
612 template<class Unit> | |
613 std::string operator()(const Unit& u) { | |
614 return(to_string_impl(u, *this)); | |
615 } | |
616 template<class Unit> | |
617 bool is_default_string(const std::string&, const Unit&) { | |
618 return(true); | |
619 } | |
620 }; | |
621 | |
622 struct format_name_impl : format_raw_name_impl { | |
623 template<class Unit> | |
624 std::string operator()(const Unit& u) { | |
625 return(name_string(u)); | |
626 } | |
627 template<class Unit> | |
628 bool is_default_string(const std::string& str, const Unit& u) { | |
629 return(str == to_string_impl(u, format_raw_name_impl())); | |
630 } | |
631 }; | |
632 | |
633 template<class Char, class Traits> | |
634 inline void do_print(std::basic_ostream<Char, Traits>& os, const std::string& s) | |
635 { | |
636 os << s.c_str(); | |
637 } | |
638 | |
639 inline void do_print(std::ostream& os, const std::string& s) | |
640 { | |
641 os << s; | |
642 } | |
643 | |
644 template<class Char, class Traits> | |
645 inline void do_print(std::basic_ostream<Char, Traits>& os, const char* s) | |
646 { | |
647 os << s; | |
648 } | |
649 | |
650 // For automatically applying the appropriate prefixes. | |
651 | |
652 } | |
653 | |
654 #ifdef BOOST_UNITS_DOXYGEN | |
655 | |
656 /// ADL customization point for automatic prefixing. | |
657 /// Returns a non-negative value. Implemented as std::abs | |
658 /// for built-in types. | |
659 template<class T> | |
660 double autoprefix_norm(const T& arg); | |
661 | |
662 #else | |
663 | |
664 template<class T, bool C = boost::is_arithmetic<T>::value> | |
665 struct autoprefix_norm_impl; | |
666 | |
667 template<class T> | |
668 struct autoprefix_norm_impl<T, true> | |
669 { | |
670 typedef double type; | |
671 static double call(const T& arg) { return std::abs(arg); } | |
672 }; | |
673 | |
674 template<class T> | |
675 struct autoprefix_norm_impl<T, false> | |
676 { | |
677 typedef one type; | |
678 static one call(const T&) { return one(); } | |
679 }; | |
680 | |
681 template<class T> | |
682 typename autoprefix_norm_impl<T>::type autoprefix_norm(const T& arg) | |
683 { | |
684 return autoprefix_norm_impl<T>::call(arg); | |
685 } | |
686 | |
687 #endif | |
688 | |
689 namespace detail { | |
690 | |
691 template<class End, class Prev, class T, class F> | |
692 bool find_matching_scale_impl(End, End, Prev, T, double, F) | |
693 { | |
694 return false; | |
695 } | |
696 | |
697 template<class Begin, class End, class Prev, class T, class F> | |
698 bool find_matching_scale_impl(Begin, End end, Prev prev, T t, double x, F f) | |
699 { | |
700 if(Begin::item::value() > x) { | |
701 f(prev, t); | |
702 return true; | |
703 } else { | |
704 return detail::find_matching_scale_impl( | |
705 typename Begin::next(), | |
706 end, | |
707 typename Begin::item(), | |
708 t, | |
709 x, | |
710 f | |
711 ); | |
712 } | |
713 } | |
714 | |
715 template<class End, class T, class F> | |
716 bool find_matching_scale_i(End, End, T, double, F) | |
717 { | |
718 return false; | |
719 } | |
720 | |
721 template<class Begin, class End, class T, class F> | |
722 bool find_matching_scale_i(Begin, End end, T t, double x, F f) | |
723 { | |
724 if(Begin::item::value() > x) { | |
725 return false; | |
726 } else { | |
727 return detail::find_matching_scale_impl(typename Begin::next(), end, typename Begin::item(), t, x, f); | |
728 } | |
729 } | |
730 | |
731 template<class Scales, class T, class F> | |
732 bool find_matching_scale(T t, double x, F f) | |
733 { | |
734 return detail::find_matching_scale_i(Scales(), dimensionless_type(), t, x, f); | |
735 } | |
736 | |
737 typedef list<scale<10, static_rational<-24> >, | |
738 list<scale<10, static_rational<-21> >, | |
739 list<scale<10, static_rational<-18> >, | |
740 list<scale<10, static_rational<-15> >, | |
741 list<scale<10, static_rational<-12> >, | |
742 list<scale<10, static_rational<-9> >, | |
743 list<scale<10, static_rational<-6> >, | |
744 list<scale<10, static_rational<-3> >, | |
745 list<scale<10, static_rational<0> >, | |
746 list<scale<10, static_rational<3> >, | |
747 list<scale<10, static_rational<6> >, | |
748 list<scale<10, static_rational<9> >, | |
749 list<scale<10, static_rational<12> >, | |
750 list<scale<10, static_rational<15> >, | |
751 list<scale<10, static_rational<18> >, | |
752 list<scale<10, static_rational<21> >, | |
753 list<scale<10, static_rational<24> >, | |
754 list<scale<10, static_rational<27> >, | |
755 dimensionless_type> > > > > > > > > > > > > > > > > > engineering_prefixes; | |
756 | |
757 typedef list<scale<2, static_rational<10> >, | |
758 list<scale<2, static_rational<20> >, | |
759 list<scale<2, static_rational<30> >, | |
760 list<scale<2, static_rational<40> >, | |
761 list<scale<2, static_rational<50> >, | |
762 list<scale<2, static_rational<60> >, | |
763 list<scale<2, static_rational<70> >, | |
764 dimensionless_type> > > > > > > binary_prefixes; | |
765 | |
766 template<class Os, class Quantity> | |
767 struct print_default_t { | |
768 typedef void result_type; | |
769 void operator()() const | |
770 { | |
771 *os << q->value() << ' ' << typename Quantity::unit_type(); | |
772 } | |
773 Os* os; | |
774 const Quantity* q; | |
775 }; | |
776 | |
777 template<class Os, class Quantity> | |
778 print_default_t<Os, Quantity> print_default(Os& os, const Quantity& q) | |
779 { | |
780 print_default_t<Os, Quantity> result = { &os, &q }; | |
781 return result; | |
782 } | |
783 | |
784 template<class Os> | |
785 struct print_scale_t { | |
786 typedef void result_type; | |
787 template<class Prefix, class T> | |
788 void operator()(Prefix, const T& t) const | |
789 { | |
790 *prefixed = true; | |
791 *os << t / Prefix::value() << ' '; | |
792 switch(units::get_format(*os)) { | |
793 case name_fmt: do_print(*os, Prefix::name()); break; | |
794 case raw_fmt: | |
795 case symbol_fmt: do_print(*os, Prefix::symbol()); break; | |
796 case typename_fmt: do_print(*os, units::simplify_typename(Prefix())); *os << ' '; break; | |
797 } | |
798 } | |
799 template<long N, class T> | |
800 void operator()(scale<N, static_rational<0> >, const T& t) const | |
801 { | |
802 *prefixed = false; | |
803 *os << t << ' '; | |
804 } | |
805 Os* os; | |
806 bool* prefixed; | |
807 }; | |
808 | |
809 template<class Os> | |
810 print_scale_t<Os> print_scale(Os& os, bool& prefixed) | |
811 { | |
812 print_scale_t<Os> result = { &os, &prefixed }; | |
813 return result; | |
814 } | |
815 | |
816 // puts parentheses around a unit | |
817 /// INTERNAL ONLY | |
818 template<class Dimension,class Units,class Scale, class Subformatter> | |
819 inline std::string | |
820 maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f) | |
821 { | |
822 std::string str; | |
823 | |
824 std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()); | |
825 | |
826 if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >())) | |
827 { | |
828 str += "("; | |
829 str += without_scale; | |
830 str += ")"; | |
831 } | |
832 else | |
833 { | |
834 str += without_scale; | |
835 } | |
836 | |
837 return(str); | |
838 } | |
839 | |
840 // This overload catches scaled units that have a single base unit | |
841 // raised to the first power. It causes si::nano * si::meters to not | |
842 // put parentheses around the meters. i.e. nm rather than n(m) | |
843 /// INTERNAL ONLY | |
844 template<class Dimension,class Unit,class Scale, class Subformatter> | |
845 inline std::string | |
846 maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f) | |
847 { | |
848 return f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >()); | |
849 } | |
850 | |
851 template<class Prefixes, class CharT, class Traits, class Unit, class T, class F> | |
852 void do_print_prefixed_impl(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, F default_) | |
853 { | |
854 bool prefixed; | |
855 if(detail::find_matching_scale<Prefixes>(q.value(), autoprefix_norm(q.value()), detail::print_scale(os, prefixed))) { | |
856 if(prefixed) { | |
857 switch(units::get_format(os)) { | |
858 case symbol_fmt: do_print(os, maybe_parenthesize(Unit(), format_symbol_impl())); break; | |
859 case raw_fmt: do_print(os, maybe_parenthesize(Unit(), format_raw_symbol_impl())); break; | |
860 case name_fmt: do_print(os, maybe_parenthesize(Unit(), format_name_impl())); break; | |
861 case typename_fmt: do_print(os, simplify_typename(Unit())); break; | |
862 } | |
863 } else { | |
864 os << Unit(); | |
865 } | |
866 } else { | |
867 default_(); | |
868 } | |
869 } | |
870 | |
871 // Handle units like si::kilograms that have a scale embedded in the | |
872 // base unit. This overload is disabled if the scaled base unit has | |
873 // a user-defined string representation. | |
874 template<class Prefixes, class CharT, class Traits, class Dimension, class BaseUnit, class BaseScale, class Scale, class T> | |
875 typename base_unit_info< | |
876 scaled_base_unit<BaseUnit, Scale> | |
877 >::base_unit_info_primary_template | |
878 do_print_prefixed( | |
879 std::basic_ostream<CharT, Traits>& os, | |
880 const quantity< | |
881 unit< | |
882 Dimension, | |
883 heterogeneous_system< | |
884 heterogeneous_system_impl< | |
885 list< | |
886 heterogeneous_system_dim< | |
887 scaled_base_unit<BaseUnit, BaseScale>, | |
888 static_rational<1> | |
889 >, | |
890 dimensionless_type | |
891 >, | |
892 Dimension, | |
893 Scale | |
894 > | |
895 > | |
896 >, | |
897 T | |
898 >& q) | |
899 { | |
900 quantity< | |
901 unit< | |
902 Dimension, | |
903 heterogeneous_system< | |
904 heterogeneous_system_impl< | |
905 list< | |
906 heterogeneous_system_dim<BaseUnit, static_rational<1> >, | |
907 dimensionless_type | |
908 >, | |
909 Dimension, | |
910 dimensionless_type | |
911 > | |
912 > | |
913 >, | |
914 T | |
915 > unscaled(q); | |
916 detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q)); | |
917 } | |
918 | |
919 template<class Prefixes, class CharT, class Traits, class Dimension, class L, class Scale, class T> | |
920 void do_print_prefixed( | |
921 std::basic_ostream<CharT, Traits>& os, | |
922 const quantity< | |
923 unit< | |
924 Dimension, | |
925 heterogeneous_system< | |
926 heterogeneous_system_impl< | |
927 L, | |
928 Dimension, | |
929 Scale | |
930 > | |
931 > | |
932 >, | |
933 T | |
934 >& q) | |
935 { | |
936 quantity< | |
937 unit< | |
938 Dimension, | |
939 heterogeneous_system< | |
940 heterogeneous_system_impl< | |
941 L, | |
942 Dimension, | |
943 dimensionless_type | |
944 > | |
945 > | |
946 >, | |
947 T | |
948 > unscaled(q); | |
949 detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q)); | |
950 } | |
951 | |
952 template<class Prefixes, class CharT, class Traits, class Dimension, class System, class T> | |
953 void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<unit<Dimension, System>, T>& q) | |
954 { | |
955 detail::do_print_prefixed<Prefixes>(os, quantity<unit<Dimension, typename make_heterogeneous_system<Dimension, System>::type>, T>(q)); | |
956 } | |
957 | |
958 template<class Prefixes, class CharT, class Traits, class Unit, class T> | |
959 void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q) | |
960 { | |
961 detail::print_default(os, q)(); | |
962 } | |
963 | |
964 template<class Prefixes, class CharT, class Traits, class Unit, class T> | |
965 void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::true_) | |
966 { | |
967 detail::do_print_prefixed<Prefixes>(os, q); | |
968 } | |
969 | |
970 template<class Prefixes, class CharT, class Traits, class Unit, class T> | |
971 void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::false_) | |
972 { | |
973 detail::print_default(os, q)(); | |
974 } | |
975 | |
976 inline mpl::true_ test_norm(double) { return mpl::true_(); } | |
977 inline mpl::false_ test_norm(one) { return mpl::false_(); } | |
978 | |
979 } // namespace detail | |
980 | |
981 template<class Dimension,class System> | |
982 inline std::string | |
983 typename_string(const unit<Dimension, System>&) | |
984 { | |
985 return simplify_typename(typename reduce_unit< unit<Dimension,System> >::type()); | |
986 } | |
987 | |
988 template<class Dimension,class System> | |
989 inline std::string | |
990 symbol_string(const unit<Dimension, System>&) | |
991 { | |
992 return detail::to_string_impl(unit<Dimension,System>(), detail::format_symbol_impl()); | |
993 } | |
994 | |
995 template<class Dimension,class System> | |
996 inline std::string | |
997 name_string(const unit<Dimension, System>&) | |
998 { | |
999 return detail::to_string_impl(unit<Dimension,System>(), detail::format_name_impl()); | |
1000 } | |
1001 | |
1002 /// Print a @c unit as a list of base units and their exponents. | |
1003 /// | |
1004 /// for @c symbol_format outputs e.g. "m s^-1" or "J". | |
1005 /// for @c name_format outputs e.g. "meter second^-1" or "joule". | |
1006 /// for @c raw_format outputs e.g. "m s^-1" or "meter kilogram^2 second^-2". | |
1007 /// for @c typename_format outputs the typename itself (currently demangled only on GCC). | |
1008 template<class Char, class Traits, class Dimension, class System> | |
1009 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const unit<Dimension, System>& u) | |
1010 { | |
1011 if (units::get_format(os) == typename_fmt) | |
1012 { | |
1013 detail::do_print(os, typename_string(u)); | |
1014 } | |
1015 else if (units::get_format(os) == raw_fmt) | |
1016 { | |
1017 detail::do_print(os, detail::to_string_impl(u, detail::format_raw_symbol_impl())); | |
1018 } | |
1019 else if (units::get_format(os) == symbol_fmt) | |
1020 { | |
1021 detail::do_print(os, symbol_string(u)); | |
1022 } | |
1023 else if (units::get_format(os) == name_fmt) | |
1024 { | |
1025 detail::do_print(os, name_string(u)); | |
1026 } | |
1027 else | |
1028 { | |
1029 assert(!"The format mode must be one of: typename_format, raw_format, name_format, symbol_format"); | |
1030 } | |
1031 | |
1032 return(os); | |
1033 } | |
1034 | |
1035 /// \brief Print a @c quantity. | |
1036 /// \details Prints the value followed by the unit. | |
1037 /// If the engineering_prefix, or binary_prefix is set, | |
1038 /// tries to scale the value appropriately. | |
1039 /// For example, it might print 12.345 km instead of 12345 m. | |
1040 /// (Note does @b not attempt to automatically scale scalars like double, float...) | |
1041 template<class Char, class Traits, class Unit, class T> | |
1042 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const quantity<Unit, T>& q) | |
1043 { | |
1044 if (units::get_autoprefix(os) == autoprefix_none) | |
1045 { | |
1046 os << q.value() << ' ' << Unit(); | |
1047 } | |
1048 else if (units::get_autoprefix(os) == autoprefix_engineering) | |
1049 { | |
1050 detail::maybe_print_prefixed<detail::engineering_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value()))); | |
1051 } | |
1052 else if (units::get_autoprefix(os) == autoprefix_binary) | |
1053 { | |
1054 detail::maybe_print_prefixed<detail::binary_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value()))); | |
1055 } | |
1056 else | |
1057 { | |
1058 assert(!"Autoprefixing must be one of: no_prefix, engineering_prefix, binary_prefix"); | |
1059 } | |
1060 return(os); | |
1061 } | |
1062 | |
1063 } // namespace units | |
1064 | |
1065 } // namespace boost | |
1066 | |
1067 #endif |