Database: Write more detailed documentation
I transferred information from my DESIGN file and worked it into Doxygen comments. Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
parent
48b25945cc
commit
e281286291
134
DESIGN
134
DESIGN
|
@ -66,140 +66,6 @@ Callbacks:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Database:
|
|
||||||
Databases are a generic store for information used by Ocarina. Users
|
|
||||||
need to inherit from a DatabaseEntry class (above) to properly use a
|
|
||||||
database.
|
|
||||||
|
|
||||||
The Database class is a templated class, so code could potentially
|
|
||||||
get messy. Normal class declarations can still exist in the file
|
|
||||||
include/database.h and member functions are written in the file
|
|
||||||
include/database.hpp, which will be included by database.h. Any
|
|
||||||
function not relying on a template can be written in lib/database.cpp.
|
|
||||||
|
|
||||||
- Automatic saving:
|
|
||||||
Databases can save automatically whenever a new value is inserted or
|
|
||||||
deleted. This will be more efficient for Databases that do not change
|
|
||||||
often but will be a huge performance hit for Databases that have many
|
|
||||||
changes at once. All databases will be loaded automatically from disk.
|
|
||||||
|
|
||||||
- Primary keys:
|
|
||||||
Databases use the primary_key() function of a DatabaseEntry to enforce
|
|
||||||
uniqueness. This key is used when inserting a new value into the
|
|
||||||
Database, and will not be updated after.
|
|
||||||
|
|
||||||
- Id:
|
|
||||||
The "id" field of a DatabaseEntry is also managed by the entry's
|
|
||||||
Database container It will be set to the entry's ID when the entry is
|
|
||||||
inserted into the database.
|
|
||||||
|
|
||||||
- Database:
|
|
||||||
template <class T>
|
|
||||||
class Database {
|
|
||||||
private:
|
|
||||||
std::vector<T *> _db;
|
|
||||||
std::map<const std::string, unsigned int> _keys;
|
|
||||||
unsigned int _size; /* Number of valid rows */
|
|
||||||
bool _autosave;
|
|
||||||
File _file;
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef std::vector<T *>::iterator iterator;
|
|
||||||
typedef std::vector<T *>::const_iterator const_iterator;
|
|
||||||
|
|
||||||
Database(std::string, bool);
|
|
||||||
~Database();
|
|
||||||
void save();
|
|
||||||
void load();
|
|
||||||
|
|
||||||
T *insert(const T &);
|
|
||||||
void remove(unsigned int);
|
|
||||||
unsigned int size();
|
|
||||||
unsigned int actual_size();
|
|
||||||
|
|
||||||
iterator begin();
|
|
||||||
iterator end();
|
|
||||||
iterator next(iterator &);
|
|
||||||
|
|
||||||
T *at(unsigned int);
|
|
||||||
T *find(const std::string &);
|
|
||||||
};
|
|
||||||
|
|
||||||
- File format:
|
|
||||||
File << db.size() << endl
|
|
||||||
File << INDEX_0 << db[INDEX_0].valid << db[INDEX_0] << endl;
|
|
||||||
File << INDEX_1 << db[INDEX_1].valid << db[INDEX_1] << endl;
|
|
||||||
...
|
|
||||||
|
|
||||||
- API:
|
|
||||||
Database :: Database(std::string filepath, bool autosave);
|
|
||||||
Initialize a database using "filepath" as a location to store
|
|
||||||
data on disk. If the file already exists, read the data into
|
|
||||||
the backing vector.
|
|
||||||
|
|
||||||
Database :: ~Database();
|
|
||||||
Delete all entries remaining in the database.
|
|
||||||
|
|
||||||
void Database :: save();
|
|
||||||
Save the database to disk.
|
|
||||||
|
|
||||||
void Database :: load();
|
|
||||||
Load the database from disk.
|
|
||||||
|
|
||||||
T *Database :: insert(const T &item);
|
|
||||||
Look up the item in the _keys map.
|
|
||||||
If we find an item with the same key:
|
|
||||||
- Return NULL.
|
|
||||||
Otherwise:
|
|
||||||
- Use new to allocate memory for a new item.
|
|
||||||
- Add the new item to the end of the _db.
|
|
||||||
- Add the new item to _keys.
|
|
||||||
- Set new item.id to the index of the new item.
|
|
||||||
_ Increment _size.
|
|
||||||
- If autosave == true: save().
|
|
||||||
- Return a pointer to the new item.
|
|
||||||
|
|
||||||
unsigned int Database :: remove(unsigned int id);
|
|
||||||
- Remove the item from the _keys map.
|
|
||||||
- Delete _db[id]
|
|
||||||
- Set _db[id] = NULL
|
|
||||||
- If autosave == true: save().
|
|
||||||
- Decrement _size.
|
|
||||||
|
|
||||||
unsigned int Database :: size();
|
|
||||||
return _size;
|
|
||||||
|
|
||||||
unsigned int Database :: actual_size();
|
|
||||||
return _db.size();
|
|
||||||
|
|
||||||
iterator Database :: begin();
|
|
||||||
Return _db.end() if there are no valid entries
|
|
||||||
If the first entry is valid:
|
|
||||||
- return _db.begin();
|
|
||||||
Otherwise:
|
|
||||||
- return an iterator to the first valid entry.
|
|
||||||
|
|
||||||
iterator Database :: end();
|
|
||||||
return _db.end();
|
|
||||||
|
|
||||||
iterator Database :: next(iterator &cur);
|
|
||||||
Return the next DatabaseEntry with valid == true or _db.end()
|
|
||||||
if there are no valid entries left.
|
|
||||||
|
|
||||||
T *Database :: at(unsigned int i);
|
|
||||||
If i is beyond the end of the container:
|
|
||||||
Return NULL
|
|
||||||
Otherwise:
|
|
||||||
Return _db[i];
|
|
||||||
|
|
||||||
T *Database :: find(const std::string &key);
|
|
||||||
If key is in the _keys map:
|
|
||||||
Return a pointer to the corresponding entry.
|
|
||||||
Otherwise:
|
|
||||||
Return NULL;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Index:
|
Index:
|
||||||
An index is a special database used to map a std::string key to
|
An index is a special database used to map a std::string key to
|
||||||
multiple integer values.
|
multiple integer values.
|
||||||
|
|
|
@ -61,15 +61,39 @@ public:
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our custom database class.
|
* 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>
|
template <class T>
|
||||||
class Database {
|
class Database {
|
||||||
private:
|
private:
|
||||||
|
/** Databases are backed by a std::vector. */
|
||||||
std::vector<T *> _db;
|
std::vector<T *> _db;
|
||||||
|
|
||||||
|
/** Used for keeping track of primary keys. */
|
||||||
std::map<const std::string, unsigned int> _keys;
|
std::map<const std::string, unsigned int> _keys;
|
||||||
|
|
||||||
|
/** The number of valid DatabaseEntries in the Database. */
|
||||||
unsigned int _size;
|
unsigned int _size;
|
||||||
|
|
||||||
|
/** Set to True if the Database should be saved when changed. */
|
||||||
bool _autosave;
|
bool _autosave;
|
||||||
|
|
||||||
|
/** File object for reading and writing a Database. */
|
||||||
File _file;
|
File _file;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -79,85 +103,113 @@ public:
|
||||||
typedef typename std::vector<T *>::const_iterator const_iterator;
|
typedef typename std::vector<T *>::const_iterator const_iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database constructor.
|
* Initialize a Database using filepath as a location to store data
|
||||||
|
* on disk.
|
||||||
|
*
|
||||||
* @param filepath File on disk that will be written to.
|
* @param filepath File on disk that will be written to.
|
||||||
* @param autosave True if database should be saved on every modification.
|
* @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);
|
Database(std::string, bool);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database destructor.
|
* Deletes all remaining entries in a Database to prevent memory leaks.
|
||||||
*/
|
*/
|
||||||
~Database();
|
~Database();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to write the database to disk.
|
* Called to save the Database to disk.
|
||||||
*/
|
*/
|
||||||
void save();
|
void save();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to save the database after modifications.
|
* Called to save the Database to disk ONLY if Database::_autosave
|
||||||
|
* was set to True.
|
||||||
*/
|
*/
|
||||||
void autosave();
|
void autosave();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to load the database from disk.
|
* Called to read the Database from disk.
|
||||||
*/
|
*/
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new item to the database.
|
* 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.
|
* @param item The new item to be added.
|
||||||
* @return A pointer to the item in the database.
|
* @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 &);
|
T *insert(const T &);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an item from the database.
|
* 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.
|
* @param index The index of the item that should be removed.
|
||||||
*/
|
*/
|
||||||
void remove(unsigned int);
|
void remove(unsigned int);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the size of the database.
|
* Called to find the number of valid items in the Database.
|
||||||
* @return The number of valid items in the database.
|
*
|
||||||
|
* @return Database::_size
|
||||||
*/
|
*/
|
||||||
unsigned int size();
|
unsigned int size();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the actual size of the backing vector.
|
* Called to find the size of the backing std::vector.
|
||||||
* @return The number valid and invalid items in the database.
|
*
|
||||||
|
* @return The size of Database::_db.
|
||||||
*/
|
*/
|
||||||
unsigned int actual_size();
|
unsigned int actual_size();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator pointing to the first entry in the database.
|
* @return An iterator pointing to the first valid entry in the Database.
|
||||||
|
* @return Return Database::end() if there are no valid entries.
|
||||||
*/
|
*/
|
||||||
iterator begin();
|
iterator begin();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator pointing past the end of the database.
|
* @return An iterator pointing past the end of the database.
|
||||||
*/
|
*/
|
||||||
iterator end();
|
iterator end();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator pointing to the next valid item in the database.
|
* @return An iterator pointing to the next valid item in the database.
|
||||||
*/
|
*/
|
||||||
iterator next(iterator &);
|
iterator next(iterator &);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the database item at index n.
|
* Returns the database item at the requested index.
|
||||||
* @param n The database index to access.
|
*
|
||||||
* @return A valid DatabaseItem or NULL.
|
* @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);
|
T *at(unsigned int);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a DatabaseItem with a specific primary key.
|
* Find a DatabaseItem with a specific primary key.
|
||||||
|
*
|
||||||
* @param key The key to search for.
|
* @param key The key to search for.
|
||||||
* @return A valid DatabaseItem or NULL.
|
* @return A pointer to the requested DatabaseEntry.
|
||||||
|
* @return NULL if there is no matching DatabaseEntry.
|
||||||
*/
|
*/
|
||||||
T *find(const std::string &);
|
T *find(const std::string &);
|
||||||
};
|
};
|
||||||
|
|
|
@ -79,14 +79,14 @@ void Database<T> :: load()
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
T *Database<T> :: insert(const T &val)
|
T *Database<T> :: insert(const T &item)
|
||||||
{
|
{
|
||||||
T *t = find(val.primary_key());
|
T *t = find(item.primary_key());
|
||||||
|
|
||||||
if (t != NULL)
|
if (t != NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
t = new T(val);
|
t = new T(item);
|
||||||
t->_index = actual_size();
|
t->_index = actual_size();
|
||||||
_db.push_back(t);
|
_db.push_back(t);
|
||||||
|
|
||||||
|
@ -97,15 +97,15 @@ T *Database<T> :: insert(const T &val)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void Database<T> :: remove(unsigned int id)
|
void Database<T> :: remove(unsigned int index)
|
||||||
{
|
{
|
||||||
if (id >= actual_size())
|
if (index >= actual_size())
|
||||||
return;
|
return;
|
||||||
if (_db[id] == NULL)
|
if (_db[index] == NULL)
|
||||||
return;
|
return;
|
||||||
_keys.erase(_db[id]->primary_key());
|
_keys.erase(_db[index]->primary_key());
|
||||||
delete _db[id];
|
delete _db[index];
|
||||||
_db[id] = NULL;
|
_db[index] = NULL;
|
||||||
_size--;
|
_size--;
|
||||||
autosave();
|
autosave();
|
||||||
}
|
}
|
||||||
|
@ -150,11 +150,11 @@ typename Database<T>::iterator Database<T> :: next(iterator &it)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
T *Database<T> :: at(unsigned int id)
|
T *Database<T> :: at(unsigned int index)
|
||||||
{
|
{
|
||||||
if (id >= actual_size())
|
if (index >= actual_size())
|
||||||
return NULL;
|
return NULL;
|
||||||
return _db[id];
|
return _db[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|
Loading…
Reference in New Issue