diff --git a/core/index.cpp b/core/index.cpp index 9bfee7d1..87b012b2 100644 --- a/core/index.cpp +++ b/core/index.cpp @@ -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) { diff --git a/core/tags/album.cpp b/core/tags/album.cpp index 82717ecf..e85020fa 100644 --- a/core/tags/album.cpp +++ b/core/tags/album.cpp @@ -8,7 +8,7 @@ extern "C" { #include -static database album_db("album.db", true); +static database 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); } diff --git a/core/tags/artist.cpp b/core/tags/artist.cpp index b9add54d..09bf0dd6 100644 --- a/core/tags/artist.cpp +++ b/core/tags/artist.cpp @@ -4,7 +4,7 @@ #include -static database artist_db("artist.db", true); +static database 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); } diff --git a/core/tags/genre.cpp b/core/tags/genre.cpp index 7dd6f0d9..94a5beb6 100644 --- a/core/tags/genre.cpp +++ b/core/tags/genre.cpp @@ -4,7 +4,7 @@ #include -static database genre_db("genre.db", true); +static database 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); } diff --git a/core/tags/library.cpp b/core/tags/library.cpp index 67867c78..dda472c5 100644 --- a/core/tags/library.cpp +++ b/core/tags/library.cpp @@ -4,7 +4,7 @@ #include -static database library_db("library.db", true); +static database 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); } diff --git a/core/tags/track.cpp b/core/tags/track.cpp index 3dd37f24..629a63f7 100644 --- a/core/tags/track.cpp +++ b/core/tags/track.cpp @@ -8,7 +8,7 @@ #include -static database track_db("track.db", false); +static database 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); } diff --git a/include/core/database.h b/include/core/database.h index 5e207570..3870fbb9 100644 --- a/include/core/database.h +++ b/include/core/database.h @@ -85,27 +85,21 @@ struct database { std::vector db_entries; std::map 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 +void db_init(struct database *, const char *, bool); + +/* 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 *); diff --git a/include/core/database.hpp b/include/core/database.hpp index b6c0323e..876df7eb 100644 --- a/include/core/database.hpp +++ b/include/core/database.hpp @@ -8,18 +8,22 @@ #define OCARINA_DATABASE_HPP template -database :: database(std::string filepath, bool autosave) - : db_size(0), db_autosave(autosave) +void db_init(struct database *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 -database :: ~database() +void db_deinit(struct database *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 diff --git a/tests/core/database.cpp b/tests/core/database.cpp index e125f318..e593b57b 100644 --- a/tests/core/database.cpp +++ b/tests/core/database.cpp @@ -62,21 +62,31 @@ static void test_db_entry() static void test_init() { - database db("database.db", false); + database 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 db("stress.db", false); + database db; std::vector 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 db1("save_load.db", true); - database db2("save_load.db", false); - struct int_entry *dbe; + database 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("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("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("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( diff --git a/tests/core/tags/Sconscript b/tests/core/tags/Sconscript index 9d002032..5bbdd63d 100644 --- a/tests/core/tags/Sconscript +++ b/tests/core/tags/Sconscript @@ -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") diff --git a/tests/core/tags/album.cpp b/tests/core/tags/album.cpp index 01181f84..c1e47ef4 100644 --- a/tests/core/tags/album.cpp +++ b/tests/core/tags/album.cpp @@ -37,8 +37,11 @@ static void test_album_tag() static void test_album_tag_lookup() { - database album_db("album.db", false); - Album *album = tags :: get_album("Hyrule Symphony", 1998); + database 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); } diff --git a/tests/core/tags/artist.cpp b/tests/core/tags/artist.cpp index cc72f05c..a9f42fe3 100644 --- a/tests/core/tags/artist.cpp +++ b/tests/core/tags/artist.cpp @@ -19,8 +19,11 @@ static void test_artist_tag() static void test_artist_tag_lookup() { - database artist_db("artist.db", false); - Artist *artist = tags :: get_artist("Koji Kondo"); + database 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); } diff --git a/tests/core/tags/genre.cpp b/tests/core/tags/genre.cpp index 8321f5db..c8707af1 100644 --- a/tests/core/tags/genre.cpp +++ b/tests/core/tags/genre.cpp @@ -19,8 +19,11 @@ static void test_artist_tag() static void test_genere_tag_lookup() { - database genre_db("genre.db", false); - Genre *genre = tags :: get_genre("Video Game Music"); + database 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); } diff --git a/tests/core/tags/library.cpp b/tests/core/tags/library.cpp index 745165de..ddabdeab 100644 --- a/tests/core/tags/library.cpp +++ b/tests/core/tags/library.cpp @@ -44,11 +44,12 @@ static void test_library_tag() static void test_library_tag_lookup() { - database library_db("library.db", false); + database 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()); diff --git a/tests/core/tags/track.cpp b/tests/core/tags/track.cpp index f6e5c8a2..165db865 100644 --- a/tests/core/tags/track.cpp +++ b/tests/core/tags/track.cpp @@ -5,6 +5,7 @@ extern "C" { #include } #include +#include #include #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_db("track.db", false); + database 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()