casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
UDFBase.h
Go to the documentation of this file.
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