KDbm<T>
provides a database based on char*
keys and T*
data More...
#include <kdbm.h>
Inherits: KGDbm
KDbm<T>
provides a database based on char*
keys and T*
data.
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 Memory Management).
KDbm is the class that should be used for databases based on
char*
, whereas KIntDbm should be
used for databases based on long keys.
The following example shows how to create a database and store some items in it:
KDbmdb; db.create("mydata");
db.insert("john", "scott"); db.insert("bill", "red"); db.insert("bob", "white"); db.insert("steve", "purple");
db.close();
In the next example we open the database and perform some operations with the stored items:
KDbmdb; 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();
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.
Use the create method passing the name of the file to create. Alternatively, use the open method, having previously set the force option to true. In both cases, true is returned if the database has been created successfully and subsequent calls to isOpen will return true.
Example:
db.create("test.db"); if (!db.isOpen()) cerr << "Error: can't create database" << endl;
the above code fragment is equivalent to:
db.force = true; db.open("test.db"); if (!db.isOpen()) cerr << "Error: can't create database" << endl;
If the database does not exist, see the previous section.
If the database already exists, use the
open method.
true is returned if the database has been opened
successfully and subsequent calls to
isOpen() will return true.
The basic way to look up values is through the []
operator,
using the appropriate key. Using take
it is also possible to
get the size of the retrieved item.
Example:
db.insert("bob", "white"); cout << "bob = " << db["bob"] << endl; int size; char* val = db.take("bob", size);
A NULL
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
found function, as in the following example:
char* val = db["notsure"]; if (db.found()) cout << "found 'notsure' = " << val << endl; else cout << "'notsure' not found" << endl;
The method insert
can be used to add new records to
the database, specifying the key and the data to be associated with
the key.
The key must be a string value for KDbm
and a long value for
KIntDbm
.
The data can be either a reference or a pointer to T
,
where T
is the type
used to instanciate the KDbm
(KIntDbm
)
template.
An optional third parameter can be used to specify the size of the data,
which defaults to sizeof(T)
.
KDbm<char>
(KIntDbm<char>
) 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 replace
is similar to invoke, but it replaces
the database if it already exist, otherwise works like insert.
Both insert
and replace
methods require
that the database is open in read-write mode.
KDbm and KIntDbm classes can be used in two modes.
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:
(a) you can
(b) unless you have explicitly disabled the buffer,
you should
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:
cout << "bob = " << db["bob"] << endl; cout << "bill = " << db["bill"] << endl; cout << "steve = " << db["steve"] << endl;
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:
db.disableBuffer();for (int i = 0; i < 100; i++) { char* key = keys[i]; stack.push(db[key]); }
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:
for (int i = 0; i < 100; i++) { char* key = keys[i]; char* item = strdup(db[key]); stack.push(item); }
Note that the above code is less efficient, because each item is copied
in a newly allocated ared in the call to strdup()
.
When a new item is inserted into a KDbmsizeof(T)
. 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, take should be
used rather than the []
operator.
Example:
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);
Default constructor.
Return true if the given key exists in the database, false otherwise.
Insert a new record into the database.
See Inserting and Replacing Records.
Insert a new record into the database. See Inserting and Replacing Records.
Replace a record in the database.
See Inserting and Replacing Records.
Replace a record in the database.
See Inserting and Replacing Records.
Look up a given `key' and return the information associated with
that key.
Like []
, 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.
Remove the item associated with 'key' from the database.
| Kdoc |