Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/units/io.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/units/io.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,1067 @@ +// 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. + +} + +#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> >, + 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 + { + 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::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 + { + assert(!"Autoprefixing must be one of: no_prefix, engineering_prefix, binary_prefix"); + } + return(os); +} + +} // namespace units + +} // namespace boost + +#endif