Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/units/io.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // Boost.Units - A C++ library for zero-overhead dimensional analysis and
0002 // unit/quantity manipulation and conversion
0003 //
0004 // Copyright (C) 2003-2008 Matthias Christian Schabel
0005 // Copyright (C) 2007-2010 Steven Watanabe
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See
0008 // accompanying file LICENSE_1_0.txt or copy at
0009 // http://www.boost.org/LICENSE_1_0.txt)
0010 
0011 #ifndef BOOST_UNITS_IO_HPP
0012 #define BOOST_UNITS_IO_HPP
0013 
0014 /// \file
0015 /// \brief Stream input and output for rationals, units and quantities.
0016 /// \details Functions and manipulators for output and input of units and quantities.
0017 ///   symbol and name format, and engineering and binary autoprefix.
0018 ///   Serialization output is also supported.
0019 
0020 #include <cassert>
0021 #include <cmath>
0022 #include <string>
0023 #include <iosfwd>
0024 #include <ios>
0025 #include <sstream>
0026 
0027 #include <boost/assert.hpp>
0028 #include <boost/core/nvp.hpp>
0029 
0030 #include <boost/units/units_fwd.hpp>
0031 #include <boost/units/heterogeneous_system.hpp>
0032 #include <boost/units/make_scaled_unit.hpp>
0033 #include <boost/units/quantity.hpp>
0034 #include <boost/units/scale.hpp>
0035 #include <boost/units/static_rational.hpp>
0036 #include <boost/units/unit.hpp>
0037 #include <boost/units/detail/utility.hpp>
0038 
0039 namespace boost {
0040 
0041 namespace serialization {
0042 
0043 /// Boost Serialization library support for units.
0044 template<class Archive,class System,class Dim>
0045 inline void serialize(Archive& /*ar*/,boost::units::unit<Dim,System>&,const unsigned int /*version*/)
0046 { }
0047 
0048 /// Boost Serialization library support for quantities.
0049 template<class Archive,class Unit,class Y>
0050 inline void serialize(Archive& ar,boost::units::quantity<Unit,Y>& q,const unsigned int /*version*/)
0051 {
0052     ar & boost::serialization::make_nvp("value", units::quantity_cast<Y&>(q));
0053 }
0054 
0055 } // namespace serialization
0056 
0057 namespace units {
0058 
0059 // get string representation of arbitrary type.
0060 template<class T> std::string to_string(const T& t)
0061 {
0062     std::stringstream sstr;
0063 
0064     sstr << t;
0065 
0066     return sstr.str();
0067 }
0068 
0069 /// get string representation of integral-valued @c static_rational.
0070 template<integer_type N> std::string to_string(const static_rational<N>&)
0071 {
0072     return to_string(N);
0073 }
0074 
0075 /// get string representation of @c static_rational.
0076 template<integer_type N, integer_type D> std::string to_string(const static_rational<N,D>&)
0077 {
0078     return '(' + to_string(N) + '/' + to_string(D) + ')';
0079 }
0080 
0081 /// Write @c static_rational to @c std::basic_ostream.
0082 template<class Char, class Traits, integer_type N, integer_type D>
0083 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,const static_rational<N,D>& r)
0084 {
0085     os << to_string(r);
0086     return os;
0087 }
0088 
0089 /// traits template for unit names.
0090 template<class BaseUnit>
0091 struct base_unit_info
0092 {
0093     /// INTERNAL ONLY
0094     typedef void base_unit_info_primary_template;
0095     /// The full name of the unit (returns BaseUnit::name() by default)
0096     static std::string name()
0097     {
0098         return(BaseUnit::name());
0099     }
0100     /// The symbol for the base unit (Returns BaseUnit::symbol() by default)
0101     static std::string symbol()
0102     {
0103         return(BaseUnit::symbol());  ///  \returns BaseUnit::symbol(), for example "m"
0104     }
0105 };
0106 
0107 /// \enum format_mode format of output of units, for example "m" or "meter".
0108 enum format_mode
0109 {
0110     symbol_fmt = 0,     /// default - reduces unit names to known symbols for both base and derived units.
0111     name_fmt = 1,           /// output full unit names for base and derived units, for example "meter".
0112     raw_fmt = 2,            /// output only symbols for base units (but not derived units), for example "m".
0113     typename_fmt = 3,       /// output demangled typenames (useful only for diagnosis).
0114     fmt_mask = 3 /// Bits used for format.
0115 };
0116 
0117 /// \enum autoprefix_mode automatic scaling and prefix (controlled by value of quantity) a, if any,
0118 enum autoprefix_mode
0119 {
0120     autoprefix_none = 0, /// No automatic prefix.
0121     autoprefix_engineering = 4, /// Scale and prefix with 10^3 multiples, 1234.5 m output as 1.2345 km.
0122     autoprefix_binary = 8, /// Scale and prefix with 2^10 (1024) multiples, 1024 as 1 kb.
0123     autoprefix_mask = 12 ///  Bits used for autoprefix.
0124 };
0125 
0126 namespace detail {
0127 
0128 template<bool>
0129 struct xalloc_key_holder
0130 {
0131     static int value;
0132     static bool initialized;
0133 };
0134 
0135 template<bool b>
0136 int xalloc_key_holder<b>::value = 0;
0137 
0138 template<bool b>
0139 bool xalloc_key_holder<b>::initialized = 0;
0140 
0141 struct xalloc_key_initializer_t
0142 {
0143     xalloc_key_initializer_t()
0144     {
0145         if (!xalloc_key_holder<true>::initialized)
0146         {
0147             xalloc_key_holder<true>::value = std::ios_base::xalloc();
0148             xalloc_key_holder<true>::initialized = true;
0149         }
0150     }
0151 };
0152 
0153 namespace /**/ {
0154 
0155 xalloc_key_initializer_t xalloc_key_initializer;
0156 
0157 } // namespace
0158 
0159 } // namespace detail
0160 
0161 /// returns flags controlling output.
0162 inline long get_flags(std::ios_base& ios, long mask)
0163 {
0164     return(ios.iword(detail::xalloc_key_holder<true>::value) & mask);
0165 }
0166 
0167 /// Set new flags controlling output format.
0168 inline void set_flags(std::ios_base& ios, long new_flags, long mask)
0169 {
0170     BOOST_ASSERT((~mask & new_flags) == 0);
0171     long& flags = ios.iword(detail::xalloc_key_holder<true>::value);
0172     flags = (flags & ~mask) | new_flags;
0173 }
0174 
0175 /// returns flags controlling output format.
0176 inline format_mode get_format(std::ios_base& ios)
0177 {
0178     return(static_cast<format_mode>((get_flags)(ios, fmt_mask)));
0179 }
0180 
0181 /// Set new flags controlling output format.
0182 inline void set_format(std::ios_base& ios, format_mode new_mode)
0183 {
0184     (set_flags)(ios, new_mode, fmt_mask);
0185 }
0186 
0187 /// Set new flags for type_name output format.
0188 inline std::ios_base& typename_format(std::ios_base& ios)
0189 {
0190     (set_format)(ios, typename_fmt);
0191     return(ios);
0192 }
0193 
0194 /// set new flag for raw format output, for example "m".
0195 inline std::ios_base& raw_format(std::ios_base& ios)
0196 {
0197     (set_format)(ios, raw_fmt);
0198     return(ios);
0199 }
0200 
0201 /// set new format flag for symbol output, for example "m".
0202 inline std::ios_base& symbol_format(std::ios_base& ios)
0203 {
0204     (set_format)(ios, symbol_fmt);
0205     return(ios);
0206 }
0207 
0208 /// set new format for name output, for example "meter".
0209 inline std::ios_base& name_format(std::ios_base& ios)
0210 {
0211     (set_format)(ios, name_fmt);
0212     return(ios);
0213 }
0214 
0215 /// get autoprefix flags for output.
0216 inline autoprefix_mode get_autoprefix(std::ios_base& ios)
0217 {
0218     return static_cast<autoprefix_mode>((get_flags)(ios, autoprefix_mask));
0219 }
0220 
0221 /// Get format for output.
0222 inline void set_autoprefix(std::ios_base& ios, autoprefix_mode new_mode)
0223 {
0224     (set_flags)(ios, new_mode, autoprefix_mask);
0225 }
0226 
0227 /// Clear autoprefix flags.
0228 inline std::ios_base& no_prefix(std::ios_base& ios)
0229 {
0230     (set_autoprefix)(ios, autoprefix_none);
0231     return ios;
0232 }
0233 
0234 /// Set flag for engineering prefix, so 1234.5 m displays as "1.2345 km".
0235 inline std::ios_base& engineering_prefix(std::ios_base& ios)
0236 {
0237     (set_autoprefix)(ios, autoprefix_engineering);
0238     return ios;
0239 }
0240 
0241 /// Set flag for binary prefix, so 1024 byte displays as "1 Kib".
0242 inline std::ios_base& binary_prefix(std::ios_base& ios)
0243 {
0244     (set_autoprefix)(ios, autoprefix_binary);
0245     return ios;
0246 }
0247 
0248 namespace detail {
0249 
0250 /// \return exponent string like "^1/2".
0251 template<integer_type N, integer_type D>
0252 inline std::string exponent_string(const static_rational<N,D>& r)
0253 {
0254     return '^' + to_string(r);
0255 }
0256 
0257 /// \return empty exponent string for integer rational like 2.
0258 template<>
0259 inline std::string exponent_string(const static_rational<1>&)
0260 {
0261     return "";
0262 }
0263 
0264 template<class T>
0265 inline std::string base_unit_symbol_string(const T&)
0266 {
0267     return base_unit_info<typename T::tag_type>::symbol() + exponent_string(typename T::value_type());
0268 }
0269 
0270 template<class T>
0271 inline std::string base_unit_name_string(const T&)
0272 {
0273     return base_unit_info<typename T::tag_type>::name() + exponent_string(typename T::value_type());
0274 }
0275 
0276 // stringify with symbols.
0277 template<int N>
0278 struct symbol_string_impl
0279 {
0280     template<class Begin>
0281     struct apply
0282     {
0283         typedef typename symbol_string_impl<N-1>::template apply<typename Begin::next> next;
0284         static void value(std::string& str)
0285         {
0286             str += base_unit_symbol_string(typename Begin::item()) + ' ';
0287             next::value(str);
0288         }
0289     };
0290 };
0291 
0292 template<>
0293 struct symbol_string_impl<1>
0294 {
0295     template<class Begin>
0296     struct apply
0297     {
0298         static void value(std::string& str)
0299         {
0300             str += base_unit_symbol_string(typename Begin::item());
0301         }
0302     };
0303 };
0304 
0305 template<>
0306 struct symbol_string_impl<0>
0307 {
0308     template<class Begin>
0309     struct apply
0310     {
0311         static void value(std::string& str)
0312         {
0313             // better shorthand for dimensionless?
0314             str += "dimensionless";
0315         }
0316     };
0317 };
0318 
0319 template<int N>
0320 struct scale_symbol_string_impl
0321 {
0322     template<class Begin>
0323     struct apply
0324     {
0325         static void value(std::string& str)
0326         {
0327             str += Begin::item::symbol();
0328             scale_symbol_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
0329         }
0330     };
0331 };
0332 
0333 template<>
0334 struct scale_symbol_string_impl<0>
0335 {
0336     template<class Begin>
0337     struct apply
0338     {
0339         static void value(std::string&) { }
0340     };
0341 };
0342 
0343 // stringify with names.
0344 template<int N>
0345 struct name_string_impl
0346 {
0347     template<class Begin>
0348     struct apply
0349     {
0350         typedef typename name_string_impl<N-1>::template apply<typename Begin::next> next;
0351         static void value(std::string& str)
0352         {
0353             str += base_unit_name_string(typename Begin::item()) + ' ';
0354             next::value(str);
0355         }
0356     };
0357 };
0358 
0359 template<>
0360 struct name_string_impl<1>
0361 {
0362     template<class Begin>
0363     struct apply
0364     {
0365         static void value(std::string& str)
0366         {
0367             str += base_unit_name_string(typename Begin::item());
0368         }
0369     };
0370 };
0371 
0372 template<>
0373 struct name_string_impl<0>
0374 {
0375     template<class Begin>
0376     struct apply
0377     {
0378         static void value(std::string& str)
0379         {
0380             str += "dimensionless";
0381         }
0382     };
0383 };
0384 
0385 template<int N>
0386 struct scale_name_string_impl
0387 {
0388     template<class Begin>
0389     struct apply
0390     {
0391         static void value(std::string& str)
0392         {
0393             str += Begin::item::name();
0394             scale_name_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
0395         }
0396     };
0397 };
0398 
0399 template<>
0400 struct scale_name_string_impl<0>
0401 {
0402     template<class Begin>
0403     struct apply
0404     {
0405         static void value(std::string&) { }
0406     };
0407 };
0408 
0409 } // namespace detail
0410 
0411 namespace detail {
0412 
0413 // These two overloads of symbol_string and name_string will
0414 // will pick up homogeneous_systems.  They simply call the
0415 // appropriate function with a heterogeneous_system.
0416 template<class Dimension,class System, class SubFormatter>
0417 inline std::string
0418 to_string_impl(const unit<Dimension,System>&, SubFormatter f)
0419 {
0420     return f(typename reduce_unit<unit<Dimension, System> >::type());
0421 }
0422 
0423 /// INTERNAL ONLY
0424 // this overload picks up heterogeneous units that are not scaled.
0425 template<class Dimension,class Units, class Subformatter>
0426 inline std::string
0427 to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >&, Subformatter f)
0428 {
0429     std::string str;
0430     f.template append_units_to<Units>(str);
0431     return(str);
0432 }
0433 
0434 // This overload is a special case for heterogeneous_system which
0435 // is really unitless
0436 /// INTERNAL ONLY
0437 template<class Subformatter>
0438 inline std::string
0439 to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, dimensionless_type> > >&, Subformatter)
0440 {
0441     return("dimensionless");
0442 }
0443 
0444 // this overload deals with heterogeneous_systems which are unitless
0445 // but scaled.
0446 /// INTERNAL ONLY
0447 template<class Scale, class Subformatter>
0448 inline std::string
0449 to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, Scale> > >&, Subformatter f)
0450 {
0451     std::string str;
0452     f.template append_scale_to<Scale>(str);
0453     return(str);
0454 }
0455 
0456 // this overload deals with scaled units.
0457 /// INTERNAL ONLY
0458 template<class Dimension,class Units,class Scale, class Subformatter>
0459 inline std::string
0460 to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
0461 {
0462     std::string str;
0463 
0464     f.template append_scale_to<Scale>(str);
0465 
0466     std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
0467 
0468     if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
0469     {
0470         str += "(";
0471         str += without_scale;
0472         str += ")";
0473     }
0474     else
0475     {
0476         str += without_scale;
0477     }
0478 
0479     return(str);
0480 }
0481 
0482 // This overload catches scaled units that have a single base unit
0483 // raised to the first power.  It causes si::nano * si::meters to not
0484 // put parentheses around the meters.  i.e. nm rather than n(m)
0485 /// INTERNAL ONLY
0486 template<class Dimension,class Unit,class Scale, class Subformatter>
0487 inline std::string
0488 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)
0489 {
0490     std::string str;
0491 
0492     f.template append_scale_to<Scale>(str);
0493     str += f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
0494 
0495     return(str);
0496 }
0497 
0498 // This overload is necessary to disambiguate.
0499 // it catches units that are unscaled and have a single
0500 // base unit raised to the first power.  It is treated the
0501 // same as any other unscaled unit.
0502 /// INTERNAL ONLY
0503 template<class Dimension,class Unit,class Subformatter>
0504 inline std::string
0505 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)
0506 {
0507     std::string str;
0508     f.template append_units_to<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type> >(str);
0509     return(str);
0510 }
0511 
0512 // This overload catches scaled units that have a single scaled base unit
0513 // raised to the first power.  It moves that scaling on the base unit
0514 // to the unit level scaling and recurses.  By doing this we make sure that
0515 // si::milli * si::kilograms will print g rather than mkg.
0516 //
0517 // This transformation will not be applied if base_unit_info is specialized
0518 // for the scaled base unit.
0519 //
0520 /// INTERNAL ONLY
0521 template<class Dimension,class Unit,class UnitScale, class Scale, class Subformatter>
0522 inline std::string
0523 to_string_impl(
0524     const unit<
0525         Dimension,
0526         heterogeneous_system<
0527             heterogeneous_system_impl<
0528                 list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>,
0529                 Dimension,
0530                 Scale
0531             >
0532         >
0533     >&,
0534     Subformatter f,
0535     typename base_unit_info<scaled_base_unit<Unit, UnitScale> >::base_unit_info_primary_template* = 0)
0536 {
0537     return(f(
0538         unit<
0539             Dimension,
0540             heterogeneous_system<
0541                 heterogeneous_system_impl<
0542                     list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>,
0543                     Dimension,
0544                     typename mpl::times<Scale, list<scale_list_dim<UnitScale>, dimensionless_type> >::type
0545                 >
0546             >
0547         >()));
0548 }
0549 
0550 // this overload disambuguates between the overload for an unscaled unit
0551 // and the overload for a scaled base unit raised to the first power.
0552 /// INTERNAL ONLY
0553 template<class Dimension,class Unit,class UnitScale,class Subformatter>
0554 inline std::string
0555 to_string_impl(
0556     const unit<
0557         Dimension,
0558         heterogeneous_system<
0559             heterogeneous_system_impl<
0560                 list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>,
0561                 Dimension,
0562                 dimensionless_type
0563             >
0564         >
0565     >&,
0566     Subformatter f,
0567     typename base_unit_info<scaled_base_unit<Unit, UnitScale> >::base_unit_info_primary_template* = 0)
0568 {
0569     std::string str;
0570     f.template append_units_to<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type> >(str);
0571     return(str);
0572 }
0573 
0574 struct format_raw_symbol_impl {
0575     template<class Units>
0576     void append_units_to(std::string& str) {
0577         detail::symbol_string_impl<Units::size::value>::template apply<Units>::value(str);
0578     }
0579     template<class Scale>
0580     void append_scale_to(std::string& str) {
0581         detail::scale_symbol_string_impl<Scale::size::value>::template apply<Scale>::value(str);
0582     }
0583     template<class Unit>
0584     std::string operator()(const Unit& u) {
0585         return(to_string_impl(u, *this));
0586     }
0587     template<class Unit>
0588     bool is_default_string(const std::string&, const Unit&) {
0589         return(true);
0590     }
0591 };
0592 
0593 struct format_symbol_impl : format_raw_symbol_impl {
0594     template<class Unit>
0595     std::string operator()(const Unit& u) {
0596         return(symbol_string(u));
0597     }
0598     template<class Unit>
0599     bool is_default_string(const std::string& str, const Unit& u) {
0600         return(str == to_string_impl(u, format_raw_symbol_impl()));
0601     }
0602 };
0603 
0604 struct format_raw_name_impl {
0605     template<class Units>
0606     void append_units_to(std::string& str) {
0607         detail::name_string_impl<(Units::size::value)>::template apply<Units>::value(str);
0608     }
0609     template<class Scale>
0610     void append_scale_to(std::string& str) {
0611         detail::scale_name_string_impl<Scale::size::value>::template apply<Scale>::value(str);
0612     }
0613     template<class Unit>
0614     std::string operator()(const Unit& u) {
0615         return(to_string_impl(u, *this));
0616     }
0617     template<class Unit>
0618     bool is_default_string(const std::string&, const Unit&) {
0619         return(true);
0620     }
0621 };
0622 
0623 struct format_name_impl : format_raw_name_impl {
0624     template<class Unit>
0625     std::string operator()(const Unit& u) {
0626         return(name_string(u));
0627     }
0628     template<class Unit>
0629     bool is_default_string(const std::string& str, const Unit& u) {
0630         return(str == to_string_impl(u, format_raw_name_impl()));
0631     }
0632 };
0633 
0634 template<class Char, class Traits>
0635 inline void do_print(std::basic_ostream<Char, Traits>& os, const std::string& s)
0636 {
0637     os << s.c_str();
0638 }
0639 
0640 inline void do_print(std::ostream& os, const std::string& s)
0641 {
0642     os << s;
0643 }
0644 
0645 template<class Char, class Traits>
0646 inline void do_print(std::basic_ostream<Char, Traits>& os, const char* s)
0647 {
0648     os << s;
0649 }
0650 
0651 // For automatically applying the appropriate prefixes.
0652 
0653 }
0654 
0655 #ifdef BOOST_UNITS_DOXYGEN
0656 
0657 /// ADL customization point for automatic prefixing.
0658 /// Returns a non-negative value.  Implemented as std::abs
0659 /// for built-in types.
0660 template<class T>
0661 double autoprefix_norm(const T& arg);
0662 
0663 #else
0664 
0665 template<class T, bool C = boost::is_arithmetic<T>::value>
0666 struct autoprefix_norm_impl;
0667 
0668 template<class T>
0669 struct autoprefix_norm_impl<T, true>
0670 {
0671     typedef double type;
0672     static BOOST_CONSTEXPR double call(const T& arg) { return std::abs(arg); }
0673 };
0674 
0675 template<class T>
0676 struct autoprefix_norm_impl<T, false>
0677 {
0678     typedef one type;
0679     static BOOST_CONSTEXPR one call(const T&) { return one(); }
0680 };
0681 
0682 template<class T>
0683 BOOST_CONSTEXPR
0684 typename autoprefix_norm_impl<T>::type autoprefix_norm(const T& arg)
0685 {
0686     return autoprefix_norm_impl<T>::call(arg);
0687 }
0688 
0689 #endif
0690 
0691 namespace detail {
0692 
0693 template<class End, class Prev, class T, class F>
0694 BOOST_CONSTEXPR
0695 bool find_matching_scale_impl(End, End, Prev, T, double, F)
0696 {
0697     return false;
0698 }
0699 
0700 template<class Begin, class End, class Prev, class T, class F>
0701 BOOST_CXX14_CONSTEXPR
0702 bool find_matching_scale_impl(Begin, End end, Prev prev, T t, double x, F f)
0703 {
0704     if(Begin::item::value() > x) {
0705         f(prev, t);
0706         return true;
0707     } else {
0708         return detail::find_matching_scale_impl(
0709             typename Begin::next(),
0710             end,
0711             typename Begin::item(),
0712             t,
0713             x,
0714             f
0715         );
0716     }
0717 }
0718 
0719 template<class End, class T, class F>
0720 BOOST_CONSTEXPR
0721 bool find_matching_scale_i(End, End, T, double, F)
0722 {
0723     return false;
0724 }
0725 
0726 template<class Begin, class End, class T, class F>
0727 BOOST_CXX14_CONSTEXPR
0728 bool find_matching_scale_i(Begin, End end, T t, double x, F f)
0729 {
0730     if(Begin::item::value() > x) {
0731         return false;
0732     } else {
0733         return detail::find_matching_scale_impl(typename Begin::next(), end, typename Begin::item(), t, x, f);
0734     }
0735 }
0736 
0737 template<class Scales, class T, class F>
0738 BOOST_CXX14_CONSTEXPR
0739 bool find_matching_scale(T t, double x, F f)
0740 {
0741     return detail::find_matching_scale_i(Scales(), dimensionless_type(), t, x, f);
0742 }
0743 
0744 typedef list<scale<10, static_rational<-24> >,
0745         list<scale<10, static_rational<-21> >,
0746         list<scale<10, static_rational<-18> >,
0747         list<scale<10, static_rational<-15> >,
0748         list<scale<10, static_rational<-12> >,
0749         list<scale<10, static_rational<-9> >,
0750         list<scale<10, static_rational<-6> >,
0751         list<scale<10, static_rational<-3> >,
0752         list<scale<10, static_rational<0> >,
0753         list<scale<10, static_rational<3> >,
0754         list<scale<10, static_rational<6> >,
0755         list<scale<10, static_rational<9> >,
0756         list<scale<10, static_rational<12> >,
0757         list<scale<10, static_rational<15> >,
0758         list<scale<10, static_rational<18> >,
0759         list<scale<10, static_rational<21> >,
0760         list<scale<10, static_rational<24> >,
0761         list<scale<10, static_rational<27> >,
0762         dimensionless_type> > > > > > > > > > > > > > > > > > engineering_prefixes;
0763 
0764 typedef list<scale<2, static_rational<10> >,
0765         list<scale<2, static_rational<20> >,
0766         list<scale<2, static_rational<30> >,
0767         list<scale<2, static_rational<40> >,
0768         list<scale<2, static_rational<50> >,
0769         list<scale<2, static_rational<60> >,
0770         list<scale<2, static_rational<70> >,
0771         list<scale<2, static_rational<80> >,
0772         list<scale<2, static_rational<90> >,
0773         dimensionless_type> > > > > > > > > binary_prefixes;
0774 
0775 template<class Os, class Quantity>
0776 struct print_default_t {
0777     typedef void result_type;
0778     void operator()() const
0779     {
0780         *os << q->value() << ' ' << typename Quantity::unit_type();
0781     }
0782     Os* os;
0783     const Quantity* q;
0784 };
0785 
0786 template<class Os, class Quantity>
0787 print_default_t<Os, Quantity> print_default(Os& os, const Quantity& q)
0788 {
0789     print_default_t<Os, Quantity> result = { &os, &q };
0790     return result;
0791 }
0792 
0793 template<class Os>
0794 struct print_scale_t {
0795     typedef void result_type;
0796     template<class Prefix, class T>
0797     void operator()(Prefix, const T& t) const
0798     {
0799         *prefixed = true;
0800         *os << t / Prefix::value() << ' ';
0801         switch(units::get_format(*os)) {
0802             case name_fmt: do_print(*os, Prefix::name()); break;
0803             case raw_fmt:
0804             case symbol_fmt: do_print(*os, Prefix::symbol()); break;
0805             case typename_fmt: do_print(*os, units::simplify_typename(Prefix())); *os << ' '; break;
0806         }
0807     }
0808     template<long N, class T>
0809     void operator()(scale<N, static_rational<0> >, const T& t) const
0810     {
0811         *prefixed = false;
0812         *os << t << ' ';
0813     }
0814     Os* os;
0815     bool* prefixed;
0816 };
0817 
0818 template<class Os>
0819 print_scale_t<Os> print_scale(Os& os, bool& prefixed)
0820 {
0821     print_scale_t<Os> result = { &os, &prefixed };
0822     return result;
0823 }
0824 
0825 // puts parentheses around a unit
0826 /// INTERNAL ONLY
0827 template<class Dimension,class Units,class Scale, class Subformatter>
0828 inline std::string
0829 maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
0830 {
0831     std::string str;
0832 
0833     std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
0834 
0835     if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
0836     {
0837         str += "(";
0838         str += without_scale;
0839         str += ")";
0840     }
0841     else
0842     {
0843         str += without_scale;
0844     }
0845 
0846     return(str);
0847 }
0848 
0849 // This overload catches scaled units that have a single base unit
0850 // raised to the first power.  It causes si::nano * si::meters to not
0851 // put parentheses around the meters.  i.e. nm rather than n(m)
0852 /// INTERNAL ONLY
0853 template<class Dimension,class Unit,class Scale, class Subformatter>
0854 inline std::string
0855 maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
0856 {
0857     return f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
0858 }
0859 
0860 template<class Prefixes, class CharT, class Traits, class Unit, class T, class F>
0861 void do_print_prefixed_impl(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, F default_)
0862 {
0863     bool prefixed;
0864     if(detail::find_matching_scale<Prefixes>(q.value(), autoprefix_norm(q.value()), detail::print_scale(os, prefixed))) {
0865         if(prefixed) {
0866             switch(units::get_format(os)) {
0867                 case symbol_fmt: do_print(os, maybe_parenthesize(Unit(), format_symbol_impl())); break;
0868                 case raw_fmt: do_print(os, maybe_parenthesize(Unit(), format_raw_symbol_impl())); break;
0869                 case name_fmt: do_print(os, maybe_parenthesize(Unit(), format_name_impl())); break;
0870                 case typename_fmt: do_print(os, simplify_typename(Unit())); break;
0871             }
0872         } else {
0873             os << Unit();
0874         }
0875     } else {
0876         default_();
0877     }
0878 }
0879 
0880 // Handle units like si::kilograms that have a scale embedded in the
0881 // base unit.  This overload is disabled if the scaled base unit has
0882 // a user-defined string representation.
0883 template<class Prefixes, class CharT, class Traits, class Dimension, class BaseUnit, class BaseScale, class Scale, class T>
0884 typename base_unit_info<
0885     scaled_base_unit<BaseUnit, Scale>
0886 >::base_unit_info_primary_template
0887 do_print_prefixed(
0888     std::basic_ostream<CharT, Traits>& os,
0889     const quantity<
0890         unit<
0891             Dimension,
0892             heterogeneous_system<
0893                 heterogeneous_system_impl<
0894                     list<
0895                         heterogeneous_system_dim<
0896                             scaled_base_unit<BaseUnit, BaseScale>,
0897                             static_rational<1>
0898                         >,
0899                         dimensionless_type
0900                     >,
0901                     Dimension,
0902                     Scale
0903                 >
0904             >
0905         >,
0906         T
0907     >& q)
0908 {
0909     quantity<
0910         unit<
0911             Dimension,
0912             heterogeneous_system<
0913                 heterogeneous_system_impl<
0914                     list<
0915                         heterogeneous_system_dim<BaseUnit, static_rational<1> >,
0916                         dimensionless_type
0917                     >,
0918                     Dimension,
0919                     dimensionless_type
0920                 >
0921             >
0922         >,
0923         T
0924     > unscaled(q);
0925     detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
0926 }
0927 
0928 template<class Prefixes, class CharT, class Traits, class Dimension, class L, class Scale, class T>
0929 void do_print_prefixed(
0930     std::basic_ostream<CharT, Traits>& os,
0931     const quantity<
0932         unit<
0933             Dimension,
0934             heterogeneous_system<
0935                 heterogeneous_system_impl<
0936                     L,
0937                     Dimension,
0938                     Scale
0939                 >
0940             >
0941         >,
0942         T
0943     >& q)
0944 {
0945     quantity<
0946         unit<
0947             Dimension,
0948             heterogeneous_system<
0949                 heterogeneous_system_impl<
0950                     L,
0951                     Dimension,
0952                     dimensionless_type
0953                 >
0954             >
0955         >,
0956         T
0957     > unscaled(q);
0958     detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
0959 }
0960 
0961 template<class Prefixes, class CharT, class Traits, class Dimension, class System, class T>
0962 void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<unit<Dimension, System>, T>& q)
0963 {
0964     detail::do_print_prefixed<Prefixes>(os, quantity<unit<Dimension, typename make_heterogeneous_system<Dimension, System>::type>, T>(q));
0965 }
0966 
0967 template<class Prefixes, class CharT, class Traits, class Unit, class T>
0968 void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q)
0969 {
0970     detail::print_default(os, q)();
0971 }
0972 
0973 template<class Prefixes, class CharT, class Traits, class Unit, class T>
0974 void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::true_)
0975 {
0976     detail::do_print_prefixed<Prefixes>(os, q);
0977 }
0978 
0979 template<class Prefixes, class CharT, class Traits, class Unit, class T>
0980 void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::false_)
0981 {
0982     detail::print_default(os, q)();
0983 }
0984 
0985 inline BOOST_CONSTEXPR mpl::true_ test_norm(double) { return mpl::true_(); }
0986 inline BOOST_CONSTEXPR mpl::false_ test_norm(one) { return mpl::false_(); }
0987 
0988 } // namespace detail
0989 
0990 template<class Dimension,class System>
0991 inline std::string
0992 typename_string(const unit<Dimension, System>&)
0993 {
0994     return simplify_typename(typename reduce_unit< unit<Dimension,System> >::type());
0995 }
0996 
0997 template<class Dimension,class System>
0998 inline std::string
0999 symbol_string(const unit<Dimension, System>&)
1000 {
1001     return detail::to_string_impl(unit<Dimension,System>(), detail::format_symbol_impl());
1002 }
1003 
1004 template<class Dimension,class System>
1005 inline std::string
1006 name_string(const unit<Dimension, System>&)
1007 {
1008     return detail::to_string_impl(unit<Dimension,System>(), detail::format_name_impl());
1009 }
1010 
1011 /// Print a @c unit as a list of base units and their exponents.
1012 ///
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)
1019 {
1020     if (units::get_format(os) == typename_fmt)
1021     {
1022         detail::do_print(os, typename_string(u));
1023     }
1024     else if (units::get_format(os) == raw_fmt)
1025     {
1026         detail::do_print(os, detail::to_string_impl(u, detail::format_raw_symbol_impl()));
1027     }
1028     else if (units::get_format(os) == symbol_fmt)
1029     {
1030         detail::do_print(os, symbol_string(u));
1031     }
1032     else if (units::get_format(os) == name_fmt)
1033     {
1034         detail::do_print(os, name_string(u));
1035     }
1036     else
1037     {
1038         BOOST_ASSERT_MSG(false, "The format mode must be one of: typename_format, raw_format, name_format, symbol_format");
1039     }
1040 
1041     return(os);
1042 }
1043 
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)
1052 {
1053     if (units::get_autoprefix(os) == autoprefix_none)
1054     {
1055         os << q.value() << ' ' << Unit();
1056     }
1057     else if (units::get_autoprefix(os) == autoprefix_engineering)
1058     {
1059         detail::maybe_print_prefixed<detail::engineering_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
1060     }
1061     else if (units::get_autoprefix(os) == autoprefix_binary)
1062     {
1063         detail::maybe_print_prefixed<detail::binary_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
1064     }
1065     else
1066     {
1067         BOOST_ASSERT_MSG(false, "Autoprefixing must be one of: no_prefix, engineering_prefix, binary_prefix");
1068     }
1069     return(os);
1070 }
1071 
1072 } // namespace units
1073 
1074 } // namespace boost
1075 
1076 #endif