conversion_impl.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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-2008 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_DETAIL_CONVERSION_IMPL_HPP
  11. #define BOOST_UNITS_DETAIL_CONVERSION_IMPL_HPP
  12. #include <boost/mpl/bool.hpp>
  13. #include <boost/mpl/and.hpp>
  14. #include <boost/mpl/divides.hpp>
  15. #include <boost/preprocessor/seq/enum.hpp>
  16. #include <boost/type_traits/is_same.hpp>
  17. #include <boost/units/heterogeneous_system.hpp>
  18. #include <boost/units/homogeneous_system.hpp>
  19. #include <boost/units/reduce_unit.hpp>
  20. #include <boost/units/static_rational.hpp>
  21. #include <boost/units/units_fwd.hpp>
  22. #include <boost/units/detail/dimension_list.hpp>
  23. #include <boost/units/detail/heterogeneous_conversion.hpp>
  24. #include <boost/units/detail/one.hpp>
  25. #include <boost/units/detail/static_rational_power.hpp>
  26. #include <boost/units/detail/unscale.hpp>
  27. #include <boost/units/units_fwd.hpp>
  28. namespace boost {
  29. namespace units {
  30. namespace detail {
  31. template<class Source, class Dest>
  32. struct conversion_factor_helper;
  33. template<class Source, class Dest>
  34. struct call_base_unit_converter;
  35. }
  36. /// INTERNAL ONLY
  37. struct undefined_base_unit_converter_base {
  38. BOOST_STATIC_CONSTEXPR bool is_defined = false;
  39. };
  40. /// INTERNAL ONLY
  41. struct no_default_conversion {
  42. BOOST_STATIC_CONSTEXPR bool is_defined = false;
  43. };
  44. /// INTERNAL ONLY
  45. template<class BaseUnit>
  46. struct unscaled_get_default_conversion : no_default_conversion { };
  47. /// INTERNAL ONLY
  48. template<bool is_defined>
  49. struct unscaled_get_default_conversion_impl;
  50. /// INTERNAL ONLY
  51. template<>
  52. struct unscaled_get_default_conversion_impl<true>
  53. {
  54. template<class T>
  55. struct apply
  56. {
  57. typedef typename unscaled_get_default_conversion<typename unscale<T>::type>::type type;
  58. };
  59. };
  60. /// INTERNAL ONLY
  61. template<>
  62. struct unscaled_get_default_conversion_impl<false>
  63. {
  64. template<class T>
  65. struct apply
  66. {
  67. typedef typename T::unit_type type;
  68. };
  69. };
  70. /// INTERNAL ONLY
  71. template<class BaseUnit>
  72. struct get_default_conversion
  73. {
  74. typedef typename unscaled_get_default_conversion_impl<
  75. unscaled_get_default_conversion<typename unscale<BaseUnit>::type>::is_defined
  76. >::template apply<BaseUnit>::type type;
  77. };
  78. /// INTERNAL ONLY
  79. template<class Source, class Destination>
  80. struct select_base_unit_converter
  81. {
  82. typedef Source source_type;
  83. typedef Destination destination_type;
  84. };
  85. /// INTERNAL ONLY
  86. template<class Source, class Dest>
  87. struct base_unit_converter_base : undefined_base_unit_converter_base {
  88. };
  89. /// INTERNAL ONLY
  90. template<class Source>
  91. struct base_unit_converter_base<Source, BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Source, typename Source::dimension_type)>
  92. {
  93. BOOST_STATIC_CONSTEXPR bool is_defined = true;
  94. typedef one type;
  95. static BOOST_CONSTEXPR type value() {
  96. return(one());
  97. }
  98. };
  99. /// INTERNAL ONLY
  100. template<class Source, class Dest>
  101. struct base_unit_converter : base_unit_converter_base<Source, Dest> { };
  102. namespace detail {
  103. template<class Source, class Dest>
  104. struct do_call_base_unit_converter {
  105. typedef select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type> selector;
  106. typedef typename selector::source_type source_type;
  107. typedef typename selector::destination_type destination_type;
  108. typedef base_unit_converter<source_type, destination_type> converter;
  109. typedef typename mpl::divides<typename get_scale_list<Source>::type, typename get_scale_list<source_type>::type>::type source_factor;
  110. typedef typename mpl::divides<typename get_scale_list<Dest>::type, typename get_scale_list<destination_type>::type>::type destination_factor;
  111. typedef typename mpl::divides<source_factor, destination_factor>::type factor;
  112. typedef eval_scale_list<factor> eval_factor;
  113. typedef typename multiply_typeof_helper<typename converter::type, typename eval_factor::type>::type type;
  114. static BOOST_CONSTEXPR type value()
  115. {
  116. return(converter::value() * eval_factor::value());
  117. }
  118. };
  119. template<bool forward_is_defined, bool reverse_is_defined>
  120. struct call_base_unit_converter_base_unit_impl;
  121. template<>
  122. struct call_base_unit_converter_base_unit_impl<true, true>
  123. {
  124. template<class Source, class Dest>
  125. struct apply
  126. : do_call_base_unit_converter<Source, typename Dest::unit_type>
  127. {
  128. };
  129. };
  130. template<>
  131. struct call_base_unit_converter_base_unit_impl<true, false>
  132. {
  133. template<class Source, class Dest>
  134. struct apply
  135. : do_call_base_unit_converter<Source, typename Dest::unit_type>
  136. {
  137. };
  138. };
  139. template<>
  140. struct call_base_unit_converter_base_unit_impl<false, true>
  141. {
  142. template<class Source, class Dest>
  143. struct apply
  144. {
  145. typedef do_call_base_unit_converter<Dest, typename Source::unit_type> converter;
  146. typedef typename divide_typeof_helper<one, typename converter::type>::type type;
  147. static BOOST_CONSTEXPR type value() {
  148. return(one() / converter::value());
  149. }
  150. };
  151. };
  152. template<>
  153. struct call_base_unit_converter_base_unit_impl<false, false>
  154. {
  155. template<class Source, class Dest>
  156. struct apply
  157. {
  158. typedef typename reduce_unit<typename get_default_conversion<Source>::type>::type new_source;
  159. typedef typename reduce_unit<typename get_default_conversion<Dest>::type>::type new_dest;
  160. typedef call_base_unit_converter<Source, new_source> start;
  161. typedef detail::conversion_factor_helper<
  162. new_source,
  163. new_dest
  164. > conversion;
  165. typedef call_base_unit_converter<Dest, new_dest> end;
  166. typedef typename divide_typeof_helper<
  167. typename multiply_typeof_helper<
  168. typename start::type,
  169. typename conversion::type
  170. >::type,
  171. typename end::type
  172. >::type type;
  173. static BOOST_CONSTEXPR type value() {
  174. return(start::value() * conversion::value() / end::value());
  175. }
  176. };
  177. };
  178. template<int N>
  179. struct get_default_conversion_impl
  180. {
  181. template<class Begin>
  182. struct apply
  183. {
  184. typedef typename Begin::item source_pair;
  185. typedef typename source_pair::value_type exponent;
  186. typedef typename source_pair::tag_type source;
  187. typedef typename reduce_unit<typename get_default_conversion<source>::type>::type new_source;
  188. typedef typename get_default_conversion_impl<N-1>::template apply<typename Begin::next> next_iteration;
  189. typedef typename multiply_typeof_helper<typename power_typeof_helper<new_source, exponent>::type, typename next_iteration::unit_type>::type unit_type;
  190. typedef call_base_unit_converter<source, new_source> conversion;
  191. typedef typename multiply_typeof_helper<typename conversion::type, typename next_iteration::type>::type type;
  192. static BOOST_CONSTEXPR type value() {
  193. return(static_rational_power<exponent>(conversion::value()) * next_iteration::value());
  194. }
  195. };
  196. };
  197. template<>
  198. struct get_default_conversion_impl<0>
  199. {
  200. template<class Begin>
  201. struct apply
  202. {
  203. typedef unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, no_scale> > > unit_type;
  204. typedef one type;
  205. static BOOST_CONSTEXPR one value() {
  206. return(one());
  207. }
  208. };
  209. };
  210. template<bool is_defined>
  211. struct call_base_unit_converter_impl;
  212. template<>
  213. struct call_base_unit_converter_impl<true>
  214. {
  215. template<class Source, class Dest>
  216. struct apply
  217. : do_call_base_unit_converter<Source, Dest>
  218. {
  219. };
  220. };
  221. template<>
  222. struct call_base_unit_converter_impl<false>
  223. {
  224. template<class Source, class Dest>
  225. struct apply {
  226. typedef typename reduce_unit<typename get_default_conversion<Source>::type>::type new_source;
  227. typedef typename Dest::system_type::type system_list;
  228. typedef typename get_default_conversion_impl<system_list::size::value>::template apply<system_list> impl;
  229. typedef typename impl::unit_type new_dest;
  230. typedef call_base_unit_converter<Source, new_source> start;
  231. typedef conversion_factor_helper<new_source, new_dest> conversion;
  232. typedef typename divide_typeof_helper<
  233. typename multiply_typeof_helper<
  234. typename start::type,
  235. typename conversion::type
  236. >::type,
  237. typename impl::type
  238. >::type type;
  239. static BOOST_CONSTEXPR type value() {
  240. return(start::value() * conversion::value() / impl::value());
  241. }
  242. };
  243. };
  244. #define BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, Dest)\
  245. base_unit_converter<\
  246. typename select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type>::source_type,\
  247. typename select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type>::destination_type\
  248. >::is_defined
  249. template<class Source, class Dest>
  250. struct call_base_unit_converter : call_base_unit_converter_impl<BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, Dest)>::template apply<Source, Dest>
  251. {
  252. };
  253. template<class Source, class Dest>
  254. struct call_base_unit_converter<Source, BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Dest, typename Source::dimension_type)> :
  255. call_base_unit_converter_base_unit_impl<
  256. BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, typename Dest::unit_type),
  257. BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Dest, typename Source::unit_type)
  258. >::template apply<Source, Dest>
  259. {
  260. };
  261. template<int N>
  262. struct conversion_impl
  263. {
  264. template<class Begin, class DestinationSystem>
  265. struct apply
  266. {
  267. typedef typename conversion_impl<N-1>::template apply<
  268. typename Begin::next,
  269. DestinationSystem
  270. > next_iteration;
  271. typedef typename Begin::item unit_pair;
  272. typedef typename unit_pair::tag_type unit;
  273. typedef typename unit::dimension_type dimensions;
  274. typedef typename reduce_unit<units::unit<dimensions, DestinationSystem> >::type reduced_unit;
  275. typedef detail::call_base_unit_converter<unit, reduced_unit> converter;
  276. typedef typename multiply_typeof_helper<typename converter::type, typename next_iteration::type>::type type;
  277. static BOOST_CONSTEXPR type value() { return(static_rational_power<typename unit_pair::value_type>(converter::value()) * next_iteration::value()); }
  278. };
  279. };
  280. template<>
  281. struct conversion_impl<0>
  282. {
  283. template<class Begin, class DestinationSystem>
  284. struct apply
  285. {
  286. typedef one type;
  287. static BOOST_CONSTEXPR type value() { return(one()); }
  288. };
  289. };
  290. } // namespace detail
  291. /// forward to conversion_factor (intentionally allowing ADL)
  292. /// INTERNAL ONLY
  293. template<class Unit1, class T1, class Unit2, class T2>
  294. struct conversion_helper<quantity<Unit1, T1>, quantity<Unit2, T2> >
  295. {
  296. /// INTERNAL ONLY
  297. typedef quantity<Unit2, T2> destination_type;
  298. static BOOST_CONSTEXPR destination_type convert(const quantity<Unit1, T1>& source)
  299. {
  300. return(destination_type::from_value(static_cast<T2>(source.value() * conversion_factor(Unit1(), Unit2()))));
  301. }
  302. };
  303. namespace detail {
  304. template<class Source, class Dest>
  305. struct conversion_factor_helper;
  306. template<class D, class L1, class L2>
  307. struct conversion_factor_helper<unit<D, homogeneous_system<L1> >, unit<D, homogeneous_system<L2> > >
  308. : conversion_factor_helper<
  309. typename reduce_unit<unit<D, homogeneous_system<L1> > >::type,
  310. typename reduce_unit<unit<D, homogeneous_system<L2> > >::type
  311. >
  312. {
  313. //typedef typename reduce_unit<unit<D, homogeneous_system<L1> > >::type source_unit;
  314. //typedef typename source_unit::system_type::type unit_list;
  315. //typedef typename detail::conversion_impl<unit_list::size::value>::template apply<
  316. // unit_list,
  317. // homogeneous_system<L2>
  318. //> impl;
  319. //typedef typename impl::type type;
  320. //static BOOST_CONSTEXPR type value()
  321. //{
  322. // return(impl::value());
  323. //}
  324. };
  325. template<class D, class L1, class L2>
  326. struct conversion_factor_helper<unit<D, heterogeneous_system<L1> >, unit<D, homogeneous_system<L2> > >
  327. : conversion_factor_helper<
  328. typename reduce_unit<unit<D, heterogeneous_system<L1> > >::type,
  329. typename reduce_unit<unit<D, homogeneous_system<L2> > >::type
  330. >
  331. {
  332. //typedef typename detail::conversion_impl<L1::type::size::value>::template apply<
  333. // typename L1::type,
  334. // homogeneous_system<L2>
  335. //> impl;
  336. //typedef eval_scale_list<typename L1::scale> scale;
  337. //typedef typename multiply_typeof_helper<typename impl::type, typename scale::type>::type type;
  338. //static BOOST_CONSTEXPR type value()
  339. //{
  340. // return(impl::value() * scale::value());
  341. //}
  342. };
  343. // There is no simple algorithm for doing this conversion
  344. // other than just defining it as the reverse of the
  345. // heterogeneous->homogeneous case
  346. template<class D, class L1, class L2>
  347. struct conversion_factor_helper<unit<D, homogeneous_system<L1> >, unit<D, heterogeneous_system<L2> > >
  348. : conversion_factor_helper<
  349. typename reduce_unit<unit<D, homogeneous_system<L1> > >::type,
  350. typename reduce_unit<unit<D, heterogeneous_system<L2> > >::type
  351. >
  352. {
  353. //typedef typename detail::conversion_impl<L2::type::size::value>::template apply<
  354. // typename L2::type,
  355. // homogeneous_system<L1>
  356. //> impl;
  357. //typedef eval_scale_list<typename L2::scale> scale;
  358. //typedef typename multiply_typeof_helper<typename impl::type, typename scale::type>::type type;
  359. //static BOOST_CONSTEXPR type value()
  360. //{
  361. // return(one() / (impl::value() * scale::value()));
  362. //}
  363. };
  364. /// Requires that all possible conversions
  365. /// between base units are defined.
  366. template<class D, class S1, class S2>
  367. struct conversion_factor_helper<unit<D, heterogeneous_system<S1> >, unit<D, heterogeneous_system<S2> > >
  368. {
  369. /// INTERNAL ONLY
  370. typedef typename detail::extract_base_units<S1::type::size::value>::template apply<
  371. typename S1::type,
  372. dimensionless_type
  373. >::type from_base_units;
  374. /// INTERNAL ONLY
  375. typedef typename detail::extract_base_units<S2::type::size::value>::template apply<
  376. typename S2::type,
  377. from_base_units
  378. >::type all_base_units;
  379. /// INTERNAL ONLY
  380. typedef typename detail::make_homogeneous_system<all_base_units>::type system;
  381. typedef typename detail::conversion_impl<S1::type::size::value>::template apply<
  382. typename S1::type,
  383. system
  384. > conversion1;
  385. typedef typename detail::conversion_impl<S2::type::size::value>::template apply<
  386. typename S2::type,
  387. system
  388. > conversion2;
  389. typedef eval_scale_list<typename mpl::divides<typename S1::scale, typename S2::scale>::type> scale;
  390. typedef typename multiply_typeof_helper<
  391. typename conversion1::type,
  392. typename divide_typeof_helper<typename scale::type, typename conversion2::type>::type
  393. >::type type;
  394. static BOOST_CONSTEXPR type value()
  395. {
  396. return(conversion1::value() * (scale::value() / conversion2::value()));
  397. }
  398. };
  399. } // namespace detail
  400. } // namespace units
  401. } // namespace boost
  402. #endif // BOOST_UNITS_CONVERSION_IMPL_HPP