CCP4 Coordinate Library Project

Object interface: File Operations on Library's Classes.

All classes in the Library employ a uniform technology of storing their content in disk files and its subsequent retrieval. This allows for automatical reading/writing of arbitrary system of linked classes. If an application derives childs from Library's classes, it must provide for this technology, otherwise the file operations on classes will not work correctly.

In order to comply with the Library's system of class I/O, a class should provide for the following:
  1. it must originate from class CStream (found in file stream_.h). All Library's classes originate from CStream, therefore if they are parents of derived classes, this condition holds automatically.

  2. it must have a default constructor without parameters and a special "stream" constructor
    CDerivedClass ( RPCStream Object );
    
    Both of them should fully initialize the class' data; parameter Object must be passed to the stream constructor of parent untouched (see example below).

  3. it must have member functions
    void write ( RCFile f );
    void read  ( RCFile f );
    
    which, correspondingly, write and read the class' data using the file class CFile. These functions should also call the parent's write and read.

  4. the definition of class must be preceeded by macros
    DefineClass(CDerivedClass)
    DefineStreamFunctions(CDerivedClass)
    
  5. the implementation of class must include macro
    MakeStreamFunctions(CDerivedClass)
    

After all the above conditions are satisfied, a class (e.g. CLibClass may be stored on disk and retrieved in either of the following ways:

Method 1: use methods CLibClass::write(RCFile f):
CFile     f;
CLibClass LC;
  f.assign ( FileName );
  if (f.rewrite())  {
    LC.write ( f );
    f.shut();
  } else
    printf ( " can't open file for writting\n" );
and CLibClass::read(RCFile f)
CFile     f;
CLibClass LC;
  f.assign ( FileName );
  if (f.reset())  {
    LC.read ( f );
    f.shut();
  } else
    printf ( " can't open file for reading\n" );
This method represents merely a uniform unsophisticated approach to streaming the classes, which does not actually involve creation of class instances -- and therefore the special stream constructor from above does not participate in this. However, the all rules listed above must be satisfied if CLibClass is to replace one of the Library classes and the Library is therefore expected to take care of all file operations on it.

Method 2: use stream functions StreamWrite(RCFile f,RPCLibClass LC):
CFile      f;
PCLibClass LC;
  LC = new CLibClass();
  . . . . . . . . . .
  f.assign ( FileName );
  if (f.rewrite())  {
    StreamWrite ( f,LC );
    f.shut();
  } else
    printf ( " can't open file for writting\n" );
and StreamRead(RCFile f,RPCLibClass LC)
CFile      f;
PCLibClass LC;
  LC = NULL;
  f.assign ( FileName );
  if (f.reset())  {
    StreamRead ( f,LC );
    f.shut();
  } else
    printf ( " can't open file for reading\n" );
This method will work even if class CLibClass is not found at the specified file position, in which case LC will be assigned NULL. This is a more general method of streaming the classes, which simplifies file operations on arbitrary dynamically-linked class hierarchies. Note that Method 1 and Method 2 cannot be mixed up, and that on each write/StreamWrite executed at writing the file, there should be exactly one call of read/StreamRead, correspondingly, at reading the file.

EXAMPLE
The following illustrates the abovewritten on the example of deriving a class from Library's class CAtom:

in header new_catom.h file:
DefineClass(CNewAtom)
DefineStreamFunctions(CNewAtom)

class CNewAtom : public CAtom  {

  public :
    CNewAtom();
    CNewAtom( RPCStream Object );
    ~CNewAtom();  // destructor
    void write ( RCFile f );
    void read  ( RCFile f );

  protected :
    int      new_int_data;
    realtype new_real_data;
    pstr     new_dynamical_string;

    void  InitNewAtom();  // common initializer

};

in implementational new_catom.cpp file:
CNewAtom::CNewAtom() : CAtom()  {
  InitNewAtom();
}

CNewAtom::CNewAtom ( RPCStream Object ) : CAtom(Object)  {
  InitNewAtom();
}

CNewAtom~CNewAtom()  {
  if (new_dynamical_string)  delete new_dynamical_string;
}

void CNewAtom::InitNewAtom()  {
  new_int_data  = 1;
  new_real_data = 0.001;
  new_dynamical_string = NULL;
  CreateCopy ( new_dynamical_string,"new dynamical string" );
}
void CNewAtom::write ( RCFile f )  {
  CAtom::write  ( f );
  f.WriteInt    ( &new_int_data  );
  f.WriteReal   ( &new_real_data );
  f.CreateWrite ( new_dynamical_string );
}
void CNewAtom::read ( RCFile f )  {
// read() must strictly preserve the order of file operations
// set in the corresponding write() function
  CAtom::read ( f );
  f.ReadInt    ( &new_int_data  );
  f.ReadReal   ( &new_real_data );
  f.CreateRead ( new_dynamical_string );
}
MakeStreamFunctions(CNewAtom)

Below, CLibClass stands for the name of any Library class or class derived from a Library class.

Function Purpose
CLibClass::CLibClass Default constructor for Library classes
CLibClass::CLibClass Stream constructor for Library classes.
CLibClass::write Writing the class data into a disk file.
CLibClass::read Reading the class data from disk file.
StreamWrite Writing a class into a disk file.
StreamRead Reading a class from a disk file.
DefineClass Macrodefinition of major types associated with the class.
DefineStructure Macrodefinition of major types associated with the structure.
DefineStreamFunctions Macrodefinition of prototypes of stream functions (StreamWrite and StreamRead) for a class.
MakeStreamFunctions Macrogeneration of stream functions (StreamWrite and StreamRead) for a class.


 CLibClass::CLibClass ( 
 )
PURPOSE
Default constructor for Library classes
DESCRIPTION

Default constructor performs initialization of class' data. All Library classes and classes derived from them must have the default constructor.

NOTE 1: Default constructors are used in Library's file operations on classes.

NOTE 2: All Library classes are derived from class CStream, which provides support for file operations on classes.


EXAMPLE

CLibClass::CLibClass() : CStream()  {
  CLibClassIntVariable = 0;
}


 CLibClass::CLibClass ( 
RPCStream  Object )
PURPOSE
Stream constructor for Library classes.
ARGUMENTS
RPCStream Object
This parameter must be passed to the parent class untouched.

DESCRIPTION

Stream constructor performs initialization of class' data and passes its argument to the parent class. All Library classes and classes derived from them must have the default constructor.

NOTE 1: Stream constructors are used in Library's file operations on classes.

NOTE 2: All Library classes are derived from class CStream, which provides support for file operations on classes.


EXAMPLE

CLibClass::CLibClass(RPCStream Object) : CStream(Object)  {
  CLibClassIntVariable = 0;
}


 CLibClass::write ( 
RCFile  f )
PURPOSE
Writing the class data into a disk file.
ARGUMENTS
RCFile f
Reference to the instance of file class CFile. The file is supplied already opened and adjusted to the appropriate position -- do not attempt to change that. The file must be left opened when the function returns.

DESCRIPTION

This virtual function, first defined in class CStream (file stream_.h), should provide for writing the class data into file given as the function's argument. The given file is already open; the function must not attempt to neither open nor close it, as well as change its current position by means other than normal output operations. It must not attempt to read from the file, either.

If the class is derived from another class, other than CStream, the write function must also call write function of the class' parent by placing statement
CParentClass::write(f);
(CParentClass stands for the name of parential class), where appropriate within the function body.

NOTE : It is crucially important that write and read functions of a class handle equal amount of bytes in strictly the same order.


EXAMPLE

See examples on the top of this page.


 CLibClass::read ( 
RCFile  f )
PURPOSE
Reading the class data from disk file.
ARGUMENTS
RCFile f
Reference to the instance of file class CFile. The file is supplied already opened and adjusted to the appropriate position -- do not attempt to change that. The file must be left opened when the function returns.

DESCRIPTION

This virtual function, first defined in class CStream (file stream_.h), should provide for reading the class data from file given as the function's argument. The given file is already open; the function must not attempt to neither open nor close it, as well as change its current position by means other than normal input operations. It must not attempt to write into the file, either.

If the class is derived from another class, other than CStream, the read function must also call read function of the class' parent by placing statement
CParentClass::read(f);
(CParentClass stands for the name of parential class), where required within the function body.

NOTE : It is crucially important that write and read functions of a class handle equal amount of bytes in strictly the same order.


EXAMPLE

See examples on the top of this page.


void StreamWrite ( 
RCFile  f, 
RPCStream Object )
PURPOSE
Writing a class into a disk file.
ARGUMENTS
RCFile f
Reference to the instance of file class CFile.

RPCStream Object
Reference to the pointer of a class, which is to be written. The class must be derived from CStream and satisfy all the conditions listed on top of this page.

DESCRIPTION

This function is part of the Library's technology of performing file operation on classes. Combined with StreamRead, it allows for automatical writing/reading an arbitrary dynamically linked hierarchy of classes.

The function writes the class data into disk file, preceeding it with a few bytes of auxilary information. It is perfectly Ok to give this function a NULL pointer for Object which is interpreted as "empty" class or "no class".

NOTE 1: The function is generated automatically by macros DefineStreamFunctions and MakeStreamFunctions.

NOTE 2: For each call to StreamWrite made at writing a file, there must be exactly one call to StreamRead at reading it at strictly the same file position.


EXAMPLE

See examples on the top of this page.


void StreamRead ( 
RCFile  f, 
RPCStream Object )
PURPOSE
Reading a class from a disk file.
ARGUMENTS
RCFile f
Reference to the instance of file class CFile.

RPCStream Object
Reference to the pointer of a class, which is to be read. The class must be derived from CStream and satisfy all the conditions listed on top of this page.

DESCRIPTION

This function is part of the Library's technology of performing file operation on classes. Combined with StreamWrite, it allows for automatical reading/writing an arbitrary dynamically linked hierarchy of classes.

If Object is set to NULL, the corresponding class will be allocated, initialized and read from the disk file; Object will then return pointer on it. If Object points to an existing instance of the class before being passed to StreamRead, the function will use that instance to stuff it with data from the file.

If StreamWrite has placed an "empty" class at given position in the file, StreamRead will always return Object=NULL; in this case, if Object pointed to an allocated class before being passed to StreamRead, that class will be automatically disposed.

NOTE 1: The function is generated automatically by macros DefineStreamFunctions and MakeStreamFunctions.

NOTE 2: For each call to StreamRead made at reading a file, there must be exactly one call to StreamWrite at writing it at strictly the same file position.


EXAMPLE

See examples on the top of this page.


 DefineClass ( 
  ClassName )
PURPOSE
Macrodefinition of major types associated with the class.
ARGUMENTS
ClassName
Name of a class.

DESCRIPTION

This macro defines the types of class pointer, class reference, pointer on pointer and reference to pointer. Each pointer is made by prefix "P", and each reference - by prefix "R". Thus
PClassName - is pointer on class ClassName
RClassName - is reference to class ClassName
PPClassName - is pointer on PClassName
RPClassName - is reference to PClassName

NOTE 1: These type definitions are used by macros DefineStreamFunctions and MakeStreamFunctions and through all the Library, therefore definition of each class should be prefaced with this macro.

NOTE 2: In the Library, the class names always start with capital "C". This however is not a requirement of any syntax or macrodefinition(s).


EXAMPLE

See example on the top of this page.


 DefineStructure ( 
  StructName )
PURPOSE
Macrodefinition of major types associated with the structure.
ARGUMENTS
StructName
Name of a structure.

DESCRIPTION

This macro defines the types of structure pointer, structure reference, pointer on pointer and reference to pointer. Each pointer is made by prefix "P", and each reference - by prefix "R". Thus
PStructName - is pointer on structure StructName
RStructName - is reference to structure StructName
PPStructName - is pointer on PStructName
RPStructName - is reference to PStructName

NOTE : In the Library, the structure names always start with capital "S". This however is not a requirement of any syntax or macrodefinition(s).


 DefineStreamFunctions ( 
  ClassName )
PURPOSE
Macrodefinition of prototypes of stream functions (StreamWrite and StreamRead) for a class.
ARGUMENTS
ClassName
Name of a class.

DESCRIPTION

This macro defines the prototypes of stream functions (StreamWrite and StreamRead) for class ClassName. These prototypes may be implicitely used by the Library, therefore always issue this macro.

NOTE 1: This macro will not work if DefineClass macro for that class was not issued before it.

NOTE 2: In the Library, the class names always start with capital "C". This however is not a requirement of any syntax or macrodefinition(s).


EXAMPLE

See example on the top of this page.


 MakeStreamFunctions ( 
  ClassName )
PURPOSE
Macrogeneration of stream functions (StreamWrite and StreamRead) for a class.
ARGUMENTS
ClassName
Name of a class.

DESCRIPTION

This macro generates stream functions StreamWrite and StreamRead for class ClassName.

NOTE 1: This macro will not work if DefineClass macro for that class was not issued before it.

NOTE 2: In the Library, the class names always start with capital "C". This however is not a requirement of any syntax or macrodefinition(s).


EXAMPLE

See example on the top of this page.



Back to index