// 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-2008 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace serialization { /// Boost Serialization library support for units. template inline void serialize(Archive& ar,boost::units::unit&,const unsigned int /*version*/) { } /// Boost Serialization library support for quantities. template inline void serialize(Archive& ar,boost::units::quantity& q,const unsigned int /*version*/) { ar & boost::serialization::make_nvp("value", units::quantity_cast(q)); } } // namespace serialization namespace units { // get string representation of arbitrary type template 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 std::string to_string(const static_rational&) { return to_string(N); } // get string representation of @c static_rational template std::string to_string(const static_rational&) { return '(' + to_string(N) + '/' + to_string(D) + ')'; } /// Write @c static_rational to @c std::basic_ostream. template inline std::basic_ostream& operator<<(std::basic_ostream& os,const static_rational& r) { os << to_string(r); return os; } /// traits template for unit names template struct base_unit_info { /// 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()); } }; enum format_mode { symbol_fmt = 0, // default - reduces unit names to known symbols for both base and derived units name_fmt, // output full unit names for base and derived units raw_fmt, // output only symbols for base units typename_fmt // output demangled typenames }; namespace detail { template struct xalloc_key_holder { static int value; static bool initialized; }; template int xalloc_key_holder::value = 0; template bool xalloc_key_holder::initialized = 0; struct xalloc_key_initializer_t { xalloc_key_initializer_t() { if (!xalloc_key_holder::initialized) { xalloc_key_holder::value = std::ios_base::xalloc(); xalloc_key_holder::initialized = true; } } }; namespace /**/ { xalloc_key_initializer_t xalloc_key_initializer; } // namespace } // namespace detail inline format_mode get_format(std::ios_base& ios) { return(static_cast(ios.iword(detail::xalloc_key_holder::value))); } inline void set_format(std::ios_base& ios, format_mode new_mode) { ios.iword(detail::xalloc_key_holder::value) = static_cast(new_mode); } inline std::ios_base& typename_format(std::ios_base& ios) { (set_format)(ios, typename_fmt); return(ios); } inline std::ios_base& raw_format(std::ios_base& ios) { (set_format)(ios, raw_fmt); return(ios); } inline std::ios_base& symbol_format(std::ios_base& ios) { (set_format)(ios, symbol_fmt); return(ios); } inline std::ios_base& name_format(std::ios_base& ios) { (set_format)(ios, name_fmt); return(ios); } namespace detail { template inline std::string exponent_string(const static_rational& r) { return '^' + to_string(r); } template<> inline std::string exponent_string(const static_rational<1>&) { return ""; } template inline std::string base_unit_symbol_string(const T&) { return base_unit_info::symbol() + exponent_string(typename T::value_type()); } template inline std::string base_unit_name_string(const T&) { return base_unit_info::name() + exponent_string(typename T::value_type()); } // stringify with symbols template struct symbol_string_impl { template struct apply { typedef typename symbol_string_impl::template apply 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 struct apply { static void value(std::string& str) { str += base_unit_symbol_string(typename Begin::item()); }; }; }; template<> struct symbol_string_impl<0> { template struct apply { static void value(std::string& str) { // better shorthand for dimensionless? str += "dimensionless"; } }; }; template struct scale_symbol_string_impl { template struct apply { static void value(std::string& str) { str += Begin::item::symbol(); scale_symbol_string_impl::template apply::value(str); } }; }; template<> struct scale_symbol_string_impl<0> { template struct apply { static void value(std::string&) { } }; }; // stringify with names template struct name_string_impl { template struct apply { typedef typename name_string_impl::template apply 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 struct apply { static void value(std::string& str) { str += base_unit_name_string(typename Begin::item()); }; }; }; template<> struct name_string_impl<0> { template struct apply { static void value(std::string& str) { str += "dimensionless"; } }; }; template struct scale_name_string_impl { template struct apply { static void value(std::string& str) { str += Begin::item::name(); scale_name_string_impl::template apply::value(str); } }; }; template<> struct scale_name_string_impl<0> { template 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 inline std::string to_string_impl(const unit&, SubFormatter f) { return f(typename reduce_unit >::type()); } /// INTERNAL ONLY // this overload picks up heterogeneous units that are not scaled. template inline std::string to_string_impl(const unit > >&, Subformatter f) { std::string str; f.template append_units_to(str); return(str); } // This overload is a special case for heterogeneous_system which // is really unitless /// INTERNAL ONLY template inline std::string to_string_impl(const unit > >&, Subformatter) { return("dimensionless"); } // this overload deals with heterogeneous_systems which are unitless // but scaled. /// INTERNAL ONLY template inline std::string to_string_impl(const unit > >&, Subformatter f) { std::string str; f.template append_scale_to(str); return(str); } // this overload deals with scaled units. /// INTERNAL ONLY template inline std::string to_string_impl(const unit > >&, Subformatter f) { std::string str; f.template append_scale_to(str); std::string without_scale = f(unit > >()); if (f.is_default_string(without_scale, unit > >())) { 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 inline std::string to_string_impl(const unit >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f) { std::string str; f.template append_scale_to(str); str += f(unit >, 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 inline std::string to_string_impl(const unit >,dimensionless_type>, Dimension, dimensionless_type> > >&, Subformatter f) { std::string str; f.template append_units_to >,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 // /// INTERNAL ONLY template inline std::string to_string_impl(const unit, static_rational<1> >, dimensionless_type>, Dimension, Scale> > >&, Subformatter f) { return(f( unit< Dimension, heterogeneous_system< heterogeneous_system_impl< list >, dimensionless_type>, Dimension, typename mpl::times >::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 inline std::string to_string_impl(const unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >&, Subformatter f) { std::string str; f.template append_units_to, static_rational<1> >, dimensionless_type> >(str); return(str); } struct format_raw_symbol_impl { template void append_units_to(std::string& str) { detail::symbol_string_impl::template apply::value(str); } template void append_scale_to(std::string& str) { detail::scale_symbol_string_impl::template apply::value(str); } template std::string operator()(const Unit& unit) { return(to_string_impl(unit, *this)); } template bool is_default_string(const std::string&, const Unit&) { return(true); } }; struct format_symbol_impl : format_raw_symbol_impl { template std::string operator()(const Unit& unit) { return(symbol_string(unit)); } template bool is_default_string(const std::string& str, const Unit& unit) { return(str == to_string_impl(unit, format_raw_symbol_impl())); } }; struct format_raw_name_impl { template void append_units_to(std::string& str) { detail::name_string_impl<(Units::size::value)>::template apply::value(str); } template void append_scale_to(std::string& str) { detail::scale_name_string_impl::template apply::value(str); } template std::string operator()(const Unit& unit) { return(to_string_impl(unit, *this)); } template bool is_default_string(const std::string&, const Unit&) { return(true); } }; struct format_name_impl : format_raw_name_impl { template std::string operator()(const Unit& unit) { return(name_string(unit)); } template bool is_default_string(const std::string& str, const Unit& unit) { return(str == to_string_impl(unit, format_raw_name_impl())); } }; template inline void do_print(std::basic_ostream& os, const std::string& s) { os << s.c_str(); } inline void do_print(std::ostream& os, const std::string& s) { os << s; } template inline void do_print(std::basic_ostream& os, const char* s) { os << s; } } // namespace detail template inline std::string typename_string(const unit&) { return simplify_typename(typename reduce_unit< unit >::type()); } template inline std::string symbol_string(const unit&) { return detail::to_string_impl(unit(), detail::format_symbol_impl()); } template inline std::string name_string(const unit&) { return detail::to_string_impl(unit(), detail::format_name_impl()); } /// Print an @c unit as a list of base units and exponents /// /// for @c symbol_format this gives e.g. "m s^-1" or "J" /// for @c name_format this gives e.g. "meter second^-1" or "joule" /// for @c raw_format this gives e.g. "m s^-1" or "meter kilogram^2 second^-2" /// for @c typename_format this gives the typename itself (currently demangled only on GCC) template inline std::basic_ostream& operator<<(std::basic_ostream& os, const unit& 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); } /// INTERNAL ONLY /// Print a @c quantity. Prints the value followed by the unit template inline std::basic_ostream& operator<<(std::basic_ostream& os, const quantity& q) { os << q.value() << ' ' << Unit(); return(os); } } // namespace units } // namespace boost #endif