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