]>
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 { | |
49 | static const bool is_defined = false; | |
50 | }; | |
51 | ||
52 | /// INTERNAL ONLY | |
53 | struct no_default_conversion { | |
54 | static const 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 | static const bool is_defined = true; | |
114 | typedef one type; | |
115 | static type value() { | |
116 | one result; | |
117 | return(result); | |
118 | } | |
119 | }; | |
120 | ||
121 | /// INTERNAL ONLY | |
122 | template<class Source, class Dest> | |
123 | struct base_unit_converter : base_unit_converter_base<Source, Dest> { }; | |
124 | ||
125 | namespace detail { | |
126 | ||
127 | template<class Source, class Dest> | |
128 | struct do_call_base_unit_converter { | |
129 | typedef select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type> selector; | |
130 | typedef typename selector::source_type source_type; | |
131 | typedef typename selector::destination_type destination_type; | |
132 | typedef base_unit_converter<source_type, destination_type> converter; | |
133 | typedef typename mpl::divides<typename get_scale_list<Source>::type, typename get_scale_list<source_type>::type>::type source_factor; | |
134 | typedef typename mpl::divides<typename get_scale_list<Dest>::type, typename get_scale_list<destination_type>::type>::type destination_factor; | |
135 | typedef typename mpl::divides<source_factor, destination_factor>::type factor; | |
136 | typedef eval_scale_list<factor> eval_factor; | |
137 | typedef typename multiply_typeof_helper<typename converter::type, typename eval_factor::type>::type type; | |
138 | static type value() | |
139 | { | |
140 | return(converter::value() * eval_factor::value()); | |
141 | } | |
142 | }; | |
143 | ||
144 | template<bool forward_is_defined, bool reverse_is_defined> | |
145 | struct call_base_unit_converter_base_unit_impl; | |
146 | ||
147 | template<> | |
148 | struct call_base_unit_converter_base_unit_impl<true, true> | |
149 | { | |
150 | template<class Source, class Dest> | |
151 | struct apply | |
152 | : do_call_base_unit_converter<Source, typename Dest::unit_type> | |
153 | { | |
154 | }; | |
155 | }; | |
156 | ||
157 | template<> | |
158 | struct call_base_unit_converter_base_unit_impl<true, false> | |
159 | { | |
160 | template<class Source, class Dest> | |
161 | struct apply | |
162 | : do_call_base_unit_converter<Source, typename Dest::unit_type> | |
163 | { | |
164 | }; | |
165 | }; | |
166 | ||
167 | template<> | |
168 | struct call_base_unit_converter_base_unit_impl<false, true> | |
169 | { | |
170 | template<class Source, class Dest> | |
171 | struct apply | |
172 | { | |
173 | typedef do_call_base_unit_converter<Dest, typename Source::unit_type> converter; | |
174 | typedef typename divide_typeof_helper<one, typename converter::type>::type type; | |
175 | static type value() { | |
176 | one numerator; | |
177 | return(numerator / converter::value()); | |
178 | } | |
179 | }; | |
180 | }; | |
181 | ||
182 | template<> | |
183 | struct call_base_unit_converter_base_unit_impl<false, false> | |
184 | { | |
185 | template<class Source, class Dest> | |
186 | struct apply | |
187 | { | |
188 | typedef typename reduce_unit<typename get_default_conversion<Source>::type>::type new_source; | |
189 | typedef typename reduce_unit<typename get_default_conversion<Dest>::type>::type new_dest; | |
190 | typedef call_base_unit_converter<Source, new_source> start; | |
191 | typedef detail::conversion_factor_helper< | |
192 | new_source, | |
193 | new_dest | |
194 | > conversion; | |
195 | typedef call_base_unit_converter<Dest, new_dest> end; | |
196 | typedef typename divide_typeof_helper< | |
197 | typename multiply_typeof_helper< | |
198 | typename start::type, | |
199 | typename conversion::type | |
200 | >::type, | |
201 | typename end::type | |
202 | >::type type; | |
203 | static type value() { | |
204 | return(start::value() * conversion::value() / end::value()); | |
205 | } | |
206 | }; | |
207 | }; | |
208 | ||
209 | template<int N> | |
210 | struct get_default_conversion_impl | |
211 | { | |
212 | template<class Begin> | |
213 | struct apply | |
214 | { | |
215 | typedef typename Begin::item source_pair; | |
216 | typedef typename source_pair::value_type exponent; | |
217 | typedef typename source_pair::tag_type source; | |
218 | typedef typename reduce_unit<typename get_default_conversion<source>::type>::type new_source; | |
219 | typedef typename get_default_conversion_impl<N-1>::template apply<typename Begin::next> next_iteration; | |
220 | typedef typename multiply_typeof_helper<typename power_typeof_helper<new_source, exponent>::type, typename next_iteration::unit_type>::type unit_type; | |
221 | typedef call_base_unit_converter<source, new_source> conversion; | |
222 | typedef typename multiply_typeof_helper<typename conversion::type, typename next_iteration::type>::type type; | |
223 | static type value() { | |
224 | return(static_rational_power<exponent>(conversion::value()) * next_iteration::value()); | |
225 | } | |
226 | }; | |
227 | }; | |
228 | ||
229 | template<> | |
230 | struct get_default_conversion_impl<0> | |
231 | { | |
232 | template<class Begin> | |
233 | struct apply | |
234 | { | |
235 | typedef unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, no_scale> > > unit_type; | |
236 | typedef one type; | |
237 | static one value() { | |
238 | one result; | |
239 | return(result); | |
240 | } | |
241 | }; | |
242 | }; | |
243 | ||
244 | template<bool is_defined> | |
245 | struct call_base_unit_converter_impl; | |
246 | ||
247 | template<> | |
248 | struct call_base_unit_converter_impl<true> | |
249 | { | |
250 | template<class Source, class Dest> | |
251 | struct apply | |
252 | : do_call_base_unit_converter<Source, Dest> | |
253 | { | |
254 | }; | |
255 | }; | |
256 | ||
257 | template<> | |
258 | struct call_base_unit_converter_impl<false> | |
259 | { | |
260 | template<class Source, class Dest> | |
261 | struct apply { | |
262 | typedef typename reduce_unit<typename get_default_conversion<Source>::type>::type new_source; | |
263 | typedef typename Dest::system_type::type system_list; | |
264 | typedef typename get_default_conversion_impl<system_list::size::value>::template apply<system_list> impl; | |
265 | typedef typename impl::unit_type new_dest; | |
266 | typedef call_base_unit_converter<Source, new_source> start; | |
267 | typedef conversion_factor_helper<new_source, new_dest> conversion; | |
268 | typedef typename divide_typeof_helper< | |
269 | typename multiply_typeof_helper< | |
270 | typename start::type, | |
271 | typename conversion::type | |
272 | >::type, | |
273 | typename impl::type | |
274 | >::type type; | |
275 | static type value() { | |
276 | return(start::value() * conversion::value() / impl::value()); | |
277 | } | |
278 | }; | |
279 | }; | |
280 | ||
281 | #define BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, Dest)\ | |
282 | base_unit_converter<\ | |
283 | typename select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type>::source_type,\ | |
284 | typename select_base_unit_converter<typename unscale<Source>::type, typename unscale<Dest>::type>::destination_type\ | |
285 | >::is_defined | |
286 | ||
287 | template<class Source, class Dest> | |
288 | struct call_base_unit_converter : call_base_unit_converter_impl<BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, Dest)>::template apply<Source, Dest> | |
289 | { | |
290 | }; | |
291 | ||
292 | template<class Source, class Dest> | |
293 | struct call_base_unit_converter<Source, BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Dest, typename Source::dimension_type)> : | |
294 | call_base_unit_converter_base_unit_impl< | |
295 | BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Source, typename Dest::unit_type), | |
296 | BOOST_UNITS_DETAIL_BASE_UNIT_CONVERTER_IS_DEFINED(Dest, typename Source::unit_type) | |
297 | >::template apply<Source, Dest> | |
298 | { | |
299 | }; | |
300 | ||
301 | template<int N> | |
302 | struct conversion_impl | |
303 | { | |
304 | template<class Begin, class DestinationSystem> | |
305 | struct apply | |
306 | { | |
307 | typedef typename conversion_impl<N-1>::template apply< | |
308 | typename Begin::next, | |
309 | DestinationSystem | |
310 | > next_iteration; | |
311 | typedef typename Begin::item unit_pair; | |
312 | typedef typename unit_pair::tag_type unit; | |
313 | typedef typename unit::dimension_type dimensions; | |
314 | typedef typename reduce_unit<units::unit<dimensions, DestinationSystem> >::type reduced_unit; | |
315 | typedef detail::call_base_unit_converter<unit, reduced_unit> converter; | |
316 | typedef typename multiply_typeof_helper<typename converter::type, typename next_iteration::type>::type type; | |
317 | static type value() { return(static_rational_power<typename unit_pair::value_type>(converter::value()) * next_iteration::value()); } | |
318 | }; | |
319 | }; | |
320 | ||
321 | template<> | |
322 | struct conversion_impl<0> | |
323 | { | |
324 | template<class Begin, class DestinationSystem> | |
325 | struct apply | |
326 | { | |
327 | typedef one type; | |
328 | static type value() { one result; return(result); } | |
329 | }; | |
330 | }; | |
331 | ||
332 | } // namespace detail | |
333 | ||
334 | /// forward to conversion_factor (intentionally allowing ADL) | |
335 | /// INTERNAL ONLY | |
336 | template<class Unit1, class T1, class Unit2, class T2> | |
337 | struct conversion_helper<quantity<Unit1, T1>, quantity<Unit2, T2> > | |
338 | { | |
339 | /// INTERNAL ONLY | |
340 | typedef quantity<Unit2, T2> destination_type; | |
341 | static destination_type convert(const quantity<Unit1, T1>& source) | |
342 | { | |
343 | Unit1 u1; | |
344 | Unit2 u2; | |
345 | return(destination_type::from_value(static_cast<T2>(source.value() * conversion_factor(u1, u2)))); | |
346 | } | |
347 | }; | |
348 | ||
349 | namespace detail { | |
350 | ||
351 | template<class Source, class Dest> | |
352 | struct conversion_factor_helper; | |
353 | ||
354 | template<class D, class L1, class L2> | |
355 | struct conversion_factor_helper<unit<D, homogeneous_system<L1> >, unit<D, homogeneous_system<L2> > > | |
356 | : conversion_factor_helper< | |
357 | typename reduce_unit<unit<D, homogeneous_system<L1> > >::type, | |
358 | typename reduce_unit<unit<D, homogeneous_system<L2> > >::type | |
359 | > | |
360 | { | |
361 | //typedef typename reduce_unit<unit<D, homogeneous_system<L1> > >::type source_unit; | |
362 | //typedef typename source_unit::system_type::type unit_list; | |
363 | //typedef typename detail::conversion_impl<unit_list::size::value>::template apply< | |
364 | // unit_list, | |
365 | // homogeneous_system<L2> | |
366 | //> impl; | |
367 | //typedef typename impl::type type; | |
368 | //static type value() | |
369 | //{ | |
370 | // return(impl::value()); | |
371 | //} | |
372 | }; | |
373 | ||
374 | template<class D, class L1, class L2> | |
375 | struct conversion_factor_helper<unit<D, heterogeneous_system<L1> >, unit<D, homogeneous_system<L2> > > | |
376 | : conversion_factor_helper< | |
377 | typename reduce_unit<unit<D, heterogeneous_system<L1> > >::type, | |
378 | typename reduce_unit<unit<D, homogeneous_system<L2> > >::type | |
379 | > | |
380 | { | |
381 | //typedef typename detail::conversion_impl<L1::type::size::value>::template apply< | |
382 | // typename L1::type, | |
383 | // homogeneous_system<L2> | |
384 | //> impl; | |
385 | //typedef eval_scale_list<typename L1::scale> scale; | |
386 | //typedef typename multiply_typeof_helper<typename impl::type, typename scale::type>::type type; | |
387 | //static type value() | |
388 | //{ | |
389 | // return(impl::value() * scale::value()); | |
390 | //} | |
391 | }; | |
392 | ||
393 | // There is no simple algorithm for doing this conversion | |
394 | // other than just defining it as the reverse of the | |
395 | // heterogeneous->homogeneous case | |
396 | template<class D, class L1, class L2> | |
397 | struct conversion_factor_helper<unit<D, homogeneous_system<L1> >, unit<D, heterogeneous_system<L2> > > | |
398 | : conversion_factor_helper< | |
399 | typename reduce_unit<unit<D, homogeneous_system<L1> > >::type, | |
400 | typename reduce_unit<unit<D, heterogeneous_system<L2> > >::type | |
401 | > | |
402 | { | |
403 | //typedef typename detail::conversion_impl<L2::type::size::value>::template apply< | |
404 | // typename L2::type, | |
405 | // homogeneous_system<L1> | |
406 | //> impl; | |
407 | //typedef eval_scale_list<typename L2::scale> scale; | |
408 | //typedef typename multiply_typeof_helper<typename impl::type, typename scale::type>::type type; | |
409 | //static type value() | |
410 | //{ | |
411 | // one numerator; | |
412 | // return(numerator / (impl::value() * scale::value())); | |
413 | //} | |
414 | }; | |
415 | ||
416 | /// Requires that all possible conversions | |
417 | /// between base units are defined. | |
418 | template<class D, class S1, class S2> | |
419 | struct conversion_factor_helper<unit<D, heterogeneous_system<S1> >, unit<D, heterogeneous_system<S2> > > | |
420 | { | |
421 | /// INTERNAL ONLY | |
422 | typedef typename detail::extract_base_units<S1::type::size::value>::template apply< | |
423 | typename S1::type, | |
424 | dimensionless_type | |
425 | >::type from_base_units; | |
426 | /// INTERNAL ONLY | |
427 | typedef typename detail::extract_base_units<S2::type::size::value>::template apply< | |
428 | typename S2::type, | |
429 | from_base_units | |
430 | >::type all_base_units; | |
431 | /// INTERNAL ONLY | |
432 | typedef typename detail::make_homogeneous_system<all_base_units>::type system; | |
433 | typedef typename detail::conversion_impl<S1::type::size::value>::template apply< | |
434 | typename S1::type, | |
435 | system | |
436 | > conversion1; | |
437 | typedef typename detail::conversion_impl<S2::type::size::value>::template apply< | |
438 | typename S2::type, | |
439 | system | |
440 | > conversion2; | |
441 | typedef eval_scale_list<typename mpl::divides<typename S1::scale, typename S2::scale>::type> scale; | |
442 | typedef typename multiply_typeof_helper< | |
443 | typename conversion1::type, | |
444 | typename divide_typeof_helper<typename scale::type, typename conversion2::type>::type | |
445 | >::type type; | |
446 | static type value() | |
447 | { | |
448 | return(conversion1::value() * (scale::value() / conversion2::value())); | |
449 | } | |
450 | }; | |
451 | ||
452 | } // namespace detail | |
453 | ||
454 | } // namespace units | |
455 | ||
456 | } // namespace boost | |
457 | ||
458 | #endif // BOOST_UNITS_CONVERSION_IMPL_HPP |