/** * Copyright 2013 (c) Anna Schumaker. * * DO NOT INCLUDE THIS FILE DIRECTLY. THIS IS A TEMPLATE DEFINITION FILE * AND ONLY MEANT TO BE INCLUDED BY include/database.h! */ #ifndef OCARINA_DATABASE_HPP #define OCARINA_DATABASE_HPP template static inline void __dbe_free(struct database *db, struct db_entry *dbe) { if (dbe) { db->db_keys.erase(dbe->dbe_key); g_free(dbe->dbe_key); db->db_entries[dbe->dbe_index] = NULL; db->db_ops->dbe_free(dbe); db->db_size--; } } template static inline struct db_entry *__dbe_read(struct database *db, unsigned int index) { struct db_entry *dbe = NULL; int valid; file_readf(&db->db_file, "%d", &valid); if (valid) dbe = db->db_ops->dbe_read(&db->db_file); db->db_entries[index] = (T *)dbe; return dbe; } template static inline void __dbe_setup(struct database *db, unsigned int index) { struct db_entry *dbe = db->db_entries[index]; if (dbe) { dbe->dbe_index = index; dbe->dbe_key = db->db_ops->dbe_key(dbe); db->db_keys[dbe->dbe_key] = index; db->db_size++; if (db->db_ops->dbe_setup) db->db_ops->dbe_setup(dbe); } } template static inline void __dbe_write(struct database *db, struct db_entry *dbe) { if (dbe) { file_writef(&db->db_file, "%u ", true); db->db_ops->dbe_write(&db->db_file, dbe); } else file_writef(&db->db_file, "%u", false); file_writef(&db->db_file, "\n"); } template void db_init(struct database *db, const char *filepath, bool autosave, const struct db_ops *ops) { db->db_ops = ops; db->db_size = 0; db->db_autosave = autosave; file_init(&db->db_file, filepath, 0); } template void db_deinit(struct database *db) { T *dbe, *next; db_for_each(dbe, next, db) __dbe_free(db, dbe); } template void db_save(struct database *db) { if (file_open(&db->db_file, OPEN_WRITE) == false) return; file_writef(&db->db_file, "%u\n", db_actual_size(db)); for (unsigned int i = 0; i < db_actual_size(db); i++) __dbe_write(db, db->db_entries[i]); file_close(&db->db_file); } template void db_autosave(struct database *db) { if (db->db_autosave == true) db_save(db); } template void db_load(struct database *db) { unsigned int size; if (file_open(&db->db_file, OPEN_READ) == false) return; file_readf(&db->db_file, "%u", &size); db->db_entries.resize(size); for (unsigned int i = 0; i < size; i++) { if (__dbe_read(db, i)) __dbe_setup(db, i); } file_close(&db->db_file); } template T *db_insert(struct database *db, T *item) { if (item) { db->db_entries.push_back(item); __dbe_setup(db, db_actual_size(db) - 1); db_autosave(db); } return item; } template void db_remove(struct database *db, T *item) { if (item == NULL) return; if (db_at(db, item->dbe_index) != item) return; __dbe_free(db, item); db_autosave(db); } template unsigned int db_actual_size(const struct database *db) { return db->db_entries.size(); } template T *__db_next(const struct database *db, unsigned int index) { for (; index < db->db_entries.size(); index++) { if (db->db_entries[index]) return db->db_entries[index]; } return NULL; } template T *db_first(const struct database *db) { return __db_next(db, 0); } template T *db_next(const struct database *db, T *ent) { if (ent) return __db_next(db, ent->dbe_index + 1); return NULL; } template T *db_at(struct database *db, unsigned int index) { if (index >= db_actual_size(db)) return NULL; return db->db_entries[index]; } template T *db_get(struct database *db, const gchar *key) { std::map::iterator it; it = db->db_keys.find(key); if (it == db->db_keys.end()) return NULL; return db->db_entries[it->second]; } template T *db_find(struct database *db, const gchar *key) { T *dbe = db_get(db, key); if (dbe) return dbe; dbe = (T *)db->db_ops->dbe_alloc(key); return db_insert(db, dbe); } #endif /* OCARINA_DATABASE_HPP */