File indexing completed on 2025-01-18 09:53:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_UNITS_DETAIL_CONVERSION_IMPL_HPP
0012 #define BOOST_UNITS_DETAIL_CONVERSION_IMPL_HPP
0013
0014 #include <boost/mpl/bool.hpp>
0015 #include <boost/mpl/and.hpp>
0016 #include <boost/mpl/divides.hpp>
0017 #include <boost/preprocessor/seq/enum.hpp>
0018 #include <boost/type_traits/is_same.hpp>
0019
0020 #include <boost/units/heterogeneous_system.hpp>
0021 #include <boost/units/homogeneous_system.hpp>
0022 #include <boost/units/reduce_unit.hpp>
0023 #include <boost/units/static_rational.hpp>
0024 #include <boost/units/units_fwd.hpp>
0025 #include <boost/units/detail/dimension_list.hpp>
0026 #include <boost/units/detail/heterogeneous_conversion.hpp>
0027 #include <boost/units/detail/one.hpp>
0028 #include <boost/units/detail/static_rational_power.hpp>
0029 #include <boost/units/detail/unscale.hpp>
0030
0031 #include <boost/units/units_fwd.hpp>
0032
0033 namespace boost {
0034
0035 namespace units {
0036
0037 namespace detail {
0038
0039 template<class Source, class Dest>
0040 struct conversion_factor_helper;
0041
0042 template<class Source, class Dest>
0043 struct call_base_unit_converter;
0044
0045 }
0046
0047
0048 struct undefined_base_unit_converter_base {
0049 BOOST_STATIC_CONSTEXPR bool is_defined = false;
0050 };
0051
0052
0053 struct no_default_conversion {
0054 BOOST_STATIC_CONSTEXPR bool is_defined = false;
0055 };
0056
0057
0058 template<class BaseUnit>
0059 struct unscaled_get_default_conversion : no_default_conversion { };
0060
0061
0062 template<bool is_defined>
0063 struct unscaled_get_default_conversion_impl;
0064
0065
0066 template<>
0067 struct unscaled_get_default_conversion_impl<true>
0068 {
0069 template<class T>
0070 struct apply
0071 {
0072 typedef typename unscaled_get_default_conversion<typename unscale<T>::type>::type type;
0073 };
0074 };
0075
0076
0077 template<>
0078 struct unscaled_get_default_conversion_impl<false>
0079 {
0080 template<class T>
0081 struct apply
0082 {
0083 typedef typename T::unit_type type;
0084 };
0085 };
0086
0087
0088 template<class BaseUnit>
0089 struct get_default_conversion
0090 {
0091 typedef typename unscaled_get_default_conversion_impl<
0092 unscaled_get_default_conversion<typename unscale<BaseUnit>::type>::is_defined
0093 >::template apply<BaseUnit>::type type;
0094 };
0095
0096
0097 template<class Source, class Destination>
0098 struct select_base_unit_converter
0099 {
0100 typedef Source source_type;
0101 typedef Destination destination_type;
0102 };
0103
0104
0105 template<class Source, class Dest>
0106 struct base_unit_converter_base : undefined_base_unit_converter_base {
0107 };
0108
0109
0110 template<class Source>
0111 struct base_unit_converter_base<Source, BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Source, typename Source::dimension_type)>
0112 {
0113 BOOST_STATIC_CONSTEXPR bool is_defined = true;
0114 typedef one type;
0115 static BOOST_CONSTEXPR type value() {
0116 return(one());
0117 }
0118 };
0119
0120
0121 template<class Source, class Dest>
0122 struct base_unit_converter : base_unit_converter_base<Source, Dest> { };
0123
0124 namespace detail {
0125
0126 template<class Source, class Dest>
0127 struct do_call_base_unit_converter {
0128 typedef select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type> selector;
0129 typedef typename selector::source_type source_type;
0130 typedef typename selector::destination_type destination_type;
0131 typedef base_unit_converter<source_type, destination_type> converter;
0132 typedef typename mpl::divides<typename get_scale_list<Source>::type, typename get_scale_list<source_type>::type>::type source_factor;
0133 typedef typename mpl::divides<typename get_scale_list<Dest>::type, typename get_scale_list<destination_type>::type>::type destination_factor;
0134 typedef typename mpl::divides<source_factor, destination_factor>::type factor;
0135 typedef eval_scale_list<factor> eval_factor;
0136 typedef typename multiply_typeof_helper<typename converter::type, typename eval_factor::type>::type type;
0137 static BOOST_CONSTEXPR type value()
0138 {
0139 return(converter::value() * eval_factor::value());
0140 }
0141 };
0142
0143 template<bool forward_is_defined, bool reverse_is_defined>
0144 struct call_base_unit_converter_base_unit_impl;
0145
0146 template<>
0147 struct call_base_unit_converter_base_unit_impl<true, true>
0148 {
0149 template<class Source, class Dest>
0150 struct apply
0151 : do_call_base_unit_converter<Source, typename Dest::unit_type>
0152 {
0153 };
0154 };
0155
0156 template<>
0157 struct call_base_unit_converter_base_unit_impl<true, false>
0158 {
0159 template<class Source, class Dest>
0160 struct apply
0161 : do_call_base_unit_converter<Source, typename Dest::unit_type>
0162 {
0163 };
0164 };
0165
0166 template<>
0167 struct call_base_unit_converter_base_unit_impl<false, true>
0168 {
0169 template<class Source, class Dest>
0170 struct apply
0171 {
0172 typedef do_call_base_unit_converter<Dest, typename Source::unit_type> converter;
0173 typedef typename divide_typeof_helper<one, typename converter::type>::type type;
0174 static BOOST_CONSTEXPR type value() {
0175 return(one() / converter::value());
0176 }
0177 };
0178 };
0179
0180 template<>
0181 struct call_base_unit_converter_base_unit_impl<false, false>
0182 {
0183 template<class Source, class Dest>
0184 struct apply
0185 {
0186 typedef typename reduce_unit<typename get_default_conversion<Source>::type>::type new_source;
0187 typedef typename reduce_unit<typename get_default_conversion<Dest>::type>::type new_dest;
0188 typedef call_base_unit_converter<Source, new_source> start;
0189 typedef detail::conversion_factor_helper<
0190 new_source,
0191 new_dest
0192 > conversion;
0193 typedef call_base_unit_converter<Dest, new_dest> end;
0194 typedef typename divide_typeof_helper<
0195 typename multiply_typeof_helper<
0196 typename start::type,
0197 typename conversion::type
0198 >::type,
0199 typename end::type
0200 >::type type;
0201 static BOOST_CONSTEXPR type value() {
0202 return(start::value() * conversion::value() / end::value());
0203 }
0204 };
0205 };
0206
0207 template<int N>
0208 struct get_default_conversion_impl
0209 {
0210 template<class Begin>
0211 struct apply
0212 {
0213 typedef typename Begin::item source_pair;
0214 typedef typename source_pair::value_type exponent;
0215 typedef typename source_pair::tag_type source;
0216 typedef typename reduce_unit<typename get_default_conversion<source>::type>::type new_source;
0217 typedef typename get_default_conversion_impl<N-1>::template apply<typename Begin::next> next_iteration;
0218 typedef typename multiply_typeof_helper<typename power_typeof_helper<new_source, exponent>::type, typename next_iteration::unit_type>::type unit_type;
0219 typedef call_base_unit_converter<source, new_source> conversion;
0220 typedef typename multiply_typeof_helper<typename conversion::type, typename next_iteration::type>::type type;
0221 static BOOST_CONSTEXPR type value() {
0222 return(static_rational_power<exponent>(conversion::value()) * next_iteration::value());
0223 }
0224 };
0225 };
0226
0227 template<>
0228 struct get_default_conversion_impl<0>
0229 {
0230 template<class Begin>
0231 struct apply
0232 {
0233 typedef unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, no_scale> > > unit_type;
0234 typedef one type;
0235 static BOOST_CONSTEXPR one value() {
0236 return(one());
0237 }
0238 };
0239 };
0240
0241 template<bool is_defined>
0242 struct call_base_unit_converter_impl;
0243
0244 template<>
0245 struct call_base_unit_converter_impl<true>
0246 {
0247 template<class Source, class Dest>
0248 struct apply
0249 : do_call_base_unit_converter<Source, Dest>
0250 {
0251 };
0252 };
0253
0254 template<>
0255 struct call_base_unit_converter_impl<false>
0256 {
0257 template<class Source, class Dest>
0258 struct apply {
0259 typedef typename reduce_unit<typename get_default_conversion<Source>::type>::type new_source;
0260 typedef typename Dest::system_type::type system_list;
0261 typedef typename get_default_conversion_impl<system_list::size::value>::template apply<system_list> impl;
0262 typedef typename impl::unit_type new_dest;
0263 typedef call_base_unit_converter<Source, new_source> start;
0264 typedef conversion_factor_helper<new_source, new_dest> conversion;
0265 typedef typename divide_typeof_helper<
0266 typename multiply_typeof_helper<
0267 typename start::type,
0268 typename conversion::type
0269 >::type,
0270 typename impl::type
0271 >::type type;
0272 static BOOST_CONSTEXPR type value() {
0273 return(start::value() * conversion::value() / impl::value());
0274 }
0275 };
0276 };
0277
0278 #define BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, Dest)\
0279 base_unit_converter<\
0280 typename select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type>::source_type,\
0281 typename select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type>::destination_type\
0282 >::is_defined
0283
0284 template<class Source, class Dest>
0285 struct call_base_unit_converter : call_base_unit_converter_impl<BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, Dest)>::template apply<Source, Dest>
0286 {
0287 };
0288
0289 template<class Source, class Dest>
0290 struct call_base_unit_converter<Source, BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Dest, typename Source::dimension_type)> :
0291 call_base_unit_converter_base_unit_impl<
0292 BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, typename Dest::unit_type),
0293 BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Dest, typename Source::unit_type)
0294 >::template apply<Source, Dest>
0295 {
0296 };
0297
0298 template<int N>
0299 struct conversion_impl
0300 {
0301 template<class Begin, class DestinationSystem>
0302 struct apply
0303 {
0304 typedef typename conversion_impl<N-1>::template apply<
0305 typename Begin::next,
0306 DestinationSystem
0307 > next_iteration;
0308 typedef typename Begin::item unit_pair;
0309 typedef typename unit_pair::tag_type unit;
0310 typedef typename unit::dimension_type dimensions;
0311 typedef typename reduce_unit<units::unit<dimensions, DestinationSystem> >::type reduced_unit;
0312 typedef detail::call_base_unit_converter<unit, reduced_unit> converter;
0313 typedef typename multiply_typeof_helper<typename converter::type, typename next_iteration::type>::type type;
0314 static BOOST_CONSTEXPR type value() { return(static_rational_power<typename unit_pair::value_type>(converter::value()) * next_iteration::value()); }
0315 };
0316 };
0317
0318 template<>
0319 struct conversion_impl<0>
0320 {
0321 template<class Begin, class DestinationSystem>
0322 struct apply
0323 {
0324 typedef one type;
0325 static BOOST_CONSTEXPR type value() { return(one()); }
0326 };
0327 };
0328
0329 }
0330
0331
0332
0333 template<class Unit1, class T1, class Unit2, class T2>
0334 struct conversion_helper<quantity<Unit1, T1>, quantity<Unit2, T2> >
0335 {
0336
0337 typedef quantity<Unit2, T2> destination_type;
0338 static BOOST_CONSTEXPR destination_type convert(const quantity<Unit1, T1>& source)
0339 {
0340 return(destination_type::from_value(static_cast<T2>(source.value() * conversion_factor(Unit1(), Unit2()))));
0341 }
0342 };
0343
0344 namespace detail {
0345
0346 template<class Source, class Dest>
0347 struct conversion_factor_helper;
0348
0349 template<class D, class L1, class L2>
0350 struct conversion_factor_helper<unit<D, homogeneous_system<L1> >, unit<D, homogeneous_system<L2> > >
0351 : conversion_factor_helper<
0352 typename reduce_unit<unit<D, homogeneous_system<L1> > >::type,
0353 typename reduce_unit<unit<D, homogeneous_system<L2> > >::type
0354 >
0355 {
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367 };
0368
0369 template<class D, class L1, class L2>
0370 struct conversion_factor_helper<unit<D, heterogeneous_system<L1> >, unit<D, homogeneous_system<L2> > >
0371 : conversion_factor_helper<
0372 typename reduce_unit<unit<D, heterogeneous_system<L1> > >::type,
0373 typename reduce_unit<unit<D, homogeneous_system<L2> > >::type
0374 >
0375 {
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386 };
0387
0388
0389
0390
0391 template<class D, class L1, class L2>
0392 struct conversion_factor_helper<unit<D, homogeneous_system<L1> >, unit<D, heterogeneous_system<L2> > >
0393 : conversion_factor_helper<
0394 typename reduce_unit<unit<D, homogeneous_system<L1> > >::type,
0395 typename reduce_unit<unit<D, heterogeneous_system<L2> > >::type
0396 >
0397 {
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408 };
0409
0410
0411
0412 template<class D, class S1, class S2>
0413 struct conversion_factor_helper<unit<D, heterogeneous_system<S1> >, unit<D, heterogeneous_system<S2> > >
0414 {
0415
0416 typedef typename detail::extract_base_units<S1::type::size::value>::template apply<
0417 typename S1::type,
0418 dimensionless_type
0419 >::type from_base_units;
0420
0421 typedef typename detail::extract_base_units<S2::type::size::value>::template apply<
0422 typename S2::type,
0423 from_base_units
0424 >::type all_base_units;
0425
0426 typedef typename detail::make_homogeneous_system<all_base_units>::type system;
0427 typedef typename detail::conversion_impl<S1::type::size::value>::template apply<
0428 typename S1::type,
0429 system
0430 > conversion1;
0431 typedef typename detail::conversion_impl<S2::type::size::value>::template apply<
0432 typename S2::type,
0433 system
0434 > conversion2;
0435 typedef eval_scale_list<typename mpl::divides<typename S1::scale, typename S2::scale>::type> scale;
0436 typedef typename multiply_typeof_helper<
0437 typename conversion1::type,
0438 typename divide_typeof_helper<typename scale::type, typename conversion2::type>::type
0439 >::type type;
0440 static BOOST_CONSTEXPR type value()
0441 {
0442 return(conversion1::value() * (scale::value() / conversion2::value()));
0443 }
0444 };
0445
0446 }
0447
0448 }
0449
0450 }
0451
0452 #endif