]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 { | |
11fdf7f2 | 49 | BOOST_STATIC_CONSTEXPR bool is_defined = false; |
7c673cae FG |
50 | }; |
51 | ||
52 | /// INTERNAL ONLY | |
53 | struct no_default_conversion { | |
11fdf7f2 | 54 | BOOST_STATIC_CONSTEXPR bool is_defined = false; |
7c673cae FG |
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 | { | |
11fdf7f2 | 113 | BOOST_STATIC_CONSTEXPR bool is_defined = true; |
7c673cae | 114 | typedef one type; |
11fdf7f2 TL |
115 | static BOOST_CONSTEXPR type value() { |
116 | return(one()); | |
7c673cae FG |
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; | |
11fdf7f2 | 137 | static BOOST_CONSTEXPR type value() |
7c673cae FG |
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; | |
11fdf7f2 TL |
174 | static BOOST_CONSTEXPR type value() { |
175 | return(one() / converter::value()); | |
7c673cae FG |
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; | |
11fdf7f2 | 201 | static BOOST_CONSTEXPR type value() { |
7c673cae FG |
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; | |
11fdf7f2 | 221 | static BOOST_CONSTEXPR type value() { |
7c673cae FG |
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; | |
11fdf7f2 TL |
235 | static BOOST_CONSTEXPR one value() { |
236 | return(one()); | |
7c673cae FG |
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; | |
11fdf7f2 | 272 | static BOOST_CONSTEXPR type value() { |
7c673cae FG |
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; | |
11fdf7f2 | 314 | static BOOST_CONSTEXPR type value() { return(static_rational_power<typename unit_pair::value_type>(converter::value()) * next_iteration::value()); } |
7c673cae FG |
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; | |
11fdf7f2 | 325 | static BOOST_CONSTEXPR type value() { return(one()); } |
7c673cae FG |
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; | |
11fdf7f2 | 338 | static BOOST_CONSTEXPR destination_type convert(const quantity<Unit1, T1>& source) |
7c673cae | 339 | { |
11fdf7f2 | 340 | return(destination_type::from_value(static_cast<T2>(source.value() * conversion_factor(Unit1(), Unit2())))); |
7c673cae FG |
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; | |
11fdf7f2 | 363 | //static BOOST_CONSTEXPR type value() |
7c673cae FG |
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; | |
11fdf7f2 | 382 | //static BOOST_CONSTEXPR type value() |
7c673cae FG |
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; | |
11fdf7f2 | 404 | //static BOOST_CONSTEXPR type value() |
7c673cae | 405 | //{ |
11fdf7f2 | 406 | // return(one() / (impl::value() * scale::value())); |
7c673cae FG |
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; | |
11fdf7f2 | 440 | static BOOST_CONSTEXPR type value() |
7c673cae FG |
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 |