ocarina/include/core/database.h

219 lines
5.6 KiB
C
Raw Normal View History

/**
* Copyright 2013 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_DATABASE_H
#define OCARINA_CORE_DATABASE_H
#include <core/file.h>
#include <map>
#include <vector>
template<class T> class Database;
/**
* The DatabaseEntry class is the base class for storing
* generic data inside a Database.
*/
class DatabaseEntry {
private:
template <class T> friend class Database;
unsigned int _index; /**< The location of an item in the Database. */
public:
DatabaseEntry(); /**< Initialize _index to 0. */
virtual ~DatabaseEntry() = 0; /**< Virtual destructor */
/**
* Called to access a DatabaseEntry's index.
*
* @return DatabaseEntry::_index
*/
const unsigned int index();
/**
* 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;
/**
* This function is called by the Database to write a specific
* DatabaseEntry instance to disk.
*
* @param file File to use when writing data.
*/
virtual void write(File &) = 0;
/**
* This function is called by the Database to read a single
* DatabaseEntry instance from disk.
*
* @param file File to use when reading data.
*/
virtual void read(File &) = 0;
};
/**
* 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>
class Database {
private:
/** Databases are backed by a std::vector. */
std::vector<T *> _db;
/** Used for keeping track of primary keys. */
std::map<const std::string, unsigned int> _keys;
/** The number of valid DatabaseEntries in the Database. */
unsigned int _size;
/** Set to True if the Database should be saved when changed. */
bool _autosave;
/** File object for reading and writing a Database. */
File _file;
public:
/** Iterator access for our backing std::vector */
typedef typename std::vector<T *>::iterator iterator;
/** Const iterator access for our backing std::vector */
typedef typename std::vector<T *>::const_iterator const_iterator;
/**
* Initialize a Database using filepath as a location to store data
* on disk.
*
* @param filepath File on disk that will be written to.
* @param autosave Set to True if the Database should be saved upon
* every insertion and deletion. If this is set
* to False then the Database will have to be saved
* manually.
*/
Database(std::string, bool);
/**
* Deletes all remaining entries in a Database to prevent memory leaks.
*/
~Database();
/**
* Called to save the Database to disk.
*/
void save();
/**
* Called to save the Database to disk ONLY if Database::_autosave
* was set to True.
*/
void autosave();
/**
* Called to read the Database from disk.
*/
void load();
/**
* Called to add a new item to the Database. Upon successful insertion,
* this function will:
* -# Allocate a new DatabaseEntry instance.
* -# Set the DatabaseEntry::_index field to the size of Database::_db.
* -# Add the new DatabaseEntry to the end of Database::_db.
* -# Increment Database::_size.
* -# Call Database::autosave() to commit changes.
*
* @param item The new item to be added.
* @return If Database::_keys already contains an instance with the
* same DatabaseEntry::primary_key(), then return NULL.
* @return Otherwise, return a pointer to the new instance stored
* in the Database.
*/
T *insert(const T &);
/**
* Called to remove an item from the Database. This function will:
* -# Delete memory allocated for the DatabaseEntry
* -# Set Database::_db[index] = NULL
* -# Decrement Database::_size
* -# Call Database::autosave() to commit changes
*
* @param index The index of the item that should be removed.
*/
void remove(unsigned int);
/**
* Called to find the number of valid items in the Database.
*
* @return Database::_size
*/
unsigned int size();
/**
* Called to find the size of the backing std::vector.
*
* @return The size of Database::_db.
*/
unsigned int actual_size();
/**
* @return An iterator pointing to the first valid entry in the Database.
* @return Return Database::end() if there are no valid entries.
*/
iterator begin();
/**
* @return An iterator pointing past the end of the database.
*/
iterator end();
/**
* @return An iterator pointing to the next valid item in the database.
*/
iterator next(iterator &);
/**
* Returns the database item at the requested index.
*
* @param index The database index to access.
* @return A pointer to the requested DatabaseEntry.
* @return NULL if there is no valid DatabaseEntry at the requested index.
*/
T *at(unsigned int);
/**
* Find a DatabaseItem with a specific primary key.
*
* @param key The key to search for.
* @return A pointer to the requested DatabaseEntry.
* @return NULL if there is no matching DatabaseEntry.
*/
T *find(const std::string &);
};
#include "database.hpp"
#endif /* OCARINA_CORE_DATABASE_H */