User Documentation
RAVL, Recognition And Vision Library
DEVELOP HOME PAGE CLASS LIST CONTENTS
Ravl - Core - IO - Type Converter


Automatic type conversion

The problem of proliferation of formats is not limited to files. It occurs in the structures used to represent the data used within programs as well. If there are N different representations for some data within a program, and M different file formats, there could be a requirement for up to N*M load routines.

Fortunately the concept of a `Process' for transforming data from the previous section provides a solution. As has been done for file formats it is possible to keep a database of known transformations between different data representations. Using this database we can identify a transformation or set of transformations that converts between the representation used by a file format and that used by the program.

The set of transformations known to the program can be throught of as a graph, each node corresponding to a data representation, and the edges as transformations between them. The problem of finding the quickest way of converting one type to another becomes one of searching for the shortest path through the graph. This is a well-known and studied problem, and is easily solved. Figure 17 shows a simple type conversion graph. The numbers shown next to the edges are the defined costs of conversions which will be discussed next. It is possible to convert between any two nodes in this graph even though not all conversions are defined; it is this consideration which justifies the added complexity of using such graphs, over a simple conversion list.

The nodes of the graph in Figure 17, are represented by the class `DPTypeInfoC', and the edges by the class `DPProcInfoC'. Both these classes contains virtual methods which allow the type conversion mechanism both to handle data, and construct conversion pipes without any direct reference to types themselves.

Figure 17: A simple type conversion graph.
typeconv.eps

Sometimes information is lost in a conversion, e.g. turning a real number into an integer. This means that not all paths through the graph are equally desirable. Since the IO routines can not know what aspects of the information being handled are important we cannot guarantee the best conversion path is chosen. It is possible to define a heuristic, which chooses the path which 'loses' the least information. For this a value is associated with each conversion which estimates the relative information lost in the conversion. The value is provided by the programmer, and should be the ratio of bits used in the representation of the output divided by the number used to represent the input data. The graph search then becomes a search for the least cost, leading to a problem with known solutions from computer science. The heuristic described above is a little ad-hoc, but in practice has provided satisfactory behaviour.

With the use of templating the addition of new conversion can be made very easy. As with processes described earlier only a single function need be defined. The following example defines the conversion from an interger to a floating point number, (defined as RealT in AMMA), which loses no information and hence has a cost of one.

RealT DPConvIntT2RealT ( const IntT &val )
{ return ( RealT) val ; }

DP_REGISTER_CONVERTION ( DPConvIntT2RealT,1 ) ;

The type conversion mechanism is available should the user wish to use it. The interface consists of 3 functions. The first, 'DPCanConvert' tests if a conversion is possible, and takes as argument references the C++ rtti type_info structure. A Boolean is returned indicating whether a conversion is possible. The second function, `DPDoConvertion' takes as arguments two abstract handles, RCAbstractC, which can wrap any other C++ type rather like a void * in 'C'. This will convert the handle from its original type to the one required, if possible. If the conversion fails an invalid handle is returned. Finally a templated function, DPTypeConvert is provided which wraps the `DPDoConvertion' operation so the user can use the type conversion without any special constructions. This final mechanism is provided mainly for testing the type conversion mechanism, as if both types are fully defined, conversion can be done through conventional C++ means. The following example uses the interface to convert an integer to a double, the hard way.

int i = 10;
double j;
if(DPTypeConvert(i,j))
{ cout << "Conversion succeeded"; }

Normal classes:

 DPConverterBaseC Converter base class
 DPConverterC Type conversion handle.
 DPConverterFuncC Setup data conversion function.
 DPTypeInfoC Type information handle.
 DPTypeInfoInstC Type information instance body.

Normal functions:

 RegisterConversion(OutT (*func)(const InT & in) ,RealT,const char *) Register a conversion function.
 DPCanConvert(const type_info &,const type_info &) Test if conversion is possible.
 DPDoConvertion(const RCAbstractC &,const type_info &,const type_info &) Do conversion through abstract handles.
 DPTypeConvert(const InT &,OutT &) Convert between two types using the type conversion graph.
 DPTypeConvert(const RCWrapAbstractC &,OutT &) Convert between a abstract handle to an object and a known type.
 TypeInfo(const type_info &) Access extra information about a type.
 TypeInfo(const char *) Access extra information about a type.
Documentation by CxxDoc: Tue Aug 13 10:00:52 2002