Promotions.H

Go to the documentation of this file.
00001 /*!@file Util/Promotions.H basic definitions for template type promotions */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Util/Promotions.H $
00035 // $Id: Promotions.H 4731 2005-06-29 19:33:51Z rjpeters $
00036 //
00037 
00038 #ifndef PROMOTIONS_H_DEFINED
00039 #define PROMOTIONS_H_DEFINED
00040 
00041 #include "Util/Types.H"
00042 #include "Util/log.H"
00043 #include <limits>
00044 
00045 
00046 /*! The idea here is to create a mechanism by which a given template
00047 type can be promoted to a more capable type (e.g., byte to float, or
00048 PixRGB<byte> to PixRGB<float>), typically to hold the result of some
00049 operation that may exceed the capacity of the original type (e.g., the
00050 result of adding two bytes may not fit within the range of possible
00051 values for byte). See http://www.oonumerics.org/blitz/traits.html for
00052 further details.  The way to use this is as follows: if you have a
00053 template type T (which may be scalar or not) that you wish to promote
00054 to a more capable type that would have "similar characteristics" to
00055 another type TT, then use the type promote_trait<T,TT>::TP. For
00056 example: promote_trait<T,float>::TP is a float if T was a byte, and is
00057 a PixRGB<float> if T was a PixRGB<byte> */
00058 
00059 
00060 //! Promote from T1 and T2 to a type than can hold T1 * T2
00061 /*! Basic promotion mechanism: given T1 and T2, TP provides the
00062  appropriate type to hold the result of an operation involving T1 and
00063  T2.  Default is to promote to type T1, that is, no change (this is
00064  used when T2 is "weaker" than T1; when T2 is "stronger" that T1, the
00065  explicit specialized rules below are used). */
00066 template <class T1, class T2>
00067 struct promote_trait { typedef T1 TP; enum { willPromote = 0 }; };
00068 
00069 // Here go the various specializations:
00070 
00071 // NOTE: we follow the basic C++ integral promotions, promoting to int
00072 // from byte, int16 and int32
00073 template <> struct promote_trait<byte, byte>          { typedef int         TP; enum { willPromote = 1 }; };
00074 template <> struct promote_trait<byte, int16>         { typedef int         TP; enum { willPromote = 1 }; };
00075 template <> struct promote_trait<byte, int32>         { typedef int         TP; enum { willPromote = 1 }; };
00076 template <> struct promote_trait<byte, float>         { typedef float       TP; enum { willPromote = 1 }; };
00077 template <> struct promote_trait<byte, double>        { typedef double      TP; enum { willPromote = 1 }; };
00078 template <> struct promote_trait<byte, long double>   { typedef long double TP; enum { willPromote = 1 }; };
00079 
00080 template <> struct promote_trait<int16, byte>         { typedef int         TP; enum { willPromote = 1 }; };
00081 template <> struct promote_trait<int16, int16>        { typedef int         TP; enum { willPromote = 1 }; };
00082 template <> struct promote_trait<int16, int32>        { typedef int         TP; enum { willPromote = 1 }; };
00083 template <> struct promote_trait<int16, float>        { typedef float       TP; enum { willPromote = 1 }; };
00084 template <> struct promote_trait<int16, double>       { typedef double      TP; enum { willPromote = 1 }; };
00085 template <> struct promote_trait<int16, long double>  { typedef long double TP; enum { willPromote = 1 }; };
00086 
00087 template <> struct promote_trait<int32, float>        { typedef float       TP; enum { willPromote = 1 }; };
00088 template <> struct promote_trait<int32, double>       { typedef double      TP; enum { willPromote = 1 }; };
00089 template <> struct promote_trait<int32, long double>  { typedef long double TP; enum { willPromote = 1 }; };
00090 
00091 template <> struct promote_trait<float, double>       { typedef double      TP; enum { willPromote = 1 }; };
00092 template <> struct promote_trait<float, long double>  { typedef long double TP; enum { willPromote = 1 }; };
00093 
00094 template <> struct promote_trait<double, long double> { typedef long double TP; enum { willPromote = 1 }; };
00095 
00096 //! A macro for specializing promote_trait for template types.
00097 /*! See e.g. usage in PixelsTypes.H. */
00098 #define SPECIALIZE_PROMOTE_TRAIT(T_TYPE, T_PARAMS, T_ARGS)                                                                                                                 \
00099 template <T_PARAMS> class T_TYPE;                                                                                                                               \
00100 template <> struct promote_trait<T_TYPE<byte T_ARGS> , byte>          { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };                     \
00101 template <> struct promote_trait<T_TYPE<byte T_ARGS> , int16>         { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };                     \
00102 template <> struct promote_trait<T_TYPE<byte T_ARGS> , int32>         { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };                     \
00103 template <> struct promote_trait<T_TYPE<byte T_ARGS> , float>         { typedef T_TYPE<float T_ARGS>       TP; enum { willPromote = 1 }; };                     \
00104 template <> struct promote_trait<T_TYPE<byte T_ARGS> , double>        { typedef T_TYPE<double T_ARGS>      TP; enum { willPromote = 1 }; };                     \
00105 template <> struct promote_trait<T_TYPE<byte T_ARGS> , long double>   { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };                     \
00106                                                                                                                                                                 \
00107 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , byte>         { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };                     \
00108 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , int16>        { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };                     \
00109 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , int32>        { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };                     \
00110 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , float>        { typedef T_TYPE<float T_ARGS>       TP; enum { willPromote = 1 }; };                     \
00111 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , double>       { typedef T_TYPE<double T_ARGS>      TP; enum { willPromote = 1 }; };                     \
00112 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , long double>  { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };                     \
00113                                                                                                                                                                 \
00114 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , float>        { typedef T_TYPE<float T_ARGS>       TP; enum { willPromote = 1 }; };                     \
00115 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , double>       { typedef T_TYPE<double T_ARGS>      TP; enum { willPromote = 1 }; };                     \
00116 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , long double>  { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };                     \
00117                                                                                                                                                                 \
00118 template <> struct promote_trait<T_TYPE<float T_ARGS> , double>       { typedef T_TYPE<double T_ARGS>      TP; enum { willPromote = 1 }; };                     \
00119 template <> struct promote_trait<T_TYPE<float T_ARGS> , long double>  { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };                     \
00120                                                                                                                                                                 \
00121 template <> struct promote_trait<T_TYPE<double T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };                     \
00122                                                                                                                                                                 \
00123 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<byte T_ARGS> >          { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };     \
00124 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<int16 T_ARGS> >         { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };     \
00125 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<int32 T_ARGS> >         { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };     \
00126 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<float T_ARGS> >         { typedef T_TYPE<float T_ARGS>       TP; enum { willPromote = 1 }; };     \
00127 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<double T_ARGS> >        { typedef T_TYPE<double T_ARGS>      TP; enum { willPromote = 1 }; };     \
00128 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<long double T_ARGS> >   { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };     \
00129                                                                                                                                                                 \
00130 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<byte T_ARGS> >         { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };     \
00131 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<int16 T_ARGS> >        { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };     \
00132 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<int32 T_ARGS> >        { typedef T_TYPE<int T_ARGS>         TP; enum { willPromote = 1 }; };     \
00133 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<float T_ARGS> >        { typedef T_TYPE<float T_ARGS>       TP; enum { willPromote = 1 }; };     \
00134 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<double T_ARGS> >       { typedef T_TYPE<double T_ARGS>      TP; enum { willPromote = 1 }; };     \
00135 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<long double T_ARGS> >  { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };     \
00136                                                                                                                                                                 \
00137 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , T_TYPE<float T_ARGS> >        { typedef T_TYPE<float T_ARGS>       TP; enum { willPromote = 1 }; };     \
00138 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , T_TYPE<double T_ARGS> >       { typedef T_TYPE<double T_ARGS>      TP; enum { willPromote = 1 }; };     \
00139 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , T_TYPE<long double T_ARGS> >  { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };     \
00140                                                                                                                                                                 \
00141 template <> struct promote_trait<T_TYPE<float T_ARGS> , T_TYPE<double T_ARGS> >       { typedef T_TYPE<double T_ARGS>      TP; enum { willPromote = 1 }; };     \
00142 template <> struct promote_trait<T_TYPE<float T_ARGS> , T_TYPE<long double T_ARGS> >  { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };     \
00143                                                                                                                                                                 \
00144 template <> struct promote_trait<T_TYPE<double T_ARGS> , T_TYPE<long double T_ARGS> > { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };
00145 
00146 // ######################################################################
00147 
00148 // The following defines rules to safely convert from type TT to type
00149 // T, clamping the values to the destination type's range if
00150 // necessary. The function to use is clamped_convert<T>(xx), which
00151 // will convert xx from type TT to type T, clamping its value to the
00152 // acceptable range for T if necessary.
00153 
00154 // Basically there's a promoteFromTo<T1,T2> struct that exposes an
00155 // enum is_preserving which is set to 1 or 0 depending on whether T1
00156 // --> T2 is value-preserving or not. Then defined a convert_helper
00157 // struct that has a convert() function that does the real work,
00158 // except the struct can be specialized on whether the conversion is
00159 // preserving or not. Then the actual clamped_convert function just
00160 // forwards to convert_helper<T1,T2>::convert(), which picks the right
00161 // implementation. This way all of the important information is
00162 // specified by how we define promoteFromTo<T1,T2>::is_preserving, and
00163 // this specification is cleanly separated from the implementation
00164 // that uses it.
00165 
00166 // by default, promotion is considered range-preserving (will not
00167 // require clamping by us in clamped_convert). The rationale for this
00168 // weirdness is that for unknown types we will leave it to the
00169 // converting operator=() of that type to deal with the clamping.
00170 template <class T1, class T2>
00171 struct promoteFromTo { enum { is_preserving = 1 }; };
00172 
00173 // promote from T to itself is a range-preserving no-op:
00174 template <class T>
00175 struct promoteFromTo<T, T> { enum { is_preserving = 1 }; };
00176 
00177 // these rules declare which conversions are not range-preserving and
00178 // will require clamping within clamped_convert; they are used to
00179 // enforce clamping of builtin types:
00180 
00181 template <> struct promoteFromTo<int16      , byte>   { enum { is_preserving = 0 }; };
00182 template <> struct promoteFromTo<int32      , byte>   { enum { is_preserving = 0 }; };
00183 template <> struct promoteFromTo<float      , byte>   { enum { is_preserving = 0 }; };
00184 template <> struct promoteFromTo<double     , byte>   { enum { is_preserving = 0 }; };
00185 template <> struct promoteFromTo<long double, byte>   { enum { is_preserving = 0 }; };
00186 
00187 template <> struct promoteFromTo<int32      , int16>  { enum { is_preserving = 0 }; };
00188 template <> struct promoteFromTo<float      , int16>  { enum { is_preserving = 0 }; };
00189 template <> struct promoteFromTo<double     , int16>  { enum { is_preserving = 0 }; };
00190 template <> struct promoteFromTo<long double, int16>  { enum { is_preserving = 0 }; };
00191 
00192 template <> struct promoteFromTo<float      , int32>  { enum { is_preserving = 0 }; };
00193 template <> struct promoteFromTo<double     , int32>  { enum { is_preserving = 0 }; };
00194 template <> struct promoteFromTo<long double, int32>  { enum { is_preserving = 0 }; };
00195 
00196 template <> struct promoteFromTo<double     , float>  { enum { is_preserving = 0 }; };
00197 template <> struct promoteFromTo<long double, float>  { enum { is_preserving = 0 }; };
00198 
00199 template <> struct promoteFromTo<long double, double> { enum { is_preserving = 0 }; };
00200 
00201 //! Helper struct to handle rounding between different types
00202 /*! Note that we aren't worried about clamping here, that is handled
00203     separately by convert_helper (see below). We have different
00204     specializations of round_helper depending on whether the src and
00205     dest types are integral or floating-point. The only case where we
00206     have to do any actual rounding is when we're going from
00207     floating->integral. */
00208 template <class dst_type, class src_type,
00209           bool need_rounding =
00210           (std::numeric_limits<dst_type>::is_integer
00211            && !std::numeric_limits<src_type>::is_integer)>
00212 struct round_helper;
00213 
00214 template <class dst_type, class src_type>
00215 struct round_helper<dst_type, src_type, false> // no rounding needed
00216 {
00217   inline static dst_type round(src_type x)
00218   { return dst_type(x); }
00219 };
00220 
00221 template <class dst_type, class src_type>
00222 struct round_helper<dst_type, src_type, true> // rounding needed
00223 {
00224   inline static dst_type round(src_type x)
00225   {
00226     if      (x > 0) return dst_type(x+0.5); // round toward +Inf
00227     else if (x < 0) return dst_type(x-0.5); // round toward -Inf
00228     else            return dst_type(0);
00229   }
00230 };
00231 
00232 //! Helper struct to handle type conversions at compile time.
00233 /*! Helps decide whether to clamp or not at compile time so that we
00234     don't waste time in a test at run time; because
00235     std::numeric_limits is a pile of trash, we also need to
00236     parameterize the helper by a boolean indicating whether the type
00237     we convert to is integer or not. This will determine which numeric
00238     limits we use to do the clamping: */
00239 template <class dst_type, class src_type,
00240           bool is_preserving =
00241                   promoteFromTo<src_type, dst_type>::is_preserving,
00242           bool dst_type_is_integer =
00243                   std::numeric_limits<dst_type>::is_integer>
00244 struct convert_helper;
00245 
00246 // clamp and convert if non-preserving; dest type is integral:
00247 template <class dst_type, class src_type>
00248 struct convert_helper<dst_type, src_type,
00249                       /* is_preserving = */ false,
00250                       /* dst_type_is_integer = */ true>
00251 {
00252   inline static dst_type convert(src_type x)
00253   {
00254     if (x < std::numeric_limits<dst_type>::min())
00255       return std::numeric_limits<dst_type>::min();
00256     if (x > std::numeric_limits<dst_type>::max())
00257       return std::numeric_limits<dst_type>::max();
00258     return dst_type(x);
00259   }
00260 
00261   inline static dst_type rounded_convert(src_type x)
00262   {
00263     if (x < std::numeric_limits<dst_type>::min())
00264       return std::numeric_limits<dst_type>::min();
00265     if (x > std::numeric_limits<dst_type>::max())
00266       return std::numeric_limits<dst_type>::max();
00267 
00268     return round_helper<dst_type, src_type>::round(x);
00269   }
00270 };
00271 
00272 // clamp and convert if non-preserving; dest type is non-integral:
00273 template <class dst_type, class src_type>
00274 struct convert_helper<dst_type, src_type,
00275                       /* is_preserving = */ false,
00276                       /* dst_type_is_integer = */ false>
00277 {
00278   inline static dst_type convert(src_type x)
00279   {
00280     if (x < -std::numeric_limits<dst_type>::max())
00281       return -std::numeric_limits<dst_type>::max();
00282     if (x > std::numeric_limits<dst_type>::max())
00283       return std::numeric_limits<dst_type>::max();
00284     return dst_type(x);
00285   }
00286 
00287   inline static dst_type rounded_convert(src_type x)
00288   {
00289     if (x < -std::numeric_limits<dst_type>::max())
00290       return -std::numeric_limits<dst_type>::max();
00291     if (x > std::numeric_limits<dst_type>::max())
00292       return std::numeric_limits<dst_type>::max();
00293 
00294     return round_helper<dst_type, src_type>::round(x);
00295   }
00296 };
00297 
00298 // cast without checking range if preserving; for builtin types, this
00299 // means that we know that we can safely cast (the destination types
00300 // can represent all values of the source type); for other types, we
00301 // here assume that the conversion constructor will take care of the
00302 // clamping:
00303 template <class dst_type, class src_type>
00304 struct convert_helper<dst_type, src_type,
00305                       /* is_preserving = */ true,
00306                       /* dst_type_is_integer = */ true>
00307 {
00308   inline static dst_type convert(src_type x)
00309   {
00310     return dst_type(x);
00311   }
00312 
00313   inline static dst_type rounded_convert(src_type x)
00314   {
00315     return round_helper<dst_type, src_type>::round(x);
00316   }
00317 };
00318 
00319 template <class dst_type, class src_type>
00320 struct convert_helper<dst_type, src_type,
00321                       /* is_preserving = */ true,
00322                       /* dst_type_is_integer = */ false>
00323 {
00324   inline static dst_type convert(src_type x)
00325   {
00326     return dst_type(x);
00327   }
00328 
00329   inline static dst_type rounded_convert(src_type x)
00330   {
00331     return round_helper<dst_type, src_type>::round(x);
00332   }
00333 };
00334 
00335 //! Convert safely from src_type to type dst_type, clamping if necessary.
00336 template <class dst_type, class src_type>
00337 inline
00338 dst_type clamped_convert(src_type x)
00339 {
00340   return convert_helper<dst_type, src_type>::convert(x);
00341 }
00342 
00343 //! Convert safely from src_type to type dst_type, clamping and rounding as needed.
00344 template <class dst_type, class src_type>
00345 inline
00346 dst_type clamped_rounded_convert(src_type x)
00347 {
00348   return convert_helper<dst_type, src_type>::rounded_convert(x);
00349 }
00350 
00351 #endif
00352 
00353 // ######################################################################
00354 /* So things look consistent in everyone's emacs... */
00355 /* Local Variables: */
00356 /* indent-tabs-mode: nil */
00357 /* End: */
Generated on Sun May 8 08:42:28 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3