Initial commit
This commit is contained in:
288
Lib/Include/CML/et/array_promotions.h
Normal file
288
Lib/Include/CML/et/array_promotions.h
Normal file
@@ -0,0 +1,288 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* Defines promotions between array types.
|
||||
*
|
||||
* @todo Can/should an expression with a fixed-size argument promote to a
|
||||
* fixed array instead of a dynamic array?
|
||||
*/
|
||||
|
||||
#ifndef array_promotions_h
|
||||
#define array_promotions_h
|
||||
|
||||
#include <cml/core/cml_meta.h>
|
||||
#include <cml/et/scalar_promotions.h>
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
#define VAL_MAX(_a_,_b_) ( ((_a_)>(_b_))?(_a_):(_b_) )
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* This is specialized for 1D and 2D promotions: */
|
||||
template<class A1, class A2, typename DTag1, typename DTag2,
|
||||
typename PromotedSizeTag> struct promote;
|
||||
|
||||
/* Promote 1D fixed-size arrays to a 1D fixed-size array: */
|
||||
template<class A1, class A2>
|
||||
struct promote<A1,A2,oned_tag,oned_tag,fixed_size_tag>
|
||||
{
|
||||
typedef typename A1::value_type left_scalar;
|
||||
typedef typename A2::value_type right_scalar;
|
||||
|
||||
/* First, promote the scalar type: */
|
||||
typedef typename ScalarPromote<
|
||||
left_scalar,right_scalar>::type promoted_scalar;
|
||||
|
||||
/* Next, deduce the array size: */
|
||||
enum { Size = VAL_MAX((size_t)A1::array_size, (size_t)A2::array_size) };
|
||||
|
||||
/* Finally, generate the promoted array type: */
|
||||
typedef fixed_1D<promoted_scalar,Size> type;
|
||||
};
|
||||
|
||||
/* Promote 1D dynamic arrays to a 1D dynamic array: */
|
||||
template<class A1, class A2>
|
||||
struct promote<A1,A2,oned_tag,oned_tag,dynamic_size_tag>
|
||||
{
|
||||
typedef typename A1::value_type left_scalar;
|
||||
typedef typename A2::value_type right_scalar;
|
||||
|
||||
/* First, promote the scalar type: */
|
||||
typedef typename ScalarPromote<
|
||||
left_scalar,right_scalar>::type promoted_scalar;
|
||||
|
||||
/* Next, rebind to get the proper allocator: */
|
||||
typedef typename CML_DEFAULT_ARRAY_ALLOC
|
||||
::rebind<promoted_scalar>::other allocator;
|
||||
|
||||
/* Finally, generate the promoted array type: */
|
||||
typedef dynamic_1D<promoted_scalar,allocator> type;
|
||||
};
|
||||
|
||||
/* Promote fixed 2D+1D array expressions to a fixed 1D array: */
|
||||
template<class A1, class A2>
|
||||
struct promote<A1,A2,twod_tag,oned_tag,fixed_size_tag>
|
||||
{
|
||||
typedef typename A1::value_type left_scalar;
|
||||
typedef typename A2::value_type right_scalar;
|
||||
|
||||
/* First, promote the scalar type: */
|
||||
typedef typename ScalarPromote<
|
||||
left_scalar,right_scalar>::type promoted_scalar;
|
||||
|
||||
/* Next, deduce the array size: */
|
||||
enum { Size = (size_t)A1::array_rows };
|
||||
|
||||
/* Finally, generate the promoted array type: */
|
||||
typedef fixed_1D<promoted_scalar,Size> type;
|
||||
};
|
||||
|
||||
/* Promote fixed 1D+2D array expressions to a fixed 1D array: */
|
||||
template<class A1, class A2>
|
||||
struct promote<A1,A2,oned_tag,twod_tag,fixed_size_tag>
|
||||
{
|
||||
typedef typename A1::value_type left_scalar;
|
||||
typedef typename A2::value_type right_scalar;
|
||||
|
||||
/* First, promote the scalar type: */
|
||||
typedef typename ScalarPromote<
|
||||
left_scalar,right_scalar>::type promoted_scalar;
|
||||
|
||||
/* Next, deduce the array size: */
|
||||
enum { Size = (size_t)A2::array_cols };
|
||||
|
||||
/* Finally, generate the promoted array type: */
|
||||
typedef fixed_1D<promoted_scalar,Size> type;
|
||||
};
|
||||
|
||||
/* Promote dynamic 2D+1D array expression to a 1D dynamic array: */
|
||||
template<class A1, class A2>
|
||||
struct promote<A1,A2,twod_tag,oned_tag,dynamic_size_tag>
|
||||
{
|
||||
typedef typename A1::value_type left_scalar;
|
||||
typedef typename A2::value_type right_scalar;
|
||||
|
||||
/* First, promote the scalar type: */
|
||||
typedef typename ScalarPromote<
|
||||
left_scalar,right_scalar>::type promoted_scalar;
|
||||
|
||||
/* Next, rebind to get the proper allocator: */
|
||||
typedef typename CML_DEFAULT_ARRAY_ALLOC
|
||||
::rebind<promoted_scalar>::other allocator;
|
||||
|
||||
/* Finally, generate the promoted array type: */
|
||||
typedef dynamic_1D<promoted_scalar,allocator> type;
|
||||
};
|
||||
|
||||
/* Promote dynamic 1D+2D array expression to a 1D dynamic array: */
|
||||
template<class A1, class A2>
|
||||
struct promote<A1,A2,oned_tag,twod_tag,dynamic_size_tag>
|
||||
{
|
||||
typedef typename A1::value_type left_scalar;
|
||||
typedef typename A2::value_type right_scalar;
|
||||
|
||||
/* First, promote the scalar type: */
|
||||
typedef typename ScalarPromote<
|
||||
left_scalar,right_scalar>::type promoted_scalar;
|
||||
|
||||
/* Next, rebind to get the proper allocator: */
|
||||
typedef typename CML_DEFAULT_ARRAY_ALLOC
|
||||
::rebind<promoted_scalar>::other allocator;
|
||||
|
||||
/* Finally, generate the promoted array type: */
|
||||
typedef dynamic_1D<promoted_scalar,allocator> type;
|
||||
};
|
||||
|
||||
|
||||
/* This is a helper to deduce the result of a promoted 2D array: */
|
||||
template<typename LeftL, typename RightL> struct deduce_layout {
|
||||
#if defined(CML_ALWAYS_PROMOTE_TO_DEFAULT_LAYOUT)
|
||||
typedef CML_DEFAULT_ARRAY_LAYOUT promoted_layout;
|
||||
#else
|
||||
typedef typename select_if<
|
||||
same_type<LeftL,RightL>::is_true, LeftL,
|
||||
CML_DEFAULT_ARRAY_LAYOUT>::result promoted_layout;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Promote 2D fixed-size arrays to a 2D fixed-size array. The resulting
|
||||
* matrix has the same number of rows as A1, and the same number of
|
||||
* columns as A2.
|
||||
*/
|
||||
template<class A1, class A2>
|
||||
struct promote<A1,A2,twod_tag,twod_tag,fixed_size_tag>
|
||||
{
|
||||
typedef typename A1::value_type left_scalar;
|
||||
typedef typename A2::value_type right_scalar;
|
||||
|
||||
/* First, promote the scalar type: */
|
||||
typedef typename ScalarPromote<
|
||||
left_scalar,right_scalar>::type promoted_scalar;
|
||||
|
||||
/* Next, deduce the array size: */
|
||||
enum {
|
||||
Rows = (size_t)A1::array_rows,
|
||||
Cols = (size_t)A2::array_cols
|
||||
};
|
||||
|
||||
/* Then deduce the array layout: */
|
||||
typedef typename A1::layout left_layout;
|
||||
typedef typename A2::layout right_layout;
|
||||
typedef typename deduce_layout<left_layout,right_layout>
|
||||
::promoted_layout promoted_layout;
|
||||
|
||||
/* Finally, generate the promoted array type: */
|
||||
typedef fixed_2D<promoted_scalar,Rows,Cols,promoted_layout> type;
|
||||
};
|
||||
|
||||
/* Promote 2D dynamic arrays to a 2D dynamic array: */
|
||||
template<class A1, class A2>
|
||||
struct promote<A1,A2,twod_tag,twod_tag,dynamic_size_tag>
|
||||
{
|
||||
typedef typename A1::value_type left_scalar;
|
||||
typedef typename A2::value_type right_scalar;
|
||||
|
||||
/* First, promote the scalar type: */
|
||||
typedef typename ScalarPromote<
|
||||
left_scalar,right_scalar>::type promoted_scalar;
|
||||
|
||||
/* Next, rebind to get the proper allocator: */
|
||||
typedef typename CML_DEFAULT_ARRAY_ALLOC
|
||||
::rebind<promoted_scalar>::other allocator;
|
||||
|
||||
/* Then deduce the array layout: */
|
||||
typedef typename A1::layout left_layout;
|
||||
typedef typename A2::layout right_layout;
|
||||
typedef typename deduce_layout<left_layout,right_layout>
|
||||
::promoted_layout promoted_layout;
|
||||
|
||||
/* Finally, generate the promoted array type: */
|
||||
typedef dynamic_2D<promoted_scalar,promoted_layout,allocator> type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Class to promote array types.
|
||||
*
|
||||
* Both arguments must be array types.
|
||||
*
|
||||
* @sa fixed_1D
|
||||
* @sa fixed_2D
|
||||
* @sa dynamic_1D
|
||||
* @sa dynamic_2D
|
||||
*/
|
||||
template<class A1, class A2>
|
||||
struct ArrayPromote
|
||||
{
|
||||
/* Shorthand: */
|
||||
//typedef typename A1::value_type left_scalar;
|
||||
//typedef typename A2::value_type right_scalar;
|
||||
typedef typename A1::dimension_tag left_dtag;
|
||||
typedef typename A2::dimension_tag right_dtag;
|
||||
|
||||
/* Deduce the proper type based upon the characteristics of AT1 and
|
||||
* AT2. This is the table of type conversions:
|
||||
*
|
||||
* AT1 AT2 Result
|
||||
* memory size memory size memory size
|
||||
*
|
||||
* fixed fixed fixed fixed fixed fixed
|
||||
* fixed fixed dynamic dynamic dynamic dynamic
|
||||
* fixed fixed external fixed fixed fixed
|
||||
* fixed fixed external dynamic dynamic dynamic
|
||||
*
|
||||
* dynamic dynamic fixed fixed dynamic dynamic
|
||||
* dynamic dynamic dynamic dynamic dynamic dynamic
|
||||
* dynamic dynamic external fixed dynamic dynamic
|
||||
* dynamic dynamic external dynamic dynamic dynamic
|
||||
*
|
||||
* external fixed external fixed fixed fixed
|
||||
* external fixed fixed fixed fixed fixed
|
||||
* external fixed dynamic dynamic dynamic dynamic
|
||||
* external fixed external dynamic dynamic dynamic
|
||||
*
|
||||
* external dynamic external fixed dynamic dynamic
|
||||
* external dynamic fixed fixed dynamic dynamic
|
||||
* external dynamic dynamic dynamic dynamic dynamic
|
||||
* external dynamic external dynamic dynamic dynamic
|
||||
*
|
||||
* Note that if one argument is a dynamically-sized array, the result
|
||||
* must be a dynamically allocated and sized array. Likewise, if both
|
||||
* arguments have fixed size, the result can be a fixed-sized array.
|
||||
*/
|
||||
|
||||
/* Check if both arguments are fixed-size arrays. If so, the promoted
|
||||
* array will be a fixed array, and if not, it will be a dynamic array:
|
||||
*/
|
||||
typedef typename select_if<
|
||||
(same_type<typename A1::size_tag, fixed_size_tag>::is_true
|
||||
&& same_type<typename A2::size_tag, fixed_size_tag>::is_true),
|
||||
fixed_size_tag, /* True */
|
||||
dynamic_size_tag /* False */
|
||||
>::result promoted_size_tag;
|
||||
|
||||
/* Deduce the promoted type: */
|
||||
typedef typename detail::promote<
|
||||
A1, A2, left_dtag, right_dtag, promoted_size_tag>::type type;
|
||||
};
|
||||
|
||||
/* Cleanup internal macros: */
|
||||
#undef VAL_MAX
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
138
Lib/Include/CML/et/scalar_ops.h
Normal file
138
Lib/Include/CML/et/scalar_ops.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
|
||||
#ifndef ops_h
|
||||
#define ops_h
|
||||
|
||||
#include <cml/et/traits.h>
|
||||
#include <cml/et/scalar_promotions.h>
|
||||
|
||||
/** Declare a unary scalar operator, like negation. */
|
||||
#define CML_UNARY_SCALAR_OP(_op_, _op_name_) \
|
||||
template<typename ArgT> struct _op_name_ { \
|
||||
typedef ExprTraits<ArgT> arg_traits; \
|
||||
typedef typename arg_traits::const_reference arg_reference; \
|
||||
typedef typename arg_traits::value_type value_type; \
|
||||
typedef scalar_result_tag result_tag; \
|
||||
value_type apply(arg_reference arg) const { return _op_ arg; } \
|
||||
};
|
||||
|
||||
/** Declare a binary scalar operator, like addition, s1+s2. */
|
||||
#define CML_BINARY_SCALAR_OP(_op_, _op_name_) \
|
||||
template<typename LeftT, typename RightT> struct _op_name_ { \
|
||||
typedef ExprTraits<LeftT> left_traits; \
|
||||
typedef ExprTraits<RightT> right_traits; \
|
||||
typedef typename left_traits::const_reference left_reference; \
|
||||
typedef typename right_traits::const_reference right_reference; \
|
||||
typedef typename left_traits::value_type left_value; \
|
||||
typedef typename right_traits::value_type right_value; \
|
||||
typedef typename ScalarPromote<left_value,right_value>::type value_type; \
|
||||
typedef scalar_result_tag result_tag; \
|
||||
value_type apply(left_reference left, right_reference right) const { \
|
||||
return left _op_ right; } \
|
||||
};
|
||||
|
||||
/** Declare an op-assignment operator.
|
||||
*
|
||||
* @note The ExprTraits for both argument types must be defined, LeftT must
|
||||
* have an assignment operator, and ExprTraits<LeftT>::reference must specify
|
||||
* a type that allows assignment.
|
||||
*/
|
||||
#define CML_BINARY_SCALAR_OP_ASSIGN(_op_, _op_name_) \
|
||||
template<typename LeftT, typename RightT> struct _op_name_ { \
|
||||
typedef ExprTraits<LeftT> left_traits; \
|
||||
typedef ExprTraits<RightT> right_traits; \
|
||||
typedef typename left_traits::reference left_reference; \
|
||||
typedef typename right_traits::const_reference right_reference; \
|
||||
typedef typename left_traits::value_type left_value; \
|
||||
typedef typename right_traits::value_type right_value; \
|
||||
typedef typename ScalarPromote<left_value,right_value>::type value_type; \
|
||||
typedef scalar_result_tag result_tag; \
|
||||
value_type apply(left_reference left, right_reference right) const { \
|
||||
return left _op_ (LeftT) right; } \
|
||||
};
|
||||
|
||||
/** Declare a binary boolean operator, like less-than, s1 < s2.
|
||||
*
|
||||
* The operator should return the appropriate truth value for the operator.
|
||||
*
|
||||
* @note Both scalar types must have operator<() defined.
|
||||
*/
|
||||
#define CML_BOOLEAN_SCALAR_OP(_op_, _op_name_) \
|
||||
template<typename LeftT, typename RightT> struct _op_name_ { \
|
||||
typedef ExprTraits<LeftT> left_traits; \
|
||||
typedef ExprTraits<RightT> right_traits; \
|
||||
typedef typename left_traits::const_reference left_reference; \
|
||||
typedef typename right_traits::const_reference right_reference; \
|
||||
typedef scalar_result_tag result_tag; \
|
||||
bool apply(left_reference left, right_reference right) const { \
|
||||
return left _op_ right; } \
|
||||
};
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
/* Define the operators: */
|
||||
|
||||
/* Unary scalar ops: */
|
||||
CML_UNARY_SCALAR_OP(-, OpNeg)
|
||||
CML_UNARY_SCALAR_OP(+, OpPos)
|
||||
|
||||
/* Binary scalar ops: */
|
||||
CML_BINARY_SCALAR_OP(+, OpAdd)
|
||||
CML_BINARY_SCALAR_OP(-, OpSub)
|
||||
CML_BINARY_SCALAR_OP(*, OpMul)
|
||||
|
||||
#if defined(CML_RECIPROCAL_OPTIMIZATION)
|
||||
/* XXX Yikes... this should really be written out in full. *= 1./ is the
|
||||
* "_op_" parameter to the macro (see above):
|
||||
*/
|
||||
CML_BINARY_SCALAR_OP(* value_type(1)/, OpDiv)
|
||||
#else
|
||||
CML_BINARY_SCALAR_OP(/, OpDiv)
|
||||
#endif
|
||||
|
||||
/* Binary scalar op-assigns: */
|
||||
CML_BINARY_SCALAR_OP_ASSIGN( =, OpAssign)
|
||||
CML_BINARY_SCALAR_OP_ASSIGN(+=, OpAddAssign)
|
||||
CML_BINARY_SCALAR_OP_ASSIGN(-=, OpSubAssign)
|
||||
CML_BINARY_SCALAR_OP_ASSIGN(*=, OpMulAssign)
|
||||
|
||||
#if defined(CML_RECIPROCAL_OPTIMIZATION)
|
||||
/* XXX Yikes... this should really be written out in full. *= 1./ is the
|
||||
* "_op_" parameter to the macro (see above):
|
||||
*/
|
||||
CML_BINARY_SCALAR_OP_ASSIGN(*= value_type(1)/, OpDivAssign)
|
||||
#else
|
||||
CML_BINARY_SCALAR_OP_ASSIGN(/=, OpDivAssign)
|
||||
#endif
|
||||
|
||||
/* Boolean operators for scalars: */
|
||||
CML_BOOLEAN_SCALAR_OP(==, OpEqual)
|
||||
CML_BOOLEAN_SCALAR_OP(!=, OpNotEqual)
|
||||
CML_BOOLEAN_SCALAR_OP( <, OpLess)
|
||||
CML_BOOLEAN_SCALAR_OP( >, OpGreater)
|
||||
CML_BOOLEAN_SCALAR_OP(<=, OpLessEqual)
|
||||
CML_BOOLEAN_SCALAR_OP(>=, OpGreaterEqual)
|
||||
|
||||
#undef CML_UNARY_SCALAR_OP
|
||||
#undef CML_BINARY_SCALAR_OP
|
||||
#undef CML_BINARY_SCALAR_OP_ASSIGN
|
||||
#undef CML_BOOLEAN_SCALAR_OP
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
151
Lib/Include/CML/et/scalar_promotions.h
Normal file
151
Lib/Include/CML/et/scalar_promotions.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
|
||||
#ifndef scalar_promotions_h
|
||||
#define scalar_promotions_h
|
||||
|
||||
#include <complex>
|
||||
#include <cml/core/cml_meta.h>
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
/* The type promotion code below is a slightly modified version of:
|
||||
* http://ubiety.uwaterloo.ca/~tveldhui/papers/techniques/techniques01.html
|
||||
*/
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
struct precision_trait {
|
||||
enum { precisionRank = 0,
|
||||
knowPrecisionRank = 0 };
|
||||
};
|
||||
|
||||
#define DECLARE_PRECISION(T,rank) \
|
||||
template<> \
|
||||
struct precision_trait< T > { \
|
||||
enum { precisionRank = rank, \
|
||||
knowPrecisionRank = 1 }; \
|
||||
};
|
||||
|
||||
DECLARE_PRECISION(int,100)
|
||||
DECLARE_PRECISION(unsigned int,200)
|
||||
DECLARE_PRECISION(long,300)
|
||||
DECLARE_PRECISION(unsigned long,400)
|
||||
|
||||
DECLARE_PRECISION(long long,425)
|
||||
DECLARE_PRECISION(unsigned long long,475)
|
||||
|
||||
DECLARE_PRECISION(float,500)
|
||||
DECLARE_PRECISION(double,600)
|
||||
DECLARE_PRECISION(long double,700)
|
||||
DECLARE_PRECISION(std::complex<float>,800)
|
||||
DECLARE_PRECISION(std::complex<double>,900)
|
||||
DECLARE_PRECISION(std::complex<long double>,1000)
|
||||
|
||||
template<class T>
|
||||
struct autopromote_trait {
|
||||
typedef T T_numtype;
|
||||
};
|
||||
|
||||
#define DECLARE_AUTOPROMOTE(T1,T2) \
|
||||
template<> \
|
||||
struct autopromote_trait<T1> { \
|
||||
typedef T2 T_numtype; \
|
||||
};
|
||||
|
||||
// These are the odd cases where small integer types
|
||||
// are automatically promoted to int or unsigned int for
|
||||
// arithmetic.
|
||||
DECLARE_AUTOPROMOTE(bool, int)
|
||||
DECLARE_AUTOPROMOTE(char, int)
|
||||
DECLARE_AUTOPROMOTE(unsigned char, int)
|
||||
DECLARE_AUTOPROMOTE(short int, int)
|
||||
DECLARE_AUTOPROMOTE(short unsigned int, unsigned int)
|
||||
|
||||
template<class T1, class T2, int promoteToT1>
|
||||
struct promote2 {
|
||||
typedef T1 T_promote;
|
||||
};
|
||||
|
||||
template<class T1, class T2>
|
||||
struct promote2<T1,T2,0> {
|
||||
typedef T2 T_promote;
|
||||
};
|
||||
|
||||
template<class T1_orig, class T2_orig>
|
||||
struct promote_trait {
|
||||
|
||||
// Need to remove const-ness:
|
||||
typedef typename cml::remove_const<T1_orig>::type T1_non_const;
|
||||
typedef typename cml::remove_const<T2_orig>::type T2_non_const;
|
||||
|
||||
// Handle promotion of small integers to int/unsigned int
|
||||
typedef typename autopromote_trait<T1_non_const>::T_numtype T1;
|
||||
typedef typename autopromote_trait<T2_non_const>::T_numtype T2;
|
||||
|
||||
// True if T1 is higher ranked
|
||||
enum {
|
||||
T1IsBetter =
|
||||
(int) precision_trait<T1>::precisionRank >
|
||||
(int) precision_trait<T2>::precisionRank,
|
||||
|
||||
// True if we know ranks for both T1 and T2
|
||||
knowBothRanks =
|
||||
precision_trait<T1>::knowPrecisionRank
|
||||
&& precision_trait<T2>::knowPrecisionRank,
|
||||
|
||||
// True if we know T1 but not T2
|
||||
knowT1butNotT2 = precision_trait<T1>::knowPrecisionRank
|
||||
&& !(precision_trait<T2>::knowPrecisionRank),
|
||||
|
||||
// True if we know T2 but not T1
|
||||
knowT2butNotT1 = precision_trait<T2>::knowPrecisionRank
|
||||
&& !(precision_trait<T1>::knowPrecisionRank),
|
||||
|
||||
// True if T1 is bigger than T2
|
||||
T1IsLarger = sizeof(T1) >= sizeof(T2),
|
||||
|
||||
// We know T1 but not T2: true
|
||||
// We know T2 but not T1: false
|
||||
// Otherwise, if T1 is bigger than T2: true
|
||||
defaultPromotion = knowT1butNotT2 ? false :
|
||||
(knowT2butNotT1 ? true : T1IsLarger)
|
||||
};
|
||||
|
||||
// If we have both ranks, then use them.
|
||||
// If we have only one rank, then use the unknown type.
|
||||
// If we have neither rank, then promote to the larger type.
|
||||
|
||||
enum {
|
||||
promoteToT1 = (knowBothRanks ? T1IsBetter : defaultPromotion)
|
||||
? 1 : 0
|
||||
};
|
||||
|
||||
typedef typename promote2<T1,T2,promoteToT1>::T_promote T_promote;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Defers to detail::promote_trait<>. */
|
||||
template<class E1, class E2> struct ScalarPromote
|
||||
{
|
||||
typedef typename detail::promote_trait<E1,E2>::T_promote type;
|
||||
};
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
431
Lib/Include/CML/et/size_checking.h
Normal file
431
Lib/Include/CML/et/size_checking.h
Normal file
@@ -0,0 +1,431 @@
|
||||
/* -*- 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 <stdexcept>
|
||||
#include <cml/core/cml_meta.h>
|
||||
#include <cml/core/cml_assert.h>
|
||||
#include <cml/core/fwd.h>
|
||||
#include <cml/et/traits.h>
|
||||
|
||||
#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<typename LeftT, typename RightT, typename SizeT>
|
||||
struct GetCheckedSize;
|
||||
|
||||
/* Checking for fixed-size expression: */
|
||||
template<typename LeftT, typename RightT>
|
||||
struct GetCheckedSize<LeftT,RightT,fixed_size_tag>
|
||||
{
|
||||
/* Record argument traits: */
|
||||
typedef ExprTraits<LeftT> left_traits;
|
||||
typedef ExprTraits<RightT> right_traits;
|
||||
|
||||
/* Result types: */
|
||||
typedef typename left_traits::result_tag left_result;
|
||||
typedef typename right_traits::result_tag right_result;
|
||||
|
||||
|
||||
/* For specialization below: */
|
||||
template<typename LR, typename RR, class X = void> struct impl;
|
||||
|
||||
/* Check for two matrices (linear operators only): */
|
||||
template<class X> struct impl<matrix_result_tag,matrix_result_tag,X> {
|
||||
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<class X> struct impl<matrix_result_tag,vector_result_tag,X> {
|
||||
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<class X> struct impl<vector_result_tag,matrix_result_tag,X> {
|
||||
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<class X> struct impl<matrix_result_tag,scalar_result_tag,X> {
|
||||
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<class X> struct impl<scalar_result_tag,matrix_result_tag,X> {
|
||||
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<class X> struct impl<vector_result_tag,vector_result_tag,X> {
|
||||
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<class X> struct impl<vector_result_tag,scalar_result_tag,X> {
|
||||
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<class X> struct impl<scalar_result_tag,vector_result_tag,X> {
|
||||
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<class X>
|
||||
struct impl<quaternion_result_tag,quaternion_result_tag,X> {
|
||||
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<class X> struct impl<quaternion_result_tag,vector_result_tag,X> {
|
||||
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<class X> struct impl<vector_result_tag,quaternion_result_tag,X> {
|
||||
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<class X> struct impl<quaternion_result_tag,scalar_result_tag,X> {
|
||||
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<class X> struct impl<scalar_result_tag,quaternion_result_tag,X> {
|
||||
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<left_result,right_result> 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<typename LeftT, typename RightT>
|
||||
struct GetCheckedSize<LeftT,RightT,dynamic_size_tag>
|
||||
{
|
||||
/* Type of the size checker (for calling equal_or_fail): */
|
||||
typedef GetCheckedSize<LeftT,RightT,dynamic_size_tag> self;
|
||||
|
||||
/* Record argument traits: */
|
||||
typedef ExprTraits<LeftT> left_traits;
|
||||
typedef ExprTraits<RightT> right_traits;
|
||||
|
||||
/* Result types: */
|
||||
typedef typename left_traits::result_tag left_result;
|
||||
typedef typename right_traits::result_tag right_result;
|
||||
|
||||
|
||||
/* For specialization below: */
|
||||
template<typename LR, typename RR, class X = void> struct impl;
|
||||
|
||||
/* Return the size if the same, or fail if different: */
|
||||
template<typename V> 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<class X> struct impl<matrix_result_tag,matrix_result_tag,X> {
|
||||
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<class X> struct impl<matrix_result_tag,vector_result_tag,X> {
|
||||
typedef size_t size_type;
|
||||
|
||||
/* Return the vector size: */
|
||||
#if defined(CML_CHECK_MATVEC_EXPR_SIZES)
|
||||
size_type size(const LeftT& left, const RightT& right) const
|
||||
#else
|
||||
size_type size(const LeftT& left, const RightT& /*right*/) const
|
||||
#endif
|
||||
{
|
||||
#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<class X> struct impl<vector_result_tag,matrix_result_tag,X> {
|
||||
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<class X> struct impl<matrix_result_tag,scalar_result_tag,X> {
|
||||
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<class X> struct impl<scalar_result_tag,matrix_result_tag,X> {
|
||||
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<class X> struct impl<vector_result_tag,vector_result_tag,X> {
|
||||
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<class X> struct impl<vector_result_tag,scalar_result_tag,X> {
|
||||
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<class X> struct impl<scalar_result_tag,vector_result_tag,X> {
|
||||
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<left_result,right_result> 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<typename LeftT, typename RightT, typename SizeTag>
|
||||
inline typename et::GetCheckedSize<LeftT,RightT,SizeTag>::size_type
|
||||
CheckedSize(const LeftT& left, const RightT& right, SizeTag)
|
||||
{
|
||||
return et::GetCheckedSize<LeftT,RightT,SizeTag>()(left,right);
|
||||
}
|
||||
|
||||
/** Verify the sizes of the argument matrices for matrix multiplication.
|
||||
*
|
||||
* @returns a the size of the resulting matrix.
|
||||
*/
|
||||
template<typename MatT> 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<typename MatT> inline size_t
|
||||
CheckedSquare(const MatT& m, dynamic_size_tag)
|
||||
{
|
||||
matrix_size N = m.size();
|
||||
et::GetCheckedSize<MatT,MatT,dynamic_size_tag>()
|
||||
.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
|
||||
55
Lib/Include/CML/et/tags.h
Normal file
55
Lib/Include/CML/et/tags.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
|
||||
#ifndef et_tags_h
|
||||
#define et_tags_h
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
/** Tag an expression as returning a scalar. */
|
||||
struct scalar_result_tag {};
|
||||
|
||||
/** Tag an expression as returning a vector. */
|
||||
struct vector_result_tag {};
|
||||
|
||||
/** Tag an expression as returning a matrix. */
|
||||
struct matrix_result_tag {};
|
||||
|
||||
/** Tag an expression as returning a quaternion. */
|
||||
struct quaternion_result_tag {};
|
||||
|
||||
/** Marker for unary expression ops. */
|
||||
struct unary_expression {};
|
||||
|
||||
/** Marker for biary expression ops. */
|
||||
struct binary_expression {};
|
||||
|
||||
/** Marker for expression tree operator nodes. */
|
||||
struct expr_node_tag {};
|
||||
|
||||
/** Marker for expression tree terminals (leaves). */
|
||||
struct expr_leaf_tag {};
|
||||
|
||||
/** Marker for assignable types. */
|
||||
struct assignable_tag {};
|
||||
|
||||
/** Marker for assignable types. */
|
||||
struct not_assignable_tag {};
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
143
Lib/Include/CML/et/traits.h
Normal file
143
Lib/Include/CML/et/traits.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
|
||||
#ifndef traits_h
|
||||
#define traits_h
|
||||
|
||||
#include <cml/et/tags.h>
|
||||
|
||||
/* XXX This is here temporarily, should be rolled into the traits classes
|
||||
* once it's clear how to best specify scalar args
|
||||
*/
|
||||
//#define SCALAR_ARG_TYPE const ScalarT&
|
||||
//#define ELEMENT_ARG_TYPE const Element&
|
||||
#define SCALAR_ARG_TYPE ScalarT
|
||||
#define ELEMENT_ARG_TYPE Element
|
||||
|
||||
namespace cml {
|
||||
namespace et {
|
||||
|
||||
/** The expression traits class.
|
||||
*
|
||||
* The traits class is used to provide uniform access to expression
|
||||
* objects, including scalars, when used in vector and matrix expressions.
|
||||
* One especially useful property for scalars is that scalars are
|
||||
* implicitly "promoted" to vectors or scalars as necessary via the
|
||||
* ExprTraits's get() method. Without this functionality, a separate
|
||||
* expression tree node would be needed to hold a scalar, which would
|
||||
* adversely affect performance.
|
||||
*
|
||||
* @internal This is also currently used for determining traits of scalar
|
||||
* types from the scalar operators (+,-,etc.). Really, a separate traits
|
||||
* class should probably be used for this (e.g. ScalarTraits).
|
||||
*/
|
||||
template<typename T> struct ExprTraits
|
||||
#if defined(CML_NO_DEFAULT_EXPR_TRAITS)
|
||||
/* For testing, don't default to scalar traits: */
|
||||
#else
|
||||
{
|
||||
/* Standard: */
|
||||
typedef T expr_type;
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef T const_reference;
|
||||
typedef scalar_result_tag result_tag;
|
||||
typedef fixed_memory_tag memory_tag;
|
||||
typedef unit_size_tag size_tag;
|
||||
typedef expr_type result_type;
|
||||
typedef expr_leaf_tag node_tag;
|
||||
|
||||
/** Vector-like access, just returns the value. */
|
||||
value_type get(const_reference v, size_t) const { return v; }
|
||||
|
||||
/** Matrix-like access, just returns the value. */
|
||||
value_type get(const_reference v, size_t, size_t) const { return v; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t size(const_reference) const { return 1; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t rows(double) const { return 1; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t cols(double) const { return 1; }
|
||||
}
|
||||
#endif
|
||||
;
|
||||
|
||||
#if defined(CML_NO_DEFAULT_EXPR_TRAITS)
|
||||
template<> struct ExprTraits<double>
|
||||
{
|
||||
/* Standard: */
|
||||
typedef double expr_type;
|
||||
typedef double value_type;
|
||||
typedef double& reference;
|
||||
typedef double const_reference;
|
||||
typedef scalar_result_tag result_tag;
|
||||
typedef fixed_memory_tag memory_tag;
|
||||
typedef unit_size_tag size_tag;
|
||||
typedef double result_type;
|
||||
typedef expr_leaf_tag node_tag;
|
||||
|
||||
/** Vector-like access, just returns the value. */
|
||||
value_type get(double v, size_t) const { return v; }
|
||||
|
||||
/** Matrix-like access, just returns the value. */
|
||||
value_type get(double v, size_t, size_t) const { return v; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t size(double) const { return 1; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t rows(double) const { return 1; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t cols(double) const { return 1; }
|
||||
};
|
||||
|
||||
template<> struct ExprTraits<float>
|
||||
{
|
||||
/* Standard: */
|
||||
typedef float expr_type;
|
||||
typedef float value_type;
|
||||
typedef float& reference;
|
||||
typedef float const_reference;
|
||||
typedef scalar_result_tag result_tag;
|
||||
typedef fixed_memory_tag memory_tag;
|
||||
typedef unit_size_tag size_tag;
|
||||
typedef float result_type;
|
||||
typedef expr_leaf_tag node_tag;
|
||||
|
||||
/** Vector-like access, just returns the value. */
|
||||
value_type get(float v, size_t) const { return v; }
|
||||
|
||||
/** Matrix-like access, just returns the value. */
|
||||
value_type get(float v, size_t, size_t) const { return v; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t size(float) const { return 1; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t rows(float) const { return 1; }
|
||||
|
||||
/** Size is always 1. */
|
||||
size_t cols(float) const { return 1; }
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace et
|
||||
} // namespace cml
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// vim:ft=cpp
|
||||
Reference in New Issue
Block a user