heterogeneous_system.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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_HETEROGENEOUS_SYSTEM_HPP
  11. #define BOOST_UNITS_HETEROGENEOUS_SYSTEM_HPP
  12. /// \file
  13. /// \brief A heterogeneous system is a sorted list of base unit/exponent pairs.
  14. #include <boost/mpl/bool.hpp>
  15. #include <boost/mpl/plus.hpp>
  16. #include <boost/mpl/times.hpp>
  17. #include <boost/mpl/divides.hpp>
  18. #include <boost/mpl/negate.hpp>
  19. #include <boost/mpl/less.hpp>
  20. #include <boost/mpl/size.hpp>
  21. #include <boost/mpl/begin.hpp>
  22. #include <boost/mpl/next.hpp>
  23. #include <boost/mpl/deref.hpp>
  24. #include <boost/mpl/front.hpp>
  25. #include <boost/mpl/push_front.hpp>
  26. #include <boost/mpl/pop_front.hpp>
  27. #include <boost/mpl/assert.hpp>
  28. #include <boost/type_traits/is_same.hpp>
  29. #include <boost/units/config.hpp>
  30. #include <boost/units/static_rational.hpp>
  31. #include <boost/units/dimension.hpp>
  32. #include <boost/units/units_fwd.hpp>
  33. #include <boost/units/detail/push_front_if.hpp>
  34. #include <boost/units/detail/push_front_or_add.hpp>
  35. #include <boost/units/detail/linear_algebra.hpp>
  36. #include <boost/units/detail/unscale.hpp>
  37. namespace boost {
  38. namespace units {
  39. namespace detail {
  40. // A normal system is a sorted list of base units.
  41. // A heterogeneous system is a sorted list of base unit/exponent pairs.
  42. // As long as we don't need to convert heterogeneous systems
  43. // directly everything is cool.
  44. template<class T>
  45. struct is_zero : mpl::false_ {};
  46. template<>
  47. struct is_zero<static_rational<0> > : mpl::true_ {};
  48. } // namespace detail
  49. /// INTERNAL ONLY
  50. template<class L, class Dimensions, class Scale>
  51. struct heterogeneous_system_impl
  52. {
  53. typedef L type;
  54. typedef Dimensions dimensions;
  55. typedef Scale scale;
  56. };
  57. /// INTERNAL ONLY
  58. typedef dimensionless_type no_scale;
  59. /// A system that can represent any possible combination
  60. /// of units at the expense of not preserving information
  61. /// about how it was created. Do not create specializations
  62. /// of this template directly. Instead use @c reduce_unit and
  63. /// @c base_unit<...>::unit_type.
  64. template<class T>
  65. struct heterogeneous_system : T {};
  66. /// INTERNAL ONLY
  67. struct heterogeneous_system_dim_tag {};
  68. /// INTERNAL ONLY
  69. template<class Unit, class Exponent>
  70. struct heterogeneous_system_dim
  71. {
  72. typedef heterogeneous_system_dim_tag tag;
  73. typedef heterogeneous_system_dim type;
  74. typedef Unit tag_type;
  75. typedef Exponent value_type;
  76. };
  77. /// INTERNAL ONLY
  78. #define BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(BaseUnit, Dimensions) \
  79. boost::units::unit< \
  80. Dimensions, \
  81. boost::units::heterogeneous_system< \
  82. boost::units::heterogeneous_system_impl< \
  83. boost::units::list< \
  84. boost::units::heterogeneous_system_dim< \
  85. BaseUnit, \
  86. boost::units::static_rational<1> \
  87. >, \
  88. boost::units::dimensionless_type \
  89. >, \
  90. Dimensions, \
  91. boost::units::no_scale \
  92. > \
  93. > \
  94. >
  95. } // namespace units
  96. } // namespace boost
  97. #if BOOST_UNITS_HAS_BOOST_TYPEOF
  98. #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
  99. BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::heterogeneous_system_impl, (class)(class)(class))
  100. BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::heterogeneous_system, (class))
  101. BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::heterogeneous_system_dim, (class)(class))
  102. #endif
  103. namespace boost {
  104. namespace mpl {
  105. /// INTERNAL ONLY
  106. template<>
  107. struct less_impl<boost::units::heterogeneous_system_dim_tag, boost::units::heterogeneous_system_dim_tag>
  108. {
  109. template<class T0, class T1>
  110. struct apply : mpl::less<typename T0::tag_type, typename T1::tag_type> {};
  111. };
  112. }
  113. namespace units {
  114. namespace detail {
  115. template<class Unit1, class Exponent1>
  116. struct is_empty_dim<heterogeneous_system_dim<Unit1,Exponent1> > : detail::is_zero<Exponent1> {};
  117. } // namespace detail
  118. } // namespace units
  119. namespace mpl {
  120. /// INTERNAL ONLY
  121. template<>
  122. struct plus_impl<boost::units::heterogeneous_system_dim_tag, boost::units::heterogeneous_system_dim_tag>
  123. {
  124. template<class T0, class T1>
  125. struct apply
  126. {
  127. typedef boost::units::heterogeneous_system_dim<
  128. typename T0::tag_type,
  129. typename mpl::plus<typename T0::value_type,typename T1::value_type>::type
  130. > type;
  131. };
  132. };
  133. /// INTERNAL ONLY
  134. template<>
  135. struct times_impl<boost::units::heterogeneous_system_dim_tag, boost::units::detail::static_rational_tag>
  136. {
  137. template<class T0, class T1>
  138. struct apply
  139. {
  140. typedef boost::units::heterogeneous_system_dim<
  141. typename T0::tag_type,
  142. typename mpl::times<typename T0::value_type,T1>::type
  143. > type;
  144. };
  145. };
  146. /// INTERNAL ONLY
  147. template<>
  148. struct divides_impl<boost::units::heterogeneous_system_dim_tag, boost::units::detail::static_rational_tag>
  149. {
  150. template<class T0, class T1>
  151. struct apply
  152. {
  153. typedef boost::units::heterogeneous_system_dim<
  154. typename T0::tag_type,
  155. typename mpl::divides<typename T0::value_type,T1>::type
  156. > type;
  157. };
  158. };
  159. /// INTERNAL ONLY
  160. template<>
  161. struct negate_impl<boost::units::heterogeneous_system_dim_tag>
  162. {
  163. template<class T>
  164. struct apply
  165. {
  166. typedef boost::units::heterogeneous_system_dim<typename T::tag_type, typename mpl::negate<typename T::value_type>::type> type;
  167. };
  168. };
  169. } // namespace mpl
  170. namespace units {
  171. namespace detail {
  172. template<int N>
  173. struct make_heterogeneous_system_impl
  174. {
  175. template<class UnitsBegin, class ExponentsBegin>
  176. struct apply
  177. {
  178. typedef typename push_front_if<!(is_zero<typename ExponentsBegin::item>::value)>::template apply<
  179. typename make_heterogeneous_system_impl<N-1>::template apply<
  180. typename UnitsBegin::next,
  181. typename ExponentsBegin::next
  182. >::type,
  183. heterogeneous_system_dim<typename UnitsBegin::item, typename ExponentsBegin::item>
  184. >::type type;
  185. };
  186. };
  187. template<>
  188. struct make_heterogeneous_system_impl<0>
  189. {
  190. template<class UnitsBegin, class ExponentsBegin>
  191. struct apply
  192. {
  193. typedef dimensionless_type type;
  194. };
  195. };
  196. template<class Dimensions, class System>
  197. struct make_heterogeneous_system
  198. {
  199. typedef typename calculate_base_unit_exponents<typename System::type, Dimensions>::type exponents;
  200. BOOST_MPL_ASSERT_MSG((!boost::is_same<exponents, inconsistent>::value), the_specified_dimension_is_not_representible_in_the_given_system, (types<Dimensions, System>));
  201. typedef typename make_heterogeneous_system_impl<System::type::size::value>::template apply<
  202. typename System::type,
  203. exponents
  204. >::type unit_list;
  205. typedef heterogeneous_system<heterogeneous_system_impl<unit_list, Dimensions, no_scale> > type;
  206. };
  207. template<class Dimensions, class T>
  208. struct make_heterogeneous_system<Dimensions, heterogeneous_system<T> >
  209. {
  210. typedef heterogeneous_system<T> type;
  211. };
  212. template<class T0, class T1>
  213. struct multiply_systems
  214. {
  215. typedef heterogeneous_system<
  216. heterogeneous_system_impl<
  217. typename mpl::times<typename T0::type, typename T1::type>::type,
  218. typename mpl::times<typename T0::dimensions, typename T1::dimensions>::type,
  219. typename mpl::times<typename T0::scale, typename T1::scale>::type
  220. >
  221. > type;
  222. };
  223. template<class T0, class T1>
  224. struct divide_systems
  225. {
  226. typedef heterogeneous_system<
  227. heterogeneous_system_impl<
  228. typename mpl::divides<typename T0::type, typename T1::type>::type,
  229. typename mpl::divides<typename T0::dimensions, typename T1::dimensions>::type,
  230. typename mpl::divides<typename T0::scale, typename T1::scale>::type
  231. >
  232. > type;
  233. };
  234. } // namespace detail
  235. /// INTERNAL ONLY
  236. template<class S, long N, long D>
  237. struct static_power<heterogeneous_system<S>, static_rational<N,D> >
  238. {
  239. typedef heterogeneous_system<
  240. heterogeneous_system_impl<
  241. typename static_power<typename S::type, static_rational<N,D> >::type,
  242. typename static_power<typename S::dimensions, static_rational<N,D> >::type,
  243. typename static_power<typename S::scale, static_rational<N,D> >::type
  244. >
  245. > type;
  246. };
  247. /// INTERNAL ONLY
  248. template<class S, long N, long D>
  249. struct static_root<heterogeneous_system<S>, static_rational<N,D> >
  250. {
  251. typedef heterogeneous_system<
  252. heterogeneous_system_impl<
  253. typename static_root<typename S::type, static_rational<N,D> >::type,
  254. typename static_root<typename S::dimensions, static_rational<N,D> >::type,
  255. typename static_root<typename S::scale, static_rational<N,D> >::type
  256. >
  257. > type;
  258. };
  259. namespace detail {
  260. template<int N>
  261. struct unscale_heterogeneous_system_impl
  262. {
  263. template<class Begin>
  264. struct apply
  265. {
  266. typedef typename push_front_or_add<
  267. typename unscale_heterogeneous_system_impl<N-1>::template apply<
  268. typename Begin::next
  269. >::type,
  270. typename unscale<typename Begin::item>::type
  271. >::type type;
  272. };
  273. };
  274. template<>
  275. struct unscale_heterogeneous_system_impl<0>
  276. {
  277. template<class Begin>
  278. struct apply
  279. {
  280. typedef dimensionless_type type;
  281. };
  282. };
  283. } // namespace detail
  284. /// Unscale all the base units. e.g
  285. /// km s -> m s
  286. /// cm km -> m^2
  287. /// INTERNAL ONLY
  288. template<class T>
  289. struct unscale<heterogeneous_system<T> >
  290. {
  291. typedef heterogeneous_system<
  292. heterogeneous_system_impl<
  293. typename detail::unscale_heterogeneous_system_impl<
  294. T::type::size::value
  295. >::template apply<
  296. typename T::type
  297. >::type,
  298. typename T::dimensions,
  299. no_scale
  300. >
  301. > type;
  302. };
  303. /// INTERNAL ONLY
  304. template<class Unit, class Exponent>
  305. struct unscale<heterogeneous_system_dim<Unit, Exponent> >
  306. {
  307. typedef heterogeneous_system_dim<typename unscale<Unit>::type, Exponent> type;
  308. };
  309. namespace detail {
  310. template<int N>
  311. struct get_scale_list_of_heterogeneous_system_impl
  312. {
  313. template<class Begin>
  314. struct apply
  315. {
  316. typedef typename mpl::times<
  317. typename get_scale_list_of_heterogeneous_system_impl<N-1>::template apply<
  318. typename Begin::next
  319. >::type,
  320. typename get_scale_list<typename Begin::item>::type
  321. >::type type;
  322. };
  323. };
  324. template<>
  325. struct get_scale_list_of_heterogeneous_system_impl<0>
  326. {
  327. template<class Begin>
  328. struct apply
  329. {
  330. typedef dimensionless_type type;
  331. };
  332. };
  333. } // namespace detail
  334. /// INTERNAL ONLY
  335. template<class T>
  336. struct get_scale_list<heterogeneous_system<T> >
  337. {
  338. typedef typename mpl::times<
  339. typename detail::get_scale_list_of_heterogeneous_system_impl<
  340. T::type::size::value
  341. >::template apply<typename T::type>::type,
  342. typename T::scale
  343. >::type type;
  344. };
  345. /// INTERNAL ONLY
  346. template<class Unit, class Exponent>
  347. struct get_scale_list<heterogeneous_system_dim<Unit, Exponent> >
  348. {
  349. typedef typename static_power<typename get_scale_list<Unit>::type, Exponent>::type type;
  350. };
  351. namespace detail {
  352. template<class System, class Dimension>
  353. struct check_system : mpl::false_ {};
  354. template<class System, class Dimension, class Scale>
  355. struct check_system<heterogeneous_system<heterogeneous_system_impl<System, Dimension, Scale> >, Dimension> : mpl::true_ {};
  356. } // namespace detail
  357. } // namespace units
  358. } // namespace boost
  359. #endif