ocarina/include/core/database.h

159 lines
4.4 KiB
C
Raw Normal View History

/**
* Copyright 2013 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_DATABASE_H
#define OCARINA_CORE_DATABASE_H
extern "C" {
#include <core/file.h>
}
#include <map>
#include <string>
#include <vector>
/**
* The DatabaseEntry class is the base class for storing
* generic data inside a Database.
*/
struct db_entry {
unsigned int dbe_index; /* The db_entry's position in the database. */
db_entry(); /**< Initialize _index to 0. */
virtual ~db_entry() = 0; /**< Virtual destructor */
/**
* The primary key of a DatabaseEntry is a unique string representing
* a single DatabaseEntry instance. This is used for preventing
* duplicate entries in a Database. The primary key is not expected
* to change once a DatabaseEntry has been initialized.
*
* @return A unique string identifying a DatabaseEntry instance.
*/
virtual const std::string primary_key() const = 0;
};
struct db_ops {
/* Allocate a new struct db_entry from a given key. */
struct db_entry *(*dbe_alloc)(const gchar *);
/* Free a struct db_entry. */
void (*dbe_free)(struct db_entry *);
/* Read a single struct db_entry from disk. */
struct db_entry *(*dbe_read)(struct file *);
/* Set up a struct db_entry after adding to the database. */
void (*dbe_setup)(struct db_entry *);
/* Write a single struct db_entry to disk. */
void (*dbe_write)(struct file *, struct db_entry *);
};
/**
* Databases are a generic store for information used by Ocarina. Users
* need to inherit from a DatabaseEntry class to properly use a Database.
*
* When writing a Database to disk, Databases need to store their size in
* addition to values and valid bits at each index. For example, let's say
* we have a Database with the following values: { 1, 2, NULL, 4 }. On
* disk this would look like:
*
* 4
* 0 true 1
* 1 true 2
* 2 false
* 3 true 4
* <index> <valid> <data>
*
* The Database class will add a newline after each DatabaseEntry.
*/
template <class T>
struct database {
unsigned int db_size; /* The database's count of valid entries. */
bool db_autosave; /* True if the database saves when changed. */
struct file db_file; /* The database's associated file object. */
const struct db_ops *db_ops; /* The database's operations vector. */
std::vector<T *> db_entries;
std::map<const std::string, unsigned int> db_keys;
};
/*
* Initialize a database using filepath as a location on disk to store data
* and autosave as a hint for if this database should be automatically saved.
*/
template <class T>
void db_init(struct database<T> *, const char *, bool, const struct db_ops *);
/* Called to prevent memory leaks by freeing all remaining database entries. */
template <class T>
void db_deinit(struct database<T> *);
/* Called to write the database to disk. */
template <class T>
void db_save(struct database<T> *);
/* Save the database to disk iff database->db_autosave is set to True */
template <class T>
void db_autosave(struct database<T> *);
/* Called to read the database from disk. */
template <class T>
void db_load(struct database<T> *);
/* Returns the size of the backing std::vector. */
template <class T>
unsigned int db_actual_size(const struct database<T> *);
/*
* Called to add a new item to the database. The caller MUST check if the
* database already contains a similar item before calling this function.
*/
template <class T>
T *db_insert(struct database<T> *, T *);
/* Called to remove an item from the database. */
template <class T>
void db_remove(struct database<T> *, T *);
/* Returns the database item at the requested index. */
template <class T>
T *db_at(struct database<T> *, unsigned int);
/* Returns the database item with the specified key. */
template <class T>
T *db_get(struct database<T> *, const gchar *);
/*
* Similar to db_get(), but allocate and return a new item if the
* database doesn't contain an item with the specified key.
*/
template <class T>
T *db_find(struct database<T> *, const gchar *);
/* Returns the first valid database item. */
template <class T>
T *db_first(const struct database<T> *);
/* Returns the next valid database item. */
template <class T>
T *db_next(const struct database<T> *, T *);
#define db_for_each(ent, next, db) \
for (ent = db_first(db), next = db_next(db, ent); \
ent != NULL; \
ent = next, next = db_next(db, ent))
#include "database.hpp"
#endif /* OCARINA_CORE_DATABASE_H */