]> Dogcows Code - chaz/yoink/blob - src/Moof/cml/et/size_checking.h
extreme refactoring
[chaz/yoink] / src / Moof / cml / et / size_checking.h
1 /* -*- C++ -*- ------------------------------------------------------------
2
3 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
4
5 The Configurable Math Library (CML) is distributed under the terms of the
6 Boost Software License, v1.0 (see cml/LICENSE for details).
7
8 *-----------------------------------------------------------------------*/
9 /** @file
10 * @brief
11 *
12 * Define matrix and vector linear expression size-checking classes.
13 */
14
15 #ifndef size_checking_h
16 #define size_checking_h
17
18 #include <stdexcept>
19 #include <cml/core/cml_meta.h>
20 #include <cml/core/cml_assert.h>
21 #include <cml/core/fwd.h>
22 #include <cml/et/traits.h>
23
24 #if defined(_MSC_VER) && _MSC_VER < 1400
25 #pragma warning(push)
26 #pragma warning(disable:4348)
27 // XXX This is a terrible hack for VC7.1, and should really be fixed by
28 // separating out the "impl" templates from GetCheckedSize.
29 #endif
30
31 /* This is used below to create a more meaningful compile-time error when
32 * fixed-size vector arguments don't match at compile time:
33 */
34 struct incompatible_expression_size_error;
35
36 /* This is used below to create a more meaningful compile-time error when a
37 * function is not provided with a square matrix or MatrixExpr argument:
38 */
39 struct square_matrix_arg_expected_error;
40
41 namespace cml {
42 namespace et {
43 namespace detail {
44
45 } // namespace detail
46
47 /* Forward declare for specialization below: */
48 template<typename LeftT, typename RightT, typename SizeT>
49 struct GetCheckedSize;
50
51 /* Checking for fixed-size expression: */
52 template<typename LeftT, typename RightT>
53 struct GetCheckedSize<LeftT,RightT,fixed_size_tag>
54 {
55 /* Record argument traits: */
56 typedef ExprTraits<LeftT> left_traits;
57 typedef ExprTraits<RightT> right_traits;
58
59 /* Result types: */
60 typedef typename left_traits::result_tag left_result;
61 typedef typename right_traits::result_tag right_result;
62
63
64 /* For specialization below: */
65 template<typename LR, typename RR, class X = void> struct impl;
66
67 /* Check for two matrices (linear operators only): */
68 template<class X> struct impl<matrix_result_tag,matrix_result_tag,X> {
69 typedef matrix_size size_type;
70 CML_STATIC_REQUIRE_M(
71 (size_t)LeftT::array_rows == (size_t)RightT::array_rows
72 && (size_t)LeftT::array_cols == (size_t)RightT::array_cols,
73 incompatible_expression_size_error);
74
75 /* Record the array size as a constant: */
76 enum {
77 array_rows = LeftT::array_rows,
78 array_cols = LeftT::array_cols
79 };
80
81 /* Return the matrix size: */
82 size_type size() const { return size_type(array_rows,array_cols); }
83 };
84
85 /* Check for a matrix and a vector: */
86 template<class X> struct impl<matrix_result_tag,vector_result_tag,X> {
87 typedef size_t size_type;
88 CML_STATIC_REQUIRE_M(
89 (size_t)LeftT::array_cols == (size_t)RightT::array_size,
90 incompatible_expression_size_error);
91
92 /* Record the array size as a constant: */
93 enum { array_size = LeftT::array_rows };
94
95 /* Return the vector size: */
96 size_type size() const { return size_type(array_size); }
97 };
98
99 /* Check for a vector and a matrix: */
100 template<class X> struct impl<vector_result_tag,matrix_result_tag,X> {
101 typedef size_t size_type;
102 CML_STATIC_REQUIRE_M(
103 (size_t)LeftT::array_size == (size_t)RightT::array_rows,
104 incompatible_expression_size_error);
105
106 /* Record the array size as a constant: */
107 enum { array_size = RightT::array_cols };
108
109 /* Return the vector size: */
110 size_type size() const { return size_type(array_size); }
111 };
112
113 /* Check for a matrix and a scalar: */
114 template<class X> struct impl<matrix_result_tag,scalar_result_tag,X> {
115 typedef matrix_size size_type;
116
117 /* Record the array size as a constant: */
118 enum {
119 array_rows = LeftT::array_rows,
120 array_cols = LeftT::array_cols
121 };
122
123 /* Return the matrix size: */
124 size_type size() const { return size_type(array_rows,array_cols); }
125 };
126
127 /* Check for a scalar and a matrix: */
128 template<class X> struct impl<scalar_result_tag,matrix_result_tag,X> {
129 typedef matrix_size size_type;
130
131 /* Record the array size as a constant: */
132 enum {
133 array_rows = RightT::array_rows,
134 array_cols = RightT::array_cols
135 };
136
137 /* Return the matrix size: */
138 size_type size() const { return size_type(array_rows,array_cols); }
139 };
140
141
142 /* Check for two vectors: */
143 template<class X> struct impl<vector_result_tag,vector_result_tag,X> {
144 typedef size_t size_type;
145 CML_STATIC_REQUIRE_M(
146 (size_t)LeftT::array_size == (size_t)RightT::array_size,
147 incompatible_expression_size_error);
148
149 /* Record the array size as a constant: */
150 enum { array_size = LeftT::array_size };
151
152 /* Return the vector size: */
153 size_type size() const { return size_type(array_size); }
154 };
155
156 /* Check for a vector and a scalar: */
157 template<class X> struct impl<vector_result_tag,scalar_result_tag,X> {
158 typedef size_t size_type;
159
160 /* Record the array size as a constant: */
161 enum { array_size = LeftT::array_size };
162
163 /* Return the vector size: */
164 size_type size() const { return size_type(array_size); }
165 };
166
167 /* Check for a scalar and a vector: */
168 template<class X> struct impl<scalar_result_tag,vector_result_tag,X> {
169 typedef size_t size_type;
170
171 /* Record the array size as a constant: */
172 enum { array_size = RightT::array_size };
173
174 /* Return the vector size: */
175 size_type size() const { return size_type(array_size); }
176 };
177
178
179 /* Check for two quaternions: */
180 template<class X>
181 struct impl<quaternion_result_tag,quaternion_result_tag,X> {
182 typedef size_t size_type;
183
184 /* Record the quaternion size as a constant: */
185 enum { array_size = 4 };
186
187 /* Return the quaternion size: */
188 size_type size() const { return size_type(array_size); }
189 };
190
191 /* Check for a quaternion and a vector: */
192 template<class X> struct impl<quaternion_result_tag,vector_result_tag,X> {
193 typedef size_t size_type;
194 CML_STATIC_REQUIRE_M(
195 RightT::array_size == 4,
196 incompatible_expression_size_error);
197
198 /* Record the quaternion size as a constant: */
199 enum { array_size = 4 };
200
201 /* Return the quaternion size: */
202 size_type size() const { return size_type(array_size); }
203 };
204
205 /* Check for a vector and a quaternion: */
206 template<class X> struct impl<vector_result_tag,quaternion_result_tag,X> {
207 typedef size_t size_type;
208 CML_STATIC_REQUIRE_M(
209 LeftT::array_size == 4,
210 incompatible_expression_size_error);
211
212 /* Record the quaternion size as a constant: */
213 enum { array_size = 4 };
214
215 /* Return the quaternion size: */
216 size_type size() const { return size_type(array_size); }
217 };
218
219 /* Check for a quaternion and a scalar: */
220 template<class X> struct impl<quaternion_result_tag,scalar_result_tag,X> {
221 typedef size_t size_type;
222
223 /* Record the quaternion size as a constant: */
224 enum { array_size = 4 };
225
226 /* Return the quaternion size: */
227 size_type size() const { return size_type(array_size); }
228 };
229
230 /* Check for a scalar and a quaternion: */
231 template<class X> struct impl<scalar_result_tag,quaternion_result_tag,X> {
232 typedef size_t size_type;
233
234 /* Record the array size as a constant: */
235 enum { array_size = 4 };
236
237 /* Return the quaternion size: */
238 size_type size() const { return size_type(array_size); }
239 };
240
241 /* Record the type of the checker: */
242 typedef impl<left_result,right_result> check_type;
243 typedef typename check_type::size_type size_type;
244
245 /* The implementation: */
246 size_type operator()(const LeftT&, const RightT&) const {
247 return check_type().size();
248 }
249 };
250
251 /* Checking for resizeable expression: */
252 template<typename LeftT, typename RightT>
253 struct GetCheckedSize<LeftT,RightT,dynamic_size_tag>
254 {
255 /* Type of the size checker (for calling equal_or_fail): */
256 typedef GetCheckedSize<LeftT,RightT,dynamic_size_tag> self;
257
258 /* Record argument traits: */
259 typedef ExprTraits<LeftT> left_traits;
260 typedef ExprTraits<RightT> right_traits;
261
262 /* Result types: */
263 typedef typename left_traits::result_tag left_result;
264 typedef typename right_traits::result_tag right_result;
265
266
267 /* For specialization below: */
268 template<typename LR, typename RR, class X = void> struct impl;
269
270 /* Return the size if the same, or fail if different: */
271 template<typename V> V equal_or_fail(V left, V right) const {
272 if(left != right)
273 throw std::invalid_argument(
274 "expressions have incompatible sizes.");
275 return left;
276 }
277
278 /* Check for two matrices (linear operators only): */
279 template<class X> struct impl<matrix_result_tag,matrix_result_tag,X> {
280 typedef matrix_size size_type;
281
282 /* Return the matrix size, or fail if incompatible: */
283 size_type size(const LeftT& left, const RightT& right) const {
284 #if defined(CML_CHECK_MATRIX_EXPR_SIZES)
285 return self().equal_or_fail(left.size(), right.size());
286 #else
287 return left.size();
288 #endif
289 }
290 };
291
292 /* Check for a matrix and a vector: */
293 template<class X> struct impl<matrix_result_tag,vector_result_tag,X> {
294 typedef size_t size_type;
295
296 /* Return the vector size: */
297 size_type size(const LeftT& left, const RightT& right) const {
298 #if defined(CML_CHECK_MATVEC_EXPR_SIZES)
299 self().equal_or_fail(left.cols(), right.size());
300 #endif
301 return left.rows();
302 }
303 };
304
305 /* Check for a vector and a matrix: */
306 template<class X> struct impl<vector_result_tag,matrix_result_tag,X> {
307 typedef size_t size_type;
308
309 /* Return the vector size: */
310 size_type size(const LeftT& left, const RightT& right) const {
311 #if defined(CML_CHECK_MATVEC_EXPR_SIZES)
312 self().equal_or_fail(left.size(), right.rows());
313 #endif
314 return right.cols(right);
315 }
316 };
317
318 /* Check for a matrix and a scalar: */
319 template<class X> struct impl<matrix_result_tag,scalar_result_tag,X> {
320 typedef matrix_size size_type;
321
322 /* Return the matrix size: */
323 size_type size(const LeftT& left, const RightT&) const {
324 return left.size();
325 }
326 };
327
328 /* Check for a scalar and a matrix: */
329 template<class X> struct impl<scalar_result_tag,matrix_result_tag,X> {
330 typedef matrix_size size_type;
331
332 /* Return the matrix size: */
333 size_type size(const LeftT&, const RightT& right) const {
334 return right.size();
335 }
336 };
337
338 /* Check for two vectors: */
339 template<class X> struct impl<vector_result_tag,vector_result_tag,X> {
340 typedef size_t size_type;
341
342 /* Return the vector size: */
343 size_type size(const LeftT& left, const RightT& right) const {
344 #if defined(CML_CHECK_VECTOR_EXPR_SIZES)
345 return self().equal_or_fail(left.size(), right.size());
346 #else
347 return left.size();
348 #endif
349 }
350 };
351
352 /* Check for a vector and a scalar: */
353 template<class X> struct impl<vector_result_tag,scalar_result_tag,X> {
354 typedef size_t size_type;
355
356 /* Return the vector size: */
357 size_type size(const LeftT& left, const RightT&) const {
358 return left.size();
359 }
360 };
361
362 /* Check for a scalar and a vector: */
363 template<class X> struct impl<scalar_result_tag,vector_result_tag,X> {
364 typedef size_t size_type;
365
366 /* Return the vector size: */
367 size_type size(const LeftT&, const RightT& right) const {
368 return right.size();
369 }
370 };
371
372 /* Record the type of the checker: */
373 typedef impl<left_result,right_result> check_type;
374 typedef typename check_type::size_type size_type;
375
376 /* The implementation: */
377 size_type operator()(const LeftT& left, const RightT& right) const {
378 return check_type().size(left,right);
379 }
380 };
381
382 /** Generator for GetCheckedSize. */
383 template<typename LeftT, typename RightT, typename SizeTag>
384 inline typename et::GetCheckedSize<LeftT,RightT,SizeTag>::size_type
385 CheckedSize(const LeftT& left, const RightT& right, SizeTag)
386 {
387 return et::GetCheckedSize<LeftT,RightT,SizeTag>()(left,right);
388 }
389
390 /** Verify the sizes of the argument matrices for matrix multiplication.
391 *
392 * @returns a the size of the resulting matrix.
393 */
394 template<typename MatT> inline size_t
395 CheckedSquare(const MatT&, fixed_size_tag)
396 {
397 CML_STATIC_REQUIRE_M(
398 ((size_t)MatT::array_rows == (size_t)MatT::array_cols),
399 square_matrix_arg_expected_error);
400 return (size_t)MatT::array_rows;
401 }
402
403 /** Verify the sizes of the argument matrices for matrix multiplication.
404 *
405 * @returns the size of the resulting matrix.
406 */
407 template<typename MatT> inline size_t
408 CheckedSquare(const MatT& m, dynamic_size_tag)
409 {
410 matrix_size N = m.size();
411 et::GetCheckedSize<MatT,MatT,dynamic_size_tag>()
412 .equal_or_fail(N.first, N.second);
413 return N.first;
414 }
415
416 } // namespace et
417 } // namespace cml
418
419 #if defined(_MSC_VER) && _MSC_VER < 1400
420 #pragma warning(pop)
421 #endif
422
423 #endif
424
425 // -------------------------------------------------------------------------
426 // vim:ft=cpp
This page took 0.051231 seconds and 4 git commands to generate.