From 3ff992cf52f4f5edabb012ffe44160e49b670ee7 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Fri, 18 Sep 2015 09:37:48 -0400 Subject: [PATCH] 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 --- core/tags/track.cpp | 8 ++++---- include/core/database.h | 36 +++++++++++++++--------------------- include/core/database.hpp | 33 +++++++++++++++------------------ tests/core/database.cpp | 20 +++++++++++++------- 4 files changed, 47 insertions(+), 50 deletions(-) diff --git a/core/tags/track.cpp b/core/tags/track.cpp index 68b5507b..3dd37f24 100644 --- a/core/tags/track.cpp +++ b/core/tags/track.cpp @@ -171,11 +171,11 @@ void tags :: remove_track(Track *track) void tags :: remove_library_tracks(Library *library) { - database::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(); } diff --git a/include/core/database.h b/include/core/database.h index 7f2468e7..5e207570 100644 --- a/include/core/database.h +++ b/include/core/database.h @@ -86,10 +86,6 @@ struct database { std::vector db_entries; std::map db_keys; - /** Iterator access for our backing std::vector */ - typedef typename std::vector::iterator iterator; - /** Const iterator access for our backing std::vector */ - typedef typename std::vector::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 *, const gchar *); template T *db_find(struct database *, const gchar *); +/* Returns the first valid database item. */ +template +T *db_first(const struct database *); + +/* Returns the next valid database item. */ +template +T *db_next(const struct database *, 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 */ diff --git a/include/core/database.hpp b/include/core/database.hpp index 5cce813d..b6c0323e 100644 --- a/include/core/database.hpp +++ b/include/core/database.hpp @@ -17,9 +17,9 @@ database :: database(std::string filepath, bool autosave) template database :: ~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 @@ -114,30 +114,27 @@ unsigned int db_actual_size(const struct database *db) } template -typename database::iterator database :: begin() +T *__db_next(const struct database *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 -typename database::iterator database :: end() +T *db_first(const struct database *db) { - return db_entries.end(); + return __db_next(db, 0); } template -typename database::iterator database :: next(iterator &it) +T *db_next(const struct database *db, T *ent) { - do { - it++; - } while ((it != end()) && (*it) == NULL); - return it; + if (ent) + return __db_next(db, ent->index() + 1); + return NULL; } template diff --git a/tests/core/database.cpp b/tests/core/database.cpp index f09aa9f8..e125f318 100644 --- a/tests/core/database.cpp +++ b/tests/core/database.cpp @@ -72,9 +72,8 @@ static void test_init() static void test_stress(unsigned int N) { database db("stress.db", false); - database::iterator it; std::vector 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);