/* -*- 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 * * @note GCC4 requires a copy constructor to elide---it won't elide a * compiler-generated copy constructor! */ #ifndef matrix_class_ops_h #define matrix_class_ops_h #if defined(_MSC_VER) && _MSC_VER < 1400 #pragma warning(disable:4003) // XXX Horrible hack to turn off warnings about "not enough actual params" // for the macros below. #endif /* This is to circumvent the problem of commas in a macro argument. It's * used to instantiate CML_ACCUMULATED_MATRIX_MULT: */ #define TEMPLATED_MATRIX_MACRO matrix /* XXX HACK!!! This is a hack to resize in the assign() functions only when * auto resizing is turned off. */ #if !defined(CML_MATRIX_RESIZE_ON_ASSIGNMENT) #define _DO_MATRIX_SET_RESIZE(_R_,_C_) cml::et::detail::Resize(*this,_R_,_C_) #else #define _DO_MATRIX_SET_RESIZE(_R_,_C_) #endif /** Set a matrix from 2x2 values. * * The layout assumed for the values is that of the matrix being assigned. */ #define CML_ASSIGN_MAT_22 \ matrix_type& \ set( \ ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \ ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11 \ ) \ { \ _DO_MATRIX_SET_RESIZE(2,2); \ /* This is overkill, but simplifies size checking: */ \ value_type v[2][2] = {{e00,e01},{e10,e11}}; \ typedef et::OpAssign OpT; \ typedef const value_type element; \ cml::matrix, basis_orient, row_major> \ src(&v[0][0]); \ et::UnrollAssignment(*this,src); \ return *this; \ } /** Create a matrix from 3x3 values. * * The layout assumed for the values is that of the matrix being assigned. */ #define CML_ASSIGN_MAT_33 \ matrix_type& \ set( \ ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, ELEMENT_ARG_TYPE e02, \ ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, ELEMENT_ARG_TYPE e12, \ ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, ELEMENT_ARG_TYPE e22 \ ) \ { \ _DO_MATRIX_SET_RESIZE(3,3); \ /* This is overkill, but simplifies size checking: */ \ value_type v[3][3] = { \ {e00,e01,e02}, \ {e10,e11,e12}, \ {e20,e21,e22} \ }; \ typedef et::OpAssign OpT; \ typedef const value_type element; \ cml::matrix, basis_orient, row_major> \ src(&v[0][0]); \ et::UnrollAssignment(*this,src); \ return *this; \ } /** Create a matrix from 4x4 values. * * The layout assumed for the values is that of the matrix being assigned. */ #define CML_ASSIGN_MAT_44 \ matrix_type& \ set( \ ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \ ELEMENT_ARG_TYPE e02, ELEMENT_ARG_TYPE e03, \ ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, \ ELEMENT_ARG_TYPE e12, ELEMENT_ARG_TYPE e13, \ ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, \ ELEMENT_ARG_TYPE e22, ELEMENT_ARG_TYPE e23, \ ELEMENT_ARG_TYPE e30, ELEMENT_ARG_TYPE e31, \ ELEMENT_ARG_TYPE e32, ELEMENT_ARG_TYPE e33 \ ) \ { \ _DO_MATRIX_SET_RESIZE(4,4); \ /* This is overkill, but simplifies size checking: */ \ value_type v[4][4] = { \ {e00,e01,e02,e03}, \ {e10,e11,e12,e13}, \ {e20,e21,e22,e23}, \ {e30,e31,e32,e33} \ }; \ typedef et::OpAssign OpT; \ typedef const value_type element; \ cml::matrix, basis_orient, row_major> \ src(&v[0][0]); \ et::UnrollAssignment(*this,src); \ return *this; \ } /** Create a matrix from 2x2 values. * * The layout assumed for the values is that of the matrix being assigned. */ #define CML_CONSTRUCT_MAT_22 \ matrix( \ ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \ ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11 \ ) \ { \ set( \ e00,e01, \ e10,e11 \ ); \ } /** Create a matrix from 3x3 values. * * The layout assumed for the values is that of the matrix being assigned. */ #define CML_CONSTRUCT_MAT_33 \ matrix( \ ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, ELEMENT_ARG_TYPE e02, \ ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, ELEMENT_ARG_TYPE e12, \ ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, ELEMENT_ARG_TYPE e22 \ ) \ { \ set( \ e00,e01,e02, \ e10,e11,e12, \ e20,e21,e22 \ ); \ } /** Create a matrix from 4x4 values. * * The layout assumed for the values is that of the matrix being assigned. */ #define CML_CONSTRUCT_MAT_44 \ matrix( \ ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \ ELEMENT_ARG_TYPE e02, ELEMENT_ARG_TYPE e03, \ ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, \ ELEMENT_ARG_TYPE e12, ELEMENT_ARG_TYPE e13, \ ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, \ ELEMENT_ARG_TYPE e22, ELEMENT_ARG_TYPE e23, \ ELEMENT_ARG_TYPE e30, ELEMENT_ARG_TYPE e31, \ ELEMENT_ARG_TYPE e32, ELEMENT_ARG_TYPE e33 \ ) \ { \ set( \ e00,e01,e02,e03, \ e10,e11,e12,e13, \ e20,e21,e22,e23, \ e30,e31,e32,e33 \ ); \ } /** Copy-construct a matrix from a fixed-size array of values. */ #define CML_MAT_COPY_FROM_FIXED_ARRAY(_R_,_C_) \ matrix(const value_type m[_R_][_C_]) { \ typedef et::OpAssign OpT; \ cml::matrix, \ basis_orient, row_major> src(&m[0][0]); \ et::UnrollAssignment(*this,src); \ } /** Copy-construct a matrix from a runtime-sized array of values. */ #define CML_MAT_COPY_FROM_ARRAY(_add_) \ matrix(const value_type* const v, size_t R, size_t C) _add_ { \ typedef et::OpAssign OpT; \ cml::matrix, basis_orient, \ row_major > src(const_cast(v),R,C); \ et::UnrollAssignment(*this,src); \ } /** Copy this matrix from another using the given elementwise op. * * @internal This is required for GCC4, since it won't elide the default * copy constructor. */ #define CML_MAT_COPY_FROM_MATTYPE \ matrix(const matrix_type& m) : array_type() { \ typedef et::OpAssign OpT; \ et::UnrollAssignment(*this,m); \ } /** Copy this matrix from another using the given elementwise op. * * This allows copies from arbitrary matrix types. */ #define CML_MAT_COPY_FROM_MAT \ template \ matrix(const TEMPLATED_MATRIX_MACRO& m) { \ typedef et::OpAssign OpT; \ et::UnrollAssignment(*this,m); \ } /** Declare a function to copy this matrix from a matrix expression. */ #define CML_MAT_COPY_FROM_MATXPR \ template \ matrix(MATXPR_ARG_TYPE e) { \ /* Verify that a promotion exists at compile time: */ \ typedef typename et::MatrixPromote< \ matrix_type, typename XprT::result_type>::type result_type; \ typedef typename XprT::value_type src_value_type; \ typedef et::OpAssign OpT; \ et::UnrollAssignment(*this,e); \ } #if defined(CML_USE_GENERATED_MATRIX_ASSIGN_OP) #define CML_MAT_ASSIGN_FROM_MATTYPE #else /** Assign from the same matrix type. * * @param m the matrix to copy from. * * @note This is required for GCC4, otherwise it generates a slow * assignment operator using memcpy. * * @note ICC9/Linux-x86 seems to prefer its own assignment operator (need * to figure out why). */ #define CML_MAT_ASSIGN_FROM_MATTYPE \ matrix_type& operator=(const matrix_type& m) { \ typedef et::OpAssign OpT; \ et::UnrollAssignment(*this,m); \ return *this; \ } #endif /** Assign this matrix from another using the given elementwise op. * * This allows assignment from arbitrary matrix types. * * @param _op_ the operator (e.g. +=) * @param _op_name_ the op functor (e.g. et::OpAssign) */ #define CML_MAT_ASSIGN_FROM_MAT(_op_, _op_name_) \ template matrix_type& \ operator _op_ (const TEMPLATED_MATRIX_MACRO& m) { \ typedef _op_name_ OpT; \ et::UnrollAssignment(*this,m); \ return *this; \ } /** Declare a function to assign this matrix from a matrix expression. * * @param _op_ the operator (e.g. +=) * @param _op_name_ the op functor (e.g. et::OpAssign) */ #define CML_MAT_ASSIGN_FROM_MATXPR(_op_, _op_name_) \ template matrix_type& \ operator _op_ (MATXPR_ARG_TYPE e) { \ /* Verify that a promotion exists at compile time: */ \ typedef typename et::MatrixPromote< \ matrix_type, typename XprT::result_type>::type result_type; \ typedef typename XprT::value_type src_value_type; \ typedef _op_name_ OpT; \ et::UnrollAssignment(*this,e); \ return *this; \ } /** Declare a function to assign this matrix from a scalar. * * @param _op_ the operator (e.g. +=) * @param _op_name_ the op functor (e.g. et::OpAssign) * * @internal This shouldn't be used for ops, like +=, which aren't * defined in vector algebra. */ #define CML_MAT_ASSIGN_FROM_SCALAR(_op_, _op_name_) \ matrix_type& operator _op_ (ELEMENT_ARG_TYPE s) { \ typedef _op_name_ OpT; \ et::UnrollAssignment(*this,s); \ return *this; \ } /** Accumulated matrix multiplication. * * @throws std::invalid_argument if the matrices are not square. */ #define CML_ACCUMULATED_MATRIX_MULT(_arg_type_) \ matrix_type& operator*=(_arg_type_ m) { \ typedef typename et::MatrixPromote< \ matrix_type, _arg_type_>::type result_type; \ cml::et::CheckedSquare(*this, typename result_type::size_tag()); \ return (*this = (*this)*m); \ } /* These should only be used for testing: */ #define CML_MATRIX_BRACE_OPERATORS \ template struct row_ref { \ typedef typename Matrix::reference reference; \ reference operator[](size_t col) { return m(row,col); } \ Matrix& m; \ size_t row; \ }; \ \ template struct const_row_ref { \ typedef typename Matrix::const_reference const_reference; \ const_reference operator[](size_t col) const { return m(row,col); } \ const Matrix& m; \ size_t row; \ }; \ \ row_ref operator[](size_t row) { \ row_ref ref = { *this, row }; return ref; \ } \ \ const_row_ref operator[](size_t row) const { \ const_row_ref ref = { *this, row }; return ref; \ } #endif // ------------------------------------------------------------------------- // vim:ft=cpp