]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/units/include/boost/units/io.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / units / include / boost / units / io.hpp
CommitLineData
7c673cae
FG
1// Boost.Units - A C++ library for zero-overhead dimensional analysis and
2// unit/quantity manipulation and conversion
3//
4// Copyright (C) 2003-2008 Matthias Christian Schabel
5// Copyright (C) 2007-2010 Steven Watanabe
6//
7// Distributed under the Boost Software License, Version 1.0. (See
8// accompanying file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10
11#ifndef BOOST_UNITS_IO_HPP
12#define BOOST_UNITS_IO_HPP
13
14/// \file
15/// \brief Stream input and output for rationals, units and quantities.
16/// \details Functions and manipulators for output and input of units and quantities.
17/// symbol and name format, and engineering and binary autoprefix.
18/// Serialization output is also supported.
19
20#include <cassert>
21#include <cmath>
22#include <string>
23#include <iosfwd>
24#include <ios>
25#include <sstream>
26
27#include <boost/assert.hpp>
28#include <boost/serialization/nvp.hpp>
29
30#include <boost/units/units_fwd.hpp>
31#include <boost/units/heterogeneous_system.hpp>
32#include <boost/units/make_scaled_unit.hpp>
33#include <boost/units/quantity.hpp>
34#include <boost/units/scale.hpp>
35#include <boost/units/static_rational.hpp>
36#include <boost/units/unit.hpp>
37#include <boost/units/detail/utility.hpp>
38
39namespace boost {
40
41namespace serialization {
42
43/// Boost Serialization library support for units.
44template<class Archive,class System,class Dim>
45inline void serialize(Archive& /*ar*/,boost::units::unit<Dim,System>&,const unsigned int /*version*/)
46{ }
47
48/// Boost Serialization library support for quantities.
49template<class Archive,class Unit,class Y>
50inline void serialize(Archive& ar,boost::units::quantity<Unit,Y>& q,const unsigned int /*version*/)
51{
52 ar & boost::serialization::make_nvp("value", units::quantity_cast<Y&>(q));
53}
54
55} // namespace serialization
56
57namespace units {
58
59// get string representation of arbitrary type.
60template<class T> std::string to_string(const T& t)
61{
62 std::stringstream sstr;
63
64 sstr << t;
65
66 return sstr.str();
67}
68
69/// get string representation of integral-valued @c static_rational.
70template<integer_type N> std::string to_string(const static_rational<N>&)
71{
72 return to_string(N);
73}
74
75/// get string representation of @c static_rational.
76template<integer_type N, integer_type D> std::string to_string(const static_rational<N,D>&)
77{
78 return '(' + to_string(N) + '/' + to_string(D) + ')';
79}
80
81/// Write @c static_rational to @c std::basic_ostream.
82template<class Char, class Traits, integer_type N, integer_type D>
83inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,const static_rational<N,D>& r)
84{
85 os << to_string(r);
86 return os;
87}
88
89/// traits template for unit names.
90template<class BaseUnit>
91struct base_unit_info
92{
93 /// INTERNAL ONLY
94 typedef void base_unit_info_primary_template;
95 /// The full name of the unit (returns BaseUnit::name() by default)
96 static std::string name()
97 {
98 return(BaseUnit::name());
99 }
100 /// The symbol for the base unit (Returns BaseUnit::symbol() by default)
101 static std::string symbol()
102 {
103 return(BaseUnit::symbol()); /// \returns BaseUnit::symbol(), for example "m"
104 }
105};
106
107/// \enum format_mode format of output of units, for example "m" or "meter".
108enum format_mode
109{
110 symbol_fmt = 0, /// default - reduces unit names to known symbols for both base and derived units.
111 name_fmt = 1, /// output full unit names for base and derived units, for example "meter".
112 raw_fmt = 2, /// output only symbols for base units (but not derived units), for example "m".
113 typename_fmt = 3, /// output demangled typenames (useful only for diagnosis).
114 fmt_mask = 3 /// Bits used for format.
115};
116
117/// \enum autoprefix_mode automatic scaling and prefix (controlled by value of quantity) a, if any,
118enum autoprefix_mode
119{
120 autoprefix_none = 0, /// No automatic prefix.
121 autoprefix_engineering = 4, /// Scale and prefix with 10^3 multiples, 1234.5 m output as 1.2345 km.
122 autoprefix_binary = 8, /// Scale and prefix with 2^10 (1024) multiples, 1024 as 1 kb.
123 autoprefix_mask = 12 /// Bits used for autoprefix.
124};
125
126namespace detail {
127
128template<bool>
129struct xalloc_key_holder
130{
131 static int value;
132 static bool initialized;
133};
134
135template<bool b>
136int xalloc_key_holder<b>::value = 0;
137
138template<bool b>
139bool xalloc_key_holder<b>::initialized = 0;
140
141struct xalloc_key_initializer_t
142{
143 xalloc_key_initializer_t()
144 {
145 if (!xalloc_key_holder<true>::initialized)
146 {
147 xalloc_key_holder<true>::value = std::ios_base::xalloc();
148 xalloc_key_holder<true>::initialized = true;
149 }
150 }
151};
152
153namespace /**/ {
154
155xalloc_key_initializer_t xalloc_key_initializer;
156
157} // namespace
158
159} // namespace detail
160
161/// returns flags controlling output.
162inline long get_flags(std::ios_base& ios, long mask)
163{
164 return(ios.iword(detail::xalloc_key_holder<true>::value) & mask);
165}
166
167/// Set new flags controlling output format.
168inline void set_flags(std::ios_base& ios, long new_flags, long mask)
169{
170 BOOST_ASSERT((~mask & new_flags) == 0);
171 long& flags = ios.iword(detail::xalloc_key_holder<true>::value);
172 flags = (flags & ~mask) | new_flags;
173}
174
175/// returns flags controlling output format.
176inline format_mode get_format(std::ios_base& ios)
177{
178 return(static_cast<format_mode>((get_flags)(ios, fmt_mask)));
179}
180
181/// Set new flags controlling output format.
182inline void set_format(std::ios_base& ios, format_mode new_mode)
183{
184 (set_flags)(ios, new_mode, fmt_mask);
185}
186
187/// Set new flags for type_name output format.
188inline std::ios_base& typename_format(std::ios_base& ios)
189{
190 (set_format)(ios, typename_fmt);
191 return(ios);
192}
193
194/// set new flag for raw format output, for example "m".
195inline std::ios_base& raw_format(std::ios_base& ios)
196{
197 (set_format)(ios, raw_fmt);
198 return(ios);
199}
200
201/// set new format flag for symbol output, for example "m".
202inline std::ios_base& symbol_format(std::ios_base& ios)
203{
204 (set_format)(ios, symbol_fmt);
205 return(ios);
206}
207
208/// set new format for name output, for example "meter".
209inline std::ios_base& name_format(std::ios_base& ios)
210{
211 (set_format)(ios, name_fmt);
212 return(ios);
213}
214
215/// get autoprefix flags for output.
216inline autoprefix_mode get_autoprefix(std::ios_base& ios)
217{
218 return static_cast<autoprefix_mode>((get_flags)(ios, autoprefix_mask));
219}
220
221/// Get format for output.
222inline void set_autoprefix(std::ios_base& ios, autoprefix_mode new_mode)
223{
224 (set_flags)(ios, new_mode, autoprefix_mask);
225}
226
227/// Clear autoprefix flags.
228inline std::ios_base& no_prefix(std::ios_base& ios)
229{
230 (set_autoprefix)(ios, autoprefix_none);
231 return ios;
232}
233
234/// Set flag for engineering prefix, so 1234.5 m displays as "1.2345 km".
235inline std::ios_base& engineering_prefix(std::ios_base& ios)
236{
237 (set_autoprefix)(ios, autoprefix_engineering);
238 return ios;
239}
240
241/// Set flag for binary prefix, so 1024 byte displays as "1 Kib".
242inline std::ios_base& binary_prefix(std::ios_base& ios)
243{
244 (set_autoprefix)(ios, autoprefix_binary);
245 return ios;
246}
247
248namespace detail {
249
250/// \return exponent string like "^1/2".
251template<integer_type N, integer_type D>
252inline std::string exponent_string(const static_rational<N,D>& r)
253{
254 return '^' + to_string(r);
255}
256
257/// \return empty exponent string for integer rational like 2.
258template<>
259inline std::string exponent_string(const static_rational<1>&)
260{
261 return "";
262}
263
264template<class T>
265inline std::string base_unit_symbol_string(const T&)
266{
267 return base_unit_info<typename T::tag_type>::symbol() + exponent_string(typename T::value_type());
268}
269
270template<class T>
271inline std::string base_unit_name_string(const T&)
272{
273 return base_unit_info<typename T::tag_type>::name() + exponent_string(typename T::value_type());
274}
275
276// stringify with symbols.
277template<int N>
278struct symbol_string_impl
279{
280 template<class Begin>
281 struct apply
282 {
283 typedef typename symbol_string_impl<N-1>::template apply<typename Begin::next> next;
284 static void value(std::string& str)
285 {
286 str += base_unit_symbol_string(typename Begin::item()) + ' ';
287 next::value(str);
288 }
289 };
290};
291
292template<>
293struct symbol_string_impl<1>
294{
295 template<class Begin>
296 struct apply
297 {
298 static void value(std::string& str)
299 {
300 str += base_unit_symbol_string(typename Begin::item());
301 }
302 };
303};
304
305template<>
306struct symbol_string_impl<0>
307{
308 template<class Begin>
309 struct apply
310 {
311 static void value(std::string& str)
312 {
313 // better shorthand for dimensionless?
314 str += "dimensionless";
315 }
316 };
317};
318
319template<int N>
320struct scale_symbol_string_impl
321{
322 template<class Begin>
323 struct apply
324 {
325 static void value(std::string& str)
326 {
327 str += Begin::item::symbol();
328 scale_symbol_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
329 }
330 };
331};
332
333template<>
334struct scale_symbol_string_impl<0>
335{
336 template<class Begin>
337 struct apply
338 {
339 static void value(std::string&) { }
340 };
341};
342
343// stringify with names.
344template<int N>
345struct name_string_impl
346{
347 template<class Begin>
348 struct apply
349 {
350 typedef typename name_string_impl<N-1>::template apply<typename Begin::next> next;
351 static void value(std::string& str)
352 {
353 str += base_unit_name_string(typename Begin::item()) + ' ';
354 next::value(str);
355 }
356 };
357};
358
359template<>
360struct name_string_impl<1>
361{
362 template<class Begin>
363 struct apply
364 {
365 static void value(std::string& str)
366 {
367 str += base_unit_name_string(typename Begin::item());
368 }
369 };
370};
371
372template<>
373struct name_string_impl<0>
374{
375 template<class Begin>
376 struct apply
377 {
378 static void value(std::string& str)
379 {
380 str += "dimensionless";
381 }
382 };
383};
384
385template<int N>
386struct scale_name_string_impl
387{
388 template<class Begin>
389 struct apply
390 {
391 static void value(std::string& str)
392 {
393 str += Begin::item::name();
394 scale_name_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
395 }
396 };
397};
398
399template<>
400struct scale_name_string_impl<0>
401{
402 template<class Begin>
403 struct apply
404 {
405 static void value(std::string&) { }
406 };
407};
408
409} // namespace detail
410
411namespace detail {
412
413// These two overloads of symbol_string and name_string will
414// will pick up homogeneous_systems. They simply call the
415// appropriate function with a heterogeneous_system.
416template<class Dimension,class System, class SubFormatter>
417inline std::string
418to_string_impl(const unit<Dimension,System>&, SubFormatter f)
419{
420 return f(typename reduce_unit<unit<Dimension, System> >::type());
421}
422
423/// INTERNAL ONLY
424// this overload picks up heterogeneous units that are not scaled.
425template<class Dimension,class Units, class Subformatter>
426inline std::string
427to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >&, Subformatter f)
428{
429 std::string str;
430 f.template append_units_to<Units>(str);
431 return(str);
432}
433
434// This overload is a special case for heterogeneous_system which
435// is really unitless
436/// INTERNAL ONLY
437template<class Subformatter>
438inline std::string
439to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, dimensionless_type> > >&, Subformatter)
440{
441 return("dimensionless");
442}
443
444// this overload deals with heterogeneous_systems which are unitless
445// but scaled.
446/// INTERNAL ONLY
447template<class Scale, class Subformatter>
448inline std::string
449to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, Scale> > >&, Subformatter f)
450{
451 std::string str;
452 f.template append_scale_to<Scale>(str);
453 return(str);
454}
455
456// this overload deals with scaled units.
457/// INTERNAL ONLY
458template<class Dimension,class Units,class Scale, class Subformatter>
459inline std::string
460to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
461{
462 std::string str;
463
464 f.template append_scale_to<Scale>(str);
465
466 std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
467
468 if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
469 {
470 str += "(";
471 str += without_scale;
472 str += ")";
473 }
474 else
475 {
476 str += without_scale;
477 }
478
479 return(str);
480}
481
482// This overload catches scaled units that have a single base unit
483// raised to the first power. It causes si::nano * si::meters to not
484// put parentheses around the meters. i.e. nm rather than n(m)
485/// INTERNAL ONLY
486template<class Dimension,class Unit,class Scale, class Subformatter>
487inline std::string
488to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
489{
490 std::string str;
491
492 f.template append_scale_to<Scale>(str);
493 str += f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
494
495 return(str);
496}
497
498// This overload is necessary to disambiguate.
499// it catches units that are unscaled and have a single
500// base unit raised to the first power. It is treated the
501// same as any other unscaled unit.
502/// INTERNAL ONLY
503template<class Dimension,class Unit,class Subformatter>
504inline std::string
505to_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)
506{
507 std::string str;
508 f.template append_units_to<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type> >(str);
509 return(str);
510}
511
512// This overload catches scaled units that have a single scaled base unit
513// raised to the first power. It moves that scaling on the base unit
514// to the unit level scaling and recurses. By doing this we make sure that
515// si::milli * si::kilograms will print g rather than mkg.
516//
517// This transformation will not be applied if base_unit_info is specialized
518// for the scaled base unit.
519//
520/// INTERNAL ONLY
521template<class Dimension,class Unit,class UnitScale, class Scale, class Subformatter>
522inline std::string
523to_string_impl(
524 const unit<
525 Dimension,
526 heterogeneous_system<
527 heterogeneous_system_impl<
528 list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>,
529 Dimension,
530 Scale
531 >
532 >
533 >&,
534 Subformatter f,
535 typename base_unit_info<scaled_base_unit<Unit, UnitScale> >::base_unit_info_primary_template* = 0)
536{
537 return(f(
538 unit<
539 Dimension,
540 heterogeneous_system<
541 heterogeneous_system_impl<
542 list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>,
543 Dimension,
544 typename mpl::times<Scale, list<scale_list_dim<UnitScale>, dimensionless_type> >::type
545 >
546 >
547 >()));
548}
549
550// this overload disambuguates between the overload for an unscaled unit
551// and the overload for a scaled base unit raised to the first power.
552/// INTERNAL ONLY
553template<class Dimension,class Unit,class UnitScale,class Subformatter>
554inline std::string
555to_string_impl(
556 const unit<
557 Dimension,
558 heterogeneous_system<
559 heterogeneous_system_impl<
560 list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>,
561 Dimension,
562 dimensionless_type
563 >
564 >
565 >&,
566 Subformatter f,
567 typename base_unit_info<scaled_base_unit<Unit, UnitScale> >::base_unit_info_primary_template* = 0)
568{
569 std::string str;
570 f.template append_units_to<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type> >(str);
571 return(str);
572}
573
574struct format_raw_symbol_impl {
575 template<class Units>
576 void append_units_to(std::string& str) {
577 detail::symbol_string_impl<Units::size::value>::template apply<Units>::value(str);
578 }
579 template<class Scale>
580 void append_scale_to(std::string& str) {
581 detail::scale_symbol_string_impl<Scale::size::value>::template apply<Scale>::value(str);
582 }
583 template<class Unit>
584 std::string operator()(const Unit& u) {
585 return(to_string_impl(u, *this));
586 }
587 template<class Unit>
588 bool is_default_string(const std::string&, const Unit&) {
589 return(true);
590 }
591};
592
593struct format_symbol_impl : format_raw_symbol_impl {
594 template<class Unit>
595 std::string operator()(const Unit& u) {
596 return(symbol_string(u));
597 }
598 template<class Unit>
599 bool is_default_string(const std::string& str, const Unit& u) {
600 return(str == to_string_impl(u, format_raw_symbol_impl()));
601 }
602};
603
604struct format_raw_name_impl {
605 template<class Units>
606 void append_units_to(std::string& str) {
607 detail::name_string_impl<(Units::size::value)>::template apply<Units>::value(str);
608 }
609 template<class Scale>
610 void append_scale_to(std::string& str) {
611 detail::scale_name_string_impl<Scale::size::value>::template apply<Scale>::value(str);
612 }
613 template<class Unit>
614 std::string operator()(const Unit& u) {
615 return(to_string_impl(u, *this));
616 }
617 template<class Unit>
618 bool is_default_string(const std::string&, const Unit&) {
619 return(true);
620 }
621};
622
623struct format_name_impl : format_raw_name_impl {
624 template<class Unit>
625 std::string operator()(const Unit& u) {
626 return(name_string(u));
627 }
628 template<class Unit>
629 bool is_default_string(const std::string& str, const Unit& u) {
630 return(str == to_string_impl(u, format_raw_name_impl()));
631 }
632};
633
634template<class Char, class Traits>
635inline void do_print(std::basic_ostream<Char, Traits>& os, const std::string& s)
636{
637 os << s.c_str();
638}
639
640inline void do_print(std::ostream& os, const std::string& s)
641{
642 os << s;
643}
644
645template<class Char, class Traits>
646inline void do_print(std::basic_ostream<Char, Traits>& os, const char* s)
647{
648 os << s;
649}
650
651// For automatically applying the appropriate prefixes.
652
653}
654
655#ifdef BOOST_UNITS_DOXYGEN
656
657/// ADL customization point for automatic prefixing.
658/// Returns a non-negative value. Implemented as std::abs
659/// for built-in types.
660template<class T>
661double autoprefix_norm(const T& arg);
662
663#else
664
665template<class T, bool C = boost::is_arithmetic<T>::value>
666struct autoprefix_norm_impl;
667
668template<class T>
669struct autoprefix_norm_impl<T, true>
670{
671 typedef double type;
672 static double call(const T& arg) { return std::abs(arg); }
673};
674
675template<class T>
676struct autoprefix_norm_impl<T, false>
677{
678 typedef one type;
679 static one call(const T&) { return one(); }
680};
681
682template<class T>
683typename autoprefix_norm_impl<T>::type autoprefix_norm(const T& arg)
684{
685 return autoprefix_norm_impl<T>::call(arg);
686}
687
688#endif
689
690namespace detail {
691
692template<class End, class Prev, class T, class F>
693bool find_matching_scale_impl(End, End, Prev, T, double, F)
694{
695 return false;
696}
697
698template<class Begin, class End, class Prev, class T, class F>
699bool find_matching_scale_impl(Begin, End end, Prev prev, T t, double x, F f)
700{
701 if(Begin::item::value() > x) {
702 f(prev, t);
703 return true;
704 } else {
705 return detail::find_matching_scale_impl(
706 typename Begin::next(),
707 end,
708 typename Begin::item(),
709 t,
710 x,
711 f
712 );
713 }
714}
715
716template<class End, class T, class F>
717bool find_matching_scale_i(End, End, T, double, F)
718{
719 return false;
720}
721
722template<class Begin, class End, class T, class F>
723bool find_matching_scale_i(Begin, End end, T t, double x, F f)
724{
725 if(Begin::item::value() > x) {
726 return false;
727 } else {
728 return detail::find_matching_scale_impl(typename Begin::next(), end, typename Begin::item(), t, x, f);
729 }
730}
731
732template<class Scales, class T, class F>
733bool find_matching_scale(T t, double x, F f)
734{
735 return detail::find_matching_scale_i(Scales(), dimensionless_type(), t, x, f);
736}
737
738typedef list<scale<10, static_rational<-24> >,
739 list<scale<10, static_rational<-21> >,
740 list<scale<10, static_rational<-18> >,
741 list<scale<10, static_rational<-15> >,
742 list<scale<10, static_rational<-12> >,
743 list<scale<10, static_rational<-9> >,
744 list<scale<10, static_rational<-6> >,
745 list<scale<10, static_rational<-3> >,
746 list<scale<10, static_rational<0> >,
747 list<scale<10, static_rational<3> >,
748 list<scale<10, static_rational<6> >,
749 list<scale<10, static_rational<9> >,
750 list<scale<10, static_rational<12> >,
751 list<scale<10, static_rational<15> >,
752 list<scale<10, static_rational<18> >,
753 list<scale<10, static_rational<21> >,
754 list<scale<10, static_rational<24> >,
755 list<scale<10, static_rational<27> >,
756 dimensionless_type> > > > > > > > > > > > > > > > > > engineering_prefixes;
757
758typedef list<scale<2, static_rational<10> >,
759 list<scale<2, static_rational<20> >,
760 list<scale<2, static_rational<30> >,
761 list<scale<2, static_rational<40> >,
762 list<scale<2, static_rational<50> >,
763 list<scale<2, static_rational<60> >,
764 list<scale<2, static_rational<70> >,
765 list<scale<2, static_rational<80> >,
766 list<scale<2, static_rational<90> >,
767 dimensionless_type> > > > > > > > > binary_prefixes;
768
769template<class Os, class Quantity>
770struct print_default_t {
771 typedef void result_type;
772 void operator()() const
773 {
774 *os << q->value() << ' ' << typename Quantity::unit_type();
775 }
776 Os* os;
777 const Quantity* q;
778};
779
780template<class Os, class Quantity>
781print_default_t<Os, Quantity> print_default(Os& os, const Quantity& q)
782{
783 print_default_t<Os, Quantity> result = { &os, &q };
784 return result;
785}
786
787template<class Os>
788struct print_scale_t {
789 typedef void result_type;
790 template<class Prefix, class T>
791 void operator()(Prefix, const T& t) const
792 {
793 *prefixed = true;
794 *os << t / Prefix::value() << ' ';
795 switch(units::get_format(*os)) {
796 case name_fmt: do_print(*os, Prefix::name()); break;
797 case raw_fmt:
798 case symbol_fmt: do_print(*os, Prefix::symbol()); break;
799 case typename_fmt: do_print(*os, units::simplify_typename(Prefix())); *os << ' '; break;
800 }
801 }
802 template<long N, class T>
803 void operator()(scale<N, static_rational<0> >, const T& t) const
804 {
805 *prefixed = false;
806 *os << t << ' ';
807 }
808 Os* os;
809 bool* prefixed;
810};
811
812template<class Os>
813print_scale_t<Os> print_scale(Os& os, bool& prefixed)
814{
815 print_scale_t<Os> result = { &os, &prefixed };
816 return result;
817}
818
819// puts parentheses around a unit
820/// INTERNAL ONLY
821template<class Dimension,class Units,class Scale, class Subformatter>
822inline std::string
823maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
824{
825 std::string str;
826
827 std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
828
829 if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
830 {
831 str += "(";
832 str += without_scale;
833 str += ")";
834 }
835 else
836 {
837 str += without_scale;
838 }
839
840 return(str);
841}
842
843// This overload catches scaled units that have a single base unit
844// raised to the first power. It causes si::nano * si::meters to not
845// put parentheses around the meters. i.e. nm rather than n(m)
846/// INTERNAL ONLY
847template<class Dimension,class Unit,class Scale, class Subformatter>
848inline std::string
849maybe_parenthesize(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
850{
851 return f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
852}
853
854template<class Prefixes, class CharT, class Traits, class Unit, class T, class F>
855void do_print_prefixed_impl(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, F default_)
856{
857 bool prefixed;
858 if(detail::find_matching_scale<Prefixes>(q.value(), autoprefix_norm(q.value()), detail::print_scale(os, prefixed))) {
859 if(prefixed) {
860 switch(units::get_format(os)) {
861 case symbol_fmt: do_print(os, maybe_parenthesize(Unit(), format_symbol_impl())); break;
862 case raw_fmt: do_print(os, maybe_parenthesize(Unit(), format_raw_symbol_impl())); break;
863 case name_fmt: do_print(os, maybe_parenthesize(Unit(), format_name_impl())); break;
864 case typename_fmt: do_print(os, simplify_typename(Unit())); break;
865 }
866 } else {
867 os << Unit();
868 }
869 } else {
870 default_();
871 }
872}
873
874// Handle units like si::kilograms that have a scale embedded in the
875// base unit. This overload is disabled if the scaled base unit has
876// a user-defined string representation.
877template<class Prefixes, class CharT, class Traits, class Dimension, class BaseUnit, class BaseScale, class Scale, class T>
878typename base_unit_info<
879 scaled_base_unit<BaseUnit, Scale>
880>::base_unit_info_primary_template
881do_print_prefixed(
882 std::basic_ostream<CharT, Traits>& os,
883 const quantity<
884 unit<
885 Dimension,
886 heterogeneous_system<
887 heterogeneous_system_impl<
888 list<
889 heterogeneous_system_dim<
890 scaled_base_unit<BaseUnit, BaseScale>,
891 static_rational<1>
892 >,
893 dimensionless_type
894 >,
895 Dimension,
896 Scale
897 >
898 >
899 >,
900 T
901 >& q)
902{
903 quantity<
904 unit<
905 Dimension,
906 heterogeneous_system<
907 heterogeneous_system_impl<
908 list<
909 heterogeneous_system_dim<BaseUnit, static_rational<1> >,
910 dimensionless_type
911 >,
912 Dimension,
913 dimensionless_type
914 >
915 >
916 >,
917 T
918 > unscaled(q);
919 detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
920}
921
922template<class Prefixes, class CharT, class Traits, class Dimension, class L, class Scale, class T>
923void do_print_prefixed(
924 std::basic_ostream<CharT, Traits>& os,
925 const quantity<
926 unit<
927 Dimension,
928 heterogeneous_system<
929 heterogeneous_system_impl<
930 L,
931 Dimension,
932 Scale
933 >
934 >
935 >,
936 T
937 >& q)
938{
939 quantity<
940 unit<
941 Dimension,
942 heterogeneous_system<
943 heterogeneous_system_impl<
944 L,
945 Dimension,
946 dimensionless_type
947 >
948 >
949 >,
950 T
951 > unscaled(q);
952 detail::do_print_prefixed_impl<Prefixes>(os, unscaled, detail::print_default(os, q));
953}
954
955template<class Prefixes, class CharT, class Traits, class Dimension, class System, class T>
956void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<unit<Dimension, System>, T>& q)
957{
958 detail::do_print_prefixed<Prefixes>(os, quantity<unit<Dimension, typename make_heterogeneous_system<Dimension, System>::type>, T>(q));
959}
960
961template<class Prefixes, class CharT, class Traits, class Unit, class T>
962void do_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q)
963{
964 detail::print_default(os, q)();
965}
966
967template<class Prefixes, class CharT, class Traits, class Unit, class T>
968void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::true_)
969{
970 detail::do_print_prefixed<Prefixes>(os, q);
971}
972
973template<class Prefixes, class CharT, class Traits, class Unit, class T>
974void maybe_print_prefixed(std::basic_ostream<CharT, Traits>& os, const quantity<Unit, T>& q, mpl::false_)
975{
976 detail::print_default(os, q)();
977}
978
979inline mpl::true_ test_norm(double) { return mpl::true_(); }
980inline mpl::false_ test_norm(one) { return mpl::false_(); }
981
982} // namespace detail
983
984template<class Dimension,class System>
985inline std::string
986typename_string(const unit<Dimension, System>&)
987{
988 return simplify_typename(typename reduce_unit< unit<Dimension,System> >::type());
989}
990
991template<class Dimension,class System>
992inline std::string
993symbol_string(const unit<Dimension, System>&)
994{
995 return detail::to_string_impl(unit<Dimension,System>(), detail::format_symbol_impl());
996}
997
998template<class Dimension,class System>
999inline std::string
1000name_string(const unit<Dimension, System>&)
1001{
1002 return detail::to_string_impl(unit<Dimension,System>(), detail::format_name_impl());
1003}
1004
1005/// Print a @c unit as a list of base units and their exponents.
1006///
1007/// for @c symbol_format outputs e.g. "m s^-1" or "J".
1008/// for @c name_format outputs e.g. "meter second^-1" or "joule".
1009/// for @c raw_format outputs e.g. "m s^-1" or "meter kilogram^2 second^-2".
1010/// for @c typename_format outputs the typename itself (currently demangled only on GCC).
1011template<class Char, class Traits, class Dimension, class System>
1012inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const unit<Dimension, System>& u)
1013{
1014 if (units::get_format(os) == typename_fmt)
1015 {
1016 detail::do_print(os, typename_string(u));
1017 }
1018 else if (units::get_format(os) == raw_fmt)
1019 {
1020 detail::do_print(os, detail::to_string_impl(u, detail::format_raw_symbol_impl()));
1021 }
1022 else if (units::get_format(os) == symbol_fmt)
1023 {
1024 detail::do_print(os, symbol_string(u));
1025 }
1026 else if (units::get_format(os) == name_fmt)
1027 {
1028 detail::do_print(os, name_string(u));
1029 }
1030 else
1031 {
1032 BOOST_ASSERT_MSG(false, "The format mode must be one of: typename_format, raw_format, name_format, symbol_format");
1033 }
1034
1035 return(os);
1036}
1037
1038/// \brief Print a @c quantity.
1039/// \details Prints the value followed by the unit.
1040/// If the engineering_prefix, or binary_prefix is set,
1041/// tries to scale the value appropriately.
1042/// For example, it might print 12.345 km instead of 12345 m.
1043/// (Note does @b not attempt to automatically scale scalars like double, float...)
1044template<class Char, class Traits, class Unit, class T>
1045inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const quantity<Unit, T>& q)
1046{
1047 if (units::get_autoprefix(os) == autoprefix_none)
1048 {
1049 os << q.value() << ' ' << Unit();
1050 }
1051 else if (units::get_autoprefix(os) == autoprefix_engineering)
1052 {
1053 detail::maybe_print_prefixed<detail::engineering_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
1054 }
1055 else if (units::get_autoprefix(os) == autoprefix_binary)
1056 {
1057 detail::maybe_print_prefixed<detail::binary_prefixes>(os, q, detail::test_norm(autoprefix_norm(q.value())));
1058 }
1059 else
1060 {
1061 BOOST_ASSERT_MSG(false, "Autoprefixing must be one of: no_prefix, engineering_prefix, binary_prefix");
1062 }
1063 return(os);
1064}
1065
1066} // namespace units
1067
1068} // namespace boost
1069
1070#endif