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