/*************************************************************************************************
 * xdepot.o
 * C++ API of Depot, the basic API of QDBM
 *                                                       Copyright(c) 2000-2003 Mikio Hirabayashi
 *************************************************************************************************/


#ifndef _XDEPOT_H                        /* duplication check */
#define _XDEPOT_H


#include <xqdbm.h>
#include <xadbm.h>

extern "C" {
#include <depot.h>
#include <stdlib.h>
}



/**
 * Error container for Depot.
 */
class qdbm::Depot_error : public virtual DBM_error {
public:
  //----------------------------------------------------------------
  // public member functions
  //----------------------------------------------------------------
  /**
   * Create an instance.
   */
  Depot_error() throw();
  /**
   * Create an instance.
   * @param ecode the error code.
   */
  Depot_error(int ecode) throw();
  /**
   * Copy constructor.
   * @param de a source instance.
   */
  Depot_error(const Depot_error& de) throw();
  /**
   * Release resources of the instance.
   */
  virtual ~Depot_error() throw();
  /**
   * Assignment operator.
   * @param de a source instance.
   * @return reference to itself.
   */
  virtual Depot_error& operator=(const Depot_error& de) throw();
  /**
   * Assignment operator.
   * @param ecode the error code.
   * @return reference to itself.
   */
  virtual Depot_error& operator=(int ecode) throw();
  /**
   * Equality operator.
   * @param de a comparing instance.
   * @return true if the both equal, else, false.
   */
  virtual bool operator==(const Depot_error &de) const throw();
  /**
   * Inequality operator.
   * @param de a comparing instance.
   * @return true if the both do not equal, else, false.
   */
  virtual bool operator!=(const Depot_error &de) const throw();
  /**
   * Equality operator.
   * @param ecode a comparing error code.
   * @return true if the both equal, else, false.
   */
  virtual bool operator==(int ecode) const throw();
  /**
   * Inequality operator.
   * @param ecode a comparing error code.
   * @return true if the both do not equal, else, false.
   */
  virtual bool operator!=(int ecode) const throw();
  /**
   * Get the error code.
   * @return the error code.
   */
  virtual int code() const throw();
  /**
   * Get the error message.
   * @return the string.
   */
  virtual const char* message() const throw();
private:
  //----------------------------------------------------------------
  // private member variables
  //----------------------------------------------------------------
  /** The error code. */
  int ecode;
};



/**
 * C++ API of Depot, the basic API of QDBM.
 */
class qdbm::Depot : public virtual ADBM {
public:
  //----------------------------------------------------------------
  // public static member constants
  //----------------------------------------------------------------
  static const int ENOERR = DP_ENOERR;         ///< error code: no error
  static const int EFATAL = DP_EFATAL;         ///< error code: with fatal error
  static const int EMODE = DP_EMODE;           ///< error code: invalid mode
  static const int EBROKEN = DP_EBROKEN;       ///< error code: broken database file
  static const int EKEEP = DP_EKEEP;           ///< error code: existing record
  static const int ENOITEM = DP_ENOITEM;       ///< error code: no item found
  static const int EALLOC = DP_EALLOC;         ///< error code: memory allocation error
  static const int EMAP = DP_EMAP;             ///< error code: memory mapping error
  static const int EOPEN = DP_EOPEN;           ///< error code: open error
  static const int ECLOSE = DP_ECLOSE;         ///< error code: close error
  static const int ETRUNC = DP_ETRUNC;         ///< error code: trunc error
  static const int ESYNC = DP_ESYNC;           ///< error code: sync error
  static const int ESTAT = DP_ESTAT;           ///< error code: stat error
  static const int ESEEK = DP_ESEEK;           ///< error code: seek error
  static const int EREAD = DP_EREAD;           ///< error code: read error
  static const int EWRITE = DP_EWRITE;         ///< error code: write error
  static const int ELOCK = DP_ELOCK;           ///< error code: lock error
  static const int EUNLINK = DP_EUNLINK;       ///< error code: unlink error
  static const int EMKDIR = DP_EMKDIR;         ///< error code: mkdir error
  static const int ERMDIR = DP_ERMDIR;         ///< error code: rmdir error
  static const int EMISC = DP_EMISC;           ///< error code: miscellaneous error
  static const int OREADER = DP_OREADER;       ///< open mode: open as a reader
  static const int OWRITER = DP_OWRITER;       ///< open mode: open as a writer
  static const int OCREAT = DP_OCREAT;         ///< open mode: writer creating
  static const int OTRUNC = DP_OTRUNC;         ///< open mode: writer truncating
  static const int DOVER = DP_DOVER;           ///< write mode: overwrite the existing value
  static const int DKEEP = DP_DKEEP;           ///< write mode: keep the existing value
  static const int DCAT = DP_DCAT;             ///< write mode: concatenate values
public:
  //----------------------------------------------------------------
  // public static member functions
  //----------------------------------------------------------------
  /**
   * Get the version information.
   * @return the string of the version information.
   */
  static const char* version() throw();
  /**
   * Remove a database file.
   * @param name the name of a database file.
   * @throw Depot_error if an error occures.
   */
  static void remove(const char* name) throw(Depot_error);
public:
  //----------------------------------------------------------------
  // public member functions
  //----------------------------------------------------------------
  /**
   * Get the database handle.
   * @param name the name of a database file.
   * @param omode the connection mode: `Depot::OWRITER' as a writer, `Depot::OREADER' as
   * a reader.  If the mode is `Depot::OWRITER', the following may be added by bitwise or:
   * `Depot::OCREAT', which means it creates a new database if not exist, `Depot::OTRUNC',
   * which means it creates a new database regardless if one exists.
   * @param bnum the number of elements of the bucket array.  If it is not more than 0,
   * the default value is specified.  The size of a bucket array is determined on creating,
   * and can not be changed except for by optimization of the database.  Suggested size of a
   * bucket array is about from 0.5 to 4 times of the number of all records to store.
   * @throw Depot_error if an error occures.
   * @note While connecting as a writer, an exclusive lock is invoked to the database file.
   * While connecting as a reader, a shared lock is invoked to the database file.  The thread
   * blocks until the lock is achieved.
   */
  Depot(const char* name, int omode = Depot::OREADER, int bnum = -1) throw(Depot_error);
  /**
   * Release the resources.
   * @note If the database handle is not closed yet, it is closed.
   */
  virtual ~Depot() throw();
  /**
   * Close the database handle.
   * @throw Depot_error if an error occures.
   * @note Updating a database is assured to be written when the handle is closed.  If a writer
   * opens a database but does not close it appropriately, the database will be broken.
   */
  virtual void close() throw(Depot_error);
  /**
   * Store a record.
   * @param kbuf the pointer to the region of a key.
   * @param ksiz the size of the region of the key.  If it is negative, the size is assigned
   * with `std::strlen(kbuf)'.
   * @param vbuf the pointer to the region of a value.
   * @param vsiz the size of the region of the value.  If it is negative, the size is assigned
   * with `std::strlen(vbuf)'.
   * @param dmode behavior when the key overlaps, by the following values: `Depot::DOVER',
   * which means the specified value overwrites the existing one, `Depot::DKEEP', which means the
   * existing value is kept, `Depot::DCAT', which means the specified value is concatenated at
   * the end of the existing value.
   * @throw Depot_error if an error occures or replace is cancelled.
   */
  virtual void put(const char* kbuf, int ksiz, const char* vbuf, int vsiz,
                   int dmode = Depot::DOVER) throw(Depot_error);
  /**
   * Delete a record.
   * @param kbuf the pointer to the region of a key.
   * @param ksiz the size of the region of the key.  If it is negative, the size is assigned
   * with `std::strlen(kbuf)'.
   * @throw Depot_error if an error occures or no record corresponds.
   */
  virtual void out(const char* kbuf, int ksiz) throw(Depot_error);
  /**
   * Retrieve a record.
   * @param kbuf the pointer to the region of a key.
   * @param ksiz the size of the region of the key.  If it is negative, the size is assigned
   * with `std::strlen(kbuf)'.
   * @param start the offset address of the beginning of the region of the value to be read.
   * @param max the max size to read with.  If it is negative, the size is unlimited.
   * @param sp a pointer to the variable to which the size of the region of the return value
   * assigned.  If it is 0, it is not used.
   * @return the pointer to the region of the value of the corresponding record.
   * @throw Depot_error if an error occures, no record corresponds, or the size of the value
   * of the corresponding record is less than `start'.
   * @note Because an additional zero code is appended at the end of the region of the return
   * value, the return value can be treated as a character string.  Because the region of the
   * return value is allocated with the `std::malloc' call, it should be released with the
   * `std::free' call if it is no longer in use.
   */
  virtual char* get(const char* kbuf, int ksiz, int start = 0, int max = -1, int* sp = 0)
    throw(Depot_error);
  /**
   * Get the size of the value of a record.
   * @param kbuf the pointer to the region of a key.
   * @param ksiz the size of the region of the key.  If it is negative, the size is assigned
   * with `std::strlen(kbuf)'.
   * @return the size of the value of the corresponding record.
   * @throw Depot_error if an error occures or no record corresponds.
   * @note Because this function does not read the entity of a record, it is faster than `get'.
   */
  virtual int vsiz(const char* kbuf, int ksiz) throw(Depot_error);
  /**
   * Initialize the iterator of the database handle.
   * @throw Depot_error if an error occures.
   * @note The iterator is used in order to access the key of every record stored in a database.
   */
  virtual void iterinit() throw(Depot_error);
  /**
   * Get the next key of the iterator.
   * @param sp a pointer to the variable to which the size of the region of the return value
   * assigned.  If it is 0, it is not used.
   * @return the pointer to the region of the next key.
   * @throw Depot_error if an error occures or no record is to be get out of the iterator.
   * @note Because an additional zero code is appended at the end of the region of the return
   * value, the return value can be treated as a character string.  Because the region of the
   * return value is allocated with the `std::malloc' call, it should be released with the
   * `std::free' call if it is no longer in use.
   * @note It is possible to access every record by iteration of calling this function.
   * However, it is not assured if updating the database is occurred while the iteration.
   * Besides, the order of this traversal access method is arbitrary, so it is not assured that
   * the order of storing matches the one of the traversal access.
   */
  virtual char* iternext(int* sp = 0) throw(Depot_error);
  /**
   * Set alignment of the database handle.
   * @param align the basic size of alignment.
   * @throw Depot_error if an error occures.
   * @note If alignment is set to a database, the efficiency of overwriting values are improved.
   * The basic size of alignment is suggested to be average size of the values of the records
   * to be stored.  When a record is storing, the size of the region reserved for its value is
   * determined as multiple of the alignment size.  The alignment size is determined as multiple
   * of the basic size of alignment.  Because alignment setting is not saved in a database,
   * you should specify alignment every opening a database.
   */
  virtual void setalign(int align) throw(Depot_error);
  /**
   * Synchronize contents of updating the database with the file and the device.
   * @throw Depot_error if an error occures.
   * @note This function is useful when another process uses the connected database file.
   */
  virtual void sync() throw(Depot_error);
  /**
   * Optimize the database.
   * @param bnum the number of the elements of the bucket array.  If it is not more than 0,
   * the default value is specified.
   * @throw Depot_error if an error occures.
   * @note In an alternating succession of deleting and storing with overwrite or concatenate,
   * dispensable regions accumulate.  This function is useful to do away with them.
   */
  virtual void optimize(int bnum = -1) throw(Depot_error);
  /**
   * Get the name of the database.
   * @return the pointer to the region of the name of the database.
   * @throw Depot_error if an error occures.
   * @note Because the region of the return value is allocated with the `std::malloc' call,
   * it should be released with the `std::free' call if it is no longer in use.
   */
  virtual char* name() throw(Depot_error);
  /**
   * Get the size of the database file.
   * @return the size of the database file.
   * @throw Depot_error if an error occures.
   */
  virtual int fsiz() throw(Depot_error);
  /**
   * Get the number of the elements of the bucket array.
   * @return the number of the elements of the bucket array.
   * @throw Depot_error if an error occures.
   */
  virtual int bnum() throw(Depot_error);
  /**
   * Get the number of the used elements of the bucket array.
   * @return the number of the used elements of the bucket array.
   * @throw Depot_error if an error occures.
   * @note This function is inefficient because it accesses all elements of the bucket array.
   */
  virtual int busenum() throw(Depot_error);
  /**
   * Get the number of the records stored in the database.
   * @return the number of the records stored in the database.
   * @throw Depot_error if an error occures.
   */
  virtual int rnum() throw(Depot_error);
  /**
   * Check whether the database handle is a writer or not.
   * @return true if the handle is a writer, false if not.
   * @throw Depot_error if an error occures.
   */
  virtual bool writable() throw(Depot_error);
  /**
   * Check whether the database has a fatal error or not.
   * @return true if the database has a fatal error, false if not.
   * @throw Depot_error if an error occures.
   */
  virtual bool fatalerror() throw(Depot_error);
  /**
   * Get the inode number of the database file.
   * @return the inode number of the database file.
   * @throw Depot_error if an error occures.
   */
  virtual int inode() throw(Depot_error);
  /**
   * Get the file descriptor of the database file.
   * @return the file descriptor of the database file.
   * @throw Depot_error if an error occures.
   * @note Handling the file descriptor of a database file directly is not suggested.
   */
  virtual int fdesc() throw(Depot_error);
  /**
   * Store a record.
   * @param key reference to a key object.
   * @param val reference to a value object.
   * @param replace whether the existing value is to be overwritten or not.
   * @throw Depot_error if an error occures or replace is cancelled.
   */
  virtual void storerec(const Datum& key, const Datum& val, bool replace = true)
    throw(Depot_error);
  /**
   * Delete a record.
   * @param key reference to a key object.
   * @throw Depot_error if an error occures or no record corresponds.
   */
  virtual void deleterec(const Datum& key) throw(Depot_error);
  /**
   * Fetch a record.
   * @param key reference to a key object.
   * @return the pointer to an instance of the value of the corresponding record.
   * @throw Depot_error if an error occures or no record corresponds.
   * @note The instance pointed to by the return value is to be destloyed by the caller.
   */
  virtual Datum* fetchrec(const Datum& key) throw(Depot_error);
  /**
   * Get the first key.
   * @return the pointer to an instance of the value of the first record.
   * @throw Depot_error if an error occures or no record corresponds.
   * @note The instance pointed to by the return value is to be destloyed by the caller.
   */
  virtual Datum* firstkey() throw(Depot_error);
  /**
   * Get the next key.
   * @return the pointer to an instance of the value of the first record.
   * @throw Depot_error if an error occures or no record corresponds.
   * @note The instance pointed to by the return value is to be destloyed by the caller.
   */
  virtual Datum* nextkey() throw(Depot_error);
  /**
   * Check whether an fatal error occured or not.
   * @return true if the database has a fatal error, false if not.
   * @throw Depot_error if an error occures.
   */
  virtual bool error() throw(Depot_error);
  /**
   * No effect.
   * @throw Depot_error if an error occures.
   */
  virtual void clearerror() throw(Depot_error);
private:
  //----------------------------------------------------------------
  // private member variables
  //----------------------------------------------------------------
  /** The database handle. */
  DEPOT* depot;
  //----------------------------------------------------------------
  // private member functions
  //----------------------------------------------------------------
  /** copy constructor: This should not be used. */
  Depot(const Depot& depot) throw(Depot_error);
  /** assignment operator: This should not be used. */
  virtual Depot& operator=(const Depot& depot) throw(Depot_error);
};



#endif                                   /* duplication check */


/* END OF FILE */
