casa
$Rev:20696$
|
00001 //# UDFBase.h: Abstract base class for a user-defined TaQL function 00002 //# Copyright (C) 2010 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id: UDFBase.h 21146 2011-11-30 14:43:25Z gervandiepen $ 00027 00028 #ifndef TABLES_UDFBASE_H 00029 #define TABLES_UDFBASE_H 00030 00031 //# Includes 00032 #include <tables/Tables/ExprNodeRep.h> 00033 #include <tables/Tables/Table.h> 00034 #include <tables/Tables/TaQLStyle.h> 00035 #include <casa/Containers/Block.h> 00036 #include <casa/OS/Mutex.h> 00037 #include <casa/stdmap.h> 00038 00039 00040 namespace casa { 00041 00042 // <summary> 00043 // Abstract base class for a user-defined TaQL function 00044 // </summary> 00045 // 00046 // <synopsis> 00047 // This class makes it possible to add user-defined functions (UDF) to TaQL. 00048 // A UDF has to be implemented in a class derived from this class. A few 00049 // functions have to be implemented in the class as described below. 00050 // 00051 // A UDF is a class derived from this base class. It must contain the 00052 // following member functions. See also the example below. 00053 // <table border=0> 00054 // <tr> 00055 // <td><src>makeObject</src></td> 00056 // <td>a static function to create an object of the UDF class. This function 00057 // needs to be registered. 00058 // </td> 00059 // </tr> 00060 // <tr> 00061 // <td><src>setup</src></td> 00062 // <td>this virtual function is called after the object has been created. 00063 // It should initialize the object using the function arguments that 00064 // can be obtained using the function <src>operands()</src>. The setup 00065 // function should perform the following: 00066 // <ul> 00067 // <li>Define the data type of the result using <src>setDataType<src>. 00068 // The data type should be derived from the data types of the function 00069 // arguments. The possible data types are defined in class 00070 // TableExprNodeRep. 00071 // Note that a UDF can support multiple data types. For example, a 00072 // function like <src>min</src> can be used for Int, Double, or a mix. 00073 // Function 'checkDT' in class TableExprNodeMulti can be used to 00074 // check the data types of the operands and determine the result 00075 // data type. 00076 // <li>Define the dimensionality of the result using <src>setNDim</src>. 00077 // A value of 0 means a scalar. A value of -1 means an array with 00078 // a dimensionality that can vary from row to row. 00079 // <li>Optionally use <src>setShape</src> to define the shape if the 00080 // results are arrays with a shape that is the same for all rows. 00081 // It will also set ndim if setNDim was not used yet, otherwise 00082 // it checks if it ndim matches. 00083 // <li>Optionally set the unit of the result using <src>setUnit</src>. 00084 // TaQL has full support of units, so UDFs should behave the same. 00085 // It is possible to change the unit of the function arguments. 00086 // For example: 00087 // <ul> 00088 // <li>a function like 'sin' can force its argument to be 00089 // in radians; TaQL will scale the argument as needed. This can be 00090 // done like 00091 // <src>TableExprNodeUnit::adaptUnit (operands()[i], "rad");</src> 00092 // <li>A function like 'asin' will have a result in radians. 00093 // Such a UDF should set its result unit to rad. 00094 // <li>A function like 'min' wants its arguments to have the same 00095 // unit and will set its result unit to it. It can be done like: 00096 // <src>setUnit (TableExprFuncNode::makeEqualUnits 00097 // (operands(), 0, operands().size()));</src> 00098 // <li>Optionally define if the result is a constant value using 00099 // <src>setConstant</src>. It means that the function is not 00100 // dependent on the row number in the table being queried. 00101 // This is usually the case if all UDF arguments are constant. 00102 // </ul> 00103 // See class TableExprFuncNode for more info about these functions. 00104 // </ul> 00105 // </td> 00106 // </tr> 00107 // <tr> 00108 // <td><src>getXXX</src></td> 00109 // <td>there are virtual get functions for each possible data type. The 00110 // get functions matching the data types that can be set by the setup 00111 // function need to be implemented. 00112 // </td> 00113 // </tr> 00114 // </table> 00115 // 00116 // A UDF has to be made known to TaQL by adding it to the UDF registry with 00117 // its name and 'makeObject' function. 00118 // UDFs will usually reside in a shared library that is loaded dynamically. 00119 // TaQL will load a UDF in the following way: 00120 // <ul> 00121 // <li> The UDF name used in TaQL consists of two parts: a library name 00122 // and function name separated by a dot. Both parts need to be given. 00123 // Note that the library name can also be seen as a UDF scope, so 00124 // different UDFs with equal names can be used from different libraries. 00125 // A UDF should be registered with this full name. 00126 // <li> If a UDF is not found in the registry, it will be tried to load 00127 // a shared library using the library name part. The libraries tried 00128 // to be loaded are lib<library>.so and libcasa_<library>.so. 00129 // On Mac .dylib will be tried. If loaded successfully, a special 00130 // function 'register_libname' will be called first. It should 00131 // register each UDF in the shared library using UDFBase::register. 00132 // </ul> 00133 // </synopsis> 00134 // 00135 // <example> 00136 // <srcblock> 00137 // class TestUDF: public UDFBase 00138 // { 00139 // public: 00140 // TestUDF() {} 00141 // static UDFBase* makeObject (const String&) 00142 // { return new TestUDF(); } 00143 // virtual void setup (const Table&, const TaQLStyle&) 00144 // { 00145 // AlwaysAssert (operands().size() == 1, AipsError); 00146 // AlwaysAssert (operands()[0]->dataType() == TableExprNodeRep::NTInt, 00147 // AipsError); 00148 // AlwaysAssert (operands()[0]->valueType() == TableExprNodeRep::VTScalar, 00149 // AipsError); 00150 // setDataType (TableExprNodeRep::NTBool); 00151 // setNDim (0); // scalar result 00152 // setConstant (operands()[0].isConstant()); // constant result? 00153 // 00154 // } 00155 // Bool getBool (const TableExprId& id) 00156 // { return operands()[0]->getInt(id) == 1; } 00157 // }; 00158 // </srcblock> 00159 // This example returns True if the function argument matches 1. 00160 // It can be seen that it checks if the argument is an integer scalar. 00161 // </example> 00162 00163 class UDFBase 00164 { 00165 public: 00166 // The signature of a global or static member function creating an object 00167 // of the UDF. 00168 typedef UDFBase* MakeUDFObject (const String& functionName); 00169 00170 // Only default constructor is needed. 00171 UDFBase(); 00172 00173 // Destructor. 00174 virtual ~UDFBase(); 00175 00176 // Evaluate the function and return the result. 00177 // Their default implementations throw a "not implemented" exception. 00178 // <group> 00179 virtual Bool getBool (const TableExprId& id); 00180 virtual Int64 getInt (const TableExprId& id); 00181 virtual Double getDouble (const TableExprId& id); 00182 virtual DComplex getDComplex (const TableExprId& id); 00183 virtual String getString (const TableExprId& id); 00184 virtual TaqlRegex getRegex (const TableExprId& id); 00185 virtual MVTime getDate (const TableExprId& id); 00186 virtual Array<Bool> getArrayBool (const TableExprId& id); 00187 virtual Array<Int64> getArrayInt (const TableExprId& id); 00188 virtual Array<Double> getArrayDouble (const TableExprId& id); 00189 virtual Array<DComplex> getArrayDComplex (const TableExprId& id); 00190 virtual Array<String> getArrayString (const TableExprId& id); 00191 virtual Array<MVTime> getArrayDate (const TableExprId& id); 00192 // </group> 00193 00194 // Get the unit. 00195 const String& getUnit() const 00196 { return itsUnit; } 00197 00198 private: 00199 // Set up the function object. 00200 virtual void setup (const Table& table, 00201 const TaQLStyle&) = 0; 00202 00203 protected: 00204 // Get the operands. 00205 PtrBlock<TableExprNodeRep*>& operands() 00206 { return itsOperands; } 00207 00208 // Set the data type. 00209 // This function must be called by the setup function of the derived class. 00210 void setDataType (TableExprNodeRep::NodeDataType); 00211 00212 // Set the dimensionality of the results. 00213 // <br> 0 means that the results are scalars. 00214 // <br> -1 means that the results are arrays with unknown dimensionality. 00215 // <br> >0 means that the results are arrays with that dimensionality. 00216 // This function must be called by the setup function of the derived class. 00217 void setNDim (Int ndim); 00218 00219 // Set the shape of the results if it is fixed and known. 00220 void setShape (const IPosition& shape); 00221 00222 // Set the unit of the result. 00223 // If this function is not called by the setup function of the derived 00224 // class, the result has no unit. 00225 void setUnit (const String& unit); 00226 00227 // Define if the result is constant (e.g. if all arguments are constant). 00228 // If this function is not called by the setup function of the derived 00229 // class, the result is not constant. 00230 void setConstant (Bool isConstant); 00231 00232 public: 00233 // Register a the name and construction function of a UDF (thread-safe). 00234 // An exception is thrown if this name already exists with a different 00235 // construction function. 00236 static void registerUDF (const String& name, MakeUDFObject* func); 00237 00238 // Initialize the function object. 00239 void init (const PtrBlock<TableExprNodeRep*>& arg, 00240 const Table& table, const TaQLStyle&); 00241 00242 // Get the data type. 00243 TableExprNodeRep::NodeDataType dataType() const 00244 { return itsDataType; } 00245 00246 // Get the dimensionality of the results. 00247 // (0=scalar, -1=array with variable ndim, >0=array with fixed ndim 00248 Int ndim() const 00249 { return itsNDim; } 00250 00251 // Get the result shape if the same for all results. 00252 const IPosition& shape() const 00253 { return itsShape; } 00254 00255 // Tell if the UDF gives a constant result. 00256 Bool isConstant() const 00257 { return itsIsConstant; } 00258 00259 // Create a UDF object (thread-safe). 00260 static UDFBase* createUDF (const String& name); 00261 00262 private: 00263 //# Data members. 00264 PtrBlock<TableExprNodeRep*> itsOperands; 00265 TableExprNodeRep::NodeDataType itsDataType; 00266 Int itsNDim; 00267 IPosition itsShape; 00268 String itsUnit; 00269 Bool itsIsConstant; 00270 static map<String, MakeUDFObject*> theirRegistry; 00271 static Mutex theirMutex; 00272 }; 00273 00274 } // end namespace 00275 00276 #endif