core/database: Introduce the dbe_free() database operation
The Track tag needs to do some cleanup when removed from a database, so we need to use this op when removing items. Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
parent
049156a523
commit
c8021639ba
|
@ -9,11 +9,6 @@ index_entry :: index_entry()
|
|||
ie_set = SET_INIT();
|
||||
}
|
||||
|
||||
index_entry :: ~index_entry()
|
||||
{
|
||||
set_deinit(&ie_set);
|
||||
}
|
||||
|
||||
static struct db_entry *index_alloc(const gchar *key)
|
||||
{
|
||||
struct index_entry *ent = new struct index_entry;
|
||||
|
@ -21,6 +16,13 @@ static struct db_entry *index_alloc(const gchar *key)
|
|||
return ent;
|
||||
}
|
||||
|
||||
static void index_free(struct db_entry *dbe)
|
||||
{
|
||||
struct index_entry *ent = (struct index_entry *)dbe;
|
||||
set_deinit(&ent->ie_set);
|
||||
delete (struct index_entry *)dbe;
|
||||
}
|
||||
|
||||
const std::string index_entry :: primary_key() const
|
||||
{
|
||||
return ie_key;
|
||||
|
@ -45,6 +47,7 @@ void index_entry :: read(file &file)
|
|||
|
||||
static const struct db_ops index_ops = {
|
||||
index_alloc,
|
||||
index_free,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -43,6 +43,11 @@ static struct db_entry *album_alloc(const gchar *key)
|
|||
return album;
|
||||
}
|
||||
|
||||
static void album_free(struct db_entry *dbe)
|
||||
{
|
||||
delete (struct album *)dbe;
|
||||
}
|
||||
|
||||
const std::string album :: primary_key() const
|
||||
{
|
||||
return __album_key(al_name, al_year);
|
||||
|
@ -63,6 +68,7 @@ void album :: write(file &file)
|
|||
|
||||
static const struct db_ops album_ops = {
|
||||
album_alloc,
|
||||
album_free,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,11 @@ static db_entry *artist_alloc(const gchar *name)
|
|||
return artist;
|
||||
}
|
||||
|
||||
static void artist_free(struct db_entry *dbe)
|
||||
{
|
||||
delete (struct artist *)dbe;
|
||||
}
|
||||
|
||||
const std::string artist :: primary_key() const
|
||||
{
|
||||
return ar_name;
|
||||
|
@ -49,6 +54,7 @@ void artist :: write(file &file)
|
|||
|
||||
static const struct db_ops artist_ops = {
|
||||
artist_alloc,
|
||||
artist_free,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,11 @@ static struct db_entry *genre_alloc(const gchar *name)
|
|||
return genre;
|
||||
}
|
||||
|
||||
static void genre_free(struct db_entry *dbe)
|
||||
{
|
||||
delete (struct genre *)dbe;
|
||||
}
|
||||
|
||||
const std::string genre :: primary_key() const
|
||||
{
|
||||
return ge_name;
|
||||
|
@ -48,6 +53,7 @@ void genre :: write(file &file)
|
|||
|
||||
static const struct db_ops genre_ops = {
|
||||
genre_alloc,
|
||||
genre_free,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,11 @@ static struct db_entry *library_alloc(const gchar *path)
|
|||
return library;
|
||||
}
|
||||
|
||||
static void library_free(struct db_entry *dbe)
|
||||
{
|
||||
delete (struct library *)dbe;
|
||||
}
|
||||
|
||||
const std::string library :: primary_key() const
|
||||
{
|
||||
return li_path;
|
||||
|
@ -47,6 +52,7 @@ void library :: write(file &file)
|
|||
|
||||
static const struct db_ops library_ops = {
|
||||
library_alloc,
|
||||
library_free,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -82,10 +82,13 @@ out:
|
|||
g_free(path);
|
||||
}
|
||||
|
||||
track :: ~track()
|
||||
static void track_free(struct db_entry *dbe)
|
||||
{
|
||||
if (tr_library)
|
||||
tr_library->li_size--;
|
||||
struct track *track = (struct track *)dbe;
|
||||
|
||||
if (track->tr_library)
|
||||
track->tr_library->li_size--;
|
||||
delete track;
|
||||
}
|
||||
|
||||
const std::string track :: primary_key() const
|
||||
|
@ -136,6 +139,8 @@ void track :: write(file &file)
|
|||
|
||||
|
||||
static const struct db_ops track_ops = {
|
||||
NULL,
|
||||
track_free,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,9 @@ struct db_entry {
|
|||
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 *);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,18 @@
|
|||
#ifndef OCARINA_DATABASE_HPP
|
||||
#define OCARINA_DATABASE_HPP
|
||||
|
||||
|
||||
template <class T>
|
||||
static inline void __dbe_free(struct database<T> *db, struct db_entry *dbe)
|
||||
{
|
||||
if (dbe) {
|
||||
db->db_keys.erase(dbe->primary_key());
|
||||
db->db_entries[dbe->dbe_index] = NULL;
|
||||
db->db_size--;
|
||||
db->db_ops->dbe_free(dbe);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void db_init(struct database<T> *db, const char *filepath, bool autosave,
|
||||
const struct db_ops *ops)
|
||||
|
@ -20,12 +32,9 @@ void db_init(struct database<T> *db, const char *filepath, bool autosave,
|
|||
template <class T>
|
||||
void db_deinit(struct database<T> *db)
|
||||
{
|
||||
T *t, *u;
|
||||
db_for_each(t, u, db) {
|
||||
db->db_entries[t->dbe_index] = NULL;
|
||||
delete t;
|
||||
db->db_size--;
|
||||
}
|
||||
T *dbe, *next;
|
||||
db_for_each(dbe, next, db)
|
||||
__dbe_free(db, dbe);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
@ -106,10 +115,7 @@ void db_remove(struct database<T> *db, T *item)
|
|||
return;
|
||||
if (db_at(db, item->dbe_index) != item)
|
||||
return;
|
||||
db->db_entries[item->dbe_index] = NULL;
|
||||
db->db_keys.erase(item->primary_key());
|
||||
delete item;
|
||||
db->db_size--;
|
||||
__dbe_free(db, item);
|
||||
db_autosave(db);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ struct index_entry : public db_entry {
|
|||
struct set ie_set;
|
||||
|
||||
index_entry(); /**< Create an empty IndexEntry. */
|
||||
~index_entry();
|
||||
|
||||
/**
|
||||
* Access the key stored by this IndexEntry.
|
||||
|
|
|
@ -35,7 +35,6 @@ struct track : public db_entry {
|
|||
|
||||
track(const std::string &);
|
||||
track(); /**< Track constructor. */
|
||||
~track(); /**< Track destructor. */
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,8 @@ struct int_entry : public db_entry {
|
|||
void read(file &f) { file_readf(&f, "%u", &ie_val); }
|
||||
};
|
||||
|
||||
unsigned int test_free_count = 0;
|
||||
|
||||
static struct db_entry *int_alloc(const gchar *key)
|
||||
{
|
||||
struct int_entry *ent = new int_entry;
|
||||
|
@ -37,9 +39,15 @@ static struct db_entry *int_alloc(const gchar *key)
|
|||
return ent;
|
||||
}
|
||||
|
||||
static void int_free(struct db_entry *dbe)
|
||||
{
|
||||
test_free_count++;
|
||||
delete (struct int_entry *)dbe;
|
||||
}
|
||||
|
||||
static const struct db_ops int_ops = {
|
||||
int_alloc,
|
||||
int_free,
|
||||
};
|
||||
|
||||
|
||||
|
@ -57,7 +65,9 @@ static void test_db_entry()
|
|||
file_open(&f, OPEN_WRITE);
|
||||
ent->write(f);
|
||||
file_close(&f);
|
||||
delete ent;
|
||||
|
||||
int_ops.dbe_free(ent);
|
||||
test_equal(test_free_count, 1);
|
||||
|
||||
ent = new int_entry();
|
||||
test_equal(ent->ie_val, 0);
|
||||
|
@ -69,7 +79,8 @@ static void test_db_entry()
|
|||
|
||||
test_equal(ent->ie_val, 1);
|
||||
test_equal(ent->primary_key(), "1");
|
||||
delete ent;
|
||||
int_ops.dbe_free(ent);
|
||||
test_equal(test_free_count, 2);
|
||||
}
|
||||
|
||||
static void test_init()
|
||||
|
@ -97,6 +108,7 @@ static void test_stress(unsigned int N)
|
|||
unsigned int i;
|
||||
gchar *key;
|
||||
|
||||
test_free_count = 0;
|
||||
db_init(&db, "stress.db", false, &int_ops);
|
||||
|
||||
/* db_insert() */
|
||||
|
@ -162,6 +174,7 @@ static void test_stress(unsigned int N)
|
|||
db_remove(&db, &rmv);
|
||||
test_equal(db.db_size, N / 2);
|
||||
test_equal(db_actual_size(&db), N + 1);
|
||||
test_equal(test_free_count, (N / 2) + 1);
|
||||
|
||||
/* db_for_each() (db_first() / db_next()) */
|
||||
i = 1;
|
||||
|
@ -184,6 +197,7 @@ static void test_stress(unsigned int N)
|
|||
test_equal(db.db_size, 0);
|
||||
test_equal(db_actual_size(&db), N + 1);
|
||||
test_equal(db_first(&db), NULL);
|
||||
test_equal(test_free_count, N + 1);
|
||||
}
|
||||
|
||||
static void test_basics() { test_stress(10); }
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
|
||||
static void test_entry()
|
||||
{
|
||||
const struct db_ops *index_ops = test_index_ops();
|
||||
struct set_iter it;
|
||||
index_entry *ie;
|
||||
unsigned int i;
|
||||
struct file f;
|
||||
|
||||
ie = (index_entry *)test_index_ops()->dbe_alloc("Link");
|
||||
ie = (index_entry *)index_ops->dbe_alloc("Link");
|
||||
test_equal(ie->primary_key(), "Link");
|
||||
set_insert(&ie->ie_set, 0);
|
||||
set_insert(&ie->ie_set, 1);
|
||||
|
@ -30,7 +31,7 @@ static void test_entry()
|
|||
file_writef(&f, "Zelda\n0 \n");
|
||||
ie->write(f);
|
||||
file_close(&f);
|
||||
delete ie;
|
||||
index_ops->dbe_free(ie);
|
||||
|
||||
ie = new index_entry();
|
||||
test_equal(ie->primary_key(), "");
|
||||
|
@ -52,7 +53,7 @@ static void test_entry()
|
|||
i++;
|
||||
} test_loop_passed();
|
||||
|
||||
delete ie;
|
||||
index_ops->dbe_free(ie);
|
||||
}
|
||||
|
||||
static void test_stress(unsigned int N)
|
||||
|
|
|
@ -34,7 +34,7 @@ static void test_album()
|
|||
file_writef(&f, "0 \n");
|
||||
album->write(f);
|
||||
file_close(&f);
|
||||
delete album;
|
||||
album_ops->dbe_free(album);
|
||||
|
||||
album = new struct album();
|
||||
test_verify_empty(album);
|
||||
|
@ -46,7 +46,7 @@ static void test_album()
|
|||
album->read(f);
|
||||
file_close(&f);
|
||||
test_verify_hyrule(album);
|
||||
delete album;
|
||||
album_ops->dbe_free(album);
|
||||
}
|
||||
|
||||
static void test_album_compare()
|
||||
|
@ -61,8 +61,8 @@ static void test_album_compare()
|
|||
test_equal(album_compare(twilight, skyward), 1);
|
||||
test_equal(album_compare(skyward, twilight), -1);
|
||||
|
||||
delete skyward;
|
||||
delete twilight;
|
||||
album_ops->dbe_free(twilight);
|
||||
album_ops->dbe_free(skyward);
|
||||
}
|
||||
|
||||
static void test_album_db()
|
||||
|
|
|
@ -33,7 +33,7 @@ static void test_artist()
|
|||
file_writef(&f, "1 \n1 ");
|
||||
artist->write(f);
|
||||
file_close(&f);
|
||||
delete artist;
|
||||
artist_ops->dbe_free(artist);
|
||||
|
||||
artist = new struct artist();
|
||||
test_verify_empty(artist);
|
||||
|
@ -47,7 +47,7 @@ static void test_artist()
|
|||
artist->read(f);
|
||||
file_close(&f);
|
||||
test_verify_koji(artist);
|
||||
delete artist;
|
||||
artist_ops->dbe_free(artist);
|
||||
}
|
||||
|
||||
static void test_artist_compare()
|
||||
|
@ -62,8 +62,8 @@ static void test_artist_compare()
|
|||
test_equal(artist_compare(koji, hajime), 1);
|
||||
test_equal(artist_compare(hajime, koji), -1);
|
||||
|
||||
delete hajime;
|
||||
delete koji;
|
||||
artist_ops->dbe_free(koji);
|
||||
artist_ops->dbe_free(hajime);
|
||||
}
|
||||
|
||||
static void test_artist_db()
|
||||
|
|
|
@ -33,7 +33,7 @@ static void test_genre()
|
|||
file_writef(&f, "1 \n1 ");
|
||||
genre->write(f);
|
||||
file_close(&f);
|
||||
delete genre;
|
||||
genre_ops->dbe_free(genre);
|
||||
|
||||
genre = new struct genre();
|
||||
test_verify_empty(genre);
|
||||
|
@ -47,7 +47,7 @@ static void test_genre()
|
|||
genre->read(f);
|
||||
file_close(&f);
|
||||
test_verify_vg(genre);
|
||||
delete genre;
|
||||
genre_ops->dbe_free(genre);
|
||||
}
|
||||
|
||||
static void test_genre_compare()
|
||||
|
@ -62,8 +62,8 @@ static void test_genre_compare()
|
|||
test_equal(genre_compare(video, game), 1);
|
||||
test_equal(genre_compare(game, video), -1);
|
||||
|
||||
delete game;
|
||||
delete video;
|
||||
genre_ops->dbe_free(video);
|
||||
genre_ops->dbe_free(game);
|
||||
}
|
||||
|
||||
static void test_genere_db()
|
||||
|
|
|
@ -59,9 +59,9 @@ static void test_library()
|
|||
test_verify_zelda(library);
|
||||
test_equal(library_file(library, "impa.ogg"), "/home/Zelda/Music/impa.ogg");
|
||||
|
||||
delete library;
|
||||
delete zelda;
|
||||
delete link;
|
||||
library_ops->dbe_free(link);
|
||||
library_ops->dbe_free(zelda);
|
||||
library_ops->dbe_free(library);
|
||||
}
|
||||
|
||||
static void test_library_db()
|
||||
|
|
|
@ -75,6 +75,7 @@ static void test_verify_notrack(struct track *track)
|
|||
|
||||
static void test_track()
|
||||
{
|
||||
const struct db_ops *track_ops = test_track_ops();
|
||||
time_t rawtime = time(NULL);
|
||||
struct tm *now = localtime(&rawtime);
|
||||
struct track *track = new struct track;;
|
||||
|
@ -83,7 +84,7 @@ static void test_track()
|
|||
file f;
|
||||
|
||||
test_verify_empty(track);
|
||||
delete track;
|
||||
track_ops->dbe_free(track);
|
||||
|
||||
std::setlocale(LC_TIME, "C");
|
||||
filter_init();
|
||||
|
@ -102,7 +103,7 @@ static void test_track()
|
|||
track->write(f);
|
||||
file_close(&f);
|
||||
|
||||
delete track;
|
||||
track_ops->dbe_free(track);
|
||||
test_equal(library->li_size, 0);
|
||||
|
||||
track = new struct track;
|
||||
|
@ -110,7 +111,7 @@ static void test_track()
|
|||
track->read(f);
|
||||
test_verify_notrack(track);
|
||||
test_equal(library->li_size, 1);
|
||||
delete track;
|
||||
track_ops->dbe_free(track);
|
||||
|
||||
track = new struct track;
|
||||
track->read(f);
|
||||
|
@ -122,7 +123,7 @@ static void test_track()
|
|||
test_equal(track->tr_count, 1);
|
||||
test_equal(track_last_play(track), date);
|
||||
|
||||
delete track;
|
||||
track_ops->dbe_free(track);
|
||||
g_free(date);
|
||||
}
|
||||
|
||||
|
@ -148,6 +149,7 @@ static void test_track_filter()
|
|||
|
||||
static void test_track_compare()
|
||||
{
|
||||
const struct db_ops *track_ops = test_track_ops();
|
||||
struct track *title = new struct track("0/Hyrule Symphony/01 - Title Theme.ogg");
|
||||
struct track *kokiri = new struct track("0/Hyrule Symphony/02 - Kokiri Forest.ogg");
|
||||
|
||||
|
@ -155,8 +157,8 @@ static void test_track_compare()
|
|||
test_equal(track_compare(kokiri, title), -1);
|
||||
test_equal(track_compare(title, kokiri), 1);
|
||||
|
||||
delete title;
|
||||
delete kokiri;
|
||||
track_ops->dbe_free(title);
|
||||
track_ops->dbe_free(kokiri);
|
||||
}
|
||||
|
||||
static void test_track_db()
|
||||
|
|
Loading…
Reference in New Issue