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