1 // Boost.Units - A C++ library for zero-overhead dimensional analysis and
2 // unit/quantity manipulation and conversion
4 // Copyright (C) 2003-2008 Matthias Christian Schabel
5 // Copyright (C) 2007-2010 Steven Watanabe
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)
11 #ifndef BOOST_UNITS_IO_HPP
12 #define BOOST_UNITS_IO_HPP
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.
27 #include <boost/assert.hpp>
28 #include <boost/serialization/nvp.hpp>
30 #include <boost/units/units_fwd.hpp>
31 #include <boost/units/heterogeneous_system.hpp>
32 #include <boost/units/make_scaled_unit.hpp>
33 #include <boost/units/quantity.hpp>
34 #include <boost/units/scale.hpp>
35 #include <boost/units/static_rational.hpp>
36 #include <boost/units/unit.hpp>
37 #include <boost/units/detail/utility.hpp>
41 namespace serialization {
43 /// Boost Serialization library support for units.
44 template<class Archive,class System,class Dim>
45 inline void serialize(Archive& /*ar*/,boost::units::unit<Dim,System>&,const unsigned int /*version*/)
48 /// Boost Serialization library support for quantities.
49 template<class Archive,class Unit,class Y>
50 inline void serialize(Archive& ar,boost::units::quantity<Unit,Y>& q,const unsigned int /*version*/)
52 ar & boost::serialization::make_nvp("value", units::quantity_cast<Y&>(q));
55 } // namespace serialization
59 // get string representation of arbitrary type.
60 template<class T> std::string to_string(const T& t)
62 std::stringstream sstr;
69 /// get string representation of integral-valued @c static_rational.
70 template<integer_type N> std::string to_string(const static_rational<N>&)
75 /// get string representation of @c static_rational.
76 template<integer_type N, integer_type D> std::string to_string(const static_rational<N,D>&)
78 return '(' + to_string(N) + '/' + to_string(D) + ')';
81 /// Write @c static_rational to @c std::basic_ostream.
82 template<class Char, class Traits, integer_type N, integer_type D>
83 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,const static_rational<N,D>& r)
89 /// traits template for unit names.
90 template<class BaseUnit>
94 typedef void base_unit_info_primary_template;
95 /// The full name of the unit (returns BaseUnit::name() by default)
96 static std::string name()
98 return(BaseUnit::name());
100 /// The symbol for the base unit (Returns BaseUnit::symbol() by default)
101 static std::string symbol()
103 return(BaseUnit::symbol()); /// \returns BaseUnit::symbol(), for example "m"
107 /// \enum format_mode format of output of units, for example "m" or "meter".
110 symbol_fmt = 0, /// default - reduces unit names to known symbols for both base and derived units.
111 name_fmt = 1, /// output full unit names for base and derived units, for example "meter".
112 raw_fmt = 2, /// output only symbols for base units (but not derived units), for example "m".
113 typename_fmt = 3, /// output demangled typenames (useful only for diagnosis).
114 fmt_mask = 3 /// Bits used for format.
117 /// \enum autoprefix_mode automatic scaling and prefix (controlled by value of quantity) a, if any,
120 autoprefix_none = 0, /// No automatic prefix.
121 autoprefix_engineering = 4, /// Scale and prefix with 10^3 multiples, 1234.5 m output as 1.2345 km.
122 autoprefix_binary = 8, /// Scale and prefix with 2^10 (1024) multiples, 1024 as 1 kb.
123 autoprefix_mask = 12 /// Bits used for autoprefix.
129 struct xalloc_key_holder
132 static bool initialized;
136 int xalloc_key_holder<b>::value = 0;
139 bool xalloc_key_holder<b>::initialized = 0;
141 struct xalloc_key_initializer_t
143 xalloc_key_initializer_t()
145 if (!xalloc_key_holder<true>::initialized)
147 xalloc_key_holder<true>::value = std::ios_base::xalloc();
148 xalloc_key_holder<true>::initialized = true;
155 xalloc_key_initializer_t xalloc_key_initializer;
159 } // namespace detail
161 /// returns flags controlling output.
162 inline long get_flags(std::ios_base& ios, long mask)
164 return(ios.iword(detail::xalloc_key_holder<true>::value) & mask);
167 /// Set new flags controlling output format.
168 inline void set_flags(std::ios_base& ios, long new_flags, long mask)
170 BOOST_ASSERT((~mask & new_flags) == 0);
171 long& flags = ios.iword(detail::xalloc_key_holder<true>::value);
172 flags = (flags & ~mask) | new_flags;
175 /// returns flags controlling output format.
176 inline format_mode get_format(std::ios_base& ios)
178 return(static_cast<format_mode>((get_flags)(ios, fmt_mask)));
181 /// Set new flags controlling output format.
182 inline void set_format(std::ios_base& ios, format_mode new_mode)
184 (set_flags)(ios, new_mode, fmt_mask);
187 /// Set new flags for type_name output format.
188 inline std::ios_base& typename_format(std::ios_base& ios)
190 (set_format)(ios, typename_fmt);
194 /// set new flag for raw format output, for example "m".
195 inline std::ios_base& raw_format(std::ios_base& ios)
197 (set_format)(ios, raw_fmt);
201 /// set new format flag for symbol output, for example "m".
202 inline std::ios_base& symbol_format(std::ios_base& ios)
204 (set_format)(ios, symbol_fmt);
208 /// set new format for name output, for example "meter".
209 inline std::ios_base& name_format(std::ios_base& ios)
211 (set_format)(ios, name_fmt);
215 /// get autoprefix flags for output.
216 inline autoprefix_mode get_autoprefix(std::ios_base& ios)
218 return static_cast<autoprefix_mode>((get_flags)(ios, autoprefix_mask));
221 /// Get format for output.
222 inline void set_autoprefix(std::ios_base& ios, autoprefix_mode new_mode)
224 (set_flags)(ios, new_mode, autoprefix_mask);
227 /// Clear autoprefix flags.
228 inline std::ios_base& no_prefix(std::ios_base& ios)
230 (set_autoprefix)(ios, autoprefix_none);
234 /// Set flag for engineering prefix, so 1234.5 m displays as "1.2345 km".
235 inline std::ios_base& engineering_prefix(std::ios_base& ios)
237 (set_autoprefix)(ios, autoprefix_engineering);
241 /// Set flag for binary prefix, so 1024 byte displays as "1 Kib".
242 inline std::ios_base& binary_prefix(std::ios_base& ios)
244 (set_autoprefix)(ios, autoprefix_binary);
250 /// \return exponent string like "^1/2".
251 template<integer_type N, integer_type D>
252 inline std::string exponent_string(const static_rational<N,D>& r)
254 return '^' + to_string(r);
257 /// \return empty exponent string for integer rational like 2.
259 inline std::string exponent_string(const static_rational<1>&)
265 inline std::string base_unit_symbol_string(const T&)
267 return base_unit_info<typename T::tag_type>::symbol() + exponent_string(typename T::value_type());
271 inline std::string base_unit_name_string(const T&)
273 return base_unit_info<typename T::tag_type>::name() + exponent_string(typename T::value_type());
276 // stringify with symbols.
278 struct symbol_string_impl
280 template<class Begin>
283 typedef typename symbol_string_impl<N-1>::template apply<typename Begin::next> next;
284 static void value(std::string& str)
286 str += base_unit_symbol_string(typename Begin::item()) + ' ';
293 struct symbol_string_impl<1>
295 template<class Begin>
298 static void value(std::string& str)
300 str += base_unit_symbol_string(typename Begin::item());
306 struct symbol_string_impl<0>
308 template<class Begin>
311 static void value(std::string& str)
313 // better shorthand for dimensionless?
314 str += "dimensionless";
320 struct scale_symbol_string_impl
322 template<class Begin>
325 static void value(std::string& str)
327 str += Begin::item::symbol();
328 scale_symbol_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
334 struct scale_symbol_string_impl<0>
336 template<class Begin>
339 static void value(std::string&) { }
343 // stringify with names.
345 struct name_string_impl
347 template<class Begin>
350 typedef typename name_string_impl<N-1>::template apply<typename Begin::next> next;
351 static void value(std::string& str)
353 str += base_unit_name_string(typename Begin::item()) + ' ';
360 struct name_string_impl<1>
362 template<class Begin>
365 static void value(std::string& str)
367 str += base_unit_name_string(typename Begin::item());
373 struct name_string_impl<0>
375 template<class Begin>
378 static void value(std::string& str)
380 str += "dimensionless";
386 struct scale_name_string_impl
388 template<class Begin>
391 static void value(std::string& str)
393 str += Begin::item::name();
394 scale_name_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
400 struct scale_name_string_impl<0>
402 template<class Begin>
405 static void value(std::string&) { }
409 } // namespace detail
413 // These two overloads of symbol_string and name_string will
414 // will pick up homogeneous_systems. They simply call the
415 // appropriate function with a heterogeneous_system.
416 template<class Dimension,class System, class SubFormatter>
418 to_string_impl(const unit<Dimension,System>&, SubFormatter f)
420 return f(typename reduce_unit<unit<Dimension, System> >::type());
424 // this overload picks up heterogeneous units that are not scaled.
425 template<class Dimension,class Units, class Subformatter>
427 to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >&, Subformatter f)
430 f.template append_units_to<Units>(str);
434 // This overload is a special case for heterogeneous_system which
435 // is really unitless
437 template<class Subformatter>
439 to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, dimensionless_type> > >&, Subformatter)
441 return("dimensionless");
444 // this overload deals with heterogeneous_systems which are unitless
447 template<class Scale, class Subformatter>
449 to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, Scale> > >&, Subformatter f)
452 f.template append_scale_to<Scale>(str);
456 // this overload deals with scaled units.
458 template<class Dimension,class Units,class Scale, class Subformatter>
460 to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
464 f.template append_scale_to<Scale>(str);
466 std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
468 if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
471 str += without_scale;
476 str += without_scale;
482 // This overload catches scaled units that have a single base unit
483 // raised to the first power. It causes si::nano * si::meters to not
484 // put parentheses around the meters. i.e. nm rather than n(m)
486 template<class Dimension,class Unit,class Scale, class Subformatter>
488 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)
492 f.template append_scale_to<Scale>(str);
493 str += f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
498 // This overload is necessary to disambiguate.
499 // it catches units that are unscaled and have a single
500 // base unit raised to the first power. It is treated the
501 // same as any other unscaled unit.
503 template<class Dimension,class Unit,class Subformatter>
505 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)
508 f.template append_units_to<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type> >(str);
512 // This overload catches scaled units that have a single scaled base unit
513 // raised to the first power. It moves that scaling on the base unit
514 // to the unit level scaling and recurses. By doing this we make sure that
515 // si::milli * si::kilograms will print g rather than mkg.
517 // This transformation will not be applied if base_unit_info is specialized
518 // for the scaled base unit.
521 template<class Dimension,class Unit,class UnitScale, class Scale, class Subformatter>
526 heterogeneous_system<
527 heterogeneous_system_impl<
528 list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>,
535 typename base_unit_info<scaled_base_unit<Unit, UnitScale> >::base_unit_info_primary_template* = 0)
540 heterogeneous_system<
541 heterogeneous_system_impl<
542 list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>,
544 typename mpl::times<Scale, list<scale_list_dim<UnitScale>, dimensionless_type> >::type
550 // this overload disambuguates between the overload for an unscaled unit
551 // and the overload for a scaled base unit raised to the first power.
553 template<class Dimension,class Unit,class UnitScale,class Subformatter>
558 heterogeneous_system<
559 heterogeneous_system_impl<
560 list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>,
567 typename base_unit_info<scaled_base_unit<Unit, UnitScale> >::base_unit_info_primary_template* = 0)
570 f.template append_units_to<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type> >(str);
574 struct format_raw_symbol_impl {
575 template<class Units>
576 void append_units_to(std::string& str) {
577 detail::symbol_string_impl<Units::size::value>::template apply<Units>::value(str);
579 template<class Scale>
580 void append_scale_to(std::string& str) {
581 detail::scale_symbol_string_impl<Scale::size::value>::template apply<Scale>::value(str);
584 std::string operator()(const Unit& u) {
585 return(to_string_impl(u, *this));
588 bool is_default_string(const std::string&, const Unit&) {
593 struct format_symbol_impl : format_raw_symbol_impl {
595 std::string operator()(const Unit& u) {
596 return(symbol_string(u));
599 bool is_default_string(const std::string& str, const Unit& u) {
600 return(str == to_string_impl(u, format_raw_symbol_impl()));
604 struct format_raw_name_impl {
605 template<class Units>
606 void append_units_to(std::string& str) {
607 detail::name_string_impl<(Units::size::value)>::template apply<Units>::value(str);
609 template<class Scale>
610 void append_scale_to(std::string& str) {
611 detail::scale_name_string_impl<Scale::size::value>::template apply<Scale>::value(str);
614 std::string operator()(const Unit& u) {
615 return(to_string_impl(u, *this));
618 bool is_default_string(const std::string&, const Unit&) {
623 struct format_name_impl : format_raw_name_impl {
625 std::string operator()(const Unit& u) {
626 return(name_string(u));
629 bool is_default_string(const std::string& str, const Unit& u) {
630 return(str == to_string_impl(u, format_raw_name_impl()));
634 template<class Char, class Traits>
635 inline void do_print(std::basic_ostream<Char, Traits>& os, const std::string& s)
640 inline void do_print(std::ostream& os, const std::string& s)
645 template<class Char, class Traits>
646 inline void do_print(std::basic_ostream<Char, Traits>& os, const char* s)
651 // For automatically applying the appropriate prefixes.
655 #ifdef BOOST_UNITS_DOXYGEN
657 /// ADL customization point for automatic prefixing.
658 /// Returns a non-negative value. Implemented as std::abs
659 /// for built-in types.
661 double autoprefix_norm(const T& arg);
665 template<class T, bool C = boost::is_arithmetic<T>::value>
666 struct autoprefix_norm_impl;
669 struct autoprefix_norm_impl<T, true>
672 static BOOST_CONSTEXPR double call(const T& arg) { return std::abs(arg); }
676 struct autoprefix_norm_impl<T, false>
679 static BOOST_CONSTEXPR one call(const T&) { return one(); }
684 typename autoprefix_norm_impl<T>::type autoprefix_norm(const T& arg)
686 return autoprefix_norm_impl<T>::call(arg);
693 template<class End, class Prev, class T, class F>
695 bool find_matching_scale_impl(End, End, Prev, T, double, F)
700 template<class Begin, class End, class Prev, class T, class F>
701 BOOST_CXX14_CONSTEXPR
702 bool find_matching_scale_impl(Begin, End end, Prev prev, T t, double x, F f)
704 if(Begin::item::value() > x) {
708 return detail::find_matching_scale_impl(
709 typename Begin::next(),
711 typename Begin::item(),
719 template<class End, class T, class F>
721 bool find_matching_scale_i(End, End, T, double, F)
726 template<class Begin, class End, class T, class F>
727 BOOST_CXX14_CONSTEXPR
728 bool find_matching_scale_i(Begin, End end, T t, double x, F f)
730 if(Begin::item::value() > x) {
733 return detail::find_matching_scale_impl(typename Begin::next(), end, typename Begin::item(), t, x, f);
737 template<class Scales, class T, class F>
738 BOOST_CXX14_CONSTEXPR
739 bool find_matching_scale(T t, double x, F f)
741 return detail::find_matching_scale_i(Scales(), dimensionless_type(), t, x, f);
744 typedef list<scale<10, static_rational<-24> >,
745 list<scale<10, static_rational<-21> >,
746 list<scale<10, static_rational<-18> >,
747 list<scale<10, static_rational<-15> >,
748 list<scale<10, static_rational<-12> >,
749 list<scale<10, static_rational<-9> >,
750 list<scale<10, static_rational<-6> >,
751 list<scale<10, static_rational<-3> >,
752 list<scale<10, static_rational<0> >,
753 list<scale<10, static_rational<3> >,
754 list<scale<10, static_rational<6> >,
755 list<scale<10, static_rational<9> >,
756 list<scale<10, static_rational<12> >,
757 list<scale<10, static_rational<15> >,
758 list<scale<10, static_rational<18> >,
759 list<scale<10, static_rational<21> >,
760 list<scale<10, static_rational<24> >,
761 list<scale<10, static_rational<27> >,
762 dimensionless_type> > > > > > > > > > > > > > > > > > engineering_prefixes;
764 typedef list<scale<2, static_rational<10> >,
765 list<scale<2, static_rational<20> >,
766 list<scale<2, static_rational<30> >,
767 list<scale<2, static_rational<40> >,
768 list<scale<2, static_rational<50> >,
769 list<scale<2, static_rational<60> >,
770 list<scale<2, static_rational<70> >,
771 list<scale<2, static_rational<80> >,
772 list<scale<2, static_rational<90> >,
773 dimensionless_type> > > > > > > > > binary_prefixes;
775 template<class Os, class Quantity>
776 struct print_default_t {
777 typedef void result_type;
778 void operator()() const
780 *os << q->value() << ' ' << typename Quantity::unit_type();
786 template<class Os, class Quantity>
787 print_default_t<Os, Quantity> print_default(Os& os, const Quantity& q)
789 print_default_t<Os, Quantity> result = { &os, &q };
794 struct print_scale_t {
795 typedef void result_type;
796 template<class Prefix, class T>
797 void operator()(Prefix, const T& t) const
800 *os << t / Prefix::value() << ' ';
801 switch(units::get_format(*os)) {
802 case name_fmt: do_print(*os, Prefix::name()); break;
804 case symbol_fmt: do_print(*os, Prefix::symbol()); break;
805 case typename_fmt: do_print(*os, units::simplify_typename(Prefix())); *os << ' '; break;
808 template<long N, class T>
809 void operator()(scale<N, static_rational<0> >, const T& t) const
819 print_scale_t<Os> print_scale(Os& os, bool& prefixed)
821 print_scale_t<Os> result = { &os, &prefixed };
825 // puts parentheses around a unit
827 template<class Dimension,class Units,class Scale, class Subformatter>
829 maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
833 std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
835 if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
838 str += without_scale;
843 str += without_scale;
849 // This overload catches scaled units that have a single base unit
850 // raised to the first power. It causes si::nano * si::meters to not
851 // put parentheses around the meters. i.e. nm rather than n(m)
853 template<class Dimension,class Unit,class Scale, class Subformatter>
855 maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
857 return f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
860 template<class Prefixes, class CharT, class Traits, class Unit, class T, class F>
861 void do_print_prefixed_impl(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, F default_)
864 if(detail::find_matching_scale<Prefixes>(q.value(), autoprefix_norm(q.value()), detail::print_scale(os, prefixed))) {
866 switch(units::get_format(os)) {
867 case symbol_fmt: do_print(os, maybe_parenthesize(Unit(), format_symbol_impl())); break;
868 case raw_fmt: do_print(os, maybe_parenthesize(Unit(), format_raw_symbol_impl())); break;
869 case name_fmt: do_print(os, maybe_parenthesize(Unit(), format_name_impl())); break;
870 case typename_fmt: do_print(os, simplify_typename(Unit())); break;
880 // Handle units like si::kilograms that have a scale embedded in the
881 // base unit. This overload is disabled if the scaled base unit has
882 // a user-defined string representation.
883 template<class Prefixes, class CharT, class Traits, class Dimension, class BaseUnit, class BaseScale, class Scale, class T>
884 typename base_unit_info<
885 scaled_base_unit<BaseUnit, Scale>
886 >::base_unit_info_primary_template
888 std::basic_ostream<CharT, Traits>& os,
892 heterogeneous_system<
893 heterogeneous_system_impl<
895 heterogeneous_system_dim<
896 scaled_base_unit<BaseUnit, BaseScale>,
912 heterogeneous_system<
913 heterogeneous_system_impl<
915 heterogeneous_system_dim<BaseUnit, static_rational<1> >,
925 detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
928 template<class Prefixes, class CharT, class Traits, class Dimension, class L, class Scale, class T>
929 void do_print_prefixed(
930 std::basic_ostream<CharT, Traits>& os,
934 heterogeneous_system<
935 heterogeneous_system_impl<
948 heterogeneous_system<
949 heterogeneous_system_impl<
958 detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
961 template<class Prefixes, class CharT, class Traits, class Dimension, class System, class T>
962 void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<unit<Dimension, System>, T>& q)
964 detail::do_print_prefixed<Prefixes>(os, quantity<unit<Dimension, typename make_heterogeneous_system<Dimension, System>::type>, T>(q));
967 template<class Prefixes, class CharT, class Traits, class Unit, class T>
968 void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q)
970 detail::print_default(os, q)();
973 template<class Prefixes, class CharT, class Traits, class Unit, class T>
974 void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::true_)
976 detail::do_print_prefixed<Prefixes>(os, q);
979 template<class Prefixes, class CharT, class Traits, class Unit, class T>
980 void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::false_)
982 detail::print_default(os, q)();
985 inline BOOST_CONSTEXPR mpl::true_ test_norm(double) { return mpl::true_(); }
986 inline BOOST_CONSTEXPR mpl::false_ test_norm(one) { return mpl::false_(); }
988 } // namespace detail
990 template<class Dimension,class System>
992 typename_string(const unit<Dimension, System>&)
994 return simplify_typename(typename reduce_unit< unit<Dimension,System> >::type());
997 template<class Dimension,class System>
999 symbol_string(const unit<Dimension, System>&)
1001 return detail::to_string_impl(unit<Dimension,System>(), detail::format_symbol_impl());
1004 template<class Dimension,class System>
1006 name_string(const unit<Dimension, System>&)
1008 return detail::to_string_impl(unit<Dimension,System>(), detail::format_name_impl());
1011 /// Print a @c unit as a list of base units and their exponents.
1013 /// for @c symbol_format outputs e.g. "m s^-1" or "J".
1014 /// for @c name_format outputs e.g. "meter second^-1" or "joule".
1015 /// for @c raw_format outputs e.g. "m s^-1" or "meter kilogram^2 second^-2".
1016 /// for @c typename_format outputs the typename itself (currently demangled only on GCC).
1017 template<class Char, class Traits, class Dimension, class System>
1018 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const unit<Dimension, System>& u)
1020 if (units::get_format(os) == typename_fmt)
1022 detail::do_print(os, typename_string(u));
1024 else if (units::get_format(os) == raw_fmt)
1026 detail::do_print(os, detail::to_string_impl(u, detail::format_raw_symbol_impl()));
1028 else if (units::get_format(os) == symbol_fmt)
1030 detail::do_print(os, symbol_string(u));
1032 else if (units::get_format(os) == name_fmt)
1034 detail::do_print(os, name_string(u));
1038 BOOST_ASSERT_MSG(false, "The format mode must be one of: typename_format, raw_format, name_format, symbol_format");
1044 /// \brief Print a @c quantity.
1045 /// \details Prints the value followed by the unit.
1046 /// If the engineering_prefix, or binary_prefix is set,
1047 /// tries to scale the value appropriately.
1048 /// For example, it might print 12.345 km instead of 12345 m.
1049 /// (Note does @b not attempt to automatically scale scalars like double, float...)
1050 template<class Char, class Traits, class Unit, class T>
1051 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const quantity<Unit, T>& q)
1053 if (units::get_autoprefix(os) == autoprefix_none)
1055 os << q.value() << ' ' << Unit();
1057 else if (units::get_autoprefix(os) == autoprefix_engineering)
1059 detail::maybe_print_prefixed<detail::engineering_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
1061 else if (units::get_autoprefix(os) == autoprefix_binary)
1063 detail::maybe_print_prefixed<detail::binary_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
1067 BOOST_ASSERT_MSG(false, "Autoprefixing must be one of: no_prefix, engineering_prefix, binary_prefix");
1072 } // namespace units
1074 } // namespace boost