summaryrefslogtreecommitdiff
path: root/boost/units/detail/dimension_impl.hpp
blob: dbe77afef7e363ccaed1fe2af72dd2ac41b2aa9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
// Boost.Units - A C++ library for zero-overhead dimensional analysis and 
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2008 Steven Watanabe
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_UNITS_DIMENSION_IMPL_HPP
#define BOOST_UNITS_DIMENSION_IMPL_HPP

#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/less.hpp>

#include <boost/units/config.hpp>
#include <boost/units/dimensionless_type.hpp>
#include <boost/units/static_rational.hpp>
#include <boost/units/units_fwd.hpp>
#include <boost/units/detail/dimension_list.hpp>
#include <boost/units/detail/push_front_if.hpp>
#include <boost/units/detail/push_front_or_add.hpp>

/// \file 
/// \brief Core class and metaprogramming utilities for compile-time dimensional analysis.

namespace boost {

namespace units {

namespace detail {

template<int N>
struct insertion_sort_dims_insert;

template<bool is_greater>
struct insertion_sort_dims_comparison_impl;

// have to recursively add the element to the next sequence.
template<>
struct insertion_sort_dims_comparison_impl<true> {
    template<class Begin, int N, class T>
    struct apply {
        typedef list<
            typename Begin::item,
            typename insertion_sort_dims_insert<N - 1>::template apply<
                typename Begin::next,
                T
            >::type
        > type;
    };
};

// either prepend the current element or join it to
// the first remaining element of the sequence.
template<>
struct insertion_sort_dims_comparison_impl<false> {
    template<class Begin, int N, class T>
    struct apply {
        typedef typename push_front_or_add<Begin, T>::type type;
    };
};

template<int N>
struct insertion_sort_dims_insert {
    template<class Begin, class T>
    struct apply {
        typedef typename insertion_sort_dims_comparison_impl<mpl::less<typename Begin::item, T>::value>::template apply<
            Begin,
            N,
            T
        >::type type;
    };
};

template<>
struct insertion_sort_dims_insert<0> {
    template<class Begin, class T>
    struct apply {
        typedef list<T, dimensionless_type> type;
    };
};

template<int N>
struct insertion_sort_dims_mpl_sequence {
    template<class Begin>
    struct apply {
        typedef typename insertion_sort_dims_mpl_sequence<N - 1>::template apply<typename mpl::next<Begin>::type>::type next;
        typedef typename insertion_sort_dims_insert<(next::size::value)>::template apply<next, typename mpl::deref<Begin>::type>::type type;
    };
};

template<>
struct insertion_sort_dims_mpl_sequence<0> {
    template<class Begin>
    struct apply {
        typedef dimensionless_type type;
    };
};

template<int N>
struct insertion_sort_dims_impl {
    template<class Begin>
    struct apply {
        typedef typename insertion_sort_dims_impl<N - 1>::template apply<typename Begin::next>::type next;
        typedef typename insertion_sort_dims_insert<(next::size::value)>::template apply<next, typename Begin::item>::type type;
    };
};

template<>
struct insertion_sort_dims_impl<0> {
    template<class Begin>
    struct apply {
        typedef dimensionless_type type;
    };
};

template<class T>
struct sort_dims
{
    typedef typename insertion_sort_dims_mpl_sequence<mpl::size<T>::value>::template apply<typename mpl::begin<T>::type>::type type;
};


template<class T, class Next>
struct sort_dims<list<T, Next> >
{
    typedef typename insertion_sort_dims_impl<list<T, Next>::size::value>::template apply<list<T, Next> >::type type;
};

/// sorted sequences can be merged in linear time
template<bool less, bool greater>
struct merge_dimensions_func;

template<int N1, int N2>
struct merge_dimensions_impl;

template<>
struct merge_dimensions_func<true, false>
{
    template<typename Begin1, typename Begin2, int N1, int N2>
    struct apply
    {
        typedef list<
            typename Begin1::item,
            typename merge_dimensions_impl<N1 - 1, N2>::template apply<
                typename Begin1::next,
                Begin2
            >::type
        > type;
    };
};

template<>
struct merge_dimensions_func<false, true> {
    template<typename Begin1, typename Begin2, int N1, int N2>
    struct apply
    {
        typedef list<
            typename Begin2::item,
            typename merge_dimensions_impl<N2 - 1, N1>::template apply<
                typename Begin2::next,
                Begin1
            >::type
        > type;
    };
};

template<>
struct merge_dimensions_func<false, false> {
    template<typename Begin1, typename Begin2, int N1, int N2>
    struct apply
    {
        typedef typename mpl::plus<typename Begin1::item, typename Begin2::item>::type combined;
        typedef typename push_front_if<!is_empty_dim<combined>::value>::template apply<
            typename merge_dimensions_impl<N1 - 1, N2 - 1>::template apply<
                typename Begin1::next,
                typename Begin2::next
            >::type,
            combined
        >::type type;
    };
};

template<int N1, int N2>
struct merge_dimensions_impl {
    template<typename Begin1, typename Begin2>
    struct apply
    {
        typedef typename Begin1::item dim1;
        typedef typename Begin2::item dim2;

        typedef typename merge_dimensions_func<(mpl::less<dim1,dim2>::value == true),
                (mpl::less<dim2,dim1>::value == true)>::template apply<
            Begin1,
            Begin2,
            N1,
            N2
        >::type type;
    };
};

template<typename Sequence1, typename Sequence2>
struct merge_dimensions
{
    typedef typename detail::merge_dimensions_impl<Sequence1::size::value, 
                                                   Sequence2::size::value>::template 
        apply<
            Sequence1,
            Sequence2
        >::type type;
};

template<int N>
struct iterator_to_list
{
    template<typename Begin>
    struct apply
    {
        typedef list<
            typename Begin::item,
            typename iterator_to_list<N - 1>::template apply<
                typename Begin::next
            >::type
        > type;
    };
};

template<>
struct iterator_to_list<0>
{
    template<typename Begin>
    struct apply {
        typedef dimensionless_type type;
    };
};

template<int N>
struct merge_dimensions_impl<N, 0>
{
    template<typename Begin1, typename Begin2>
    struct apply
    {
        typedef typename iterator_to_list<N>::template apply<Begin1>::type type;
    };
};

template<int N>
struct merge_dimensions_impl<0, N>
{
    template<typename Begin1, typename Begin2>
    struct apply
    {
        typedef typename iterator_to_list<N>::template apply<Begin2>::type type;
    };
};

template<>
struct merge_dimensions_impl<0, 0>
{
    template<typename Begin1, typename Begin2>
    struct apply
    {
        typedef dimensionless_type type;
    };
};

template<int N>
struct static_inverse_impl
{
    template<typename Begin>
    struct apply {
        typedef list<
            typename mpl::negate<typename Begin::item>::type,
            typename static_inverse_impl<N - 1>::template apply<
                typename Begin::next
            >::type
        > type;
    };
};

template<>
struct static_inverse_impl<0>
{
    template<typename Begin>
    struct apply
    {
        typedef dimensionless_type type;
    };
};

template<int N>
struct static_power_impl
{
    template<typename Begin, typename Ex>
    struct apply
    {
        typedef list<
            typename mpl::times<typename Begin::item, Ex>::type,
            typename detail::static_power_impl<N - 1>::template apply<typename Begin::next, Ex>::type
        > type;
    };
};

template<>
struct static_power_impl<0>
{
    template<typename Begin, typename Ex>
    struct apply
    {
        typedef dimensionless_type type;
    };
};

template<int N>
struct static_root_impl {
    template<class Begin, class Ex>
    struct apply {
        typedef list<
            typename mpl::divides<typename Begin::item, Ex>::type,
            typename detail::static_root_impl<N - 1>::template apply<typename Begin::next, Ex>::type
        > type;
    };
};

template<>
struct static_root_impl<0> {
    template<class Begin, class Ex>
    struct apply 
    {
        typedef dimensionless_type type;
    };
};

} // namespace detail

} // namespace units

} // namespace boost

#endif // BOOST_UNITS_DIMENSION_IMPL_HPP