soma-io  5.1.2
soma::ReaderAlgorithm Class Reference

Link mechanism between a data source or file and an algorithm operating on arbitrary data types. More...

#include <soma-io/io/readeralgorithm.h>

Inheritance diagram for soma::ReaderAlgorithm:
Collaboration diagram for soma::ReaderAlgorithm:

Public Types

typedef bool(* ProcFunc) (ReaderAlgorithm &, carto::Object header, carto::rc_ptr< DataSource > source)
 Algorithm function type. More...
 

Public Member Functions

 ReaderAlgorithm (const std::string &algoname)
 
virtual ~ReaderAlgorithm ()
 
void registerAlgorithmType (const std::string &objectType, ProcFunc procFunc)
 Registers the algo function to call on a given object type (just fills the map) More...
 
bool execute (const std::string &filename)
 Executes the algo on the object type found in the given file. More...
 
bool execute (carto::rc_ptr< DataSource > stream)
 same as above but uses a DataSource as input More...
 
bool execute (carto::Object header, carto::rc_ptr< DataSource > source)
 Same as above but the header has already been read (or hand-made to fake it!) More...
 
bool execute (carto::rc_ptr< DataSourceInfo > dsi)
 same as above but uses DataSourceInfo as input. More...
 
const std::map< std::string, ProcFunc > & algorithmTypes () const
 Query registered process types. More...
 
- Public Member Functions inherited from carto::Algorithm
 Algorithm (const std::string &name)
 

Protected Attributes

std::map< std::string, ProcFunc_execs
 

Additional Inherited Members

- Protected Member Functions inherited from carto::Algorithm
ParameterModifier< T > inputParameter (T &ref, const std::string &name, const std::string &documentation)
 
ParameterModifier< T > outputParameter (T &ref, const std::string &name, const std::string &documentation)
 

Detailed Description

Link mechanism between a data source or file and an algorithm operating on arbitrary data types.

ReaderAlgorithm solves the data-type problem for any Cartograph commandline algorithm. It allows to hide both the file format of processed data (using DataSourceInfo) and the data type dependency. ReaderAlgorithm allows to call an algorithm operation function depending on the correct data type given by its file info (using a functions map).

No type switching needs to be hard-coded anymore. ReaderAlgorithm uses a plugin mechanism for new data types and the types list can be dynamically extended when needed.

Usage: The idea is to plug into a ReaderAlgorithm (generally a subclass) some pointers to type-specialized processing functions. These functions can be either external functions (generally template):

template <typename T>
bool doMyReaderAlgorithm( ReaderAlgorithm & algo,
Object header,
rc_ptr<DataSource> source );
ReaderAlgorithm(const std::string &algoname)
AlgorithmCaller algo

or static member functions:

template <typename T> static bool
MyReaderAlgorithm::doMyReaderAlgorithm( ReaderAlgorithm & algo,
Object header,
rc_ptr<DataSource> source );

Instantiate such an algorithm class, and register every needed type with the registerAlgorithmType() function (you can do it in your algo constructor). Then call the execute() function with the file name (or other DataSource) as an argument. The algo function registered for the correct data type will be called, if this type can be guessed by the DataSourceInfo, or an exception will be thrown if it fails.

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

A small example:

#include <aims/mesh/surface.h>
#include <aims/bucket/bucket.h>
#include <cartodata/volume/volume.h>
using namespace soma;
using namespace carto;
using namespace std;
class MyAlgo : public ReaderAlgorithm
{
public:
MyAlgo() : ReaderAlgorithm( "MyAlgo" )
{
// here are all types known by our algo
registerAlgorithmType( "Volume of S16", &exec<Volume<short> > );
registerAlgorithmType( "Volume of FLOAT", &exec<AimsData<float> > );
// use for instance another function for meshes and buckets
registerAlgorithmType( DataTypeCode<AimsSurfaceTriangle>::name(),
&exec2<AimsSufaceTriangle> );
registerAlgorithmType( DataTypeCode<AimsBucket>::name(),
&exec2<AimsBucket> );
}
private:
// template processing function, used for some of the possible types
template <typename T> static bool
exec( ReaderAlgorithm& a, Object hdr, rc_ptr<DataTypeCode> src )
{
MyAlgo & ma = (MyAlgo &) a;
// we are sure p is a MyReaderAlgorithm since this -private-
// function has been registered and called only within the
// MyReaderAlgorithm class if you're still not sure, use a
// dynamic_cast()...
// read it
Reader<T> r( src );
// it is a good habit to hold object that must be destroyed in
// a smart pointer (unique_ptr, rc_ptr or scoped_ptr)
unique_ptr<T> data;
data = r.read( hdr );
// now use your data as you like
// ...
ma.otherFunction( data ); // etc.
return true; // success
}
// another processing function that we use on some other types
template <typename T> static bool
exec2( ReaderAlgorithm &, Object hdr, rc_ptr<DataSource> src )
{
T data;
Reader<T> r( src );
unique_ptr<T> data;
data = r.read( hdr );
// other processing stuff
// ...
return true;
}
};
// main function
int main( int argc, const char** argv )
{
try
{
CartoApplication app( argc, argv, "MyAlgo" );
string fname;
app.addOption( fname, "-i", "input data file" );
app.initialize();
MyAlgo proc;
if( !proc.execute( fname ) )
{
cerr << "couldn't process file " << fname << endl;
return EXIT_FAILURE;
}
cout << "OK\n";
}
catch( user_interruption & )
{
}
catch( exception & e )
{
cerr << e.what() << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void registerAlgorithmType(const std::string &objectType, ProcFunc procFunc)
Registers the algo function to call on a given object type (just fills the map)
Definition: allocator.h:49
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 algorithms requires to manually register every possible data type to process, but so has the advantage to allow compilation of algorithms only on these types, and not on others which might cause problems. For instance you can use different algo functions for volumes of scalars (Volume 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
DataSourceInfo FormatDictionary Reader Writer

Definition at line 217 of file readeralgorithm.h.

Member Typedef Documentation

◆ ProcFunc

typedef bool(* soma::ReaderAlgorithm::ProcFunc) (ReaderAlgorithm &, carto::Object header, carto::rc_ptr< DataSource > source)

Algorithm function type.

These functions are stored in a type-to-function map and called by the execute() method. They are called with the DataSource containing the object to read and the corresponding header: here DataSourceInfo::check() has already been successfully called by execute(). 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 ReaderAlgorithm object to the algo function (callback-style)

Definition at line 231 of file readeralgorithm.h.

Constructor & Destructor Documentation

◆ ReaderAlgorithm()

soma::ReaderAlgorithm::ReaderAlgorithm ( const std::string &  algoname)

◆ ~ReaderAlgorithm()

virtual soma::ReaderAlgorithm::~ReaderAlgorithm ( )
virtual

Member Function Documentation

◆ algorithmTypes()

const std::map<std::string, ProcFunc>& soma::ReaderAlgorithm::algorithmTypes ( ) const
inline

Query registered process types.

Definition at line 256 of file readeralgorithm.h.

References _execs.

◆ execute() [1/4]

bool soma::ReaderAlgorithm::execute ( carto::Object  header,
carto::rc_ptr< DataSource source 
)

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

◆ execute() [2/4]

bool soma::ReaderAlgorithm::execute ( carto::rc_ptr< DataSource stream)

same as above but uses a DataSource as input

◆ execute() [3/4]

bool soma::ReaderAlgorithm::execute ( carto::rc_ptr< DataSourceInfo dsi)

same as above but uses DataSourceInfo as input.

Header may have already been read

◆ execute() [4/4]

bool soma::ReaderAlgorithm::execute ( const std::string &  filename)

Executes the algo on the object type found in the given file.

Uses DataSourceInfo to figure out which data should be used. This will either call the registered ProcFunc or throw a datatype_format_error exception if no algo function has been registered on that type

◆ registerAlgorithmType()

void soma::ReaderAlgorithm::registerAlgorithmType ( const std::string &  objectType,
ProcFunc  procFunc 
)

Registers the algo function to call on a given object type (just fills the map)

Member Data Documentation

◆ _execs

std::map<std::string, ProcFunc> soma::ReaderAlgorithm::_execs
protected

Definition at line 260 of file readeralgorithm.h.

Referenced by algorithmTypes().


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