core/database: Move db_find() out of the database struct

I also take the chance to modify this function slightly.  Now, if a
matching item could not be found a new item will be allocated.

I added the new function db_get() if callers just want to get an item
without allocating.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2015-10-20 10:10:26 -04:00
parent f2f23cb225
commit ffd38bd28b
14 changed files with 83 additions and 59 deletions

View File

@ -54,7 +54,7 @@ void filter :: search(const std::string &text, std::set<unsigned int> &res)
if (end == std::string::npos)
end = lc.size();
found = filter_index.find(lc.substr(begin, end - begin));
found = db_get(&filter_index, lc.substr(begin, end- begin).c_str());
if (!found) {
res.clear();
return;

View File

@ -75,21 +75,16 @@ Index :: Index(const std::string &filepath, bool autosave)
void Index :: insert(const std::string &key, unsigned int value)
{
IndexEntry *it = find(key);
if (it == NULL)
it = db_insert(this, new IndexEntry(key));
IndexEntry *it = db_find(this, key.c_str());
it->insert(value);
::db_autosave(this);
}
void Index :: remove(const std::string &key, unsigned int value)
{
IndexEntry *it = find(key);
if (it == NULL)
return;
it->remove(value);
::db_autosave(this);
IndexEntry *it = db_get(this, key.c_str());
if (it) {
it->remove(value);
::db_autosave(this);
}
}

View File

@ -100,7 +100,7 @@ void playlist :: init()
bool playlist :: has(Track *track, const std::string &name)
{
std::set<unsigned int>::iterator it;
IndexEntry *ent = playlist_db.find(name);
IndexEntry *ent = db_get(&playlist_db, name.c_str());
if (ent == NULL)
return false;
@ -132,7 +132,7 @@ void playlist :: del(Track *track, const std::string &name)
void playlist :: select(const std::string &name)
{
IndexEntry *ent = playlist_db.find(name);
IndexEntry *ent = db_get(&playlist_db, name.c_str());
if (ent != NULL)
playlist_q.fill(ent);
@ -144,7 +144,7 @@ void playlist :: select(const std::string &name)
IndexEntry *playlist :: get_tracks(const std::string &name)
{
return playlist_db.find(name);
return db_get(&playlist_db, name.c_str());
}
Queue *playlist :: get_queue()

View File

@ -1,7 +1,9 @@
/**
* Copyright 2014 (c) Anna Schumaker.
*/
extern "C" {
#include <core/string.h>
}
#include <core/tags/album.h>
#include <glib.h>
@ -25,6 +27,19 @@ Album :: Album(const std::string &name, unsigned int year)
{
}
Album :: Album(const std::string &key)
{
gchar *name, *lower;
sscanf(key.c_str(), "%u/%m[^\n]", &_year, &name);
lower = string_lowercase(name);
_name = name;
_lower = lower;
g_free(name);
g_free(lower);
}
const std::string Album :: primary_key() const
{
return make_key(GenericTag :: primary_key(), _year);
@ -55,10 +70,7 @@ void tags :: init_album_db()
Album *tags :: get_album(const std::string &name, unsigned int year)
{
Album *ret = album_db.find(make_key(name, year));
if (ret)
return ret;
return db_insert(&album_db, new Album(name, year));
return db_find(&album_db, make_key(name, year).c_str());
}
Album *tags ::get_album(const unsigned int index)

View File

@ -22,10 +22,7 @@ void tags :: init_artist_db()
Artist *tags :: get_artist(const std::string &name)
{
Artist *ret = artist_db.find(name);
if (ret)
return ret;
return db_insert(&artist_db, new Artist(name));
return db_find(&artist_db, name.c_str());
}
Artist *tags :: get_artist(const unsigned int index)

View File

@ -22,10 +22,7 @@ void tags :: init_genre_db()
Genre *tags :: get_genre(const std::string &name)
{
Genre *ret = genre_db.find(name);
if (ret)
return ret;
return db_insert(&genre_db, new Genre(name));
return db_find(&genre_db, name.c_str());
}
Genre *tags :: get_genre(const unsigned int index)

View File

@ -74,10 +74,7 @@ void tags :: init_library_db()
Library *tags :: get_library(const std::string &path)
{
Library *ret = library_db.find(path);
if (ret)
return ret;
return db_insert(&library_db, new Library(path));
return db_find(&library_db, path.c_str());
}
Library *tags :: get_library(const unsigned int index)

View File

@ -153,8 +153,7 @@ Track *tags :: add_track(Album *album, Artist *artist, Genre *genre,
unsigned int track)
{
std::string path = filepath.substr(library->primary_key().size() + 1);
Track *ret = track_db.find(make_key(library, path));
if (ret)
if (db_get(&track_db, make_key(library, path).c_str()))
return NULL;
return db_insert(&track_db, new Track(album, artist, genre, library,
path, name, length, track));

View File

@ -21,6 +21,7 @@ public:
unsigned int _index; /**< The location of an item in the Database. */
DatabaseEntry(); /**< Initialize _index to 0. */
DatabaseEntry(const std::string);
virtual ~DatabaseEntry() = 0; /**< Virtual destructor */
/**
@ -123,15 +124,6 @@ struct database {
* @return An iterator pointing to the next valid item in the database.
*/
iterator next(iterator &);
/**
* Find a DatabaseItem with a specific primary key.
*
* @param key The key to search for.
* @return A pointer to the requested DatabaseEntry.
* @return NULL if there is no matching DatabaseEntry.
*/
T *find(const std::string &);
};
@ -168,6 +160,17 @@ void db_remove(struct database<T> *, T *);
template <class T>
T *db_at(struct database<T> *, unsigned int);
/* Returns the database item with the specified key. */
template <class T>
T *db_get(struct database<T> *, const gchar *);
/*
* Similar to db_get(), but allocate and return a new item if the
* database doesn't contain an item with the specified key.
*/
template <class T>
T *db_find(struct database<T> *, const gchar *);
#include "database.hpp"
#endif /* OCARINA_CORE_DATABASE_H */

View File

@ -149,12 +149,21 @@ T *db_at(struct database<T> *db, unsigned int index)
}
template <class T>
T *database<T> :: find(const std::string &key)
T *db_get(struct database<T> *db, const gchar *key)
{
std::map<const std::string, unsigned int>::iterator it;
it = db_keys.find(key);
if (it == db_keys.end())
it = db->db_keys.find(key);
if (it == db->db_keys.end())
return NULL;
return db_entries[it->second];
return db->db_entries[it->second];
}
template <class T>
T *db_find(struct database<T> *db, const gchar *key)
{
T *dbe = db_get(db, key);
if (dbe)
return dbe;
return db_insert(db, new T(key));
}
#endif /* OCARINA_DATABASE_HPP */

View File

@ -31,6 +31,7 @@ public:
* @param year Album year
*/
Album(const std::string &, unsigned int);
Album(const std::string &);
/**
* The album's primary key is the concatenation of year

View File

@ -20,11 +20,10 @@
*/
class GenericTag : public DatabaseEntry {
private:
public:
std::string _name; /**< The name associated with this tag. */
std::string _lower; /**< The lowercase form of GenericTag::_name. */
public:
GenericTag(); /**< GenericTag constructor. */
/**

View File

@ -17,6 +17,7 @@ struct int_entry : public DatabaseEntry {
int_entry() : ie_val(0) {};
int_entry(unsigned int v) : ie_val(v) {};
int_entry(const std::string &k) { sscanf(k.c_str(), "%u", &ie_val); }
const std::string primary_key() const
{
@ -100,10 +101,10 @@ static void test_stress(unsigned int N)
} test_loop_passed();
test_equal(db_at(&db, N), NULL);
/* database.find() */
/* db_get() */
for (i = 0; i < N; i++) {
key = g_strdup_printf("%u", i);
dbe = db.find(key);
dbe = db_get(&db, key);
test_loop_not_equal(dbe, NULL, i);
test_loop_equal(dbe->primary_key(), key, i);
test_loop_equal(dbe, ptrs.at(i), i);
@ -111,21 +112,35 @@ static void test_stress(unsigned int N)
g_free(key);
} test_loop_passed();
key = g_strdup_printf("%u", N);
test_equal(db.find(key), NULL);
test_equal(db_get(&db, key), NULL);
g_free(key);
/* db_find() */
for (i = 0; i <= N; i++) {
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_equal(dbe->ie_val, i, i);
if (i < N)
test_loop_equal(dbe, ptrs.at(i), i);
g_free(key);
} test_loop_passed();
test_equal(db.db_size, N + 1);
test_equal(db_actual_size(&db), N + 1);
/* db_remove(): Even indices only! */
for (i = 0; i <= (N + 2); i += 2) {
key = g_strdup_printf("%u", i);
dbe = db.find(key);
dbe = db_get(&db, key);
db_remove(&db, dbe);
test_loop_equal(db_at(&db, i), NULL, i);
test_loop_equal(db.find(key), NULL, i);
test_loop_equal(db_get(&db, key), NULL, i);
g_free(key);
} test_loop_passed();
db_remove(&db, &rmv);
test_equal(db.db_size, N / 2);
test_equal(db_actual_size(&db), N);
test_equal(db_actual_size(&db), N + 1);
/* database.first(), database.next(), database.end() */
i = 1;

View File

@ -16,7 +16,7 @@ static void test_single_item()
Index index("index.idx", false);
index.insert("a", 0);
IndexEntry *it = index.find("a");
IndexEntry *it = db_get(&index, "a");
test_not_equal(it, (IndexEntry *)NULL);
test_equal(index.db_size, (unsigned)1);
@ -42,7 +42,7 @@ static void test_insertion(unsigned int n)
test_equal(INDEX->db_size, (n == 0) ? 0 : 26);
for (char c = 'a'; c <= 'z'; c++) {
IndexEntry *it = INDEX->find(std::string(1, c));
IndexEntry *it = db_get(INDEX, std::string(1, c).c_str());
if (n == 0) {
test_loop_equal(it, NULL, c - 'a');
return;
@ -61,7 +61,7 @@ static void test_removal(unsigned int n)
for (unsigned int i = 0; i < n; i++)
INDEX->remove(std::string(1, c), i);
it = INDEX->find(std::string(1, c));
it = db_get(INDEX, std::string(1, c).c_str());
if (n == 0) {
test_loop_equal(it, NULL, c - 'a');
return;
@ -87,8 +87,8 @@ static void test_save_load(unsigned int n)
test_equal(db_actual_size(&idx2), db_actual_size(INDEX));
for (char c = 'a'; c <= 'z'; c++) {
it1 = INDEX->find(std::string(1, c));
it2 = idx2.find(std::string(1, c));
it1 = db_get(INDEX, std::string(1, c).c_str());
it2 = db_get(&idx2, std::string(1, c).c_str());
if (n == 0) {
test_loop_equal(it1, NULL, c - 'a');
test_loop_equal(it2, NULL, c - 'a');