A.I.M.S


aims::Process Class Reference

Link mechanism between the Finder and a process operating on arbitrary data types. More...

#include <aims/io/process.h>

Inheritance diagram for aims::Process:
Collaboration diagram for aims::Process:

Public Types

typedef bool(* ProcFunc )(Process &, const std::string &, Finder &)
 Process function type. More...
 

Public Member Functions

 Process ()
 Attempts to read the header of filename and, if successful, calls the operator() of the process . More...
 
virtual ~Process ()
 
void registerProcessType (const std::string &objType, const std::string &dataType, ProcFunc procFunc)
 Registers the process to call on a given (object type, data type) couple (just fills the map) More...
 
bool execute (const std::string &filename)
 Executes the process on the object / data type found in the given file. More...
 
bool execute (Finder &f, const std::string &filename)
 Same as above but the header has already been read (or hand-made to fake it!) More...
 
const std::map< std::string,
std::map< std::string,
ProcFunc > > & 
processTypes () const
 Query registered process types. More...
 
void setReadOptions (carto::Object options)
 Set reading options. More...
 

Protected Attributes

std::map< std::string,
std::map< std::string,
ProcFunc > > 
_execs
 
carto::Object _options
 

Detailed Description

Link mechanism between the Finder and a process operating on arbitrary data types.

Process finally solves the data-type problem for every AIMS commandline (I hope...). It allows to hide both the file format of processed data (using Finder) and the data type dependency. Process allows to call a process operation function depending on the correct data type given by its file info (using a functions map).
No type switching need to be hard-coded anymore. Process uses a plugin mechanism for new data types and the types list can be dynamically extended when needed.

Usage: Subclass Process to your own class with either an external

template<class T> bool doMyProcess( Process & p,
const string & filename,
Finder & finder );

or a static member function:

template<class T> static bool
MyProcess::doMyProcess( Process & p, const string & filename,
Finder & finder );

Instantiate such a process class, and register every needed type with the registerProcessType() function (you can do it in your process constructor). Then call the execute() function with your file name as an argument. The process function registered for the correct data type will be called, if this type can be guessed by the Finder, or return false if it fails.

In fact if your process doesn't need other information (no data in your Process subclass), you don't even really need to subclass it: manually registering processing functions should be enough.

An example of it: the AimsFileInfo command

For quick use, another small example:

#include <aims/io/finder.h>
#include <aims/io/reader.h>
#include <aims/data/data.h>
class MyProcess : public Process
{
public:
MyProcess()
{
// here are all types known by our process
registerProcessType( "Volume", "S16", &exec<AimsData<short> > );
registerProcessType( "Volume", "FLOAT", &exec<AimsData<float> > );
// use for instance another function for meshes and buckets
registerProcessType( "Mesh", "VOID", &exec2<AimsSufaceTriangle> );
registerProcessType( "Bucket", "VOID", &exec2<AimsBucket> );
}
private:
// template processing function, used for some of the possible types
template<class T> static bool
exec( Process& p, const string & filename, Finder & finder )
{
MyProcess & mp = (MyProcess &) p;
// we are sure p is a MyProcess since this -private- function has
// been registered and called only within the MyProcess class
// if you're still not sure, use a dynamic_cast()...
// instantiate the data
T data;
// read it
Reader<T> r( filename );
string format = finder.format();
if( !r.read( data, 0, &format ) )
return( false );
// now use your volume as you like
// ...
mp.otherFunction( data ); // etc.
return( true ); // success
}
// another processing function that we use on some other types
template<class T> static bool
exec2( Process &, const string & filename, Finder & finder )
{
T data;
Reader<T> r( filename );
string format = finder.format();
if( !r.read( data, 0, &format ) )
return( false );
// other processing stuff
// ...
return( true );
}
};
// main function
int main( int argc, char** argv )
{
if( argc < 2 )
exit( 1 );
string fname( argv[1] );
MyProcess proc;
if( !proc.execute( fname ) )
{
cerr << "couldn't process file " << fname << endl;
exit( 1 );
}
cout << "OK\n";
return( 0 );
}
Comments
The "trick" is that processing functions are "neutral" functions and do not have any mark of the data type in their signature (nor in their return type). However they can be template functions, one for each type, with identical parameters.
This approach of binding IO to objects and corresponding processes requires to manually register every possible data type to process, but so has the advantage to allow compilation of processes only on these types, and not on others which might cause problems. For instance you can use different process functions for volumes of scalars (AimsData of float or int) and on volumes of complex, and use specific operations for the former (ie ordering, comparisons operations or casting to float or double) which would not work on the latter.
See also
Finder FileFormatDictionary Reader Writer

Definition at line 199 of file process.h.

Member Typedef Documentation

typedef bool(* aims::Process::ProcFunc)(Process &, const std::string &, Finder &)

Process function type.

These functions are stored in a type-to-function map and called by the execute() function. They are called with the file name of the object and the corresponding Finder object, the Finder::check() has already been successfully called by execute(), so the file header is available in the Finder. Each function must be specialized for a given object and data type (possibly using template functions). Unfortunately these functions pointers can not be pointer to member functions as we will need access to derived classes members (not allowed in C++ spec), so we also provide a reference to this Process object to the process function (callback-style)

Definition at line 213 of file process.h.

Constructor & Destructor Documentation

aims::Process::Process ( )

Attempts to read the header of filename and, if successful, calls the operator() of the process .

virtual aims::Process::~Process ( )
virtual

Member Function Documentation

bool aims::Process::execute ( const std::string &  filename)

Executes the process on the object / data type found in the given file.

Uses Finder to figure out which data should be used. This will either call the registered ProcFunc or return false if no process function has been registered on that type

bool aims::Process::execute ( Finder f,
const std::string &  filename 
)

Same as above but the header has already been read (or hand-made to fake it!)

const std::map<std::string, std::map<std::string, ProcFunc> >& aims::Process::processTypes ( ) const
inline

Query registered process types.

Definition at line 235 of file process.h.

Referenced by aims::AimsGraphReader::read().

void aims::Process::registerProcessType ( const std::string &  objType,
const std::string &  dataType,
ProcFunc  procFunc 
)

Registers the process to call on a given (object type, data type) couple (just fills the map)

Referenced by aims::AimsGraphReader::read().

void aims::Process::setReadOptions ( carto::Object  options)
inline

Set reading options.

Reading options are used for two things:

Definition at line 245 of file process.h.

Member Data Documentation

std::map<std::string, std::map<std::string, ProcFunc> > aims::Process::_execs
protected

Definition at line 248 of file process.h.

carto::Object aims::Process::_options
protected

Definition at line 249 of file process.h.


The documentation for this class was generated from the following file: