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) 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_UNIT_HPP
12 #define BOOST_UNITS_UNIT_HPP
13 
14 #include <boost/static_assert.hpp>
15 #include <boost/mpl/bool.hpp>
16 #include <boost/mpl/assert.hpp>
17 #include <boost/type_traits/is_same.hpp>
18 
19 #include <boost/units/config.hpp>
20 #include <boost/units/dimension.hpp>
21 #include <boost/units/operators.hpp>
22 #include <boost/units/units_fwd.hpp>
23 #include <boost/units/homogeneous_system.hpp>
24 #include <boost/units/heterogeneous_system.hpp>
25 #include <boost/units/is_dimension_list.hpp>
26 #include <boost/units/reduce_unit.hpp>
27 #include <boost/units/static_rational.hpp>
28 
29 namespace boost {
30 
31 namespace units {
32 
33 /// class representing a model-dependent unit with no associated value
34 
35 /// (e.g. meters, Kelvin, feet, etc...)
36 template<class Dim,class System, class Enable>
37 class unit
38 {
39     public:
40         typedef unit<Dim, System>   unit_type;
41         typedef unit<Dim,System>    this_type;
42         typedef Dim                 dimension_type;
43         typedef System              system_type;
44 
unit()45         unit() { }
unit(const this_type &)46         unit(const this_type&) { }
47         //~unit() { }
48 
operator =(const this_type &)49         this_type& operator=(const this_type&) { return *this; }
50 
51         // sun will ignore errors resulting from templates
52         // instantiated in the return type of a function.
53         // Make sure that we get an error anyway by putting.
54         // the check in the destructor.
55         #ifdef __SUNPRO_CC
~unit()56         ~unit() {
57             BOOST_MPL_ASSERT((detail::check_system<System, Dim>));
58             BOOST_MPL_ASSERT((is_dimension_list<Dim>));
59         }
60         #else
61     private:
62         BOOST_MPL_ASSERT((detail::check_system<System, Dim>));
63         BOOST_MPL_ASSERT((is_dimension_list<Dim>));
64         #endif
65 };
66 
67 }
68 
69 }
70 
71 #if BOOST_UNITS_HAS_BOOST_TYPEOF
72 
73 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
74 
75 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::unit, 2)
76 
77 #endif
78 
79 namespace boost {
80 
81 namespace units {
82 
83 /// Returns a unique type for every unit.
84 template<class Dim, class System>
85 struct reduce_unit<unit<Dim, System> >
86 {
87     typedef unit<
88         Dim,
89         typename detail::make_heterogeneous_system<
90             Dim,
91             System
92         >::type
93     > type;
94 };
95 
96 /// INTERNAL ONLY
97 template<class S1,class S2>
98 struct is_implicitly_convertible :
99     boost::is_same<typename reduce_unit<S1>::type, typename reduce_unit<S2>::type>
100 { };
101 
102 /// unit unary plus typeof helper
103 /// INTERNAL ONLY
104 template<class Dim,class System>
105 struct unary_plus_typeof_helper< unit<Dim,System> >
106 {
107     typedef unit<Dim,System>    type;
108 };
109 
110 /// unit unary minus typeof helper
111 /// INTERNAL ONLY
112 template<class Dim,class System>
113 struct unary_minus_typeof_helper< unit<Dim,System> >
114 {
115     typedef unit<Dim,System>    type;
116 };
117 
118 /// unit add typeof helper
119 /// INTERNAL ONLY
120 template<class Dim,
121          class System>
122 struct add_typeof_helper< unit<Dim,System>,unit<Dim,System> >
123 {
124     typedef unit<Dim,System> type;
125 };
126 
127 /// unit subtract typeof helper
128 /// INTERNAL ONLY
129 template<class Dim,
130          class System>
131 struct subtract_typeof_helper< unit<Dim,System>,unit<Dim,System> >
132 {
133     typedef unit<Dim,System>   type;
134 };
135 
136 /// unit multiply typeof helper for two identical homogeneous systems
137 /// INTERNAL ONLY
138 template<class Dim1,
139          class Dim2,
140          class System>
141 struct multiply_typeof_helper< unit<Dim1,homogeneous_system<System> >,
142                                unit<Dim2,homogeneous_system<System> > >
143 {
144     typedef unit<typename mpl::times<Dim1,Dim2>::type,homogeneous_system<System> >    type;
145 };
146 
147 /// unit multiply typeof helper for two different homogeneous systems
148 /// INTERNAL ONLY
149 template<class Dim1,
150          class Dim2,
151          class System1,
152          class System2>
153 struct multiply_typeof_helper< unit<Dim1,homogeneous_system<System1> >,
154                                unit<Dim2,homogeneous_system<System2> > >
155 {
156     typedef unit<
157         typename mpl::times<Dim1,Dim2>::type,
158         typename detail::multiply_systems<
159             typename detail::make_heterogeneous_system<Dim1, System1>::type,
160             typename detail::make_heterogeneous_system<Dim2, System2>::type
161         >::type
162     > type;
163 };
164 
165 /// unit multiply typeof helper for a heterogeneous and a homogeneous system
166 /// INTERNAL ONLY
167 template<class Dim1,
168          class Dim2,
169          class System1,
170          class System2>
171 struct multiply_typeof_helper< unit<Dim1,heterogeneous_system<System1> >,
172                                unit<Dim2,homogeneous_system<System2> > >
173 {
174     typedef unit<
175         typename mpl::times<Dim1,Dim2>::type,
176         typename detail::multiply_systems<
177             heterogeneous_system<System1>,
178             typename detail::make_heterogeneous_system<Dim2, System2>::type
179         >::type
180     > type;
181 };
182 
183 /// unit multiply typeof helper for a homogeneous and a heterogeneous system
184 /// INTERNAL ONLY
185 template<class Dim1,
186          class Dim2,
187          class System1,
188          class System2>
189 struct multiply_typeof_helper< unit<Dim1,homogeneous_system<System1> >,
190                                unit<Dim2,heterogeneous_system<System2> > >
191 {
192     typedef unit<
193         typename mpl::times<Dim1,Dim2>::type,
194         typename detail::multiply_systems<
195             typename detail::make_heterogeneous_system<Dim1, System1>::type,
196             heterogeneous_system<System2>
197         >::type
198     > type;
199 };
200 
201 /// unit multiply typeof helper for two heterogeneous systems
202 /// INTERNAL ONLY
203 template<class Dim1,
204          class Dim2,
205          class System1,
206          class System2>
207 struct multiply_typeof_helper< unit<Dim1,heterogeneous_system<System1> >,
208                                unit<Dim2,heterogeneous_system<System2> > >
209 {
210     typedef unit<
211         typename mpl::times<Dim1,Dim2>::type,
212         typename detail::multiply_systems<
213             heterogeneous_system<System1>,
214             heterogeneous_system<System2>
215         >::type
216     > type;
217 };
218 
219 /// unit divide typeof helper for two identical homogeneous systems
220 /// INTERNAL ONLY
221 template<class Dim1,
222          class Dim2,
223          class System>
224 struct divide_typeof_helper< unit<Dim1,homogeneous_system<System> >,
225                              unit<Dim2,homogeneous_system<System> > >
226 {
227     typedef unit<typename mpl::divides<Dim1,Dim2>::type,homogeneous_system<System> >    type;
228 };
229 
230 /// unit divide typeof helper for two different homogeneous systems
231 /// INTERNAL ONLY
232 template<class Dim1,
233          class Dim2,
234          class System1,
235          class System2>
236 struct divide_typeof_helper< unit<Dim1,homogeneous_system<System1> >,
237                              unit<Dim2,homogeneous_system<System2> > >
238 {
239     typedef unit<
240         typename mpl::divides<Dim1,Dim2>::type,
241         typename detail::divide_systems<
242             typename detail::make_heterogeneous_system<Dim1, System1>::type,
243             typename detail::make_heterogeneous_system<Dim2, System2>::type
244         >::type
245     > type;
246 };
247 
248 /// unit divide typeof helper for a heterogeneous and a homogeneous system
249 /// INTERNAL ONLY
250 template<class Dim1,
251          class Dim2,
252          class System1,
253          class System2>
254 struct divide_typeof_helper< unit<Dim1,heterogeneous_system<System1> >,
255                              unit<Dim2,homogeneous_system<System2> > >
256 {
257     typedef unit<
258         typename mpl::divides<Dim1,Dim2>::type,
259         typename detail::divide_systems<
260             heterogeneous_system<System1>,
261             typename detail::make_heterogeneous_system<Dim2, System2>::type
262         >::type
263     > type;
264 };
265 
266 /// unit divide typeof helper for a homogeneous and a heterogeneous system
267 /// INTERNAL ONLY
268 template<class Dim1,
269          class Dim2,
270          class System1,
271          class System2>
272 struct divide_typeof_helper< unit<Dim1,homogeneous_system<System1> >,
273                              unit<Dim2,heterogeneous_system<System2> > >
274 {
275     typedef unit<
276         typename mpl::divides<Dim1,Dim2>::type,
277         typename detail::divide_systems<
278             typename detail::make_heterogeneous_system<Dim1, System1>::type,
279             heterogeneous_system<System2>
280         >::type
281     > type;
282 };
283 
284 /// unit divide typeof helper for two heterogeneous systems
285 /// INTERNAL ONLY
286 template<class Dim1,
287          class Dim2,
288          class System1,
289          class System2>
290 struct divide_typeof_helper< unit<Dim1,heterogeneous_system<System1> >,
291                              unit<Dim2,heterogeneous_system<System2> > >
292 {
293     typedef unit<
294         typename mpl::divides<Dim1,Dim2>::type,
295         typename detail::divide_systems<
296             heterogeneous_system<System1>,
297             heterogeneous_system<System2>
298         >::type
299     > type;
300 };
301 
302 /// raise unit to a @c static_rational power
303 template<class Dim,class System,long N,long D>
304 struct power_typeof_helper<unit<Dim,System>,static_rational<N,D> >
305 {
306     typedef unit<typename static_power<Dim,static_rational<N,D> >::type,typename static_power<System, static_rational<N,D> >::type>     type;
307 
valueboost::units::power_typeof_helper308     static type value(const unit<Dim,System>&)
309     {
310         return type();
311     }
312 };
313 
314 /// take the @c static_rational root of a unit
315 template<class Dim,class System,long N,long D>
316 struct root_typeof_helper<unit<Dim,System>,static_rational<N,D> >
317 {
318     typedef unit<typename static_root<Dim,static_rational<N,D> >::type,typename static_root<System, static_rational<N,D> >::type>      type;
319 
valueboost::units::root_typeof_helper320     static type value(const unit<Dim,System>&)
321     {
322         return type();
323     }
324 };
325 
326 /// unit runtime unary plus
327 template<class Dim,class System>
328 typename unary_plus_typeof_helper< unit<Dim,System> >::type
operator +(const unit<Dim,System> &)329 operator+(const unit<Dim,System>&)
330 {
331     typedef typename unary_plus_typeof_helper< unit<Dim,System> >::type type;
332 
333     return type();
334 }
335 
336 /// unit runtime unary minus
337 template<class Dim,class System>
338 typename unary_minus_typeof_helper< unit<Dim,System> >::type
operator -(const unit<Dim,System> &)339 operator-(const unit<Dim,System>&)
340 {
341     typedef typename unary_minus_typeof_helper< unit<Dim,System> >::type    type;
342 
343     return type();
344 }
345 
346 /// runtime add two units
347 template<class Dim1,
348          class Dim2,
349          class System1,
350          class System2>
351 typename add_typeof_helper< unit<Dim1,System1>,
352                             unit<Dim2,System2> >::type
operator +(const unit<Dim1,System1> &,const unit<Dim2,System2> &)353 operator+(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
354 {
355     BOOST_STATIC_ASSERT((boost::is_same<System1,System2>::value == true));
356 
357     typedef System1                                                     system_type;
358     typedef typename add_typeof_helper< unit<Dim1,system_type>,
359                                         unit<Dim2,system_type> >::type  type;
360 
361     return type();
362 }
363 
364 /// runtime subtract two units
365 template<class Dim1,
366          class Dim2,
367          class System1,
368          class System2>
369 typename subtract_typeof_helper< unit<Dim1,System1>,
370                                  unit<Dim2,System2> >::type
operator -(const unit<Dim1,System1> &,const unit<Dim2,System2> &)371 operator-(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
372 {
373     BOOST_STATIC_ASSERT((boost::is_same<System1,System2>::value == true));
374 
375     typedef System1                                                         system_type;
376     typedef typename subtract_typeof_helper< unit<Dim1,system_type>,
377                                              unit<Dim2,system_type> >::type type;
378 
379     return type();
380 }
381 
382 /// runtime multiply two units
383 template<class Dim1,
384          class Dim2,
385          class System1,
386          class System2>
387 typename multiply_typeof_helper< unit<Dim1,System1>,
388                                  unit<Dim2,System2> >::type
operator *(const unit<Dim1,System1> &,const unit<Dim2,System2> &)389 operator*(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
390 {
391     typedef typename multiply_typeof_helper< unit<Dim1,System1>,
392                                              unit<Dim2,System2> >::type type;
393 
394     return type();
395 }
396 
397 /// runtime divide two units
398 template<class Dim1,
399          class Dim2,
400          class System1,
401          class System2>
402 typename divide_typeof_helper< unit<Dim1,System1>,
403                                unit<Dim2,System2> >::type
operator /(const unit<Dim1,System1> &,const unit<Dim2,System2> &)404 operator/(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
405 {
406     typedef typename divide_typeof_helper< unit<Dim1,System1>,
407                                            unit<Dim2,System2> >::type   type;
408 
409     return type();
410 }
411 
412 /// unit runtime @c operator==
413 template<class Dim1,
414          class Dim2,
415          class System1,
416          class System2>
417 inline
418 bool
operator ==(const unit<Dim1,System1> &,const unit<Dim2,System2> &)419 operator==(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
420 {
421     return boost::is_same<typename reduce_unit<unit<Dim1,System1> >::type, typename reduce_unit<unit<Dim2,System2> >::type>::value;
422 }
423 
424 /// unit runtime @c operator!=
425 template<class Dim1,
426          class Dim2,
427          class System1,
428          class System2>
429 inline
430 bool
operator !=(const unit<Dim1,System1> &,const unit<Dim2,System2> &)431 operator!=(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
432 {
433     return !boost::is_same<typename reduce_unit<unit<Dim1,System1> >::type, typename reduce_unit<unit<Dim2,System2> >::type>::value;
434 }
435 
436 } // namespace units
437 
438 } // namespace boost
439 
440 #endif // BOOST_UNITS_UNIT_HPP
441