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         BOOST_CONSTEXPR unit() { }
unit(const this_type &)46         BOOST_CONSTEXPR unit(const this_type&) { }
47         //~unit() { }
48 
operator =(const this_type &)49         BOOST_CXX14_CONSTEXPR 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 BOOST_CONSTEXPR 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 BOOST_CONSTEXPR 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 BOOST_CONSTEXPR
329 typename unary_plus_typeof_helper< unit<Dim,System> >::type
operator +(const unit<Dim,System> &)330 operator+(const unit<Dim,System>&)
331 {
332     typedef typename unary_plus_typeof_helper< unit<Dim,System> >::type type;
333 
334     return type();
335 }
336 
337 /// unit runtime unary minus
338 template<class Dim,class System>
339 BOOST_CONSTEXPR
340 typename unary_minus_typeof_helper< unit<Dim,System> >::type
operator -(const unit<Dim,System> &)341 operator-(const unit<Dim,System>&)
342 {
343     typedef typename unary_minus_typeof_helper< unit<Dim,System> >::type    type;
344 
345     return type();
346 }
347 
348 /// runtime add two units
349 template<class Dim1,
350          class Dim2,
351          class System1,
352          class System2>
353 BOOST_CONSTEXPR
354 typename add_typeof_helper< unit<Dim1,System1>,
355                             unit<Dim2,System2> >::type
operator +(const unit<Dim1,System1> &,const unit<Dim2,System2> &)356 operator+(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
357 {
358     BOOST_STATIC_ASSERT((boost::is_same<System1,System2>::value == true));
359 
360     typedef System1                                                     system_type;
361     typedef typename add_typeof_helper< unit<Dim1,system_type>,
362                                         unit<Dim2,system_type> >::type  type;
363 
364     return type();
365 }
366 
367 /// runtime subtract two units
368 template<class Dim1,
369          class Dim2,
370          class System1,
371          class System2>
372 BOOST_CONSTEXPR
373 typename subtract_typeof_helper< unit<Dim1,System1>,
374                                  unit<Dim2,System2> >::type
operator -(const unit<Dim1,System1> &,const unit<Dim2,System2> &)375 operator-(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
376 {
377     BOOST_STATIC_ASSERT((boost::is_same<System1,System2>::value == true));
378 
379     typedef System1                                                         system_type;
380     typedef typename subtract_typeof_helper< unit<Dim1,system_type>,
381                                              unit<Dim2,system_type> >::type type;
382 
383     return type();
384 }
385 
386 /// runtime multiply two units
387 template<class Dim1,
388          class Dim2,
389          class System1,
390          class System2>
391 BOOST_CONSTEXPR
392 typename multiply_typeof_helper< unit<Dim1,System1>,
393                                  unit<Dim2,System2> >::type
operator *(const unit<Dim1,System1> &,const unit<Dim2,System2> &)394 operator*(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
395 {
396     typedef typename multiply_typeof_helper< unit<Dim1,System1>,
397                                              unit<Dim2,System2> >::type type;
398 
399     return type();
400 }
401 
402 /// runtime divide two units
403 template<class Dim1,
404          class Dim2,
405          class System1,
406          class System2>
407 BOOST_CONSTEXPR
408 typename divide_typeof_helper< unit<Dim1,System1>,
409                                unit<Dim2,System2> >::type
operator /(const unit<Dim1,System1> &,const unit<Dim2,System2> &)410 operator/(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
411 {
412     typedef typename divide_typeof_helper< unit<Dim1,System1>,
413                                            unit<Dim2,System2> >::type   type;
414 
415     return type();
416 }
417 
418 /// unit runtime @c operator==
419 template<class Dim1,
420          class Dim2,
421          class System1,
422          class System2>
423 inline
424 BOOST_CONSTEXPR
425 bool
operator ==(const unit<Dim1,System1> &,const unit<Dim2,System2> &)426 operator==(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
427 {
428     return boost::is_same<typename reduce_unit<unit<Dim1,System1> >::type, typename reduce_unit<unit<Dim2,System2> >::type>::value;
429 }
430 
431 /// unit runtime @c operator!=
432 template<class Dim1,
433          class Dim2,
434          class System1,
435          class System2>
436 inline
437 BOOST_CONSTEXPR
438 bool
operator !=(const unit<Dim1,System1> &,const unit<Dim2,System2> &)439 operator!=(const unit<Dim1,System1>&,const unit<Dim2,System2>&)
440 {
441     return !boost::is_same<typename reduce_unit<unit<Dim1,System1> >::type, typename reduce_unit<unit<Dim2,System2> >::type>::value;
442 }
443 
444 } // namespace units
445 
446 } // namespace boost
447 
448 #endif // BOOST_UNITS_UNIT_HPP
449