io.hpp 31 KB

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