/*
Copyright (C) 1998 Pietro Iglio (iglio@kde.org)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
//////////////////////////////////////////////////////////////////////////////
//
// KDBM Package: a C++ interface to the GNU database Library
//
// Author: Pietro glio
// e-mail: iglio@kde.org
// version: 0.1a - 15 October 1998
//
//////////////////////////////////////////////////////////////////////////////
#ifndef _KDBM_H
#define _KDBM_H
#include <strings.h>
#include <stdlib.h>
#include <gdbm.h>
#include <assert.h>
static long _kdbm_long;
#define STR_DATUM(val) (datum){ val, strlen(val) +1 }
#define LONG_DATUM(val) (datum){ (char*) (_kdbm_long = val, &_kdbm_long), sizeof(long) }
#define KGDBM_DEFAULT_BLOCK_SIZE 1024
#define KGDBM_DEFAULT_ACCESS_MODE (00400 | 00200)
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* The KGDbm class is an internal class for implementing
* <a href=KDbm.html>KDbm</a> and <a href=KDbm.html>KIntDbm</a>.
* For an introductory guide, see <a href=KDbm.html>KDbm</a> documentation.
*
*
* @author Pietro Iglio (iglio@kde.org)
* @see KDbm KIntDbm
* @short Abstract base class for the KDBM package.
*/
class KGDbm
{
friend class KGDbmIterator;
public:
/**
* Used for the <a href=#open>open</a> method.
*/
enum KDbmOpenMode { read, readWrite };
/**
* Create a new database.
* If a database with the same name already exists, then it is
* replaced by the new database.
* The created database is open for reading and writing in exclusive mode.
*
* @param file is the name of the file in which the database is stored.
* @return true if successful, false if the database cannot be created.
* @see #open
*/
virtual bool create(char* file);
/**
* Open an existing database or, if a database with the given name does not
* exist and <a href=#setForceMode>setForceMode</a>(true) has been
* previously invoked, create a new one.
*
* Many readers can access the database at the same time. If a database
* is open for writing, the access is exclusive.
*
* @param file is the name of the database file.
* @param mode can be either <code>KGDbm::read</code> (default) or
* <code>KGDbm::readWrite</code>.
* <code>KGDbm::readWrite</code> implies exclusive database access.
* @return true if successful, false if the database cannot be open.
* @see #create
*/
virtual bool open(char* file, enum KDbmOpenMode mode = read);
/**
* Close the last opened database.
*/
virtual void close() {
assert(this->isOpen());
gdbm_close(this->dbf);
this->dbf = 0;
}
/**
* If there is a file system error during a database operation, returns
* the error code.
*/
virtual int errno() {
extern int errno;
return errno;
}
/**
* If there is a gdbm error during a database operation, returns the
* error code. (see <code>gdbm.h</code> for error codes).
*/
virtual int get_gdbm_errno() { return gdbm_errno; }
/**
* Return true if the last searched item has been found.
* Should be checked after using <code>[]</code> or <code>take</code> to
* retrieve database items.
*
*/
virtual bool found() {
return this->foundLastItem;
}
/**
* Reorganize the current database.
*
* If you have had a lot of deletions and would like to shrink the space
* used by the `gdbm' file, this function will reorganize the database.
* `gdbm' will not shorten the length of a `gdbm' file (deleted file space
* will be reused) except by using this reorganization.
* `reorganize' should be used very seldom.
*
*/
virtual void reorganize() {
assert(this->isOpen());
gdbm_reorganize(this->dbf);
}
/**
* Allows the programmer to make sure the disk version of the database has
* been completely updated with all changes to the current time.
*
* If the <a href=#setFastMode>fast mode</a> has been set, the database
* engine does not
* wait for writes to the disk to complete before continuing. This allows
* faster writing of databases at the risk of having a corrupted database
* if the application terminates in an abnormal fashion.
* `sync' is usually called after a complete set of changes have been made
* to the database and before some long waiting time.
* Note that the <a href=#close>close</a> method automatically invokes
* sync.
*
*/
virtual void sync() {
assert(this->isOpen());
gdbm_sync(this->dbf);
}
/**
* Return true if data buffering is enabled.
*
* See <a href="KDbm.html#MemoryManagement">Memory Management</a>
*/
virtual bool bufferIsEnabled() {
return this->buffer != 0;
}
/**
* Enable buffering for retrieved items. Since buffering is enabled by
* default, this function is meaningful only after a call to
* <a href=disableBuffer>disableBuffer</a>.
*
* See <a href="KDbm.html#MemoryManagement">Memory Management</a>
*/
virtual void enableBuffer(int _initSize = 100);
/**
* Disable buffering for retrieved items: users must explicitly release
* pointers to retrieved database items when no more needed.
*
* See <a href="KDbm.html#MemoryManagement">Memory Management</a>
*/
virtual void disableBuffer();
/**
* If <code>_newSize >= 0</code>, resizes the current buffer.
* resizeBuffer(0) will just return the current
* buffer size, leaving it unchanged.
*
* Since the buffer grows to fit retrieved items, this method is useful
* to reduce the size of the buffer periodically.
*
* See <a href="KDbm.html#MemoryManagement">Memory Management</a>
*/
virtual int resizeBuffer(int _newSize);
public:
/**
* Return true if this object is associated to an open database.
* Can be checked after a <a href=#create>create</a> or
* <a href=#open>open</a> operation to test if the database is really opened.
*/
bool isOpen() {
return (this->dbf != 0);
}
/**
* If this property is set to true before an <a href=#open>open</a>
* operation is attempted, then the database is created if it does
* not exist. Otherwise (default) <a href=#open>open</a> will
* fail.
*/
void setForceFlag(bool flag) {
assert(!this->isOpen());
force = flag;
}
/**
* See <a href=#setForceFlag>setForceFlag</a>.
*/
int getForceFlag() {
return force;
}
/**
* Used during the database creation to determine the size of various
* constructs. It is the size of a single transfer from disk to
* memory. This parameter is ignored if the file has been previously
* initialized. The minimum size is 512. If the value is less than
* 512, the file system blocksize is used, otherwise this value is used.
*
* Default is 1024.
*/
void setBlockSize(int size) {
assert(!this->isOpen());
blockSize = size;
}
/**
* See <a href=#setBlockSize>setBlockSize</a>.
*/
int getBlockSize() {
return blockSize;
}
/**
* The permission to use if a new database is created.
* It is modified by the process's umask in the usual way: the
* permissions of the created file are (mode & ~umask).
*
* See also man pages for chmod(2) and open(2).
*
* Should be set before an operation in which a new database is created.
*
* Default is <code>S_IRUSR | S_IWUSR</code>, i.e. user has read and write
* permission.
*/
void setAccessMode(int mode) {
assert(!this->isOpen());
accessMode = mode;
}
/**
* See <a href=#setAccessMode>setAccessMode</a>.
*/
int getAccessMode() {
return accessMode;
}
/**
* If this property is set to true then
* the database will be written without any disk file synchronization.
* This allows faster writes, but may produce an inconsistent database in
* the event of abnormal termination of the writer.
* Can be set at any time.
*
* Default is false.
*/
void setFastMode(bool flag);
/**
* See <a href=#setFastMode>setFastMode</a>.
*/
bool getFastMode() {
return (bool) fastMode;
}
/**
* Set the size of the internal bucket cache.
* This option may only be set once after a database has been open and
* should be set prior to accessing it in any way.
*
* Default is 100.
*/
void setCacheSize(int size) {
cacheSize = size;
if (this->isOpen()) {
int ret = gdbm_setopt(this->dbf, GDBM_CACHESIZE, &size, sizeof(int));
assert(ret == 0);
}
}
/**
* See <a href=#setCacheSize>setCacheSize</a>.
*/
int getCacheSize() {
return cacheSize;
}
protected:
GDBM_FILE dbf;
char* buffer;
int bufferSize;
KGDbm() {
this->dbf = 0;
this->force = false;
this->blockSize = KGDBM_DEFAULT_BLOCK_SIZE;
this->accessMode = KGDBM_DEFAULT_ACCESS_MODE;
this->fastMode = false;
this->buffer = 0;
this->bufferSize = 0;
this->foundLastItem = false;
// By default, the buffer is enabled
enableBuffer();
}
virtual ~KGDbm() {
if (this->buffer)
disableBuffer();
}
char* fetch(datum& _key, int* _psize = 0);
private:
bool foundLastItem;
bool force;
int blockSize;
int accessMode;
bool fastMode;
int cacheSize;
virtual void copyInBuffer(char* _str, int _len) {
if (this->bufferSize < _len)
resizeBuffer(_len);
memcpy(this->buffer, _str, _len);
}
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* KGDbmIterator is an internal class for implementing
* <a href=KDbmIterator.html>KDbmIterator</a> and
* <a href=KIntDbmIterator.html>KIntDbmIterator</a>.
*
*
*
*/
class KGDbmIterator
{
friend class KGDbm;
public:
/**
* Return true if the current database has been completely traversed and
* there is no current item.
*/
bool eof() {
return isAtEof;
}
protected:
KGDbm* db;
bool isAtEof;
datum lastKey;
KGDbmIterator( KGDbm& _db) : db(&_db), isAtEof(false) {
this->lastKey.dptr = 0;
this->lastKey.dsize = 0;
}
GDBM_FILE getDbf() const { return db->dbf; }
void setLastKey(datum& _key) {
if (lastKey.dptr)
free(lastKey.dptr);
if (_key.dptr == 0) { // Last item reached
isAtEof = true;
lastKey.dptr = 0;
}
else {
lastKey.dptr = _key.dptr;
lastKey.dsize = _key.dsize;
}
}
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
<code>KDbm<T></code> provides a database based on <code>char*</code>
keys and <code>T*</code> data.
<H3><a name=Introduction>An Introduction to the KDBM Package</a></H3>
The KDBM package is a C++ interface to the
<a href="ftp://prep.ai.mit.edu/pub/gnu/">GNU
database library (gdbm)</a>. This package includes the following classes:
<a href=KGDbm.html>KGdbm</a>, <a href=KGDbmIterator.html>KGdbmIterator</a>
(abstract base classes),
<a href=KDbm.html>KDbm</a>, <a href=KIntDbm.html>KIntDbm</a>
(database classes),
<a href=KDbmIterator.html>KDbmIterator</a> and
<a href=KIntDbmIterator.html>KIntDbmIterator</a>
(iterator classes).
The main reason to use KDBM in place of the gdbm native interface is,
apart from the C++ interface, the safer memory management model that
helps to prevent memory leaks (see section
<a href="#MemoryManagement">Memory Management</a>).
KDbm is the class that should be used for databases based on
<code>char*</code>, whereas <a href="KIntDbm.html">KIntDbm</a> should be
used for databases based on long keys.
The following example shows how to create a database and store some items in
it:
<pre>
KDbm<char> db;
db.create("mydata");
db.insert("john", "scott");
db.insert("bill", "red");
db.insert("bob", "white");
db.insert("steve", "purple");
db.close();
</pre>
In the next example we open the database and perform some operations with the
stored items:
<pre>
KDbm<char> db;
db.open("mydata");
cout << db["john"] << endl;
cout << db["bill"] << endl;
if (!db.exists("henry"))
cout << "henry does not exist!" << endl;
db.replace("bob", "black");
db.delete("steve");
db.close();
</pre>
<H3>The GNU Database Library: Basic Concepts</H3>
The <a href="ftp://prep.ai.mit.edu/pub/gnu/">GNU
database library (gdbm)</a> is a library of database functions that use
extendible hashing and works similar to the standard UNIX `dbm' functions.
However, gdbm is <bf>not</bf> a complete database package for an end user.
The basic use of `gdbm' is to store key/data pairs in a data file.
Each key must be unique and each key is paired with only one data item.
Both key and data items can be arbitrary sized.
The key/data pairs are stored in a `gdbm' disk file, called a `gdbm'
database. An application must open a `gdbm' database to be able
manipulate the keys and data contained in the database. `gdbm' allows
an application to have multiple databases open at the same time. When
an application opens a `gdbm' database, it is designated as a `reader'
or a `writer'. A `gdbm' database opened by at most one writer at a
time. However, many readers may open the database open simultaneously.
Readers and writers can not open the `gdbm' database at the same time.
For more details, see gdbm documentation.
<H3>Creating a Database:</H3>
Use the <a href="KGDbm.html#create">create</a> method passing the name of
the file to create.
Alternatively, use the <a href="KGDbm.html#open">open</a> method, having
previously set the <a href="KGDbm.html#force">force</a> option to true.
In both cases, true is returned if the database has been created
successfully and subsequent calls to
<a href="KGDbm.html#isOpen">isOpen</a> will return true.
Example:
<pre>
db.create("test.db");
if (!db.isOpen())
cerr << "Error: can't create database" << endl;
</pre>
the above code fragment is equivalent to:
<pre>
db.force = true;
db.open("test.db");
if (!db.isOpen())
cerr << "Error: can't create database" << endl;
</pre>
<H3>Opening a Database:</H3>
If the database does not exist, see the previous section.<br>
If the database already exists, use the
<a href="KGDbm.html#open">open</a> method.<br>
true is returned if the database has been opened
successfully and subsequent calls to
<a href="KGDbm.html#isOpen">isOpen()</a> will return true.
<H3>Retrieving Values:</H3>
The basic way to look up values is through the <code>[]</code> operator,
using the appropriate key. Using <code>take</code> it is also possible to
get the size of the retrieved item.
Example:
<pre>
db.insert("bob", "white");
cout << "bob = " << db["bob"] << endl;
int size;
char* val = db.take("bob", size);
</pre>
A <code>NULL</code> value is returned if there is no item associated to
the given key.
An alternative way to check if an item has been found is through the
<a href=KGDbm.html#found >found</a> function, as in the following example:
<pre>
char* val = db["notsure"];
if (db.found())
cout << "found 'notsure' = " << val << endl;
else
cout << "'notsure' not found" << endl;
</pre>
<H3><a name="Storing"></a>Inserting and Replacing Records:</H3>
The method <code>insert</code> can be used to add new records to
the database, specifying the key and the data to be associated with
the key.<BR>
The key must be a string value for <code>KDbm</code> and a long value for
<code>KIntDbm</code>.<BR>
The data can be either a reference or a pointer to <code>T</code>,
where <code>T</code> is the type
used to instanciate the <code>KDbm</code> (<code>KIntDbm</code>)
template.<BR>
An optional third parameter can be used to specify the size of the data,
which defaults to <code>sizeof(T)</code>.
<code>KDbm<char></code> (<code>KIntDbm<char></code>) are
handled in a special way, as the default size is the size of the
pointed string, assuming that is zero-terminated.
If no error occurs, the value 0 is returned.
No action is taken if the key already exists in the database, and the value
1 is returned. If the item was not stored in the database because the
caller was not an official writer, the value -1 is returned.
The method <code>replace</code> is similar to invoke, but it replaces
the database if it already exist, otherwise works like insert.
Both <code>insert</code> and <code>replace</code> methods require
that the database is open in read-write mode.
<H3><a name="MemoryManagement"></a>Memory Management:</H3>
KDbm and KIntDbm classes can be used in two modes.<BR>
In the first mode (the default one), a buffer is used to store values
that are retrieved from the database.
This way the user does not have to free the pointer to the retrieved item
once it is no more needed. However, since the buffer is reused every time a
new value is retrieved, the user must copy a value from the buffer in case
it is needed for further computation.
The second mode, with the buffer disabled, leaves to the user the
responsibility to free the pointer to any retrieved item. This approach is
more efficient in case many retrieved values must be kept (e.g., to store
them in a memory table), but the user must be careful to avoid memory leaks.
The two rules concerning memory management are:
<em>(a) you can <bf>always</bf> free pointers passed to KDBM classes and,<br>
(b) unless you have explicitly disabled the buffer,
you should <bf>never</bf> release memory returned by KDBM functions.
</em>
Methods related to buffer management are:
disableBuffer, enableBuffer, bufferIsEnabled, resizeBuffer.
The following example shows a case in which a buffer is useful to make the
code more compact:
<pre>
cout << "bob = " << db["bob"] << endl;
cout << "bill = " << db["bill"] << endl;
cout << "steve = " << db["steve"] << endl;
</pre>
In the next example, instead, the buffer is disabled since the pointers to
the retrieved items are pushed onto a stack, so we don't want that the
memory area in which the items are stored is reused:
<pre>
db.disableBuffer();
for (int i = 0; i < 100; i++) {
char* key = keys[i];
stack.push(db[key]);
}
</pre>
Once the items are no more needed, the user must free them.
Alternatively, the above code could be written with the buffer enabled in
the following way:
<pre>
for (int i = 0; i < 100; i++) {
char* key = keys[i];
char* item = strdup(db[key]);
stack.push(item);
}
</pre>
Note that the above code is less efficient, because each item is copied
in a newly allocated ared in the call to <code>strdup()</code>.
@see #enableBuffer #disableBuffer #bufferIsEnabled #resizeBuffer
<H3>Variable-length Structures:</H3>
When a new item is inserted into a KDbm<T> database, the default size
assumed for insert and replace is <code>sizeof(T)</code>. To store variable
size structures, the insert and replace methods can be called with an
optional third parameter, corresponding to the actual size of the item that
must be stored. To look up a given key, <a href="#take">take</a> should be
used rather than the <code>[]</code> operator.
Example:
<pre>
typedef struct VarObjStruct {
int a;
int count;
char var[0]; // `var' can have an arbitrary length
} VarObj;
VarObj* item = (VarObj*) malloc(sizeof(VarObj) + 20);
...
db.insert("varsize", item, sizeof(VarObj) + 20);
</pre>
<H3>Design Considerations:</H3>
The interface for KGDbm, KDbm, ... classes resembles as much as possible
the interface of QGDict, QDict, ... (<a href="http://www.troll.no">Qt</a>
dictionary), for coherence with
<a href="http://www.kde.org">KDE</a> design.
However, the KDBM package is not depending on any other KDE file, thus it
can be used without any problem for other projects.<BR>
Efficiency and a simple interface have been primary design goals.<BR>
For comments and suggestions, please e-mail me
(<a href="mailto:iglio@kde.org">
Pietro Iglio</a>).
@author Pietro Iglio (iglio@kde.org)
@see KGDbm KIntDbm
*/
template<class T>
class KDbm : public KGDbm
{
public:
/**
* Default constructor.
*/
KDbm() : KGDbm() {};
/**
* Return true if the given key exists in the database, false otherwise.
*/
bool exists(char* _key);
/**
* Insert a new record into the database.
*
* See <a href=Storing>Inserting and Replacing Records</a>.
*/
int insert(char* _key, T* _val, const int _size = sizeof(T));
/**
* Insert a new record into the database.
*
* See <a href=Storing>Inserting and Replacing Records</a>.
*/
int insert(char* _key, T& _val, const int _size = sizeof(T)) {
return insert(_key, &_val, _size);
}
/**
* Replace a record in the database.
*
* See <a href=Storing>Inserting and Replacing Records</a>.
*/
int replace(char* _key, T* val, const int _size = sizeof(T));
/**
* Replace a record in the database.
*
* See <a href=Storing>Inserting and Replacing Records</a>.
*/
int replace(char* _key, T& val, const int _size = sizeof(T)) {
return replace(_key, &val, _size);
}
/**
* Look up a given `key' and return the information associated with
* that key.
* <bf>NOTE:</bf> for T is a variable-length structure, you should use
* <a href=#take>take</a>.
*/
T* operator[] (char* _key);
/**
* Like <code>[]</code>, but returns puts in `size' the size of the
* retrieved item.
* Useful for variable-length structures, since the size of the returned
* item may vary.
*/
T* take(char* _key, int& _size);
/**
* Remove the item associated with 'key' from the database.
*
* @return true if the item was removed successfully, false otherwise (for
* example, if the item does not exist).
* @see #exists
*/
bool remove(char* _key);
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* KDbmIterator provides an iterator for KDbm databases.
*
* The access is not `key' sequential, but it is guaranteed to
* visit every `key' in the database once.
*
* Example:
*
<pre>
KDbmIterator it(db);
for (char* key = it.getFirstKey(); !it.eof(); it.getNextKey()) {
cout << key << " = " << db[key] << endl;
}
</pre>
*/
class KDbmIterator : public KGDbmIterator
{
public:
/**
* Construct an iterator for `_db'.
*/
KDbmIterator(KGDbm& _db) : KGDbmIterator(_db) {
lastKey.dptr = 0;
lastKey.dsize = 0;
};
/**
* Destroy the iterator.
*/
~KDbmIterator() {
if (lastKey.dptr)
free(lastKey.dptr);
}
/**
* Set the iterator to point to the first item in the database and return
* a pointer to its key.
* The pointer is null if the database is empty.
* <bf>Note:</bf> the returned pointer is owned by the iterator and should
* not be released.
*
* @see #getNextKey
*/
char* getFirstKey() {
assert(this->db->isOpen());
datum key = gdbm_firstkey(this->getDbf());
this->setLastKey(key);
return key.dptr;
}
/**
* Set the iterator to point to next item in the database and return
* a pointer to its key.
* The pointer is null if the previous current item was the last one.
* <bf>Note:</bf> the returned pointer is owned by the iterator and should
* not be released.
*
* @see #getFirstKey
*/
char* getNextKey() {
assert(this->db->isOpen());
datum key = gdbm_nextkey(this->getDbf(), this->lastKey);
this->setLastKey(key);
return key.dptr;
}
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* <code>KIntDbm<T></code> provides a database based on <code>long</code>
* keys and <code>T*</code> data.
*
* KIntDbm class is very similar to KDbm. The only difference is that KIntDbm
* implements a database with keys of type <code>long</code>. Please refer to
* the <a href=KDbm.html>KDbm</a> class documentation.
*
*/
template<class T>
class KIntDbm : public KGDbm
{
public:
/**
* Default constructor.
*/
KIntDbm() : KGDbm() {};
/**
* See <a href=KDbm.html>KDbm</a>
*/
bool exists(const long _key);
/**
* See <a href=Storing>Inserting and Replacing Records</a>.
*/
int insert(const long _key, T* _val, const int _size = sizeof(T));
/**
* See <a href=Storing>Inserting and Replacing Records</a>.
*/
int insert(const long _key, T& _val, const int _size = sizeof(T)) {
/**
* See <a href=Storing>Inserting and Replacing Records</a>.
*/
return insert(_key, &_val, _size);
}
/**
* See <a href=Storing>Inserting and Replacing Records</a>.
*/
int replace(const long _key, T* _val, const int _size = sizeof(T));
/**
* See <a href=KDbm.html>KDbm</a>
*/
int replace(const long _key, T& _val, const int _size = sizeof(T)) {
return replace(_key, &_val, _size);
}
/**
* See <a href=KDbm.html>KDbm</a>
*/
T* operator[] (long _key);
/**
* See <a href=KDbm.html>KDbm</a>
*/
T* take(long _key, int& _size);
/**
* Remove the item associated with 'key' from the database.
*
* @return true if the item was removed successfully, false otherwise (for
* example, if the item does not exist).
* @see #exists
*/
bool remove(long _key);
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/**
* KIntDbmIterator provides an iterator for KIntDbm databases.
*
*/
class KIntDbmIterator : public KGDbmIterator
{
public:
KIntDbmIterator(KGDbm& _db) : KGDbmIterator(_db) {};
long getFirstKey() {
assert(this->db->isOpen());
datum key = gdbm_firstkey(this->getDbf());
this->setLastKey(key);
assert(key.dsize == sizeof(long));
if (key.dptr == 0)
return 0;
else
return *(long*) key.dptr;
}
long getNextKey() {
assert(this->db->isOpen());
datum key = gdbm_nextkey(this->getDbf(), this->lastKey);
this->setLastKey(key);
if (key.dptr == 0)
return 0;
else
return *(long*) key.dptr;
}
};
//////////////////////////////////////////////////////////////////////////////
// Template specializations
extern int KDbm<char>::insert(char* _key, char* _val, const int _size);
extern int KDbm<char>::replace(char* _key, char* _val, const int _size);
extern int KIntDbm<char>::insert(const long _key, char* _val, const int _size);
extern int KIntDbm<char>::replace(const long _key, char* _val, const int _size);
//////////////////////////////////////////////////////////////////////////////
template<class T> inline T*
KDbm<T>::operator[](char* _key)
{
assert(this->isOpen());
datum key = STR_DATUM(_key);
return (T*) fetch(key);
}
template<class T> inline T*
KDbm<T>::take(char* _key, int& _size)
{
assert(this->isOpen());
datum key = STR_DATUM(_key);
return (T*) fetch(key, &_size);
}
template<class T> inline bool
KDbm<T>::exists(char* _key)
{
datum key = STR_DATUM(_key);
return (gdbm_exists(this->dbf, key) != 0);
}
template<class T> int
KDbm<T>::insert(char* _key, T* _val, const int _size)
{
datum key = STR_DATUM(_key);
datum val = { (char*) _val, _size };
return gdbm_store(dbf, key, val, GDBM_INSERT);
}
template<class T> int
KDbm<T>::replace(char* key, T* val, const int _size)
{
datum _key = STR_DATUM(key);
datum _val = { (char*) val, _size };
return gdbm_store(dbf, _key, _val, GDBM_REPLACE);
}
template<class T> inline bool
KDbm<T>::remove(char* _key) {
datum key = STR_DATUM(_key);
int res = gdbm_delete(this->dbf, key);
return (res == 0);
}
//////////////////////////////////////////////////////////////////////////////
template<class T> T*
KIntDbm<T>::operator[](long _key)
{
assert(this->isOpen());
datum key = LONG_DATUM(_key);
return (T*) fetch(key);
}
template<class T> inline T*
KIntDbm<T>::take(long _key, int& _size)
{
assert(this->isOpen());
datum key = LONG_DATUM(_key);
return (T*) fetch(key, &_size);
}
template<class T> inline bool
KIntDbm<T>::exists(long _key)
{
datum key = LONG_DATUM(_key);
return (gdbm_exists(this->dbf, key) != 0);
}
template<class T> int
KIntDbm<T>::insert(const long _key, T* _val, const int _size)
{
datum key = LONG_DATUM(_key);
datum val = { (char*) _val, _size };
return gdbm_store(dbf, key, val, GDBM_INSERT);
}
template<class T> int
KIntDbm<T>::replace(const long _key, T* _val, const int _size)
{
datum key = LONG_DATUM(_key);
datum val = { (char*) _val, _size };
return gdbm_store(dbf, key, val, GDBM_REPLACE);
}
template<class T> inline bool
KIntDbm<T>::remove(long _key)
{
datum key = LONG_DATUM(_key);
int res = gdbm_delete(this->dbf, key);
return (res == 0);
}
#endif
Documentation generated by iglio@localhost on Thu Oct 15 19:05:38 GMT 1998