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>
serialize(Archive & ar,boost::units::unit<Dim,System> &,const unsigned int)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>
serialize(Archive & ar,boost::units::quantity<Unit,Y> & q,const unsigned int)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.
to_string(const T & t)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.
to_string(const static_rational<N> &)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.
to_string(const static_rational<N,D> &)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>
operator <<(std::basic_ostream<Char,Traits> & os,const static_rational<N,D> & r)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)
nameboost::units::base_unit_info95 static std::string name()
96 {
97 return(BaseUnit::name());
98 }
99 /// The symbol for the base unit (Returns BaseUnit::symbol() by default)
symbolboost::units::base_unit_info100 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 {
xalloc_key_initializer_tboost::units::detail::xalloc_key_initializer_t142 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.
get_flags(std::ios_base & ios,long mask)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.
set_flags(std::ios_base & ios,long new_flags,long mask)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.
get_format(std::ios_base & ios)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.
set_format(std::ios_base & ios,format_mode new_mode)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.
typename_format(std::ios_base & ios)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".
raw_format(std::ios_base & ios)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".
symbol_format(std::ios_base & ios)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".
name_format(std::ios_base & ios)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.
get_autoprefix(std::ios_base & ios)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.
set_autoprefix(std::ios_base & ios,autoprefix_mode new_mode)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.
no_prefix(std::ios_base & ios)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".
engineering_prefix(std::ios_base & ios)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".
binary_prefix(std::ios_base & ios)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>
exponent_string(const static_rational<N,D> & r)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<>
exponent_string(const static_rational<1> &)258 inline std::string exponent_string(const static_rational<1>&)
259 {
260 return "";
261 }
262
263 template<class T>
base_unit_symbol_string(const 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>
base_unit_name_string(const 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;
valueboost::units::detail::symbol_string_impl::apply283 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 {
valueboost::units::detail::symbol_string_impl::apply297 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 {
valueboost::units::detail::symbol_string_impl::apply310 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 {
valueboost::units::detail::scale_symbol_string_impl::apply324 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 {
valueboost::units::detail::scale_symbol_string_impl::apply338 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;
valueboost::units::detail::name_string_impl::apply350 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 {
valueboost::units::detail::name_string_impl::apply364 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 {
valueboost::units::detail::name_string_impl::apply377 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 {
valueboost::units::detail::scale_name_string_impl::apply390 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 {
valueboost::units::detail::scale_name_string_impl::apply404 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
to_string_impl(const unit<Dimension,System> &,SubFormatter f)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
to_string_impl(const unit<Dimension,heterogeneous_system<heterogeneous_system_impl<Units,Dimension,dimensionless_type>>> &,Subformatter f)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
to_string_impl(const unit<dimensionless_type,heterogeneous_system<heterogeneous_system_impl<dimensionless_type,dimensionless_type,dimensionless_type>>> &,Subformatter)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
to_string_impl(const unit<dimensionless_type,heterogeneous_system<heterogeneous_system_impl<dimensionless_type,dimensionless_type,Scale>>> &,Subformatter f)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
to_string_impl(const unit<Dimension,heterogeneous_system<heterogeneous_system_impl<Units,Dimension,Scale>>> &,Subformatter f)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
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)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
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)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
to_string_impl(const unit<Dimension,heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<scaled_base_unit<Unit,UnitScale>,static_rational<1>>,dimensionless_type>,Dimension,Scale>>> &,Subformatter f,typename base_unit_info<scaled_base_unit<Unit,UnitScale>>::base_unit_info_primary_template * =0)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
to_string_impl(const unit<Dimension,heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<scaled_base_unit<Unit,UnitScale>,static_rational<1>>,dimensionless_type>,Dimension,dimensionless_type>>> &,Subformatter f,typename base_unit_info<scaled_base_unit<Unit,UnitScale>>::base_unit_info_primary_template * =0)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>
append_units_toboost::units::detail::format_raw_symbol_impl575 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>
append_scale_toboost::units::detail::format_raw_symbol_impl579 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>
operator ()boost::units::detail::format_raw_symbol_impl583 std::string operator()(const Unit& u) {
584 return(to_string_impl(u, *this));
585 }
586 template<class Unit>
is_default_stringboost::units::detail::format_raw_symbol_impl587 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>
operator ()boost::units::detail::format_symbol_impl594 std::string operator()(const Unit& u) {
595 return(symbol_string(u));
596 }
597 template<class Unit>
is_default_stringboost::units::detail::format_symbol_impl598 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>
append_units_toboost::units::detail::format_raw_name_impl605 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>
append_scale_toboost::units::detail::format_raw_name_impl609 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>
operator ()boost::units::detail::format_raw_name_impl613 std::string operator()(const Unit& u) {
614 return(to_string_impl(u, *this));
615 }
616 template<class Unit>
is_default_stringboost::units::detail::format_raw_name_impl617 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>
operator ()boost::units::detail::format_name_impl624 std::string operator()(const Unit& u) {
625 return(name_string(u));
626 }
627 template<class Unit>
is_default_stringboost::units::detail::format_name_impl628 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>
do_print(std::basic_ostream<Char,Traits> & os,const std::string & s)634 inline void do_print(std::basic_ostream<Char, Traits>& os, const std::string& s)
635 {
636 os << s.c_str();
637 }
638
do_print(std::ostream & os,const std::string & s)639 inline void do_print(std::ostream& os, const std::string& s)
640 {
641 os << s;
642 }
643
644 template<class Char, class Traits>
do_print(std::basic_ostream<Char,Traits> & os,const char * s)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;
callboost::units::autoprefix_norm_impl671 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;
callboost::units::autoprefix_norm_impl678 static one call(const T&) { return one(); }
679 };
680
681 template<class T>
autoprefix_norm(const T & arg)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>
find_matching_scale_impl(End,End,Prev,T,double,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>
find_matching_scale_impl(Begin,End end,Prev prev,T t,double x,F 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>
find_matching_scale_i(End,End,T,double,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>
find_matching_scale_i(Begin,End end,T t,double x,F 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>
find_matching_scale(T t,double x,F 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 list<scale<2, static_rational<80> >,
765 list<scale<2, static_rational<90> >,
766 dimensionless_type> > > > > > > > > binary_prefixes;
767
768 template<class Os, class Quantity>
769 struct print_default_t {
770 typedef void result_type;
operator ()boost::units::detail::print_default_t771 void operator()() const
772 {
773 *os << q->value() << ' ' << typename Quantity::unit_type();
774 }
775 Os* os;
776 const Quantity* q;
777 };
778
779 template<class Os, class Quantity>
print_default(Os & os,const Quantity & q)780 print_default_t<Os, Quantity> print_default(Os& os, const Quantity& q)
781 {
782 print_default_t<Os, Quantity> result = { &os, &q };
783 return result;
784 }
785
786 template<class Os>
787 struct print_scale_t {
788 typedef void result_type;
789 template<class Prefix, class T>
operator ()boost::units::detail::print_scale_t790 void operator()(Prefix, const T& t) const
791 {
792 *prefixed = true;
793 *os << t / Prefix::value() << ' ';
794 switch(units::get_format(*os)) {
795 case name_fmt: do_print(*os, Prefix::name()); break;
796 case raw_fmt:
797 case symbol_fmt: do_print(*os, Prefix::symbol()); break;
798 case typename_fmt: do_print(*os, units::simplify_typename(Prefix())); *os << ' '; break;
799 }
800 }
801 template<long N, class T>
operator ()boost::units::detail::print_scale_t802 void operator()(scale<N, static_rational<0> >, const T& t) const
803 {
804 *prefixed = false;
805 *os << t << ' ';
806 }
807 Os* os;
808 bool* prefixed;
809 };
810
811 template<class Os>
print_scale(Os & os,bool & prefixed)812 print_scale_t<Os> print_scale(Os& os, bool& prefixed)
813 {
814 print_scale_t<Os> result = { &os, &prefixed };
815 return result;
816 }
817
818 // puts parentheses around a unit
819 /// INTERNAL ONLY
820 template<class Dimension,class Units,class Scale, class Subformatter>
821 inline std::string
maybe_parenthesize(const unit<Dimension,heterogeneous_system<heterogeneous_system_impl<Units,Dimension,Scale>>> &,Subformatter f)822 maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
823 {
824 std::string str;
825
826 std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
827
828 if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
829 {
830 str += "(";
831 str += without_scale;
832 str += ")";
833 }
834 else
835 {
836 str += without_scale;
837 }
838
839 return(str);
840 }
841
842 // This overload catches scaled units that have a single base unit
843 // raised to the first power. It causes si::nano * si::meters to not
844 // put parentheses around the meters. i.e. nm rather than n(m)
845 /// INTERNAL ONLY
846 template<class Dimension,class Unit,class Scale, class Subformatter>
847 inline std::string
maybe_parenthesize(const unit<Dimension,heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit,static_rational<1>>,dimensionless_type>,Dimension,Scale>>> &,Subformatter f)848 maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
849 {
850 return f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
851 }
852
853 template<class Prefixes, class CharT, class Traits, class Unit, class T, class F>
do_print_prefixed_impl(std::basic_ostream<CharT,Traits> & os,const quantity<Unit,T> & q,F default_)854 void do_print_prefixed_impl(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, F default_)
855 {
856 bool prefixed;
857 if(detail::find_matching_scale<Prefixes>(q.value(), autoprefix_norm(q.value()), detail::print_scale(os, prefixed))) {
858 if(prefixed) {
859 switch(units::get_format(os)) {
860 case symbol_fmt: do_print(os, maybe_parenthesize(Unit(), format_symbol_impl())); break;
861 case raw_fmt: do_print(os, maybe_parenthesize(Unit(), format_raw_symbol_impl())); break;
862 case name_fmt: do_print(os, maybe_parenthesize(Unit(), format_name_impl())); break;
863 case typename_fmt: do_print(os, simplify_typename(Unit())); break;
864 }
865 } else {
866 os << Unit();
867 }
868 } else {
869 default_();
870 }
871 }
872
873 // Handle units like si::kilograms that have a scale embedded in the
874 // base unit. This overload is disabled if the scaled base unit has
875 // a user-defined string representation.
876 template<class Prefixes, class CharT, class Traits, class Dimension, class BaseUnit, class BaseScale, class Scale, class T>
877 typename base_unit_info<
878 scaled_base_unit<BaseUnit, Scale>
879 >::base_unit_info_primary_template
do_print_prefixed(std::basic_ostream<CharT,Traits> & os,const quantity<unit<Dimension,heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<scaled_base_unit<BaseUnit,BaseScale>,static_rational<1>>,dimensionless_type>,Dimension,Scale>>>,T> & q)880 do_print_prefixed(
881 std::basic_ostream<CharT, Traits>& os,
882 const quantity<
883 unit<
884 Dimension,
885 heterogeneous_system<
886 heterogeneous_system_impl<
887 list<
888 heterogeneous_system_dim<
889 scaled_base_unit<BaseUnit, BaseScale>,
890 static_rational<1>
891 >,
892 dimensionless_type
893 >,
894 Dimension,
895 Scale
896 >
897 >
898 >,
899 T
900 >& q)
901 {
902 quantity<
903 unit<
904 Dimension,
905 heterogeneous_system<
906 heterogeneous_system_impl<
907 list<
908 heterogeneous_system_dim<BaseUnit, static_rational<1> >,
909 dimensionless_type
910 >,
911 Dimension,
912 dimensionless_type
913 >
914 >
915 >,
916 T
917 > unscaled(q);
918 detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
919 }
920
921 template<class Prefixes, class CharT, class Traits, class Dimension, class L, class Scale, class T>
do_print_prefixed(std::basic_ostream<CharT,Traits> & os,const quantity<unit<Dimension,heterogeneous_system<heterogeneous_system_impl<L,Dimension,Scale>>>,T> & q)922 void do_print_prefixed(
923 std::basic_ostream<CharT, Traits>& os,
924 const quantity<
925 unit<
926 Dimension,
927 heterogeneous_system<
928 heterogeneous_system_impl<
929 L,
930 Dimension,
931 Scale
932 >
933 >
934 >,
935 T
936 >& q)
937 {
938 quantity<
939 unit<
940 Dimension,
941 heterogeneous_system<
942 heterogeneous_system_impl<
943 L,
944 Dimension,
945 dimensionless_type
946 >
947 >
948 >,
949 T
950 > unscaled(q);
951 detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
952 }
953
954 template<class Prefixes, class CharT, class Traits, class Dimension, class System, class T>
do_print_prefixed(std::basic_ostream<CharT,Traits> & os,const quantity<unit<Dimension,System>,T> & q)955 void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<unit<Dimension, System>, T>& q)
956 {
957 detail::do_print_prefixed<Prefixes>(os, quantity<unit<Dimension, typename make_heterogeneous_system<Dimension, System>::type>, T>(q));
958 }
959
960 template<class Prefixes, class CharT, class Traits, class Unit, class T>
do_print_prefixed(std::basic_ostream<CharT,Traits> & os,const quantity<Unit,T> & q)961 void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q)
962 {
963 detail::print_default(os, q)();
964 }
965
966 template<class Prefixes, class CharT, class Traits, class Unit, class T>
maybe_print_prefixed(std::basic_ostream<CharT,Traits> & os,const quantity<Unit,T> & q,mpl::true_)967 void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::true_)
968 {
969 detail::do_print_prefixed<Prefixes>(os, q);
970 }
971
972 template<class Prefixes, class CharT, class Traits, class Unit, class T>
maybe_print_prefixed(std::basic_ostream<CharT,Traits> & os,const quantity<Unit,T> & q,mpl::false_)973 void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::false_)
974 {
975 detail::print_default(os, q)();
976 }
977
test_norm(double)978 inline mpl::true_ test_norm(double) { return mpl::true_(); }
test_norm(one)979 inline mpl::false_ test_norm(one) { return mpl::false_(); }
980
981 } // namespace detail
982
983 template<class Dimension,class System>
984 inline std::string
typename_string(const unit<Dimension,System> &)985 typename_string(const unit<Dimension, System>&)
986 {
987 return simplify_typename(typename reduce_unit< unit<Dimension,System> >::type());
988 }
989
990 template<class Dimension,class System>
991 inline std::string
symbol_string(const unit<Dimension,System> &)992 symbol_string(const unit<Dimension, System>&)
993 {
994 return detail::to_string_impl(unit<Dimension,System>(), detail::format_symbol_impl());
995 }
996
997 template<class Dimension,class System>
998 inline std::string
name_string(const unit<Dimension,System> &)999 name_string(const unit<Dimension, System>&)
1000 {
1001 return detail::to_string_impl(unit<Dimension,System>(), detail::format_name_impl());
1002 }
1003
1004 /// Print a @c unit as a list of base units and their exponents.
1005 ///
1006 /// for @c symbol_format outputs e.g. "m s^-1" or "J".
1007 /// for @c name_format outputs e.g. "meter second^-1" or "joule".
1008 /// for @c raw_format outputs e.g. "m s^-1" or "meter kilogram^2 second^-2".
1009 /// for @c typename_format outputs the typename itself (currently demangled only on GCC).
1010 template<class Char, class Traits, class Dimension, class System>
operator <<(std::basic_ostream<Char,Traits> & os,const unit<Dimension,System> & u)1011 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const unit<Dimension, System>& u)
1012 {
1013 if (units::get_format(os) == typename_fmt)
1014 {
1015 detail::do_print(os, typename_string(u));
1016 }
1017 else if (units::get_format(os) == raw_fmt)
1018 {
1019 detail::do_print(os, detail::to_string_impl(u, detail::format_raw_symbol_impl()));
1020 }
1021 else if (units::get_format(os) == symbol_fmt)
1022 {
1023 detail::do_print(os, symbol_string(u));
1024 }
1025 else if (units::get_format(os) == name_fmt)
1026 {
1027 detail::do_print(os, name_string(u));
1028 }
1029 else
1030 {
1031 assert(!"The format mode must be one of: typename_format, raw_format, name_format, symbol_format");
1032 }
1033
1034 return(os);
1035 }
1036
1037 /// \brief Print a @c quantity.
1038 /// \details Prints the value followed by the unit.
1039 /// If the engineering_prefix, or binary_prefix is set,
1040 /// tries to scale the value appropriately.
1041 /// For example, it might print 12.345 km instead of 12345 m.
1042 /// (Note does @b not attempt to automatically scale scalars like double, float...)
1043 template<class Char, class Traits, class Unit, class T>
operator <<(std::basic_ostream<Char,Traits> & os,const quantity<Unit,T> & q)1044 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const quantity<Unit, T>& q)
1045 {
1046 if (units::get_autoprefix(os) == autoprefix_none)
1047 {
1048 os << q.value() << ' ' << Unit();
1049 }
1050 else if (units::get_autoprefix(os) == autoprefix_engineering)
1051 {
1052 detail::maybe_print_prefixed<detail::engineering_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
1053 }
1054 else if (units::get_autoprefix(os) == autoprefix_binary)
1055 {
1056 detail::maybe_print_prefixed<detail::binary_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
1057 }
1058 else
1059 {
1060 assert(!"Autoprefixing must be one of: no_prefix, engineering_prefix, binary_prefix");
1061 }
1062 return(os);
1063 }
1064
1065 } // namespace units
1066
1067 } // namespace boost
1068
1069 #endif
1070