core/database: Introduce the dbe_key() database operation

And store the result in the db_entry struct for use later.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2015-09-23 09:33:55 -04:00
parent f51852f62e
commit 1bef380ba7
25 changed files with 116 additions and 123 deletions

View File

@ -5,7 +5,7 @@
db_entry :: db_entry()
: dbe_index(0)
: dbe_index(0), dbe_key(NULL)
{
}

View File

@ -23,9 +23,10 @@ static void index_free(struct db_entry *dbe)
delete (struct index_entry *)dbe;
}
const std::string index_entry :: primary_key() const
static gchar *index_key(struct db_entry *dbe)
{
return ie_key;
struct index_entry *ent = (struct index_entry *)dbe;
return g_strdup(ent->ie_key.c_str());
}
static void index_write(struct file *file, struct db_entry *dbe)
@ -51,6 +52,7 @@ static struct db_entry *index_read(struct file *file)
static const struct db_ops index_ops = {
index_alloc,
index_free,
index_key,
index_read,
NULL,
index_write,

View File

@ -179,7 +179,7 @@ void collection :: update(struct library *library)
};
if (library) {
scan.path = library->primary_key();
scan.path = library->li_path;
idle :: schedule(validate_library, library);
idle :: schedule(scan_path, scan);
}

View File

@ -9,13 +9,9 @@ extern "C" {
static database<album> album_db;
static const std::string __album_key(const std::string &name, unsigned int year)
static gchar *__album_key(const std::string &name, unsigned int year)
{
gchar *g_res = g_strdup_printf("%u %s", year, name.c_str());
std :: string res = g_res;
g_free(g_res);
return res;
return g_strdup_printf("%u %s", year, name.c_str());
}
static struct album *__album_from_key(const gchar *key)
@ -48,9 +44,10 @@ static void album_free(struct db_entry *dbe)
delete (struct album *)dbe;
}
const std::string album :: primary_key() const
static gchar *album_key(struct db_entry *dbe)
{
return __album_key(al_name, al_year);
struct album *album = (struct album *)dbe;
return __album_key(album->al_name, album->al_year);
}
static struct db_entry *album_read(struct file *file)
@ -71,6 +68,7 @@ static void album_write(struct file *file, struct db_entry *dbe)
static const struct db_ops album_ops = {
album_alloc,
album_free,
album_key,
album_read,
NULL,
album_write,
@ -90,7 +88,10 @@ void album_db_deinit()
struct album *album_find(const std::string &name, unsigned int year)
{
return db_find(&album_db, __album_key(name, year).c_str());
gchar *key = __album_key(name, year);
struct album *album = db_find(&album_db, key);
g_free(key);
return album;
}
struct album *album_get(const unsigned int index)

View File

@ -29,9 +29,10 @@ static void artist_free(struct db_entry *dbe)
delete (struct artist *)dbe;
}
const std::string artist :: primary_key() const
static gchar *artist_key(struct db_entry *dbe)
{
return ar_name;
struct artist *artist = (struct artist *)dbe;
return g_strdup(artist->ar_name.c_str());
}
struct db_entry *artist_read(struct file *file)
@ -52,6 +53,7 @@ static void artist_write(struct file *file, struct db_entry *dbe)
static const struct db_ops artist_ops = {
artist_alloc,
artist_free,
artist_key,
artist_read,
NULL,
artist_write,

View File

@ -28,9 +28,10 @@ static void genre_free(struct db_entry *dbe)
delete (struct genre *)dbe;
}
const std::string genre :: primary_key() const
static gchar *genre_key(struct db_entry *dbe)
{
return ge_name;
struct genre *genre = (struct genre *)dbe;
return g_strdup_printf(genre->ge_name.c_str());
}
static struct db_entry *genre_read(struct file *file)
@ -51,6 +52,7 @@ static void genre_write(struct file *file, struct db_entry *dbe)
static const struct db_ops genre_ops = {
genre_alloc,
genre_free,
genre_key,
genre_read,
NULL,
genre_write,

View File

@ -26,9 +26,10 @@ static void library_free(struct db_entry *dbe)
delete (struct library *)dbe;
}
const std::string library :: primary_key() const
static gchar *library_key(struct db_entry *dbe)
{
return li_path;
struct library *library = (struct library *)dbe;
return g_strdup_printf(library->li_path.c_str());
}
static struct db_entry *library_read(struct file *file)
@ -57,6 +58,7 @@ static void library_write(struct file *file, struct db_entry *dbe)
static const struct db_ops library_ops = {
library_alloc,
library_free,
library_key,
library_read,
NULL,
library_write,

View File

@ -13,18 +13,11 @@ extern "C" {
static database<struct track> track_db;
static const std::string __track_key(struct library *library, const std::string &path)
static gchar *__track_key(struct library *library, const std::string &path)
{
std :: string res;
if (library) {
gchar *g_res = g_strdup_printf("%u/%s", library->dbe_index,
path.c_str());
res = g_res;
g_free(g_res);
}
return res;
if (!library)
return g_strdup("");
return g_strdup_printf("%u/%s", library->dbe_index, path.c_str());
}
track :: track()
@ -95,9 +88,10 @@ static void track_setup(struct db_entry *dbe)
track->tr_library->li_size++;
}
const std::string track :: primary_key() const
static gchar *track_key(struct db_entry *dbe)
{
return __track_key(tr_library, tr_path);
struct track *track = (struct track *)dbe;
return __track_key(track->tr_library, track->tr_path);
}
static struct db_entry *track_read(struct file *file)
@ -147,6 +141,7 @@ static void track_write(struct file *file, struct db_entry *dbe)
static const struct db_ops track_ops = {
NULL,
track_free,
track_key,
track_read,
track_setup,
track_write,
@ -176,11 +171,15 @@ const database<struct track> *track_db_get()
struct track *track_add(struct library *library, const std::string &filepath)
{
std::string path = filepath.substr(library->primary_key().size() + 1);
std::string key = __track_key(library, path);
if (db_get(&track_db, key.c_str()))
return NULL;
return db_insert(&track_db, new struct track(key));
std::string path = filepath.substr(library->li_path.size() + 1);
gchar *key = __track_key(library, path);
struct track *track = NULL;
if (!db_get(&track_db, key))
track = db_insert(&track_db, new struct track(key));
g_free(key);
return track;
}
void track_remove(struct track *track)

View File

@ -38,7 +38,7 @@ static void list_path(struct library *lib)
row[c_cols.c_id] = lib->dbe_index;
row[c_cols.c_enabled] = lib->li_enabled;
row[c_cols.c_size] = lib->li_size;
row[c_cols.c_path] = lib->primary_key();
row[c_cols.c_path] = lib->li_path;
}
}
@ -140,8 +140,8 @@ static void on_row_activated(const Gtk::TreePath &path, Gtk::TreeViewColumn *col
static void on_cursor_changed()
{
struct library *lib = current_library();
if (lib && (c_chooser->get_current_folder() != lib->primary_key()))
c_chooser->set_current_folder(lib->primary_key());
if (lib && (c_chooser->get_current_folder() != lib->li_path))
c_chooser->set_current_folder(lib->li_path);
}
static bool on_key_pressed(GdkEventKey *event)

View File

@ -9,7 +9,6 @@ extern "C" {
}
#include <map>
#include <string>
#include <vector>
/**
@ -18,19 +17,10 @@ extern "C" {
*/
struct db_entry {
unsigned int dbe_index; /* The db_entry's position in the database. */
gchar *dbe_key; /* The db_entry's hash key. */
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;
};
@ -41,6 +31,9 @@ struct db_ops {
/* Free a struct db_entry. */
void (*dbe_free)(struct db_entry *);
/* Return a unique string representing a single struct db_entry. */
gchar *(*dbe_key)(struct db_entry *);
/* Read a single struct db_entry from disk. */
struct db_entry *(*dbe_read)(struct file *);

View File

@ -11,10 +11,13 @@ 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_keys.erase(dbe->dbe_key);
g_free(dbe->dbe_key);
db->db_entries[dbe->dbe_index] = NULL;
db->db_size--;
db->db_ops->dbe_free(dbe);
db->db_size--;
}
}
@ -39,7 +42,8 @@ static inline void __dbe_setup(struct database<T> *db, unsigned int index)
if (dbe) {
dbe->dbe_index = index;
db->db_keys[dbe->primary_key()] = 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);

View File

@ -21,13 +21,6 @@ struct index_entry : public db_entry {
struct set ie_set;
index_entry(); /**< Create an empty IndexEntry. */
/**
* Access the key stored by this IndexEntry.
*
* @return IndexEntry::_key.
*/
const std::string primary_key() const;
};

View File

@ -23,15 +23,6 @@ struct album : public db_entry {
std::string al_lower; /* This album's name (lowercased). */
album(); /**< Album tag constructor */
/**
* The album's primary key is the concatenation of year
* and name, allowing for multiple albums with the same
* name but released at different times.
*
* @return Album::_year / GenericTag::primary_key() (Example: "1998/Hyrule Symphony")
*/
const std::string primary_key() const;
};

View File

@ -15,8 +15,6 @@ struct artist : public db_entry {
std::string ar_lower; /* This artist's name (lowercased). */
artist(); /**< Artist tag constructor. */
const std::string primary_key() const;
};

View File

@ -16,8 +16,6 @@ public:
std::string ge_lower; /* This genre's name (lowercased). */
genre(); /**< Genre tag constructor. */
const std::string primary_key() const;
};

View File

@ -23,13 +23,6 @@ struct library : public db_entry {
std::string li_path; /* This library's root path. */
library(); /**< Library tag constructor. */
/**
* Called to access the library tag's primary key.
*
* @return Library::_path.
*/
const std::string primary_key() const;
};

View File

@ -35,15 +35,6 @@ struct track : public db_entry {
track(const std::string &);
track(); /**< Track constructor. */
/**
* A track's primary key is the concatenation of the library index
* and the relative path.
*
* @return Track::_library->index() / Track::_path.
*/
const std::string primary_key() const;
};

View File

@ -67,6 +67,9 @@ void loop_strings_not_equal(gchar *, gchar *, unsigned int, unsigned int);
#define test_not_equal(lhs, rhs) \
test_strings_not_equal(tostring(lhs), tostring(rhs), __LINE__)
#define test_str_equal(lhs, rhs) \
test_strings_equal(lhs, g_strdup(rhs), __LINE__)
#define test_loop_equal(lhs, rhs, i) \
if (1) { \
loop_strings_equal(tostring(lhs), tostring(rhs), i, __LINE__); \
@ -81,6 +84,13 @@ void loop_strings_not_equal(gchar *, gchar *, unsigned int, unsigned int);
break; \
}
#define test_loop_str_equal(lhs, rhs, i) \
if (1) { \
loop_strings_equal(lhs, tostring(rhs), i, __LINE__); \
if (tests_failed > 0) \
break; \
}
#define test_loop_passed() \
if (tests_failed == 0) \
test_equal(tests_failed, 0)

View File

@ -17,14 +17,6 @@ struct int_entry : public db_entry {
int_entry() : ie_val(0) {};
int_entry(unsigned int v) : ie_val(v) {};
const std::string primary_key() const
{
gchar *g_val = g_strdup_printf("%u", ie_val);
std::string res = g_val;
g_free(g_val);
return res;
}
};
static unsigned int test_free_count = 0;
@ -43,6 +35,12 @@ static void int_free(struct db_entry *dbe)
delete (struct int_entry *)dbe;
}
static gchar *int_key(struct db_entry *dbe)
{
struct int_entry *ent = (struct int_entry *)dbe;
return g_strdup_printf("%u", ent->ie_val);
}
static struct db_entry *int_read(struct file *f)
{
struct int_entry *ent = new int_entry;
@ -64,6 +62,7 @@ static void int_write(struct file *file, struct db_entry *dbe)
static const struct db_ops int_ops = {
int_alloc,
int_free,
int_key,
int_read,
int_setup,
int_write,
@ -78,7 +77,7 @@ static void test_db_entry()
ent = (struct int_entry *)int_ops.dbe_alloc("1");
test_equal(ent->dbe_index, 0);
test_equal(ent->ie_val, 1);
test_equal(ent->primary_key(), "1");
test_str_equal(int_ops.dbe_key(ent), "1");
file_init(&f, "test_db_entry", 0);
file_open(&f, OPEN_WRITE);
@ -94,7 +93,7 @@ static void test_db_entry()
int_ops.dbe_setup(ent);
test_equal(ent->ie_val, 1);
test_equal(ent->primary_key(), "1");
test_str_equal(int_ops.dbe_key(ent), "1");
test_equal(test_setup_count, 1);
int_ops.dbe_free(ent);
@ -132,11 +131,14 @@ static void test_stress(unsigned int N)
/* db_insert() */
for (i = 0; i < N; i++) {
key = g_strdup_printf("%u", i);
dbe = db_insert(&db, new int_entry(i));
test_loop_not_equal(dbe, NULL, i);
test_loop_equal(dbe->dbe_index, i, i);
test_loop_equal(dbe->dbe_key, key, i);
test_loop_equal(dbe->ie_val, i, i);
ptrs.push_back(dbe);
g_free(key);
} test_loop_passed();
dbe = db_insert(&db, (struct int_entry *)NULL);
@ -159,7 +161,7 @@ static void test_stress(unsigned int N)
key = g_strdup_printf("%u", i);
dbe = db_get(&db, key);
test_loop_not_equal(dbe, NULL, i);
test_loop_equal(dbe->primary_key(), key, i);
test_loop_str_equal(int_ops.dbe_key(dbe), key, i);
test_loop_equal(dbe, ptrs.at(i), i);
test_loop_equal(dbe->ie_val, i, i);
g_free(key);
@ -173,7 +175,7 @@ static void test_stress(unsigned int N)
key = g_strdup_printf("%u", i);
dbe = db_find(&db, key);
test_loop_not_equal(dbe, NULL, i);
test_loop_equal(dbe->primary_key(), key, i);
test_loop_str_equal(int_ops.dbe_key(dbe), key, i);
test_loop_equal(dbe->ie_val, i, i);
if (i < N)
test_loop_equal(dbe, ptrs.at(i), i);

View File

@ -15,7 +15,7 @@ static void test_entry()
struct file f;
ie = (index_entry *)index_ops->dbe_alloc("Link");
test_equal(ie->primary_key(), "Link");
test_str_equal(index_ops->dbe_key(ie), "Link");
set_insert(&ie->ie_set, 0);
set_insert(&ie->ie_set, 1);
set_insert(&ie->ie_set, 2);
@ -35,12 +35,12 @@ static void test_entry()
file_open(&f, OPEN_READ);
ie = (struct index_entry *)index_ops->dbe_read(&f);
test_equal(ie->primary_key(), "Zelda");
test_str_equal(index_ops->dbe_key(ie), "Zelda");
test_equal(set_size(&ie->ie_set), 0);
index_ops->dbe_free(ie);
ie = (struct index_entry *)index_ops->dbe_read(&f);
test_equal(ie->primary_key(), "Link");
test_str_equal(index_ops->dbe_key(ie), "Link");
test_equal(set_size(&ie->ie_set), 3);
file_close(&f);
@ -55,6 +55,7 @@ static void test_entry()
static void test_stress(unsigned int N)
{
const struct db_ops *index_ops = test_index_ops();
database<index_entry> index;
index_entry *ie, *ie2;
std::string key;
@ -68,7 +69,7 @@ static void test_stress(unsigned int N)
key = c;
ie = index_insert(&index, key.c_str(), 0);
test_loop_not_equal(ie, NULL, c - 'a');
test_loop_equal(ie->primary_key(), key, c - 'a');
test_loop_str_equal(index_ops->dbe_key(ie), key, c - 'a');
for (i = 0; i < N; i++)
ie2 = index_insert(&index, key.c_str(), i);
test_loop_equal(ie, ie2, c - 'a');

View File

@ -6,18 +6,20 @@
static void test_verify_empty(struct album *album)
{
const struct db_ops *album_ops = test_album_ops();
test_equal(album->al_name, "");
test_equal(album->al_lower, "");
test_equal(album->al_year, 0);
test_equal(album->primary_key(), "0 ");
test_str_equal(album_ops->dbe_key(album), "0 ");
}
static void test_verify_hyrule(struct album *album)
{
const struct db_ops *album_ops = test_album_ops();
test_equal(album->al_name, "Hyrule Symphony");
test_equal(album->al_lower, "hyrule symphony");
test_equal(album->al_year, 1998);
test_equal(album->primary_key(), "1998 Hyrule Symphony");
test_str_equal(album_ops->dbe_key(album), "1998 Hyrule Symphony");
}
static void test_album()

View File

@ -6,16 +6,18 @@
static void test_verify_empty(struct artist *artist)
{
const struct db_ops *artist_ops = test_artist_ops();
test_equal(artist->ar_name, "");
test_equal(artist->ar_lower, "");
test_equal(artist->primary_key(), "");
test_str_equal(artist_ops->dbe_key(artist), "");
}
static void test_verify_koji(struct artist *artist)
{
const struct db_ops *artist_ops = test_artist_ops();
test_equal(artist->ar_name, "Koji Kondo");
test_equal(artist->ar_lower, "koji kondo");
test_equal(artist->primary_key(), "Koji Kondo");
test_str_equal(artist_ops->dbe_key(artist), "Koji Kondo");
}
static void test_artist()

View File

@ -6,16 +6,18 @@
static void test_verify_empty(struct genre *genre)
{
const struct db_ops *genre_ops = test_genre_ops();
test_equal(genre->ge_name, "");
test_equal(genre->ge_lower, "");
test_equal(genre->primary_key(), "");
test_str_equal(genre_ops->dbe_key(genre), "");
}
static void test_verify_vg(struct genre *genre)
{
const struct db_ops *genre_ops = test_genre_ops();
test_equal(genre->ge_name, "Video Game Music");
test_equal(genre->ge_lower, "video game music");
test_equal(genre->primary_key(), "Video Game Music");
test_str_equal(genre_ops->dbe_key(genre), "Video Game Music");
}
static void test_genre()

View File

@ -6,16 +6,18 @@
static void test_verify_zelda(struct library *library)
{
test_equal(library->primary_key(), "/home/Zelda/Music");
const struct db_ops *library_ops = test_library_ops();
test_equal(library->li_enabled, true);
test_equal(library->li_size, 0);
test_equal(library->li_size, 0);
test_str_equal(library_ops->dbe_key(library), "/home/Zelda/Music");
}
static void test_verify_link(struct library *library)
{
test_equal(library->primary_key(), "/home/Link/Music");
const struct db_ops *library_ops = test_library_ops();
test_equal(library->li_enabled, false);
test_equal(library->li_size, 0);
test_equal(library->li_size, 0);
test_str_equal(library_ops->dbe_key(library), "/home/Link/Music");
}
static void test_library()

View File

@ -14,16 +14,17 @@ extern "C" {
static void test_verify_empty(struct track *track)
{
const struct db_ops *track_ops = test_track_ops();
test_equal(track->tr_album, (struct album *)NULL);
test_equal(track->tr_artist, (struct artist *)NULL);
test_equal(track->tr_genre, (struct genre *)NULL);
test_equal(track->tr_library, (struct library *)NULL);
test_equal(track->tr_title, "");
test_equal(track->tr_lower, "");
test_equal(track->primary_key(), "");
test_equal(track_path(track), "");
test_equal(track_last_play(track), "Never");
test_equal(track->tr_title, "");
test_equal(track->tr_lower, "");
test_equal(track_path(track), "");
test_str_equal(track_ops->dbe_key(track), "");
test_equal(track_last_play(track), "Never");
test_equal(track->tr_track, 0);
test_equal(track->tr_length, 0);
@ -41,11 +42,12 @@ static void test_verify_tags(struct track *track)
static void test_verify_track(struct track *track)
{
const struct db_ops *track_ops = test_track_ops();
test_verify_tags(track);
test_equal(track->tr_title, "Title Theme");
test_equal(track->tr_lower, "title theme");
test_equal(track->primary_key(),
test_str_equal(track_ops->dbe_key(track),
"0/Hyrule Symphony/01 - Title Theme.ogg");
test_equal(track_path(track),
"tests/Music/Hyrule Symphony/01 - Title Theme.ogg");
@ -58,11 +60,12 @@ static void test_verify_track(struct track *track)
static void test_verify_notrack(struct track *track)
{
const struct db_ops *track_ops = test_track_ops();
test_verify_tags(track);
test_equal(track->tr_title, "");
test_equal(track->tr_lower, "");
test_equal(track->primary_key(),
test_str_equal(track_ops->dbe_key(track),
"0/Hyrule Symphony/00 - No Track.ogg");
test_equal(track_path(track),
"tests/Music/Hyrule Symphony/00 - No Track.ogg");