core/database: Replace database iterators with db_for_each()
This function is similar to Linux's list_for_each_safe(), and lets you iterate over a database even if the current item is removed. Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
parent
ffd38bd28b
commit
3ff992cf52
|
@ -171,11 +171,11 @@ void tags :: remove_track(Track *track)
|
|||
|
||||
void tags :: remove_library_tracks(Library *library)
|
||||
{
|
||||
database<Track>::iterator it;
|
||||
Track *it, *next;
|
||||
|
||||
for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) {
|
||||
if ((*it)->library() == library)
|
||||
db_remove(&track_db, *it);
|
||||
db_for_each(it, next, &track_db) {
|
||||
if (it->library() == library)
|
||||
db_remove(&track_db, it);
|
||||
}
|
||||
tags :: commit_track_db();
|
||||
}
|
||||
|
|
|
@ -86,10 +86,6 @@ struct database {
|
|||
std::vector<T *> db_entries;
|
||||
std::map<const std::string, unsigned int> db_keys;
|
||||
|
||||
/** Iterator access for our backing std::vector */
|
||||
typedef typename std::vector<T *>::iterator iterator;
|
||||
/** Const iterator access for our backing std::vector */
|
||||
typedef typename std::vector<T *>::const_iterator const_iterator;
|
||||
|
||||
/**
|
||||
* Initialize a Database using filepath as a location to store data
|
||||
|
@ -107,23 +103,6 @@ struct database {
|
|||
* Deletes all remaining entries in a Database to prevent memory leaks.
|
||||
*/
|
||||
~database();
|
||||
|
||||
|
||||
/**
|
||||
* @return An iterator pointing to the first valid entry in the Database.
|
||||
* @return Return Database::end() if there are no valid entries.
|
||||
*/
|
||||
iterator begin();
|
||||
|
||||
/**
|
||||
* @return An iterator pointing past the end of the database.
|
||||
*/
|
||||
iterator end();
|
||||
|
||||
/**
|
||||
* @return An iterator pointing to the next valid item in the database.
|
||||
*/
|
||||
iterator next(iterator &);
|
||||
};
|
||||
|
||||
|
||||
|
@ -171,6 +150,21 @@ T *db_get(struct database<T> *, const gchar *);
|
|||
template <class T>
|
||||
T *db_find(struct database<T> *, const gchar *);
|
||||
|
||||
/* Returns the first valid database item. */
|
||||
template <class T>
|
||||
T *db_first(const struct database<T> *);
|
||||
|
||||
/* Returns the next valid database item. */
|
||||
template <class T>
|
||||
T *db_next(const struct database<T> *, T *);
|
||||
|
||||
|
||||
#define db_for_each(ent, next, db) \
|
||||
for (ent = db_first(db), next = db_next(db, ent); \
|
||||
ent != NULL; \
|
||||
ent = next, next = db_next(db, ent))
|
||||
|
||||
|
||||
#include "database.hpp"
|
||||
|
||||
#endif /* OCARINA_CORE_DATABASE_H */
|
||||
|
|
|
@ -17,9 +17,9 @@ database<T> :: database(std::string filepath, bool autosave)
|
|||
template <class T>
|
||||
database<T> :: ~database()
|
||||
{
|
||||
iterator it;
|
||||
for (it = begin(); it != end(); it = next(it))
|
||||
delete (*it);
|
||||
T *t, *u;
|
||||
db_for_each(t, u, this)
|
||||
delete t;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
@ -114,30 +114,27 @@ unsigned int db_actual_size(const struct database<T> *db)
|
|||
}
|
||||
|
||||
template <class T>
|
||||
typename database<T>::iterator database<T> :: begin()
|
||||
T *__db_next(const struct database<T> *db, unsigned int index)
|
||||
{
|
||||
if (db_size == 0)
|
||||
return end();
|
||||
|
||||
iterator it = db_entries.begin();
|
||||
if ( (*it) != NULL )
|
||||
return it;
|
||||
return next(it);
|
||||
for (; index < db->db_entries.size(); index++) {
|
||||
if (db->db_entries[index])
|
||||
return db->db_entries[index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename database<T>::iterator database<T> :: end()
|
||||
T *db_first(const struct database<T> *db)
|
||||
{
|
||||
return db_entries.end();
|
||||
return __db_next(db, 0);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename database<T>::iterator database<T> :: next(iterator &it)
|
||||
T *db_next(const struct database<T> *db, T *ent)
|
||||
{
|
||||
do {
|
||||
it++;
|
||||
} while ((it != end()) && (*it) == NULL);
|
||||
return it;
|
||||
if (ent)
|
||||
return __db_next(db, ent->index() + 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
|
|
@ -72,9 +72,8 @@ static void test_init()
|
|||
static void test_stress(unsigned int N)
|
||||
{
|
||||
database<struct int_entry> db("stress.db", false);
|
||||
database<struct int_entry>::iterator it;
|
||||
std::vector<struct int_entry *> ptrs;
|
||||
struct int_entry *dbe, rmv(42);
|
||||
struct int_entry *dbe, *next, rmv(42);
|
||||
unsigned int i;
|
||||
gchar *key;
|
||||
|
||||
|
@ -142,12 +141,19 @@ static void test_stress(unsigned int N)
|
|||
test_equal(db.db_size, N / 2);
|
||||
test_equal(db_actual_size(&db), N + 1);
|
||||
|
||||
/* database.first(), database.next(), database.end() */
|
||||
/* db_for_each() (db_first() / db_next()) */
|
||||
i = 1;
|
||||
for (it = db.begin(); it != db.end(); it = db.next(it)) {
|
||||
test_loop_not_equal(*it, NULL, i);
|
||||
test_loop_equal(*it, ptrs.at(i), i);
|
||||
test_loop_equal((*it)->ie_val, i, i);
|
||||
db_for_each(dbe, next, &db) {
|
||||
test_loop_not_equal(dbe, NULL, i);
|
||||
if (i == (N - 1)) {
|
||||
test_loop_equal(next, NULL, i);
|
||||
} else {
|
||||
test_loop_not_equal(next, NULL, i);
|
||||
test_loop_equal(next->ie_val, i + 2, i);
|
||||
}
|
||||
test_loop_equal(dbe, ptrs.at(i), i);
|
||||
test_loop_equal(dbe->ie_val, i, i);
|
||||
test_loop_equal(db_next(&db, dbe), next, i);
|
||||
i += 2;
|
||||
} test_loop_passed();
|
||||
test_equal(i, N + 1);
|
||||
|
|
Loading…
Reference in New Issue