Listing 1: listman.h — Disk-based container list manager

#ifndef __LISTMAN_H
#define __LISTMAN_H
#include "dfile.h"

typedef ulong filepos;     /* file position type */

template <class T> struct TDSingleLinkNode  {
    filepos Next, Free;
    T Data;
    };

template <class T> struct TDDoubleLinkNode  {
    filepos Prev, Next, Free;
    T Data;
    };

template <class T> struct TDBinarySearchTreeNode  {
    filepos Left, Right, Free;
    T Data;
    };

template <class Nd, class FM> class TDListManager
{   /* Nd is node type, FM is File manager type */
    FM *_Fm;   /* -> file manager */
    struct header {
        filepos Head, Tail, Free;
        ulong NodesAllocated;   /* total count */
        ulong ItemCount;        /* active count */
        } _Hdr;

    #define HDRSIZE  sizeof(header)

   /* BEG_OFFSET places 1st node at specified offset
    * into container file (see vectman.h).....
    */
    #ifndef BEG_OFFSET
    #define BEG_OFFSET  HDRSIZE
    #endif

  public:
    TDListManager(const char *fname, int nn, int m) {
        _Fm = new FM( nn, sizeof(Nd), fname, m );
        _Hdr.Head = _Hdr.Tail = _Hdr.Free = 0;
        _Hdr.ItemCount = _Hdr.NodesAllocated = 0;
        _Fm->ReadAt( 0, (void *) &_Hdr, HDRSIZE );
    }
    ~TDListManager() {  WriteHeader();
                        delete _Fm;    }
    filepos Head() const { return _Hdr.Head; }
    void   Head(filepos hd) { _Hdr.Head = hd; }
    filepos Tail() const { return _Hdr.Tail; }
    void   Tail(filepos tl) { _Hdr.Tail = tl; }
    ulong ItemCount() const { return _Hdr.ItemCount; }
    void ItemCount( ulong c ) {  _Hdr.ItemCount = c; }
    ulong ListSize() const
        { return _Hdr.NodesAllocated; }
    int WriteHeader();
    void GetFree( Nd& );
    void PutFree( Nd& );
    virtual int ReadNode(Nd& t, ulong pos)
        { return _Fm->ReadNode( (void *) &t, pos ); }
    virtual int WriteNode(const Nd& t, ulong pos)    {
        return _Fm->WriteNode((const void *) &t, pos );
        }
};

template <class Nd,class FM>
int TDListManager<Nd,FM>::WriteHeader()
{
    if( _Fm->tempused() )
        return 1;   /* return if non-persistent */
    return _Fm->WriteAt( 0, (void *) &_Hdr, HDRSIZE );
}

template <class Nd,class FM>
void TDListManager<Nd,FM>::GetFree( Nd& node )
{   /* Get address of next free node in the file;
     * Assign new address to node.Free ....... */
    if( _Hdr.Free == 0 )   /* get new node  */
        node.Free = ( _Hdr.NodesAllocated++
                         * sizeof(Nd) ) + BEG_OFFSET;
    else    {  /* Get next free node from file... */
        filepos _free = _Hdr.Free;
        ReadNode( node, _free );
        _Hdr.Free = node.Free;
        node.Free = _free;
    }
}

template <class Nd,class FM>
void TDListManager<Nd,FM>::PutFree( Nd& node )    {
    filepos _free = node.Free;
    node.Free = _Hdr.Free;
    _Hdr.Free = _free;
    WriteNode( node, _free );
}
#endif // EOF