X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;ds=sidebyside;f=src%2FMoof%2Fcml%2Fet%2Fsize_checking.h;fp=src%2FMoof%2Fcml%2Fet%2Fsize_checking.h;h=323afb53672479dc9962f69afc178d85c8cafa83;hb=c2321281bf12a7efaedde930422c7ddbc92080d4;hp=0000000000000000000000000000000000000000;hpb=87bc17e55b0c1dc73ecc66df856d3f08fd7a7724;p=chaz%2Fyoink diff --git a/src/Moof/cml/et/size_checking.h b/src/Moof/cml/et/size_checking.h new file mode 100644 index 0000000..323afb5 --- /dev/null +++ b/src/Moof/cml/et/size_checking.h @@ -0,0 +1,426 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Define matrix and vector linear expression size-checking classes. + */ + +#ifndef size_checking_h +#define size_checking_h + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma warning(push) +#pragma warning(disable:4348) +// XXX This is a terrible hack for VC7.1, and should really be fixed by +// separating out the "impl" templates from GetCheckedSize. +#endif + +/* This is used below to create a more meaningful compile-time error when + * fixed-size vector arguments don't match at compile time: + */ +struct incompatible_expression_size_error; + +/* This is used below to create a more meaningful compile-time error when a + * function is not provided with a square matrix or MatrixExpr argument: + */ +struct square_matrix_arg_expected_error; + +namespace cml { +namespace et { +namespace detail { + +} // namespace detail + +/* Forward declare for specialization below: */ +template + struct GetCheckedSize; + +/* Checking for fixed-size expression: */ +template +struct GetCheckedSize +{ + /* Record argument traits: */ + typedef ExprTraits left_traits; + typedef ExprTraits right_traits; + + /* Result types: */ + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + + /* For specialization below: */ + template struct impl; + + /* Check for two matrices (linear operators only): */ + template struct impl { + typedef matrix_size size_type; + CML_STATIC_REQUIRE_M( + (size_t)LeftT::array_rows == (size_t)RightT::array_rows + && (size_t)LeftT::array_cols == (size_t)RightT::array_cols, + incompatible_expression_size_error); + + /* Record the array size as a constant: */ + enum { + array_rows = LeftT::array_rows, + array_cols = LeftT::array_cols + }; + + /* Return the matrix size: */ + size_type size() const { return size_type(array_rows,array_cols); } + }; + + /* Check for a matrix and a vector: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + (size_t)LeftT::array_cols == (size_t)RightT::array_size, + incompatible_expression_size_error); + + /* Record the array size as a constant: */ + enum { array_size = LeftT::array_rows }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a vector and a matrix: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + (size_t)LeftT::array_size == (size_t)RightT::array_rows, + incompatible_expression_size_error); + + /* Record the array size as a constant: */ + enum { array_size = RightT::array_cols }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a matrix and a scalar: */ + template struct impl { + typedef matrix_size size_type; + + /* Record the array size as a constant: */ + enum { + array_rows = LeftT::array_rows, + array_cols = LeftT::array_cols + }; + + /* Return the matrix size: */ + size_type size() const { return size_type(array_rows,array_cols); } + }; + + /* Check for a scalar and a matrix: */ + template struct impl { + typedef matrix_size size_type; + + /* Record the array size as a constant: */ + enum { + array_rows = RightT::array_rows, + array_cols = RightT::array_cols + }; + + /* Return the matrix size: */ + size_type size() const { return size_type(array_rows,array_cols); } + }; + + + /* Check for two vectors: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + (size_t)LeftT::array_size == (size_t)RightT::array_size, + incompatible_expression_size_error); + + /* Record the array size as a constant: */ + enum { array_size = LeftT::array_size }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a vector and a scalar: */ + template struct impl { + typedef size_t size_type; + + /* Record the array size as a constant: */ + enum { array_size = LeftT::array_size }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a scalar and a vector: */ + template struct impl { + typedef size_t size_type; + + /* Record the array size as a constant: */ + enum { array_size = RightT::array_size }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + + /* Check for two quaternions: */ + template + struct impl { + typedef size_t size_type; + + /* Record the quaternion size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a quaternion and a vector: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + RightT::array_size == 4, + incompatible_expression_size_error); + + /* Record the quaternion size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a vector and a quaternion: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + LeftT::array_size == 4, + incompatible_expression_size_error); + + /* Record the quaternion size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a quaternion and a scalar: */ + template struct impl { + typedef size_t size_type; + + /* Record the quaternion size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a scalar and a quaternion: */ + template struct impl { + typedef size_t size_type; + + /* Record the array size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Record the type of the checker: */ + typedef impl check_type; + typedef typename check_type::size_type size_type; + + /* The implementation: */ + size_type operator()(const LeftT&, const RightT&) const { + return check_type().size(); + } +}; + +/* Checking for resizeable expression: */ +template +struct GetCheckedSize +{ + /* Type of the size checker (for calling equal_or_fail): */ + typedef GetCheckedSize self; + + /* Record argument traits: */ + typedef ExprTraits left_traits; + typedef ExprTraits right_traits; + + /* Result types: */ + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + + /* For specialization below: */ + template struct impl; + + /* Return the size if the same, or fail if different: */ + template V equal_or_fail(V left, V right) const { + if(left != right) + throw std::invalid_argument( + "expressions have incompatible sizes."); + return left; + } + + /* Check for two matrices (linear operators only): */ + template struct impl { + typedef matrix_size size_type; + + /* Return the matrix size, or fail if incompatible: */ + size_type size(const LeftT& left, const RightT& right) const { +#if defined(CML_CHECK_MATRIX_EXPR_SIZES) + return self().equal_or_fail(left.size(), right.size()); +#else + return left.size(); +#endif + } + }; + + /* Check for a matrix and a vector: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT& left, const RightT& right) const { +#if defined(CML_CHECK_MATVEC_EXPR_SIZES) + self().equal_or_fail(left.cols(), right.size()); +#endif + return left.rows(); + } + }; + + /* Check for a vector and a matrix: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT& left, const RightT& right) const { +#if defined(CML_CHECK_MATVEC_EXPR_SIZES) + self().equal_or_fail(left.size(), right.rows()); +#endif + return right.cols(right); + } + }; + + /* Check for a matrix and a scalar: */ + template struct impl { + typedef matrix_size size_type; + + /* Return the matrix size: */ + size_type size(const LeftT& left, const RightT&) const { + return left.size(); + } + }; + + /* Check for a scalar and a matrix: */ + template struct impl { + typedef matrix_size size_type; + + /* Return the matrix size: */ + size_type size(const LeftT&, const RightT& right) const { + return right.size(); + } + }; + + /* Check for two vectors: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT& left, const RightT& right) const { +#if defined(CML_CHECK_VECTOR_EXPR_SIZES) + return self().equal_or_fail(left.size(), right.size()); +#else + return left.size(); +#endif + } + }; + + /* Check for a vector and a scalar: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT& left, const RightT&) const { + return left.size(); + } + }; + + /* Check for a scalar and a vector: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT&, const RightT& right) const { + return right.size(); + } + }; + + /* Record the type of the checker: */ + typedef impl check_type; + typedef typename check_type::size_type size_type; + + /* The implementation: */ + size_type operator()(const LeftT& left, const RightT& right) const { + return check_type().size(left,right); + } +}; + +/** Generator for GetCheckedSize. */ +template +inline typename et::GetCheckedSize::size_type +CheckedSize(const LeftT& left, const RightT& right, SizeTag) +{ + return et::GetCheckedSize()(left,right); +} + +/** Verify the sizes of the argument matrices for matrix multiplication. + * + * @returns a the size of the resulting matrix. + */ +template inline size_t +CheckedSquare(const MatT&, fixed_size_tag) +{ + CML_STATIC_REQUIRE_M( + ((size_t)MatT::array_rows == (size_t)MatT::array_cols), + square_matrix_arg_expected_error); + return (size_t)MatT::array_rows; +} + +/** Verify the sizes of the argument matrices for matrix multiplication. + * + * @returns the size of the resulting matrix. + */ +template inline size_t +CheckedSquare(const MatT& m, dynamic_size_tag) +{ + matrix_size N = m.size(); + et::GetCheckedSize() + .equal_or_fail(N.first, N.second); + return N.first; +} + +} // namespace et +} // namespace cml + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma warning(pop) +#endif + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp