io.hpp 32 KB

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