1 // Boost.Units - A C++ library for zero-overhead dimensional analysis and
2 // unit/quantity manipulation and conversion
4 // Copyright (C) 2003-2008 Matthias Christian Schabel
5 // Copyright (C) 2007-2008 Steven Watanabe
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)
11 #ifndef BOOST_UNITS_HETEROGENEOUS_SYSTEM_HPP
12 #define BOOST_UNITS_HETEROGENEOUS_SYSTEM_HPP
14 #include <boost/mpl/bool.hpp>
15 #include <boost/mpl/plus.hpp>
16 #include <boost/mpl/times.hpp>
17 #include <boost/mpl/divides.hpp>
18 #include <boost/mpl/negate.hpp>
19 #include <boost/mpl/less.hpp>
20 #include <boost/mpl/size.hpp>
21 #include <boost/mpl/begin.hpp>
22 #include <boost/mpl/next.hpp>
23 #include <boost/mpl/deref.hpp>
24 #include <boost/mpl/front.hpp>
25 #include <boost/mpl/push_front.hpp>
26 #include <boost/mpl/pop_front.hpp>
27 #include <boost/mpl/assert.hpp>
28 #include <boost/type_traits/is_same.hpp>
30 #include <boost/units/config.hpp>
31 #include <boost/units/static_rational.hpp>
32 #include <boost/units/dimension.hpp>
33 #include <boost/units/units_fwd.hpp>
34 #include <boost/units/detail/push_front_if.hpp>
35 #include <boost/units/detail/push_front_or_add.hpp>
36 #include <boost/units/detail/linear_algebra.hpp>
37 #include <boost/units/detail/unscale.hpp>
45 // A normal system is a sorted list of base units.
46 // A heterogeneous system is a sorted list of base unit/exponent pairs.
47 // As long as we don't need to convert heterogeneous systems
48 // directly everything is cool
51 struct is_zero
: mpl::false_
{};
54 struct is_zero
<static_rational
<0> > : mpl::true_
{};
59 template<class L
, class Dimensions
, class Scale
>
60 struct heterogeneous_system_impl
63 typedef Dimensions dimensions
;
68 typedef dimensionless_type no_scale
;
70 /// A system that can represent any possible combination
71 /// of units at the expense of not preserving information
72 /// about how it was created. Do not create specializations
73 /// of this template directly. Instead use @c reduce_unit and
74 /// @c base_unit<...>::unit_type.
76 struct heterogeneous_system
: T
{};
79 struct heterogeneous_system_dim_tag
{};
82 template<class Unit
, class Exponent
>
83 struct heterogeneous_system_dim
85 typedef heterogeneous_system_dim_tag tag
;
86 typedef heterogeneous_system_dim type
;
87 typedef Unit tag_type
;
88 typedef Exponent value_type
;
92 #define BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(BaseUnit, Dimensions) \
95 boost::units::heterogeneous_system< \
96 boost::units::heterogeneous_system_impl< \
98 boost::units::heterogeneous_system_dim< \
100 boost::units::static_rational<1> \
102 boost::units::dimensionless_type \
105 boost::units::no_scale \
115 #if BOOST_UNITS_HAS_BOOST_TYPEOF
117 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
119 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::heterogeneous_system_impl
, (class)(class)(class))
120 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::heterogeneous_system
, (class))
121 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::heterogeneous_system_dim
, (class)(class))
131 struct less_impl
<boost::units::heterogeneous_system_dim_tag
, boost::units::heterogeneous_system_dim_tag
>
133 template<class T0
, class T1
>
134 struct apply
: mpl::less
<typename
T0::tag_type
, typename
T1::tag_type
> {};
143 template<class Unit1
, class Exponent1
>
144 struct is_empty_dim
<heterogeneous_system_dim
<Unit1
,Exponent1
> > : detail::is_zero
<Exponent1
> {};
146 } // namespace detail
154 struct plus_impl
<boost::units::heterogeneous_system_dim_tag
, boost::units::heterogeneous_system_dim_tag
>
156 template<class T0
, class T1
>
159 typedef boost::units::heterogeneous_system_dim
<
160 typename
T0::tag_type
,
161 typename
mpl::plus
<typename
T0::value_type
,typename
T1::value_type
>::type
168 struct times_impl
<boost::units::heterogeneous_system_dim_tag
, boost::units::detail::static_rational_tag
>
170 template<class T0
, class T1
>
173 typedef boost::units::heterogeneous_system_dim
<
174 typename
T0::tag_type
,
175 typename
mpl::times
<typename
T0::value_type
,T1
>::type
182 struct divides_impl
<boost::units::heterogeneous_system_dim_tag
, boost::units::detail::static_rational_tag
>
184 template<class T0
, class T1
>
187 typedef boost::units::heterogeneous_system_dim
<
188 typename
T0::tag_type
,
189 typename
mpl::divides
<typename
T0::value_type
,T1
>::type
196 struct negate_impl
<boost::units::heterogeneous_system_dim_tag
>
201 typedef boost::units::heterogeneous_system_dim
<typename
T::tag_type
, typename
mpl::negate
<typename
T::value_type
>::type
> type
;
212 struct make_heterogeneous_system_impl
214 template<class UnitsBegin
, class ExponentsBegin
>
217 typedef typename push_front_if
<!(is_zero
<typename
ExponentsBegin::item
>::value
)>::template apply
<
218 typename make_heterogeneous_system_impl
<N
-1>::template apply
<
219 typename
UnitsBegin::next
,
220 typename
ExponentsBegin::next
222 heterogeneous_system_dim
<typename
UnitsBegin::item
, typename
ExponentsBegin::item
>
228 struct make_heterogeneous_system_impl
<0>
230 template<class UnitsBegin
, class ExponentsBegin
>
233 typedef dimensionless_type type
;
237 template<class Dimensions
, class System
>
238 struct make_heterogeneous_system
240 typedef typename calculate_base_unit_exponents
<typename
System::type
, Dimensions
>::type exponents
;
241 BOOST_MPL_ASSERT_MSG((!boost::is_same
<exponents
, inconsistent
>::value
), the_specified_dimension_is_not_representible_in_the_given_system
, (types
<Dimensions
, System
>));
242 typedef typename make_heterogeneous_system_impl
<System::type::size::value
>::template apply
<
243 typename
System::type
,
246 typedef heterogeneous_system
<heterogeneous_system_impl
<unit_list
, Dimensions
, no_scale
> > type
;
249 template<class Dimensions
, class T
>
250 struct make_heterogeneous_system
<Dimensions
, heterogeneous_system
<T
> >
252 typedef heterogeneous_system
<T
> type
;
255 template<class T0
, class T1
>
256 struct multiply_systems
258 typedef heterogeneous_system
<
259 heterogeneous_system_impl
<
260 typename
mpl::times
<typename
T0::type
, typename
T1::type
>::type
,
261 typename
mpl::times
<typename
T0::dimensions
, typename
T1::dimensions
>::type
,
262 typename
mpl::times
<typename
T0::scale
, typename
T1::scale
>::type
267 template<class T0
, class T1
>
268 struct divide_systems
270 typedef heterogeneous_system
<
271 heterogeneous_system_impl
<
272 typename
mpl::divides
<typename
T0::type
, typename
T1::type
>::type
,
273 typename
mpl::divides
<typename
T0::dimensions
, typename
T1::dimensions
>::type
,
274 typename
mpl::divides
<typename
T0::scale
, typename
T1::scale
>::type
279 } // namespace detail
282 template<class S
, long N
, long D
>
283 struct static_power
<heterogeneous_system
<S
>, static_rational
<N
,D
> >
285 typedef heterogeneous_system
<
286 heterogeneous_system_impl
<
287 typename static_power
<typename
S::type
, static_rational
<N
,D
> >::type
,
288 typename static_power
<typename
S::dimensions
, static_rational
<N
,D
> >::type
,
289 typename static_power
<typename
S::scale
, static_rational
<N
,D
> >::type
295 template<class S
, long N
, long D
>
296 struct static_root
<heterogeneous_system
<S
>, static_rational
<N
,D
> >
298 typedef heterogeneous_system
<
299 heterogeneous_system_impl
<
300 typename static_root
<typename
S::type
, static_rational
<N
,D
> >::type
,
301 typename static_root
<typename
S::dimensions
, static_rational
<N
,D
> >::type
,
302 typename static_root
<typename
S::scale
, static_rational
<N
,D
> >::type
310 struct unscale_heterogeneous_system_impl
312 template<class Begin
>
315 typedef typename push_front_or_add
<
316 typename unscale_heterogeneous_system_impl
<N
-1>::template apply
<
319 typename unscale
<typename
Begin::item
>::type
325 struct unscale_heterogeneous_system_impl
<0>
327 template<class Begin
>
330 typedef dimensionless_type type
;
334 } // namespace detail
336 /// Unscale all the base units. e.g
341 struct unscale
<heterogeneous_system
<T
> >
343 typedef heterogeneous_system
<
344 heterogeneous_system_impl
<
345 typename
detail::unscale_heterogeneous_system_impl
<
350 typename
T::dimensions
,
357 template<class Unit
, class Exponent
>
358 struct unscale
<heterogeneous_system_dim
<Unit
, Exponent
> >
360 typedef heterogeneous_system_dim
<typename unscale
<Unit
>::type
, Exponent
> type
;
366 struct get_scale_list_of_heterogeneous_system_impl
368 template<class Begin
>
371 typedef typename
mpl::times
<
372 typename get_scale_list_of_heterogeneous_system_impl
<N
-1>::template apply
<
375 typename get_scale_list
<typename
Begin::item
>::type
381 struct get_scale_list_of_heterogeneous_system_impl
<0>
383 template<class Begin
>
386 typedef dimensionless_type type
;
390 } // namespace detail
394 struct get_scale_list
<heterogeneous_system
<T
> >
396 typedef typename
mpl::times
<
397 typename
detail::get_scale_list_of_heterogeneous_system_impl
<
399 >::template apply
<typename
T::type
>::type
,
405 template<class Unit
, class Exponent
>
406 struct get_scale_list
<heterogeneous_system_dim
<Unit
, Exponent
> >
408 typedef typename static_power
<typename get_scale_list
<Unit
>::type
, Exponent
>::type type
;
413 template<class System
, class Dimension
>
414 struct check_system
: mpl::false_
{};
416 template<class System
, class Dimension
, class Scale
>
417 struct check_system
<heterogeneous_system
<heterogeneous_system_impl
<System
, Dimension
, Scale
> >, Dimension
> : mpl::true_
{};
419 } // namespace detail