/** * Copyright 2013 (c) Anna Schumaker. */ #ifndef OCARINA_CORE_DATABASE_H #define OCARINA_CORE_DATABASE_H #include #include #include template class Database; /** * The DatabaseEntry class is the base class for storing * generic data inside a Database. */ class DatabaseEntry { private: template 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 * * * The Database class will add a newline after each DatabaseEntry. */ template class Database { private: /** Databases are backed by a std::vector. */ std::vector _db; /** Used for keeping track of primary keys. */ std::map _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::iterator iterator; /** Const iterator access for our backing std::vector */ typedef typename std::vector::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 */