| // 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/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) |
| { |
| 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. |
| |
| template<class End, class Prev, class T, class F> |
| bool find_matching_scale_impl(End, End, Prev, T, 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, F f) |
| { |
| using std::abs; |
| if(Begin::item::value() > abs(t)) { |
| f(prev, t); |
| return true; |
| } else { |
| return detail::find_matching_scale_impl( |
| typename Begin::next(), |
| end, |
| typename Begin::item(), |
| t, |
| f |
| ); |
| } |
| } |
| |
| template<class End, class T, class F> |
| bool find_matching_scale_i(End, End, T, F) |
| { |
| return false; |
| } |
| |
| template<class Begin, class End, class T, class F> |
| bool find_matching_scale_i(Begin, End end, T t, F f) |
| { |
| using std::abs; |
| if(Begin::item::value() > abs(t)) { |
| return false; |
| } else { |
| return detail::find_matching_scale_impl(typename Begin::next(), end, typename Begin::item(), t, f); |
| } |
| } |
| |
| template<class Scales, class T, class F> |
| bool find_matching_scale(T t, F f) |
| { |
| return detail::find_matching_scale_i(Scales(), dimensionless_type(), t, 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> >, |
| 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(), 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)(); |
| } |
| |
| } // 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 |
| { |
| assert(!"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::do_print_prefixed<detail::engineering_prefixes>(os, q); |
| } |
| else if (units::get_autoprefix(os) == autoprefix_binary) |
| { |
| detail::do_print_prefixed<detail::binary_prefixes>(os, q); |
| } |
| else |
| { |
| assert(!"Autoprefixing must be one of: no_prefix, engineering_prefix, binary_prefix"); |
| } |
| return(os); |
| } |
| |
| } // namespace units |
| |
| } // namespace boost |
| |
| #endif |