1071 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1071 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| // Boost.Units - A C++ library for zero-overhead dimensional analysis and
 | |
| // unit/quantity manipulation and conversion
 | |
| //
 | |
| // Copyright (C) 2003-2008 Matthias Christian Schabel
 | |
| // Copyright (C) 2007-2010 Steven Watanabe
 | |
| //
 | |
| // Distributed under the Boost Software License, Version 1.0. (See
 | |
| // accompanying file LICENSE_1_0.txt or copy at
 | |
| // http://www.boost.org/LICENSE_1_0.txt)
 | |
| 
 | |
| #ifndef BOOST_UNITS_IO_HPP
 | |
| #define BOOST_UNITS_IO_HPP
 | |
| 
 | |
| /// \file
 | |
| /// \brief Stream input and output for rationals, units and quantities.
 | |
| /// \details Functions and manipulators for output and input of units and quantities.
 | |
| ///   symbol and name format, and engineering and binary autoprefix.
 | |
| ///   Serialization output is also supported.
 | |
| 
 | |
| #include <cassert>
 | |
| #include <cmath>
 | |
| #include <string>
 | |
| #include <iosfwd>
 | |
| #include <ios>
 | |
| #include <sstream>
 | |
| 
 | |
| #include <boost/assert.hpp>
 | |
| #include <boost/serialization/nvp.hpp>
 | |
| 
 | |
| #include <boost/units/units_fwd.hpp>
 | |
| #include <boost/units/heterogeneous_system.hpp>
 | |
| #include <boost/units/make_scaled_unit.hpp>
 | |
| #include <boost/units/quantity.hpp>
 | |
| #include <boost/units/scale.hpp>
 | |
| #include <boost/units/static_rational.hpp>
 | |
| #include <boost/units/unit.hpp>
 | |
| #include <boost/units/detail/utility.hpp>
 | |
| 
 | |
| namespace boost {
 | |
| 
 | |
| namespace serialization {
 | |
| 
 | |
| /// Boost Serialization library support for units.
 | |
| template<class Archive,class System,class Dim>
 | |
| inline void serialize(Archive& /*ar*/,boost::units::unit<Dim,System>&,const unsigned int /*version*/)
 | |
| { }
 | |
| 
 | |
| /// Boost Serialization library support for quantities.
 | |
| template<class Archive,class Unit,class Y>
 | |
| inline void serialize(Archive& ar,boost::units::quantity<Unit,Y>& q,const unsigned int /*version*/)
 | |
| {
 | |
|     ar & boost::serialization::make_nvp("value", units::quantity_cast<Y&>(q));
 | |
| }
 | |
| 
 | |
| } // namespace serialization
 | |
| 
 | |
| namespace units {
 | |
| 
 | |
| // get string representation of arbitrary type.
 | |
| template<class T> std::string to_string(const T& t)
 | |
| {
 | |
|     std::stringstream sstr;
 | |
| 
 | |
|     sstr << t;
 | |
| 
 | |
|     return sstr.str();
 | |
| }
 | |
| 
 | |
| /// get string representation of integral-valued @c static_rational.
 | |
| template<integer_type N> std::string to_string(const static_rational<N>&)
 | |
| {
 | |
|     return to_string(N);
 | |
| }
 | |
| 
 | |
| /// get string representation of @c static_rational.
 | |
| template<integer_type N, integer_type D> std::string to_string(const static_rational<N,D>&)
 | |
| {
 | |
|     return '(' + to_string(N) + '/' + to_string(D) + ')';
 | |
| }
 | |
| 
 | |
| /// Write @c static_rational to @c std::basic_ostream.
 | |
| template<class Char, class Traits, integer_type N, integer_type D>
 | |
| inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,const static_rational<N,D>& r)
 | |
| {
 | |
|     os << to_string(r);
 | |
|     return os;
 | |
| }
 | |
| 
 | |
| /// traits template for unit names.
 | |
| template<class BaseUnit>
 | |
| struct base_unit_info
 | |
| {
 | |
|     /// INTERNAL ONLY
 | |
|     typedef void base_unit_info_primary_template;
 | |
|     /// The full name of the unit (returns BaseUnit::name() by default)
 | |
|     static std::string name()
 | |
|     {
 | |
|         return(BaseUnit::name());
 | |
|     }
 | |
|     /// The symbol for the base unit (Returns BaseUnit::symbol() by default)
 | |
|     static std::string symbol()
 | |
|     {
 | |
|         return(BaseUnit::symbol());  ///  \returns BaseUnit::symbol(), for example "m"
 | |
|     }
 | |
| };
 | |
| 
 | |
| /// \enum format_mode format of output of units, for example "m" or "meter".
 | |
| enum format_mode
 | |
| {
 | |
|     symbol_fmt = 0,     /// default - reduces unit names to known symbols for both base and derived units.
 | |
|     name_fmt = 1,           /// output full unit names for base and derived units, for example "meter".
 | |
|     raw_fmt = 2,            /// output only symbols for base units (but not derived units), for example "m".
 | |
|     typename_fmt = 3,       /// output demangled typenames (useful only for diagnosis).
 | |
|     fmt_mask = 3 /// Bits used for format.
 | |
| };
 | |
| 
 | |
| /// \enum autoprefix_mode automatic scaling and prefix (controlled by value of quantity) a, if any,
 | |
| enum autoprefix_mode
 | |
| {
 | |
|     autoprefix_none = 0, /// No automatic prefix.
 | |
|     autoprefix_engineering = 4, /// Scale and prefix with 10^3 multiples, 1234.5 m output as 1.2345 km.
 | |
|     autoprefix_binary = 8, /// Scale and prefix with 2^10 (1024) multiples, 1024 as 1 kb.
 | |
|     autoprefix_mask = 12 ///  Bits used for autoprefix.
 | |
| };
 | |
| 
 | |
| namespace detail {
 | |
| 
 | |
| template<bool>
 | |
| struct xalloc_key_holder
 | |
| {
 | |
|     static int value;
 | |
|     static bool initialized;
 | |
| };
 | |
| 
 | |
| template<bool b>
 | |
| int xalloc_key_holder<b>::value = 0;
 | |
| 
 | |
| template<bool b>
 | |
| bool xalloc_key_holder<b>::initialized = 0;
 | |
| 
 | |
| struct xalloc_key_initializer_t
 | |
| {
 | |
|     xalloc_key_initializer_t()
 | |
|     {
 | |
|         if (!xalloc_key_holder<true>::initialized)
 | |
|         {
 | |
|             xalloc_key_holder<true>::value = std::ios_base::xalloc();
 | |
|             xalloc_key_holder<true>::initialized = true;
 | |
|         }
 | |
|     }
 | |
| };
 | |
| 
 | |
| namespace /**/ {
 | |
| 
 | |
| xalloc_key_initializer_t xalloc_key_initializer;
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| } // namespace detail
 | |
| 
 | |
| /// returns flags controlling output.
 | |
| inline long get_flags(std::ios_base& ios, long mask)
 | |
| {
 | |
|     return(ios.iword(detail::xalloc_key_holder<true>::value) & mask);
 | |
| }
 | |
| 
 | |
| /// Set new flags controlling output format.
 | |
| inline void set_flags(std::ios_base& ios, long new_flags, long mask)
 | |
| {
 | |
|     BOOST_ASSERT((~mask & new_flags) == 0);
 | |
|     long& flags = ios.iword(detail::xalloc_key_holder<true>::value);
 | |
|     flags = (flags & ~mask) | new_flags;
 | |
| }
 | |
| 
 | |
| /// returns flags controlling output format.
 | |
| inline format_mode get_format(std::ios_base& ios)
 | |
| {
 | |
|     return(static_cast<format_mode>((get_flags)(ios, fmt_mask)));
 | |
| }
 | |
| 
 | |
| /// Set new flags controlling output format.
 | |
| inline void set_format(std::ios_base& ios, format_mode new_mode)
 | |
| {
 | |
|     (set_flags)(ios, new_mode, fmt_mask);
 | |
| }
 | |
| 
 | |
| /// Set new flags for type_name output format.
 | |
| inline std::ios_base& typename_format(std::ios_base& ios)
 | |
| {
 | |
|     (set_format)(ios, typename_fmt);
 | |
|     return(ios);
 | |
| }
 | |
| 
 | |
| /// set new flag for raw format output, for example "m".
 | |
| inline std::ios_base& raw_format(std::ios_base& ios)
 | |
| {
 | |
|     (set_format)(ios, raw_fmt);
 | |
|     return(ios);
 | |
| }
 | |
| 
 | |
| /// set new format flag for symbol output, for example "m".
 | |
| inline std::ios_base& symbol_format(std::ios_base& ios)
 | |
| {
 | |
|     (set_format)(ios, symbol_fmt);
 | |
|     return(ios);
 | |
| }
 | |
| 
 | |
| /// set new format for name output, for example "meter".
 | |
| inline std::ios_base& name_format(std::ios_base& ios)
 | |
| {
 | |
|     (set_format)(ios, name_fmt);
 | |
|     return(ios);
 | |
| }
 | |
| 
 | |
| /// get autoprefix flags for output.
 | |
| inline autoprefix_mode get_autoprefix(std::ios_base& ios)
 | |
| {
 | |
|     return static_cast<autoprefix_mode>((get_flags)(ios, autoprefix_mask));
 | |
| }
 | |
| 
 | |
| /// Get format for output.
 | |
| inline void set_autoprefix(std::ios_base& ios, autoprefix_mode new_mode)
 | |
| {
 | |
|     (set_flags)(ios, new_mode, autoprefix_mask);
 | |
| }
 | |
| 
 | |
| /// Clear autoprefix flags.
 | |
| inline std::ios_base& no_prefix(std::ios_base& ios)
 | |
| {
 | |
|     (set_autoprefix)(ios, autoprefix_none);
 | |
|     return ios;
 | |
| }
 | |
| 
 | |
| /// Set flag for engineering prefix, so 1234.5 m displays as "1.2345 km".
 | |
| inline std::ios_base& engineering_prefix(std::ios_base& ios)
 | |
| {
 | |
|     (set_autoprefix)(ios, autoprefix_engineering);
 | |
|     return ios;
 | |
| }
 | |
| 
 | |
| /// Set flag for binary prefix, so 1024 byte displays as "1 Kib".
 | |
| inline std::ios_base& binary_prefix(std::ios_base& ios)
 | |
| {
 | |
|     (set_autoprefix)(ios, autoprefix_binary);
 | |
|     return ios;
 | |
| }
 | |
| 
 | |
| namespace detail {
 | |
| 
 | |
| /// \return exponent string like "^1/2".
 | |
| template<integer_type N, integer_type D>
 | |
| inline std::string exponent_string(const static_rational<N,D>& r)
 | |
| {
 | |
|     return '^' + to_string(r);
 | |
| }
 | |
| 
 | |
| /// \return empty exponent string for integer rational like 2.
 | |
| template<>
 | |
| inline std::string exponent_string(const static_rational<1>&)
 | |
| {
 | |
|     return "";
 | |
| }
 | |
| 
 | |
| template<class T>
 | |
| inline std::string base_unit_symbol_string(const T&)
 | |
| {
 | |
|     return base_unit_info<typename T::tag_type>::symbol() + exponent_string(typename T::value_type());
 | |
| }
 | |
| 
 | |
| template<class T>
 | |
| inline std::string base_unit_name_string(const T&)
 | |
| {
 | |
|     return base_unit_info<typename T::tag_type>::name() + exponent_string(typename T::value_type());
 | |
| }
 | |
| 
 | |
| // stringify with symbols.
 | |
| template<int N>
 | |
| struct symbol_string_impl
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         typedef typename symbol_string_impl<N-1>::template apply<typename Begin::next> next;
 | |
|         static void value(std::string& str)
 | |
|         {
 | |
|             str += base_unit_symbol_string(typename Begin::item()) + ' ';
 | |
|             next::value(str);
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct symbol_string_impl<1>
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         static void value(std::string& str)
 | |
|         {
 | |
|             str += base_unit_symbol_string(typename Begin::item());
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct symbol_string_impl<0>
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         static void value(std::string& str)
 | |
|         {
 | |
|             // better shorthand for dimensionless?
 | |
|             str += "dimensionless";
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| template<int N>
 | |
| struct scale_symbol_string_impl
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         static void value(std::string& str)
 | |
|         {
 | |
|             str += Begin::item::symbol();
 | |
|             scale_symbol_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct scale_symbol_string_impl<0>
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         static void value(std::string&) { }
 | |
|     };
 | |
| };
 | |
| 
 | |
| // stringify with names.
 | |
| template<int N>
 | |
| struct name_string_impl
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         typedef typename name_string_impl<N-1>::template apply<typename Begin::next> next;
 | |
|         static void value(std::string& str)
 | |
|         {
 | |
|             str += base_unit_name_string(typename Begin::item()) + ' ';
 | |
|             next::value(str);
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct name_string_impl<1>
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         static void value(std::string& str)
 | |
|         {
 | |
|             str += base_unit_name_string(typename Begin::item());
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct name_string_impl<0>
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         static void value(std::string& str)
 | |
|         {
 | |
|             str += "dimensionless";
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| template<int N>
 | |
| struct scale_name_string_impl
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         static void value(std::string& str)
 | |
|         {
 | |
|             str += Begin::item::name();
 | |
|             scale_name_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct scale_name_string_impl<0>
 | |
| {
 | |
|     template<class Begin>
 | |
|     struct apply
 | |
|     {
 | |
|         static void value(std::string&) { }
 | |
|     };
 | |
| };
 | |
| 
 | |
| } // namespace detail
 | |
| 
 | |
| namespace detail {
 | |
| 
 | |
| // These two overloads of symbol_string and name_string will
 | |
| // will pick up homogeneous_systems.  They simply call the
 | |
| // appropriate function with a heterogeneous_system.
 | |
| template<class Dimension,class System, class SubFormatter>
 | |
| inline std::string
 | |
| to_string_impl(const unit<Dimension,System>&, SubFormatter f)
 | |
| {
 | |
|     return f(typename reduce_unit<unit<Dimension, System> >::type());
 | |
| }
 | |
| 
 | |
| /// INTERNAL ONLY
 | |
| // this overload picks up heterogeneous units that are not scaled.
 | |
| template<class Dimension,class Units, class Subformatter>
 | |
| inline std::string
 | |
| to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >&, Subformatter f)
 | |
| {
 | |
|     std::string str;
 | |
|     f.template append_units_to<Units>(str);
 | |
|     return(str);
 | |
| }
 | |
| 
 | |
| // This overload is a special case for heterogeneous_system which
 | |
| // is really unitless
 | |
| /// INTERNAL ONLY
 | |
| template<class Subformatter>
 | |
| inline std::string
 | |
| to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, dimensionless_type> > >&, Subformatter)
 | |
| {
 | |
|     return("dimensionless");
 | |
| }
 | |
| 
 | |
| // this overload deals with heterogeneous_systems which are unitless
 | |
| // but scaled.
 | |
| /// INTERNAL ONLY
 | |
| template<class Scale, class Subformatter>
 | |
| inline std::string
 | |
| to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, Scale> > >&, Subformatter f)
 | |
| {
 | |
|     std::string str;
 | |
|     f.template append_scale_to<Scale>(str);
 | |
|     return(str);
 | |
| }
 | |
| 
 | |
| // this overload deals with scaled units.
 | |
| /// INTERNAL ONLY
 | |
| template<class Dimension,class Units,class Scale, class Subformatter>
 | |
| inline std::string
 | |
| to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
 | |
| {
 | |
|     std::string str;
 | |
| 
 | |
|     f.template append_scale_to<Scale>(str);
 | |
| 
 | |
|     std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
 | |
| 
 | |
|     if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
 | |
|     {
 | |
|         str += "(";
 | |
|         str += without_scale;
 | |
|         str += ")";
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         str += without_scale;
 | |
|     }
 | |
| 
 | |
|     return(str);
 | |
| }
 | |
| 
 | |
| // This overload catches scaled units that have a single base unit
 | |
| // raised to the first power.  It causes si::nano * si::meters to not
 | |
| // put parentheses around the meters.  i.e. nm rather than n(m)
 | |
| /// INTERNAL ONLY
 | |
| template<class Dimension,class Unit,class Scale, class Subformatter>
 | |
| 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)
 | |
| {
 | |
|     std::string str;
 | |
| 
 | |
|     f.template append_scale_to<Scale>(str);
 | |
|     str += f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
 | |
| 
 | |
|     return(str);
 | |
| }
 | |
| 
 | |
| // This overload is necessary to disambiguate.
 | |
| // it catches units that are unscaled and have a single
 | |
| // base unit raised to the first power.  It is treated the
 | |
| // same as any other unscaled unit.
 | |
| /// INTERNAL ONLY
 | |
| template<class Dimension,class Unit,class Subformatter>
 | |
| 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)
 | |
| {
 | |
|     std::string str;
 | |
|     f.template append_units_to<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type> >(str);
 | |
|     return(str);
 | |
| }
 | |
| 
 | |
| // This overload catches scaled units that have a single scaled base unit
 | |
| // raised to the first power.  It moves that scaling on the base unit
 | |
| // to the unit level scaling and recurses.  By doing this we make sure that
 | |
| // si::milli * si::kilograms will print g rather than mkg.
 | |
| //
 | |
| // This transformation will not be applied if base_unit_info is specialized
 | |
| // for the scaled base unit.
 | |
| //
 | |
| /// INTERNAL ONLY
 | |
| template<class Dimension,class Unit,class UnitScale, class Scale, class Subformatter>
 | |
| 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)
 | |
| {
 | |
|     return(f(
 | |
|         unit<
 | |
|             Dimension,
 | |
|             heterogeneous_system<
 | |
|                 heterogeneous_system_impl<
 | |
|                     list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>,
 | |
|                     Dimension,
 | |
|                     typename mpl::times<Scale, list<scale_list_dim<UnitScale>, dimensionless_type> >::type
 | |
|                 >
 | |
|             >
 | |
|         >()));
 | |
| }
 | |
| 
 | |
| // this overload disambuguates between the overload for an unscaled unit
 | |
| // and the overload for a scaled base unit raised to the first power.
 | |
| /// INTERNAL ONLY
 | |
| template<class Dimension,class Unit,class UnitScale,class Subformatter>
 | |
| 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)
 | |
| {
 | |
|     std::string str;
 | |
|     f.template append_units_to<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type> >(str);
 | |
|     return(str);
 | |
| }
 | |
| 
 | |
| struct format_raw_symbol_impl {
 | |
|     template<class Units>
 | |
|     void append_units_to(std::string& str) {
 | |
|         detail::symbol_string_impl<Units::size::value>::template apply<Units>::value(str);
 | |
|     }
 | |
|     template<class Scale>
 | |
|     void append_scale_to(std::string& str) {
 | |
|         detail::scale_symbol_string_impl<Scale::size::value>::template apply<Scale>::value(str);
 | |
|     }
 | |
|     template<class Unit>
 | |
|     std::string operator()(const Unit& u) {
 | |
|         return(to_string_impl(u, *this));
 | |
|     }
 | |
|     template<class Unit>
 | |
|     bool is_default_string(const std::string&, const Unit&) {
 | |
|         return(true);
 | |
|     }
 | |
| };
 | |
| 
 | |
| struct format_symbol_impl : format_raw_symbol_impl {
 | |
|     template<class Unit>
 | |
|     std::string operator()(const Unit& u) {
 | |
|         return(symbol_string(u));
 | |
|     }
 | |
|     template<class Unit>
 | |
|     bool is_default_string(const std::string& str, const Unit& u) {
 | |
|         return(str == to_string_impl(u, format_raw_symbol_impl()));
 | |
|     }
 | |
| };
 | |
| 
 | |
| struct format_raw_name_impl {
 | |
|     template<class Units>
 | |
|     void append_units_to(std::string& str) {
 | |
|         detail::name_string_impl<(Units::size::value)>::template apply<Units>::value(str);
 | |
|     }
 | |
|     template<class Scale>
 | |
|     void append_scale_to(std::string& str) {
 | |
|         detail::scale_name_string_impl<Scale::size::value>::template apply<Scale>::value(str);
 | |
|     }
 | |
|     template<class Unit>
 | |
|     std::string operator()(const Unit& u) {
 | |
|         return(to_string_impl(u, *this));
 | |
|     }
 | |
|     template<class Unit>
 | |
|     bool is_default_string(const std::string&, const Unit&) {
 | |
|         return(true);
 | |
|     }
 | |
| };
 | |
| 
 | |
| struct format_name_impl : format_raw_name_impl {
 | |
|     template<class Unit>
 | |
|     std::string operator()(const Unit& u) {
 | |
|         return(name_string(u));
 | |
|     }
 | |
|     template<class Unit>
 | |
|     bool is_default_string(const std::string& str, const Unit& u) {
 | |
|         return(str == to_string_impl(u, format_raw_name_impl()));
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class Char, class Traits>
 | |
| inline void do_print(std::basic_ostream<Char, Traits>& os, const std::string& s)
 | |
| {
 | |
|     os << s.c_str();
 | |
| }
 | |
| 
 | |
| inline void do_print(std::ostream& os, const std::string& s)
 | |
| {
 | |
|     os << s;
 | |
| }
 | |
| 
 | |
| template<class Char, class Traits>
 | |
| inline void do_print(std::basic_ostream<Char, Traits>& os, const char* s)
 | |
| {
 | |
|     os << s;
 | |
| }
 | |
| 
 | |
| // For automatically applying the appropriate prefixes.
 | |
| 
 | |
| }
 | |
| 
 | |
| #ifdef BOOST_UNITS_DOXYGEN
 | |
| 
 | |
| /// ADL customization point for automatic prefixing.
 | |
| /// Returns a non-negative value.  Implemented as std::abs
 | |
| /// for built-in types.
 | |
| template<class T>
 | |
| double autoprefix_norm(const T& arg);
 | |
| 
 | |
| #else
 | |
| 
 | |
| template<class T, bool C = boost::is_arithmetic<T>::value>
 | |
| struct autoprefix_norm_impl;
 | |
| 
 | |
| template<class T>
 | |
| struct autoprefix_norm_impl<T, true>
 | |
| {
 | |
|     typedef double type;
 | |
|     static double call(const T& arg) { return std::abs(arg); }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct autoprefix_norm_impl<T, false>
 | |
| {
 | |
|     typedef one type;
 | |
|     static one call(const T&) { return one(); }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| typename autoprefix_norm_impl<T>::type autoprefix_norm(const T& arg)
 | |
| {
 | |
|     return autoprefix_norm_impl<T>::call(arg);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| namespace detail {
 | |
| 
 | |
| template<class End, class Prev, class T, class F>
 | |
| bool find_matching_scale_impl(End, End, Prev, T, double, F)
 | |
| {
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| template<class Begin, class End, class Prev, class T, class F>
 | |
| bool find_matching_scale_impl(Begin, End end, Prev prev, T t, double x, F f)
 | |
| {
 | |
|     if(Begin::item::value() > x) {
 | |
|         f(prev, t);
 | |
|         return true;
 | |
|     } else {
 | |
|         return detail::find_matching_scale_impl(
 | |
|             typename Begin::next(),
 | |
|             end,
 | |
|             typename Begin::item(),
 | |
|             t,
 | |
|             x,
 | |
|             f
 | |
|         );
 | |
|     }
 | |
| }
 | |
| 
 | |
| template<class End, class T, class F>
 | |
| bool find_matching_scale_i(End, End, T, double, F)
 | |
| {
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| template<class Begin, class End, class T, class F>
 | |
| bool find_matching_scale_i(Begin, End end, T t, double x, F f)
 | |
| {
 | |
|     if(Begin::item::value() > x) {
 | |
|         return false;
 | |
|     } else {
 | |
|         return detail::find_matching_scale_impl(typename Begin::next(), end, typename Begin::item(), t, x, f);
 | |
|     }
 | |
| }
 | |
| 
 | |
| template<class Scales, class T, class F>
 | |
| bool find_matching_scale(T t, double x, F f)
 | |
| {
 | |
|     return detail::find_matching_scale_i(Scales(), dimensionless_type(), t, x, f);
 | |
| }
 | |
| 
 | |
| typedef list<scale<10, static_rational<-24> >,
 | |
|         list<scale<10, static_rational<-21> >,
 | |
|         list<scale<10, static_rational<-18> >,
 | |
|         list<scale<10, static_rational<-15> >,
 | |
|         list<scale<10, static_rational<-12> >,
 | |
|         list<scale<10, static_rational<-9> >,
 | |
|         list<scale<10, static_rational<-6> >,
 | |
|         list<scale<10, static_rational<-3> >,
 | |
|         list<scale<10, static_rational<0> >,
 | |
|         list<scale<10, static_rational<3> >,
 | |
|         list<scale<10, static_rational<6> >,
 | |
|         list<scale<10, static_rational<9> >,
 | |
|         list<scale<10, static_rational<12> >,
 | |
|         list<scale<10, static_rational<15> >,
 | |
|         list<scale<10, static_rational<18> >,
 | |
|         list<scale<10, static_rational<21> >,
 | |
|         list<scale<10, static_rational<24> >,
 | |
|         list<scale<10, static_rational<27> >,
 | |
|         dimensionless_type> > > > > > > > > > > > > > > > > > engineering_prefixes;
 | |
| 
 | |
| typedef list<scale<2, static_rational<10> >,
 | |
|         list<scale<2, static_rational<20> >,
 | |
|         list<scale<2, static_rational<30> >,
 | |
|         list<scale<2, static_rational<40> >,
 | |
|         list<scale<2, static_rational<50> >,
 | |
|         list<scale<2, static_rational<60> >,
 | |
|         list<scale<2, static_rational<70> >,
 | |
|         list<scale<2, static_rational<80> >,
 | |
|         list<scale<2, static_rational<90> >,
 | |
|         dimensionless_type> > > > > > > > > binary_prefixes;
 | |
| 
 | |
| template<class Os, class Quantity>
 | |
| struct print_default_t {
 | |
|     typedef void result_type;
 | |
|     void operator()() const
 | |
|     {
 | |
|         *os << q->value() << ' ' << typename Quantity::unit_type();
 | |
|     }
 | |
|     Os* os;
 | |
|     const Quantity* q;
 | |
| };
 | |
| 
 | |
| template<class Os, class Quantity>
 | |
| print_default_t<Os, Quantity> print_default(Os& os, const Quantity& q)
 | |
| {
 | |
|     print_default_t<Os, Quantity> result = { &os, &q };
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| template<class Os>
 | |
| struct print_scale_t {
 | |
|     typedef void result_type;
 | |
|     template<class Prefix, class T>
 | |
|     void operator()(Prefix, const T& t) const
 | |
|     {
 | |
|         *prefixed = true;
 | |
|         *os << t / Prefix::value() << ' ';
 | |
|         switch(units::get_format(*os)) {
 | |
|             case name_fmt: do_print(*os, Prefix::name()); break;
 | |
|             case raw_fmt:
 | |
|             case symbol_fmt: do_print(*os, Prefix::symbol()); break;
 | |
|             case typename_fmt: do_print(*os, units::simplify_typename(Prefix())); *os << ' '; break;
 | |
|         }
 | |
|     }
 | |
|     template<long N, class T>
 | |
|     void operator()(scale<N, static_rational<0> >, const T& t) const
 | |
|     {
 | |
|         *prefixed = false;
 | |
|         *os << t << ' ';
 | |
|     }
 | |
|     Os* os;
 | |
|     bool* prefixed;
 | |
| };
 | |
| 
 | |
| template<class Os>
 | |
| print_scale_t<Os> print_scale(Os& os, bool& prefixed)
 | |
| {
 | |
|     print_scale_t<Os> result = { &os, &prefixed };
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| // puts parentheses around a unit
 | |
| /// INTERNAL ONLY
 | |
| template<class Dimension,class Units,class Scale, class Subformatter>
 | |
| inline std::string
 | |
| maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
 | |
| {
 | |
|     std::string str;
 | |
| 
 | |
|     std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
 | |
| 
 | |
|     if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
 | |
|     {
 | |
|         str += "(";
 | |
|         str += without_scale;
 | |
|         str += ")";
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         str += without_scale;
 | |
|     }
 | |
| 
 | |
|     return(str);
 | |
| }
 | |
| 
 | |
| // This overload catches scaled units that have a single base unit
 | |
| // raised to the first power.  It causes si::nano * si::meters to not
 | |
| // put parentheses around the meters.  i.e. nm rather than n(m)
 | |
| /// INTERNAL ONLY
 | |
| template<class Dimension,class Unit,class Scale, class Subformatter>
 | |
| 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)
 | |
| {
 | |
|     return f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
 | |
| }
 | |
| 
 | |
| template<class Prefixes, class CharT, class Traits, class Unit, class T, class F>
 | |
| void do_print_prefixed_impl(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, F default_)
 | |
| {
 | |
|     bool prefixed;
 | |
|     if(detail::find_matching_scale<Prefixes>(q.value(), autoprefix_norm(q.value()), detail::print_scale(os, prefixed))) {
 | |
|         if(prefixed) {
 | |
|             switch(units::get_format(os)) {
 | |
|                 case symbol_fmt: do_print(os, maybe_parenthesize(Unit(), format_symbol_impl())); break;
 | |
|                 case raw_fmt: do_print(os, maybe_parenthesize(Unit(), format_raw_symbol_impl())); break;
 | |
|                 case name_fmt: do_print(os, maybe_parenthesize(Unit(), format_name_impl())); break;
 | |
|                 case typename_fmt: do_print(os, simplify_typename(Unit())); break;
 | |
|             }
 | |
|         } else {
 | |
|             os << Unit();
 | |
|         }
 | |
|     } else {
 | |
|         default_();
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Handle units like si::kilograms that have a scale embedded in the
 | |
| // base unit.  This overload is disabled if the scaled base unit has
 | |
| // a user-defined string representation.
 | |
| template<class Prefixes, class CharT, class Traits, class Dimension, class BaseUnit, class BaseScale, class Scale, class T>
 | |
| typename base_unit_info<
 | |
|     scaled_base_unit<BaseUnit, Scale>
 | |
| >::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)
 | |
| {
 | |
|     quantity<
 | |
|         unit<
 | |
|             Dimension,
 | |
|             heterogeneous_system<
 | |
|                 heterogeneous_system_impl<
 | |
|                     list<
 | |
|                         heterogeneous_system_dim<BaseUnit, static_rational<1> >,
 | |
|                         dimensionless_type
 | |
|                     >,
 | |
|                     Dimension,
 | |
|                     dimensionless_type
 | |
|                 >
 | |
|             >
 | |
|         >,
 | |
|         T
 | |
|     > unscaled(q);
 | |
|     detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
 | |
| }
 | |
| 
 | |
| template<class Prefixes, class CharT, class Traits, class Dimension, class L, class Scale, class T>
 | |
| void do_print_prefixed(
 | |
|     std::basic_ostream<CharT, Traits>& os,
 | |
|     const quantity<
 | |
|         unit<
 | |
|             Dimension,
 | |
|             heterogeneous_system<
 | |
|                 heterogeneous_system_impl<
 | |
|                     L,
 | |
|                     Dimension,
 | |
|                     Scale
 | |
|                 >
 | |
|             >
 | |
|         >,
 | |
|         T
 | |
|     >& q)
 | |
| {
 | |
|     quantity<
 | |
|         unit<
 | |
|             Dimension,
 | |
|             heterogeneous_system<
 | |
|                 heterogeneous_system_impl<
 | |
|                     L,
 | |
|                     Dimension,
 | |
|                     dimensionless_type
 | |
|                 >
 | |
|             >
 | |
|         >,
 | |
|         T
 | |
|     > unscaled(q);
 | |
|     detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
 | |
| }
 | |
| 
 | |
| template<class Prefixes, class CharT, class Traits, class Dimension, class System, class T>
 | |
| void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<unit<Dimension, System>, T>& q)
 | |
| {
 | |
|     detail::do_print_prefixed<Prefixes>(os, quantity<unit<Dimension, typename make_heterogeneous_system<Dimension, System>::type>, T>(q));
 | |
| }
 | |
| 
 | |
| template<class Prefixes, class CharT, class Traits, class Unit, class T>
 | |
| void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q)
 | |
| {
 | |
|     detail::print_default(os, q)();
 | |
| }
 | |
| 
 | |
| template<class Prefixes, class CharT, class Traits, class Unit, class T>
 | |
| void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::true_)
 | |
| {
 | |
|     detail::do_print_prefixed<Prefixes>(os, q);
 | |
| }
 | |
| 
 | |
| template<class Prefixes, class CharT, class Traits, class Unit, class T>
 | |
| void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::false_)
 | |
| {
 | |
|     detail::print_default(os, q)();
 | |
| }
 | |
| 
 | |
| inline mpl::true_ test_norm(double) { return mpl::true_(); }
 | |
| inline mpl::false_ test_norm(one) { return mpl::false_(); }
 | |
| 
 | |
| } // namespace detail
 | |
| 
 | |
| template<class Dimension,class System>
 | |
| inline std::string
 | |
| typename_string(const unit<Dimension, System>&)
 | |
| {
 | |
|     return simplify_typename(typename reduce_unit< unit<Dimension,System> >::type());
 | |
| }
 | |
| 
 | |
| template<class Dimension,class System>
 | |
| inline std::string
 | |
| symbol_string(const unit<Dimension, System>&)
 | |
| {
 | |
|     return detail::to_string_impl(unit<Dimension,System>(), detail::format_symbol_impl());
 | |
| }
 | |
| 
 | |
| template<class Dimension,class System>
 | |
| inline std::string
 | |
| name_string(const unit<Dimension, System>&)
 | |
| {
 | |
|     return detail::to_string_impl(unit<Dimension,System>(), detail::format_name_impl());
 | |
| }
 | |
| 
 | |
| /// Print a @c unit as a list of base units and their exponents.
 | |
| ///
 | |
| ///     for @c symbol_format outputs e.g. "m s^-1" or "J".
 | |
| ///     for @c name_format  outputs e.g. "meter second^-1" or "joule".
 | |
| ///     for @c raw_format  outputs e.g. "m s^-1" or "meter kilogram^2 second^-2".
 | |
| ///     for @c typename_format  outputs the typename itself (currently demangled only on GCC).
 | |
| template<class Char, class Traits, class Dimension, class System>
 | |
| inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const unit<Dimension, System>& u)
 | |
| {
 | |
|     if (units::get_format(os) == typename_fmt)
 | |
|     {
 | |
|         detail::do_print(os, typename_string(u));
 | |
|     }
 | |
|     else if (units::get_format(os) == raw_fmt)
 | |
|     {
 | |
|         detail::do_print(os, detail::to_string_impl(u, detail::format_raw_symbol_impl()));
 | |
|     }
 | |
|     else if (units::get_format(os) == symbol_fmt)
 | |
|     {
 | |
|         detail::do_print(os, symbol_string(u));
 | |
|     }
 | |
|     else if (units::get_format(os) == name_fmt)
 | |
|     {
 | |
|         detail::do_print(os, name_string(u));
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         BOOST_ASSERT_MSG(false, "The format mode must be one of: typename_format, raw_format, name_format, symbol_format");
 | |
|     }
 | |
| 
 | |
|     return(os);
 | |
| }
 | |
| 
 | |
| /// \brief Print a @c quantity.
 | |
| /// \details Prints the value followed by the unit.
 | |
| /// If the engineering_prefix, or binary_prefix is set,
 | |
| /// tries to scale the value appropriately.
 | |
| /// For example, it might print 12.345 km instead of 12345 m.
 | |
| /// (Note does @b not attempt to automatically scale scalars like double, float...)
 | |
| template<class Char, class Traits, class Unit, class T>
 | |
| inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const quantity<Unit, T>& q)
 | |
| {
 | |
|     if (units::get_autoprefix(os) == autoprefix_none)
 | |
|     {
 | |
|         os << q.value() << ' ' << Unit();
 | |
|     }
 | |
|     else if (units::get_autoprefix(os) == autoprefix_engineering)
 | |
|     {
 | |
|         detail::maybe_print_prefixed<detail::engineering_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
 | |
|     }
 | |
|     else if (units::get_autoprefix(os) == autoprefix_binary)
 | |
|     {
 | |
|         detail::maybe_print_prefixed<detail::binary_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         BOOST_ASSERT_MSG(false, "Autoprefixing must be one of: no_prefix, engineering_prefix, binary_prefix");
 | |
|     }
 | |
|     return(os);
 | |
| }
 | |
| 
 | |
| } // namespace units
 | |
| 
 | |
| } // namespace boost
 | |
| 
 | |
| #endif
 | 
