ProcessFunctor.H

00001 //! a data processing functor
00002 //////////////////////////////////////////////////////////////////////////
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 //////////////////////////////////////////////////////////////////////////
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 //////////////////////////////////////////////////////////////////////////
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 //////////////////////////////////////////////////////////////////////////
00031 //
00032 // Primary maintainer for this file: David J. Berg <dberg@usc.edu>
00033 // $HeadURL:svn://ilab.usc.edu/trunk/saliency/src/GenericUtils/ProcessFunctor.H$
00034 
00035 #ifdef  INVT_USE_CPPOX//we need c++ 0X features for this to work
00036 #ifndef PROCESSFUNCTOR_H_DEFINED
00037 #define PROCESSFUNCTOR_H_DEFINED
00038 
00039 #include "Util/log.H"
00040 #include <typeinfo>
00041 
00042 // ###################################################################### 
00043 // A simple class to check if you can convert frome one type to another, and if
00044 // so supplyies a confert function. By default everything is convertable to
00045 // everything else, so supply your own specialization inside the definition of
00046 // your ProcessFunctor derived class to prohibit converting or do additional
00047 // operations besides a statoc_cast, or dynamic cast.
00048 // ######################################################################
00049 // general case
00050 template<class From, class To> struct convertType {
00051   static const bool Convertable = 1;
00052   static To convert(const From& from)
00053   { return static_cast<To>(from); } };//this may return non-sense, but will never fail
00054 
00055 //attempt to copy self
00056 template<class From> struct convertType<From, From> {
00057   static const bool Convertable = 0;
00058   static From convert(const From& from)
00059   { return from; } };//this may return non-sense, but will never fail
00060 
00061 //specialization for pointers, for now don't allow
00062 template<class From, class To> struct convertType<From*, To*> {
00063   static const bool Convertable = 0; 
00064   static To convert(const From& from)
00065   { return dynamic_cast<To>(from); } };//never called
00066   
00067 //specialization for Refs, for now don't allow.
00068   template<class From, class To> struct convertType<From&, To&> {
00069     static const bool Convertable = 0; 
00070   static To convert(const From& from)
00071   { return dynamic_cast<To>(from); } };//never called};
00072       
00073 // ###################################################################### 
00074 // ProcessFunctor
00075 // ###################################################################### 
00076 /*
00077 
00078   A ProcessFunctor embodies a computation that can occur for several different
00079   types. The possible types are known a priori but the the exact type that will
00080   be input at call point is not known by the functor. A genericItem uses this to
00081   performs operations on items generically, when the exact type of the item is
00082   not known by the Functor ahead of time. Several behaviors can be achieved. 1)
00083   several different actions can be performed depending on the input type (or the
00084   type in the generic item). 2) the same action can be performed, but with some
00085   type specific manipulations first or after. 3) The same action can be
00086   performed by converting several different types to a single type of
00087   interest. 4) data can be processed for some type matches and ignored for
00088   others, resulting in a type filtering type mechanism.
00089 
00090   The functor is executed by calling the function call operator. The operator
00091   takes a container of a homogenious type as its argument. Derived classes
00092   implement a process(C<T> inp) function, where C is the container type and T is
00093   the type held in the container. The Derived class can implement one or more
00094   process functions for different types T, allowing for a range of inputs to be
00095   handled (either by implementing with named types or as a template class). If a
00096   process function is not implemented for a particular T, the functor performs
00097   no operation, or converts to the first availible type.  Whether the functor
00098   performed an operation (and hence set some member variables for the result) is
00099   checked with a call to hasData().
00100 
00101   ProcessFunctor takes at least two template arguments. The first is the
00102   container type, and the second is a variadic template of known types.  Upon
00103   creation, ProcessFunctor will create virtual functions for all known types and
00104   implements a default non-operational function. The derived class should
00105   implement the process(C<T>) for all allowed types T (could use a template
00106   class to do this);
00107 
00108   By default, no conversions will take place if the functor does not know about
00109   the type. If the flag in the function call operator is set to true, conversion
00110   will be attempted. Conversion is always attempted when the function is non-op
00111   (ie the derived class only implements for one type that the functor has
00112   definitions for). This could potentially require many conversions if you
00113   immplement for many types. The conversion unraveling is done from last to first,
00114   so if you are only going to implement for one of the know types, then try to put
00115   that type last in the type list.x
00116 
00117   see test-generics.C for an example
00118 */
00119 // ######################################################################
00120 template <template <typename...> class C, class... Tail> class ProcessFunctor;
00121 
00122 //base case in variadic template recursion
00123 // ######################################################################
00124 template <template <typename...> class C>
00125 class ProcessFunctor<C>
00126 {
00127 public:
00128   //destructor
00129   virtual ~ProcessFunctor() { };
00130   
00131   //default copy constructor, assignment Ok
00132   
00133   //process the feature
00134   template <class T>
00135   void operator()(const C<T>& data, const bool try_convert = false) 
00136   { };
00137   
00138   //check to see if we have data
00139   bool hasData() const { return itsHasData; };  
00140   
00141 protected:
00142   //constructor protected so that users cant create this class directly
00143   ProcessFunctor() : itsHasData(false) { };
00144 
00145   //set from that outside that we have data
00146   void setHasData(const bool hasdata) { itsHasData = hasdata; };
00147   
00148 private:
00149   bool itsHasData;
00150 };
00151 
00152 //recursive case in variadic template
00153 // ######################################################################
00154 template <template <typename...> class C, class Head, class... Tail>
00155 class ProcessFunctor<C, Head, Tail...> : private ProcessFunctor<C, Tail...>
00156 { 
00157 public:
00158   //destructor
00159   virtual ~ProcessFunctor() { };
00160   
00161   //default copy constructor, assignment Ok
00162   
00163   //overload operator for matching head
00164   void operator()(const C<Head>& data, const bool try_convert = false) 
00165   { 
00166     setHasData(process(data)); 
00167     
00168     //If we matched but failed keep descending as we will hit base and then we
00169     //can pop all the way up trying to convert. Otherwise, we will return at
00170     //this point. The former happens when we know about a type but did not
00171     //implemented the virtual function in our derived.
00172     if (!hasData())
00173       ProcessFunctor<C, Tail...>::operator()(data, true); 
00174   };  
00175   
00176   //overload for not matching
00177   template <class T>
00178   void operator()(const C<T>& data, const bool try_convert = false) 
00179   { 
00180     //we didn't match, so keep going
00181     ProcessFunctor<C, Tail...>::operator()(data, try_convert); 
00182     
00183     // If we get here, we have it the bottom. As we unravel, check to see if we
00184     //ever set any data.  If we didn't and the flag is set, try to convert as we
00185     //pop back up
00186     if (!hasData() && try_convert)
00187       {
00188         //If we can convert, we can call the derived process and set the data
00189         //flag. If the operation succeeds, we will unravel with no ops. Else we
00190         //will attempt to convert and call for each type as we unravel.
00191         if (convertType<C<T>, C<Head> >::Convertable)
00192           {
00193             LINFO("conver");
00194             C<Head> temp = convertType<C<T>, C<Head> >::convert(data);
00195             setHasData(process(temp)); 
00196           }
00197       }
00198   };
00199   
00200   //check to see if we have data
00201   bool hasData() const { return ProcessFunctor<C, Tail...>::hasData(); };  
00202   
00203 protected:
00204   //constructor protected so that users cant create this class directly
00205   ProcessFunctor() : ProcessFunctor<C, Tail...>() { };
00206   
00207   //set the flag indicating data is set. 
00208   void setHasData(const bool hasData)
00209   { ProcessFunctor<C, Tail...>::setHasData(hasData); }
00210   
00211 private:
00212   virtual bool process(const C<Head>& feature) 
00213   { return false; }; 
00214 };
00215 
00216 #endif
00217 #endif
Generated on Sun May 8 08:40:39 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3