core/database: Replace database constructor and destructor

Use db_init() and db_deinit() instead.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2015-09-21 09:02:13 -04:00
parent 3ff992cf52
commit 2c5b14c7f3
15 changed files with 112 additions and 76 deletions

View File

@ -70,8 +70,9 @@ void IndexEntry :: read(file &file)
Index :: Index(const std::string &filepath, bool autosave)
: database(filepath, autosave)
{}
{
db_init(this, filepath.c_str(), autosave);
}
void Index :: insert(const std::string &key, unsigned int value)
{

View File

@ -8,7 +8,7 @@ extern "C" {
#include <glib.h>
static database<Album> album_db("album.db", true);
static database<Album> album_db;
static const std::string make_key(const std::string &name, unsigned int year)
{
@ -65,6 +65,7 @@ unsigned int Album :: year()
void tags :: init_album_db()
{
db_init(&album_db, "album.db", true);
db_load(&album_db);
}

View File

@ -4,7 +4,7 @@
#include <core/tags/artist.h>
static database<Artist> artist_db("artist.db", true);
static database<Artist> artist_db;
Artist :: Artist() : GenericTag() {}
@ -17,6 +17,7 @@ Artist :: Artist(const std::string &name)
void tags :: init_artist_db()
{
db_init(&artist_db, "artist.db", true);
db_load(&artist_db);
}

View File

@ -4,7 +4,7 @@
#include <core/tags/genre.h>
static database<Genre> genre_db("genre.db", true);
static database<Genre> genre_db;
Genre :: Genre() : GenericTag() {}
@ -17,6 +17,7 @@ Genre :: Genre(const std::string &name)
void tags :: init_genre_db()
{
db_init(&genre_db, "genre.db", true);
db_load(&genre_db);
}

View File

@ -4,7 +4,7 @@
#include <core/tags/library.h>
static database<Library> library_db("library.db", true);
static database<Library> library_db;
Library :: Library()
@ -69,6 +69,7 @@ void Library :: dec_size()
void tags :: init_library_db()
{
db_init(&library_db, "library.db", true);
db_load(&library_db);
}

View File

@ -8,7 +8,7 @@
#include <glib.h>
static database<Track> track_db("track.db", false);
static database<Track> track_db;
static const std::string make_key(Library *library, const std::string &path)
{
@ -144,6 +144,7 @@ void Track :: write(file &file)
void tags :: init_track_db()
{
db_init(&track_db, "track.db", false);
db_load(&track_db);
}

View File

@ -85,27 +85,21 @@ struct database {
std::vector<T *> db_entries;
std::map<const std::string, unsigned int> db_keys;
/**
* 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();
};
/*
* 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 <class T>
void db_init(struct database<T> *, const char *, bool);
/* Called to prevent memory leaks by freeing all remaining database entries. */
template <class T>
void db_deinit(struct database<T> *);
/* Called to write the database to disk. */
template <class T>
void db_save(struct database<T> *);

View File

@ -8,18 +8,22 @@
#define OCARINA_DATABASE_HPP
template <class T>
database<T> :: database(std::string filepath, bool autosave)
: db_size(0), db_autosave(autosave)
void db_init(struct database<T> *db, const char *filepath, bool autosave)
{
file_init(&db_file, filepath.c_str(), 0);
db->db_size = 0;
db->db_autosave = autosave;
file_init(&db->db_file, filepath, 0);
}
template <class T>
database<T> :: ~database()
void db_deinit(struct database<T> *db)
{
T *t, *u;
db_for_each(t, u, this)
db_for_each(t, u, db) {
db->db_entries[t->index()] = NULL;
delete t;
db->db_size--;
}
}
template <class T>

View File

@ -62,21 +62,31 @@ static void test_db_entry()
static void test_init()
{
database<struct int_entry> db("database.db", false);
database<struct int_entry> db;
db_init(&db, "init.db", false);
/* Check initial sizes. */
test_equal(db_actual_size(&db), 0);
test_equal(db.db_entries.size(), 0);
test_equal(db.db_keys.size(), 0);
test_equal(db.db_size, 0);
test_equal(db.db_autosave, false);
test_equal(db.db_file.f_version, 0);
test_equal(db.db_file.f_name, "init.db");
db_deinit(&db);
}
static void test_stress(unsigned int N)
{
database<struct int_entry> db("stress.db", false);
database<struct int_entry> db;
std::vector<struct int_entry *> ptrs;
struct int_entry *dbe, *next, rmv(42);
unsigned int i;
gchar *key;
db_init(&db, "stress.db", false);
/* db_insert() */
for (i = 0; i < N; i++) {
dbe = db_insert(&db, new int_entry(i));
@ -157,6 +167,11 @@ static void test_stress(unsigned int N)
i += 2;
} test_loop_passed();
test_equal(i, N + 1);
db_deinit(&db);
test_equal(db.db_size, 0);
test_equal(db_actual_size(&db), N + 1);
test_equal(db_first(&db), NULL);
}
static void test_basics() { test_stress(10); }
@ -165,67 +180,65 @@ static void test_stress_100K() { test_stress(100000); }
static void test_save_load()
{
database<struct int_entry> db1("save_load.db", true);
database<struct int_entry> db2("save_load.db", false);
struct int_entry *dbe;
database<struct int_entry> db1, db2;
struct int_entry *dbe, *next;
const unsigned int N = 10;
unsigned int i;
db_init(&db1, "save_load.db", true);
db_init(&db2, "save_load.db", false);
/* 10 items should "autosave" when inserted */
for (i = 0; i < N; i++)
db_insert(&db1, new int_entry(i));
i = 0;
db_load(&db2);
test_equal(db2.db_size, N);
test_equal(db_actual_size(&db2), N);
for (i = 0; i < N; i++) {
dbe = db_at(&db2, i);
test_loop_not_equal(dbe, NULL, i);
db_for_each(dbe, next, &db2) {
test_loop_equal(dbe->ie_val, i, i);
i++;
} test_loop_passed();
/* Removing 5 items, should also trigger autosaving. */
for (i = 0; i < N; i += 2)
db_remove(&db1, db_at(&db1, i));
db2 = database<struct int_entry>("save_load.db", false);
i = 1;
db_deinit(&db2);
db_load(&db2);
test_equal(db2.db_size, N / 2);
for (i = 1; i < N; i++) {
dbe = db_at(&db2, i);
if ((i % 2) == 0) {
test_loop_equal(dbe, NULL, i);
} else {
test_loop_not_equal(dbe, NULL, i);
test_loop_equal(dbe->ie_val, i, i);
}
db_for_each(dbe, next, &db2) {
test_loop_equal(dbe->ie_val, i, i);
i += 2;
} test_loop_passed();
/* Test with autosave turned off. */
/* Manually turn autosave off. */
db1.db_autosave = false;
for (i = N; i < (2 * N); i++)
db_insert(&db2, new int_entry(i));
db_insert(&db1, new int_entry(i));
for (i = N; i < (2 * N); i += 2)
db_remove(&db2, db_at(&db2, i));
db_remove(&db1, db_at(&db1, i));
db1 = database<struct int_entry>("save_load.db", false);
db_load(&db1);
test_equal(db1.db_size, N / 2);
db_deinit(&db2);
db_load(&db2);
test_equal(db2.db_size, N / 2);
db_save(&db2);
db1 = database<struct int_entry>("save_load.db", false);
db_load(&db1);
db_save(&db1);
db_deinit(&db2);
db_load(&db2);
test_equal(db1.db_size, N);
test_equal(db_actual_size(&db1), 2 * N);
for (i = 1; i < (2 * N); i++) {
dbe = db_at(&db1, i);
if ((i % 2) == 0) {
test_loop_equal(dbe, NULL, i);
} else {
test_loop_not_equal(dbe, NULL, i);
test_loop_equal(dbe->ie_val, i, i);
}
i = 1;
test_equal(db2.db_size, N);
test_equal(db_actual_size(&db2), 2 * N);
db_for_each(dbe, next, &db2) {
test_loop_equal(dbe->ie_val, i, i);
i += 2;
} test_loop_passed();
db_deinit(&db1);
db_deinit(&db2);
}
DECLARE_UNIT_TESTS(

View File

@ -16,7 +16,8 @@ res += [ TagTest("artist", "artist.cpp") ]
res += [ TagTest("album", "album.cpp") ]
res += [ TagTest("genre", "genre.cpp") ]
res += [ TagTest("library", "library.cpp") ]
res += [ TagTest("track", "track.cpp") ]
core_objs += [ env.Object("../../../core/tags/tags.cpp") ]
res += [ TagTest("track", "track.cpp") ]
Return("res")

View File

@ -37,8 +37,11 @@ static void test_album_tag()
static void test_album_tag_lookup()
{
database<Album> album_db("album.db", false);
Album *album = tags :: get_album("Hyrule Symphony", 1998);
database<Album> album_db;
Album *album;
tags :: init_album_db();
album = tags :: get_album("Hyrule Symphony", 1998);
test_equal(album->name(), (std::string)"Hyrule Symphony");
test_equal(album->lowercase(), (std::string)"hyrule symphony");
@ -49,6 +52,7 @@ static void test_album_tag_lookup()
test_equal(tags :: get_album(0), album);
test_equal(tags :: get_album(1), (Album *)NULL);
db_init(&album_db, "album.db", false);
db_load(&album_db);
test_equal(album_db.db_size, (unsigned)1);
}

View File

@ -19,8 +19,11 @@ static void test_artist_tag()
static void test_artist_tag_lookup()
{
database<Artist> artist_db("artist.db", false);
Artist *artist = tags :: get_artist("Koji Kondo");
database<Artist> artist_db;
Artist *artist;
tags :: init_artist_db();
artist = tags :: get_artist("Koji Kondo");
test_equal(artist->name(), (std::string)"Koji Kondo");
test_equal(artist->lowercase(), (std::string)"koji kondo");
@ -30,6 +33,7 @@ static void test_artist_tag_lookup()
test_equal(tags :: get_artist(0), artist);
test_equal(tags :: get_artist(1), (Artist *)NULL);
db_init(&artist_db, "artist.db", false);
db_load(&artist_db);
test_equal(artist_db.db_size, (unsigned)1);
}

View File

@ -19,8 +19,11 @@ static void test_artist_tag()
static void test_genere_tag_lookup()
{
database<Genre> genre_db("genre.db", false);
Genre *genre = tags :: get_genre("Video Game Music");
database<Genre> genre_db;
Genre *genre;
tags :: init_genre_db();
genre = tags :: get_genre("Video Game Music");
test_equal(genre->name(), (std::string)"Video Game Music");
test_equal(genre->lowercase(), (std::string)"video game music");
@ -30,6 +33,7 @@ static void test_genere_tag_lookup()
test_equal(tags :: get_genre(0), genre);
test_equal(tags :: get_genre(1), (Genre *)NULL);
db_init(&genre_db, "genre.db", false);
db_load(&genre_db);
test_equal(genre_db.db_size, (unsigned)1);
}

View File

@ -44,11 +44,12 @@ static void test_library_tag()
static void test_library_tag_lookup()
{
database<Library> library_db("library.db", false);
database<Library> library_db;
Library *library;
test_equal(tags :: library_size(), (unsigned)0);
tags :: init_library_db();
library = tags :: get_library("/home/Zelda/Music");
test_equal(library->primary_key(), (std::string)"/home/Zelda/Music");
test_equal(library->size(), (unsigned)0);
@ -58,6 +59,7 @@ static void test_library_tag_lookup()
test_equal(tags :: get_library(0), library);
test_equal(tags :: get_library(1), (Library *)NULL);
db_init(&library_db, "library.db", false);
db_load(&library_db);
test_equal(db_actual_size(&library_db), (unsigned)tags :: library_size());

View File

@ -5,6 +5,7 @@ extern "C" {
#include <core/string.h>
}
#include <core/filter.h>
#include <core/tags/tags.h>
#include <core/tags/track.h>
#include "../test.h"
@ -62,6 +63,7 @@ static void test_track_tag_constructor()
{
file f;
tags :: init();
album = tags :: get_album("Hyrule Symphony", 1998);
artist = tags :: get_artist("Koji Kondo");
genre = tags :: get_genre("Video Game Music");
@ -107,9 +109,11 @@ static void test_track_tag_destructor()
static void test_track_tag_load_db(unsigned int size)
{
database<Track> track_db("track.db", false);
database<Track> track_db;
db_init(&track_db, "track.db", false);
db_load(&track_db);
test_equal(track_db.db_size, size);
db_deinit(&track_db);
}
static void test_track_tag_lookup()