• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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