/** * Copyright 2013 (c) Anna Schumaker. */ #ifndef OCARINA_CORE_DATABASE_H #define OCARINA_CORE_DATABASE_H extern "C" { #include } #include #include #include /** * 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; /** * 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; }; 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 *); /* Set up a struct db_entry after adding to the database. */ void (*dbe_setup)(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 * * * The Database class will add a newline after each DatabaseEntry. */ template 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 db_entries; std::map 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 void db_init(struct database *, const char *, bool, const struct db_ops *); /* Called to prevent memory leaks by freeing all remaining database entries. */ template void db_deinit(struct database *); /* Called to write the database to disk. */ template void db_save(struct database *); /* Save the database to disk iff database->db_autosave is set to True */ template void db_autosave(struct database *); /* Called to read the database from disk. */ template void db_load(struct database *); /* Returns the size of the backing std::vector. */ template unsigned int db_actual_size(const struct database *); /* * 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 T *db_insert(struct database *, T *); /* Called to remove an item from the database. */ template void db_remove(struct database *, T *); /* Returns the database item at the requested index. */ template T *db_at(struct database *, unsigned int); /* Returns the database item with the specified key. */ template T *db_get(struct database *, 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 T *db_find(struct database *, const gchar *); /* Returns the first valid database item. */ template T *db_first(const struct database *); /* Returns the next valid database item. */ template T *db_next(const struct database *, 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 */