/* -*- 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 #include namespace cml { namespace et { #define VAL_MAX(_a_,_b_) ( ((_a_)>(_b_))?(_a_):(_b_) ) namespace detail { /* This is specialized for 1D and 2D promotions: */ template struct promote; /* Promote 1D fixed-size arrays to a 1D fixed-size array: */ template struct promote { 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 type; }; /* Promote 1D dynamic arrays to a 1D dynamic array: */ template struct promote { 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::other allocator; /* Finally, generate the promoted array type: */ typedef dynamic_1D type; }; /* Promote fixed 2D+1D array expressions to a fixed 1D array: */ template struct promote { 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 type; }; /* Promote fixed 1D+2D array expressions to a fixed 1D array: */ template struct promote { 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 type; }; /* Promote dynamic 2D+1D array expression to a 1D dynamic array: */ template struct promote { 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::other allocator; /* Finally, generate the promoted array type: */ typedef dynamic_1D type; }; /* Promote dynamic 1D+2D array expression to a 1D dynamic array: */ template struct promote { 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::other allocator; /* Finally, generate the promoted array type: */ typedef dynamic_1D type; }; /* This is a helper to deduce the result of a promoted 2D array: */ template 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::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 struct promote { 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 ::promoted_layout promoted_layout; /* Finally, generate the promoted array type: */ typedef fixed_2D type; }; /* Promote 2D dynamic arrays to a 2D dynamic array: */ template struct promote { 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::other allocator; /* Then deduce the array layout: */ typedef typename A1::layout left_layout; typedef typename A2::layout right_layout; typedef typename deduce_layout ::promoted_layout promoted_layout; /* Finally, generate the promoted array type: */ typedef dynamic_2D 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 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::is_true && same_type::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