Listing 1: Class IndexedFile definition

#ifndef UTIL_INDEXED_FILE_H
#define UTIL_INDEXED_FILE_H

// XDR Stream headers
#include "Util/XDRStream.h"
#include "Util/XIO.h"

// Standard C++ headers
#include <functional>
#include <string>
#include <ios>
#include <list>

namespace Util {

template <typename Item>
struct XDR_Traits {
      typedef      XIOFileStream           xio_type;
      static oXDR_Stream& encode(oXDR_Stream& oxs, const Item& val)
            { return oxs << val; }
      static iXDR_Stream& decode(iXDR_Stream& ixs, Item& val)
            { return ixs >> val; }
};


//
// BtreeIndex --
//
template<typename Key,
       typename Compare = std::less<Key>,
       typename KeyTraits = XDR_Traits<Key>,
       size_t PageSize = 4096>
class BtreeIndex {
public:
      // public types

      // forward declartions
      class StreamposProxy;
      class Iterator;
      class PageCache;
      class Page;
      class RootPage;
      class XIODataStreambuf;
      class XInDataBuf;
      class XoutDataBuf;

      typedef Key                               key_type;
      typedef std::pair<const Key, size_t>                 value_type;
      typedef Compare                           key_compare;
      typedef Iterator                          iterator;
      typedef size_t                                  size_type;
      typedef ptrdiff_t                         difference_type;

      enum DeleteStrategy { None, Compact, Shuffle };
      enum UpdateStrategy { Unsafe, MostlySafe, Safe };

//
// class BtreeIndex::Iterator --
//
class StreamposProxy {
      friend class BtreeIndex;
      // data
      size_t                  _link;
      BtreeIndex*       _btree;
      size_t                  _page;
      size_t                  _slot;
public:
      // LWC - default copy and destroy Ok
      // conversion
      operator size_t();
      // assignment
      void operator=(size_t newlink);
private:
      StreamposProxy(size_t link, 
             BtreeIndex* btree, 
             size_t page, 
             size_t slot);
};

class Iterator : public std::iterator<
            std::bidirectional_iterator_tag, 
            std::pair<
                  const Key,
                  BtreeIndex_StreamposProxy<Key,Compare,KeyTraits,PageSize>
                  >
            > {
      friend class BtreeIndex;
      // data
      BtreeIndex*             _btree;
      size_t                        _page;
      size_t                        _slot;
public:
      Iterator()  {}

      std::pair<const Key, StreamposProxy> operator*();
      Iterator&                     operator++();
      Iterator                      operator++(int);
      Iterator&                     operator--();
      Iterator                      operator--(int);

      bool operator==(const Iterator& rhs) const;
      bool operator!=(const Iterator& rhs) const;
private:
      Iterator(BtreeIndex* btree, size_t page, size_t slot);
};


class PageCache {
      // types
      typedef std::list<Page*> PageList;

      // data
      XDR_Stream&      _xstream;
      size_t            _minSize;
      size_t            _maxSize;
      PageList      _pageList;
public:
      PageCache(XDR_Stream&);
      ~PageCache();

      Page*       get_page(size_t page);
      void        add_page(Page* p); // puts a new page into the cache
      void        reset();    // deletes any excess pages
      void        clear();    // deletes all pages
      void        flush();    // writes any dirty pages out

      void        min_size(size_t size) { _minSize = size; }
      int         max_size()        { return _maxSize; }
      void        max_size(size_t size) { _minSize = size; }
}; //> BtreeIndex::PageCache

//
// BtreeIndex::Page
//
class Page {
public:
      struct KeyInfo {
            Key         key;
            size_t            link;
            short       xlen;      // length of encoded <key,link> in data area
            KeyInfo(Key k, size_t l, short xl) : key(k), link(l), xlen(xl) {}
            KeyInfo() {}
      };
      typedef std::list<KeyInfo>      KeyList;

protected:
      // data
      const size_t       _pageId;
      size_t            _dataLen;
      size_t            _prevPage;
      size_t            _nextPage;
      bool        _dirty;           // set when changed; cleared by encode
      KeyList           _keyList;

      static const int HeaderSize = 16;
public:
      Page(size_t pageId);
      virtual ~Page();

      // access
      size_t            page_id() const         { return _pageId; }
      size_t            data_len() const        { return _dataLen; }
      size_t            prev_page() const       { return _prevPage; }
      size_t            next_page() const       { return _nextPage; }
      bool        is_dirty() const        { return _dirty; }
      size_t            num_keys() const        { return _keyList.size(); }

      // update
      KeyList&      key_list()              { return _keyList; }

      void        data_len(size_t len)  { _dataLen = len; _dirty = true; }
      void        prev_page(size_t pid)  { _prevPage = pid; _dirty = true; }
      void        next_page(size_t pid)  { _nextPage = pid; _dirty = true; }

      // test
      bool        must_split() const;

      // access / update the key list 
      size_t            add_key(BtreeIndex&, const std::pair<const Key, size_t>&); 

      bool        remove_key(int slot);
      void        update_key(size_t slot, size_t link);

      void        insert_page_link(KeyList::iterator kit, Page* p);
      void        update_page_link(Page* p);
      bool        remove_page_link(Page* p);

      // virtual functions
      virtual Page*           split(BtreeIndex&);
      virtual Page*           consolidate(BtreeIndex&);
      virtual Page*           shuffle(BtreeIndex&);   
      virtual oXDR_Stream&       encode(oXDR_Stream&);
      virtual iXDR_Stream&       decode(iXDR_Stream&);
private:
      Page(const Page&);
      Page& operator=(const Page&);
}; //> BtreeIndex::Page


//
// BtreeIndex::RootPage
//
class RootPage : public Page {
public:
      // data
      size_t            _totalKeys;
      short       _depth;
      bool        _dirtyTotal;
public:
      RootPage();
      virtual ~RootPage();

      // access
      size_t            total_keys() const            { return _totalKeys; }
      short       depth() const                 { return _depth; }
      size_t            next_free_page() const       { return _nextPage; }
      bool        is_total_dirty() const       { return _dirtyTotal; }

      // update
      void        incr_total()      { ++_totalKeys; _dirtyTotal = true; }
      void        decr_total()      { --_totalKeys; _dirtyTotal = true; }
      void        add_free_page(Page* p)  { 
p->next_page(next_page()); 
next_page(p->page_id()); }
      void        rem_free_page(Page* p)  { next_page(p->next_page()); }

      // virtual functions
      virtual Page*           split(BtreeIndex&);
      virtual Page*           consolidate(BtreeIndex&);
      virtual oXDR_Stream&       encode(oXDR_Stream&);
      virtual iXDR_Stream&       decode(iXDR_Stream&);
}; //> BtreeIndex::RootPage


// class which handles read/write to/from an externally specified memory area
class XIODataStreambuf : public XDR_Streambuf {
      // data
      XDR_Char*         _buf;
      size_t                  _size;
      size_t                  _len;
public:
      XIODataStreambuf(char* buf, size_t size, size_t len = 0);
      ~XIODataStreambuf();

      virtual pos_type seekoff(off_type off, 
                             std::ios_base::seekdir dir, 
                         std::ios_base::openmode which);
      virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which);
};


class XOutDataBuf : public oXDR_Stream {
      // data
      oXDR_Stream&            _refstrm;
      XIODataStreambuf      _xstreambuf;

public:
      XOutDataBuf(oXDR_Stream&, char* buf, size_t size);
      ~XOutDataBuf();
};


class XInDataBuf : public iXDR_Stream {
      // data
      iXDR_Stream&            _refstrm;
      XIODataStreambuf      _xstreambuf;

public:
      XInDataBuf(iXDR_Stream&, char* buf, size_t len);
      ~XInDataBuf();
};


      // construct / destroy
      explicit BtreeIndex(Compare comp = Compare());


explicit BtreeIndex(const std::string& name, 
            std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out,
            Compare comp = Compare());
      ~BtreeIndex();

      // open/close/test state
      bool              is_open();
      void              open(
const std::string& name, 
std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
      void              close();
      void              flush();
      operator void*() const;
      bool operator!() const;

      // iterators
      iterator          begin();
      iterator          end();

      // capacity
      bool              empty();
      size_type         size();

      // modifiers
      iterator          insert(const value_type& x);
      iterator          insert(const Key& k);
      template<typename InputIterator>
      void              insert(InputIterator first, InputIterator last);

      void              erase(Iterator pos);
      size_type         erase(const Key& x);
      void              erase(iterator first, iterator last);
      void              clear();

      // observers
      key_compare       key_comp() const;
      size_type         page_size() const;
      XDR_Stream&       xdrstream();

      // operations
      iterator          find(const Key& x);
      size_type         count(const Key& x);

      iterator          lower_bound(const Key& x);
      iterator          upper_bound(const Key& x);
      std::pair<iterator, iterator>
                        equal_range(const Key& x);

      // utilities
      void              reindex();
      DeleteStrategy          set_delete_strategy(DeleteStrategy strategy);
      UpdateStrategy          set_update_strategy(UpdateStrategy strategy);
      int               set_cache_size(int size);

private:
      // friends
      friend class Iterator;
      friend class StreamposProxy;
      friend class Page;
      friend class RootPage;

      // data
      Compare                       _comp;
      KeyTraits::xio_type           _xstream;
      RootPage*               _root;
      PageCache               _pageCache;
      DeleteStrategy                _dStrategy;
      UpdateStrategy                _uStrategy;

      // Iterator utility functions - used by friends
      std::pair<const Key, StreamposProxy>
                        get_value(size_t page, size_t slot);
      void              prev_iter(Iterator& it);
      void              next_iter(Iterator& it);

      // StreamposProxy utility functions - used by friends
      void              update_link(size_t page, size_t offset, size_t link);

      // BtreeIndex utility functions
      Page*             get_page(size_t pageId);
      Page*             get_free_page();
      void              add_free_page(Page* p);
      iterator          lower_bound(Page* p, int depth, const Key& k);
      iterator          upper_bound(Page* p, int depth, const Key& k);
      iterator          insert(Page*, int depth, const value_type& x);
      std::pair<bool,bool>       erase(Page* p, int depth, const Key& k, iterator pos);

      void              flush(UpdateStrategy s);
}; //> BtreeIndex


//
// Class IndexedFile
//
template<typename Key,
         typename Item,
       typename Compare = std::less<Key>,
       typename KeyTraits = XDR_Traits<Key>,
       typename ItemTraits = XDR_Traits<Item>,
       size_t PageSize = 4096>
class IndexedFile {
public:
      // types
      class ItemProxy;
      class Iterator;

      typedef Key                   key_type;
      typedef std::pair<const Key, Item>      value_type;
      typedef Compare               key_compare;
      typedef Iterator              iterator;
      typedef size_t                      size_type;
      typedef ptrdiff_t             difference_type;
      typedef BtreeIndex<Key, Compare, KeyTraits, PageSize> index_type;

      class ItemProxy {
            friend Iterator;
            // data
            IndexedFile*                  _ifile;
            index_type::StreamposProxy      _posProxy;
      public:
            // conversion
            operator Item()               { return _ifile->read( _posProxy ); }
            // assignment
            void operator=(const Item& item)       { _posProxy = _ifile->write(item); }
      private:
            ItemProxy(IndexedFile* ifile, index_type::StreamposProxy posProxy)
                        : _ifile(ifile), _posProxy(posProxy) {}
      };

      class Iterator : public std::iterator<
std::bidirectional_iterator_tag,
                         std::pair<const Key, ItemProxy> > {
            friend IndexedFile;

            // data
            IndexedFile*                  _ifile;
            index_type::iterator          _base;

      public:
            Iterator()  {}
            std::pair<const Key, ItemProxy>      operator*();
            Iterator&                     operator++();
            Iterator                      operator++(int);
            Iterator&                     operator--();
            Iterator                      operator--(int);
            index_type::iterator                base();
            bool operator==(const Iterator& x) const;
            bool operator!=(const Iterator& x) const;
      private:
            Iterator(IndexedFile* ifile, index_type::iterator base)
                        : _ifile(ifile), _base(base) {}
      };

      // construct / destroy
      explicit IndexedFile(Compare comp = Compare());
      explicit IndexedFile(
const std::string& name, 
            std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out, 
            Compare comp = Compare());
      ~IndexedFile();

      // open/close
      bool              is_open();
      void              open(
const std::string& name, 
std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
      void              close();
      void              flush();
      operator void*() const;
      bool operator!() const;

      // iterators
      Iterator          begin();
      Iterator          end();

      // capacity
      bool              empty();
      size_type         size();

      // modifiers
      Iterator          insert(const value_type& x);
      template<typename InputIterator>
      void              insert(InputIterator first, InputIterator last);

      void              erase(Iterator pos);
      size_type         erase(const Key& x);
      void              erase(Iterator first, Iterator last);
      void              clear();

      // observers
      Compare                 key_comp() const;
      size_t                  page_size() const;
      index_type&       index();
      XDR_Stream&       xdrstream();

      // operations
      Iterator          find(const Key& x);
      size_type         count(const Key& x);

      Iterator          lower_bound(const Key& x);
      Iterator          upper_bound(const Key& x);
      std::pair<Iterator, Iterator>
                              equal_range(const Key& x);

      // utilities


void              compact();
      Item              read(size_t pos); // decodes and returns the Item at pos

private:
      //
data
      index_type        _index;
      ItemTraits::xio_type      _xstream;

      // friendly utilities
      size_t                  write(const Item& item); // returns the streampos
};

} //> namespace

#endif