size_checking.h

Go to the documentation of this file.
00001 /* -*- C++ -*- ------------------------------------------------------------
00002  
00003 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
00004 
00005 The Configurable Math Library (CML) is distributed under the terms of the
00006 Boost Software License, v1.0 (see cml/LICENSE for details).
00007 
00008  *-----------------------------------------------------------------------*/
00015 #ifndef size_checking_h
00016 #define size_checking_h
00017 
00018 #include <stdexcept>
00019 #include <cml/core/cml_meta.h>
00020 #include <cml/core/cml_assert.h>
00021 #include <cml/core/fwd.h>
00022 #include <cml/et/traits.h>
00023 
00024 #if defined(_MSC_VER) && _MSC_VER < 1400
00025 #pragma warning(push)
00026 #pragma warning(disable:4348)
00027 // XXX This is a terrible hack for VC7.1, and should really be fixed by
00028 // separating out the "impl" templates from GetCheckedSize.
00029 #endif
00030 
00031 /* This is used below to create a more meaningful compile-time error when
00032  * fixed-size vector arguments don't match at compile time:
00033  */
00034 struct incompatible_expression_size_error;
00035 
00036 /* This is used below to create a more meaningful compile-time error when a
00037  * function is not provided with a square matrix or MatrixExpr argument:
00038  */
00039 struct square_matrix_arg_expected_error;
00040 
00041 namespace cml {
00042 namespace et {
00043 namespace detail {
00044 
00045 } // namespace detail
00046 
00047 /* Forward declare for specialization below: */
00048 template<typename LeftT, typename RightT, typename SizeT>
00049     struct GetCheckedSize;
00050 
00051 /* Checking for fixed-size expression: */
00052 template<typename LeftT, typename RightT>
00053 struct GetCheckedSize<LeftT,RightT,fixed_size_tag>
00054 {
00055     /* Record argument traits: */
00056     typedef ExprTraits<LeftT> left_traits;
00057     typedef ExprTraits<RightT> right_traits;
00058 
00059     /* Result types: */
00060     typedef typename left_traits::result_tag left_result;
00061     typedef typename right_traits::result_tag right_result;
00062 
00063 
00064     /* For specialization below: */
00065     template<typename LR, typename RR, class X = void> struct impl;
00066 
00067     /* Check for two matrices (linear operators only): */
00068     template<class X> struct impl<matrix_result_tag,matrix_result_tag,X> {
00069         typedef matrix_size size_type;
00070         CML_STATIC_REQUIRE_M(
00071                 (size_t)LeftT::array_rows == (size_t)RightT::array_rows
00072                 && (size_t)LeftT::array_cols == (size_t)RightT::array_cols,
00073                 incompatible_expression_size_error);
00074 
00075         /* Record the array size as a constant: */
00076         enum {
00077             array_rows = LeftT::array_rows,
00078             array_cols = LeftT::array_cols
00079         };
00080 
00081         /* Return the matrix size: */
00082         size_type size() const { return size_type(array_rows,array_cols); }
00083     };
00084 
00085     /* Check for a matrix and a vector: */
00086     template<class X> struct impl<matrix_result_tag,vector_result_tag,X> {
00087         typedef size_t size_type;
00088         CML_STATIC_REQUIRE_M(
00089                 (size_t)LeftT::array_cols == (size_t)RightT::array_size,
00090                 incompatible_expression_size_error);
00091 
00092         /* Record the array size as a constant: */
00093         enum { array_size = LeftT::array_rows };
00094 
00095         /* Return the vector size: */
00096         size_type size() const { return size_type(array_size); }
00097     };
00098 
00099     /* Check for a vector and a matrix: */
00100     template<class X> struct impl<vector_result_tag,matrix_result_tag,X> {
00101         typedef size_t size_type;
00102         CML_STATIC_REQUIRE_M(
00103                 (size_t)LeftT::array_size == (size_t)RightT::array_rows,
00104                 incompatible_expression_size_error);
00105 
00106         /* Record the array size as a constant: */
00107         enum { array_size = RightT::array_cols };
00108 
00109         /* Return the vector size: */
00110         size_type size() const { return size_type(array_size); }
00111     };
00112 
00113     /* Check for a matrix and a scalar: */
00114     template<class X> struct impl<matrix_result_tag,scalar_result_tag,X> {
00115         typedef matrix_size size_type;
00116 
00117         /* Record the array size as a constant: */
00118         enum {
00119             array_rows = LeftT::array_rows,
00120             array_cols = LeftT::array_cols
00121         };
00122 
00123         /* Return the matrix size: */
00124         size_type size() const { return size_type(array_rows,array_cols); }
00125     };
00126 
00127     /* Check for a scalar and a matrix: */
00128     template<class X> struct impl<scalar_result_tag,matrix_result_tag,X> {
00129         typedef matrix_size size_type;
00130 
00131         /* Record the array size as a constant: */
00132         enum {
00133             array_rows = RightT::array_rows,
00134             array_cols = RightT::array_cols
00135         };
00136 
00137         /* Return the matrix size: */
00138         size_type size() const { return size_type(array_rows,array_cols); }
00139     };
00140 
00141 
00142     /* Check for two vectors: */
00143     template<class X> struct impl<vector_result_tag,vector_result_tag,X> {
00144         typedef size_t size_type;
00145         CML_STATIC_REQUIRE_M(
00146                 (size_t)LeftT::array_size == (size_t)RightT::array_size,
00147                 incompatible_expression_size_error);
00148 
00149         /* Record the array size as a constant: */
00150         enum { array_size = LeftT::array_size };
00151 
00152         /* Return the vector size: */
00153         size_type size() const { return size_type(array_size); }
00154     };
00155 
00156     /* Check for a vector and a scalar: */
00157     template<class X> struct impl<vector_result_tag,scalar_result_tag,X> {
00158         typedef size_t size_type;
00159 
00160         /* Record the array size as a constant: */
00161         enum { array_size = LeftT::array_size };
00162 
00163         /* Return the vector size: */
00164         size_type size() const { return size_type(array_size); }
00165     };
00166 
00167     /* Check for a scalar and a vector: */
00168     template<class X> struct impl<scalar_result_tag,vector_result_tag,X> {
00169         typedef size_t size_type;
00170 
00171         /* Record the array size as a constant: */
00172         enum { array_size = RightT::array_size };
00173 
00174         /* Return the vector size: */
00175         size_type size() const { return size_type(array_size); }
00176     };
00177 
00178 
00179     /* Check for two quaternions: */
00180     template<class X>
00181     struct impl<quaternion_result_tag,quaternion_result_tag,X> {
00182         typedef size_t size_type;
00183 
00184         /* Record the quaternion size as a constant: */
00185         enum { array_size = 4 };
00186 
00187         /* Return the quaternion size: */
00188         size_type size() const { return size_type(array_size); }
00189     };
00190 
00191     /* Check for a quaternion and a vector: */
00192     template<class X> struct impl<quaternion_result_tag,vector_result_tag,X> {
00193         typedef size_t size_type;
00194         CML_STATIC_REQUIRE_M(
00195                 RightT::array_size == 4,
00196                 incompatible_expression_size_error);
00197 
00198         /* Record the quaternion size as a constant: */
00199         enum { array_size = 4 };
00200 
00201         /* Return the quaternion size: */
00202         size_type size() const { return size_type(array_size); }
00203     };
00204 
00205     /* Check for a vector and a quaternion: */
00206     template<class X> struct impl<vector_result_tag,quaternion_result_tag,X> {
00207         typedef size_t size_type;
00208         CML_STATIC_REQUIRE_M(
00209                 LeftT::array_size == 4,
00210                 incompatible_expression_size_error);
00211 
00212         /* Record the quaternion size as a constant: */
00213         enum { array_size = 4 };
00214 
00215         /* Return the quaternion size: */
00216         size_type size() const { return size_type(array_size); }
00217     };
00218 
00219     /* Check for a quaternion and a scalar: */
00220     template<class X> struct impl<quaternion_result_tag,scalar_result_tag,X> {
00221         typedef size_t size_type;
00222 
00223         /* Record the quaternion size as a constant: */
00224         enum { array_size = 4 };
00225 
00226         /* Return the quaternion size: */
00227         size_type size() const { return size_type(array_size); }
00228     };
00229 
00230     /* Check for a scalar and a quaternion: */
00231     template<class X> struct impl<scalar_result_tag,quaternion_result_tag,X> {
00232         typedef size_t size_type;
00233 
00234         /* Record the array size as a constant: */
00235         enum { array_size = 4 };
00236 
00237         /* Return the quaternion size: */
00238         size_type size() const { return size_type(array_size); }
00239     };
00240 
00241     /* Record the type of the checker: */
00242     typedef impl<left_result,right_result> check_type;
00243     typedef typename check_type::size_type size_type;
00244 
00245     /* The implementation: */
00246     size_type operator()(const LeftT&, const RightT&) const {
00247         return check_type().size();
00248     }
00249 };
00250 
00251 /* Checking for resizeable expression: */
00252 template<typename LeftT, typename RightT>
00253 struct GetCheckedSize<LeftT,RightT,dynamic_size_tag>
00254 {
00255     /* Type of the size checker (for calling equal_or_fail): */
00256     typedef GetCheckedSize<LeftT,RightT,dynamic_size_tag> self;
00257 
00258     /* Record argument traits: */
00259     typedef ExprTraits<LeftT> left_traits;
00260     typedef ExprTraits<RightT> right_traits;
00261 
00262     /* Result types: */
00263     typedef typename left_traits::result_tag left_result;
00264     typedef typename right_traits::result_tag right_result;
00265 
00266 
00267     /* For specialization below: */
00268     template<typename LR, typename RR, class X = void> struct impl;
00269 
00270     /* Return the size if the same, or fail if different: */
00271     template<typename V> V equal_or_fail(V left, V right) const {
00272         if(left != right)
00273             throw std::invalid_argument(
00274                     "expressions have incompatible sizes.");
00275         return left;
00276     }
00277 
00278     /* Check for two matrices (linear operators only): */
00279     template<class X> struct impl<matrix_result_tag,matrix_result_tag,X> {
00280         typedef matrix_size size_type;
00281 
00282         /* Return the matrix size, or fail if incompatible: */
00283         size_type size(const LeftT& left, const RightT& right) const {
00284 #if defined(CML_CHECK_MATRIX_EXPR_SIZES)
00285             return self().equal_or_fail(left.size(), right.size());
00286 #else
00287             return left.size();
00288 #endif
00289         }
00290     };
00291 
00292     /* Check for a matrix and a vector: */
00293     template<class X> struct impl<matrix_result_tag,vector_result_tag,X> {
00294         typedef size_t size_type;
00295 
00296         /* Return the vector size: */
00297         size_type size(const LeftT& left, const RightT& right) const {
00298 #if defined(CML_CHECK_MATVEC_EXPR_SIZES)
00299             self().equal_or_fail(left.cols(), right.size());
00300 #endif
00301             return left.rows();
00302         }
00303     };
00304 
00305     /* Check for a vector and a matrix: */
00306     template<class X> struct impl<vector_result_tag,matrix_result_tag,X> {
00307         typedef size_t size_type;
00308 
00309         /* Return the vector size: */
00310         size_type size(const LeftT& left, const RightT& right) const {
00311 #if defined(CML_CHECK_MATVEC_EXPR_SIZES)
00312             self().equal_or_fail(left.size(), right.rows());
00313 #endif
00314             return right.cols(right);
00315         }
00316     };
00317 
00318     /* Check for a matrix and a scalar: */
00319     template<class X> struct impl<matrix_result_tag,scalar_result_tag,X> {
00320         typedef matrix_size size_type;
00321 
00322         /* Return the matrix size: */
00323         size_type size(const LeftT& left, const RightT&) const {
00324             return left.size();
00325         }
00326     };
00327 
00328     /* Check for a scalar and a matrix: */
00329     template<class X> struct impl<scalar_result_tag,matrix_result_tag,X> {
00330         typedef matrix_size size_type;
00331 
00332         /* Return the matrix size: */
00333         size_type size(const LeftT&, const RightT& right) const {
00334             return right.size();
00335         }
00336     };
00337 
00338     /* Check for two vectors: */
00339     template<class X> struct impl<vector_result_tag,vector_result_tag,X> {
00340         typedef size_t size_type;
00341 
00342         /* Return the vector size: */
00343         size_type size(const LeftT& left, const RightT& right) const {
00344 #if defined(CML_CHECK_VECTOR_EXPR_SIZES)
00345             return self().equal_or_fail(left.size(), right.size());
00346 #else
00347             return left.size();
00348 #endif
00349         }
00350     };
00351 
00352     /* Check for a vector and a scalar: */
00353     template<class X> struct impl<vector_result_tag,scalar_result_tag,X> {
00354         typedef size_t size_type;
00355 
00356         /* Return the vector size: */
00357         size_type size(const LeftT& left, const RightT&) const {
00358             return left.size();
00359         }
00360     };
00361 
00362     /* Check for a scalar and a vector: */
00363     template<class X> struct impl<scalar_result_tag,vector_result_tag,X> {
00364         typedef size_t size_type;
00365 
00366         /* Return the vector size: */
00367         size_type size(const LeftT&, const RightT& right) const {
00368             return right.size();
00369         }
00370     };
00371 
00372     /* Record the type of the checker: */
00373     typedef impl<left_result,right_result> check_type;
00374     typedef typename check_type::size_type size_type;
00375 
00376     /* The implementation: */
00377     size_type operator()(const LeftT& left, const RightT& right) const {
00378         return check_type().size(left,right);
00379     }
00380 };
00381 
00383 template<typename LeftT, typename RightT, typename SizeTag>
00384 inline typename et::GetCheckedSize<LeftT,RightT,SizeTag>::size_type
00385 CheckedSize(const LeftT& left, const RightT& right, SizeTag)
00386 {
00387     return et::GetCheckedSize<LeftT,RightT,SizeTag>()(left,right);
00388 }
00389 
00394 template<typename MatT> inline size_t
00395 CheckedSquare(const MatT&, fixed_size_tag)
00396 {
00397     CML_STATIC_REQUIRE_M(
00398             ((size_t)MatT::array_rows == (size_t)MatT::array_cols),
00399             square_matrix_arg_expected_error);
00400     return (size_t)MatT::array_rows;
00401 }
00402 
00407 template<typename MatT> inline size_t
00408 CheckedSquare(const MatT& m, dynamic_size_tag)
00409 {
00410     matrix_size N = m.size();
00411     et::GetCheckedSize<MatT,MatT,dynamic_size_tag>()
00412         .equal_or_fail(N.first, N.second);
00413     return N.first;
00414 }
00415 
00416 } // namespace et
00417 } // namespace cml
00418 
00419 #if defined(_MSC_VER) && _MSC_VER < 1400
00420 #pragma warning(pop)
00421 #endif
00422 
00423 #endif
00424 
00425 // -------------------------------------------------------------------------
00426 // vim:ft=cpp

Generated on Sat Jul 18 19:35:20 2009 for CML 1.0 by  doxygen 1.5.9