core/playlist: Move playlist iterator functions into the playlist layer

I also take this chance to add extra functions for directly manipulating
the current track, since this is something we do fairly often.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2016-09-22 10:00:55 -04:00
parent f25bdab367
commit 18f1bfe801
10 changed files with 113 additions and 78 deletions

View File

@ -84,8 +84,9 @@ void playlist_generic_save(struct playlist *playlist, struct file *file,
if (flags & PL_SAVE_TRACKS) {
file_writef(file, "%u", playlist_size(playlist));
queue_for_each(&playlist->pl_queue, &it)
file_writef(file, " %u", track_index(queue_iter_val(&it)));
playlist_for_each(playlist, &it)
file_writef(file, " %u",
track_index(playlist_iter_track(&it)));
file_writef(file, "\n");
}
}
@ -131,7 +132,7 @@ void playlist_generic_load(struct playlist *playlist, struct file *file,
}
playlist_generic_set_random(playlist, f == PL_RANDOM);
queue_iter_set(&playlist->pl_queue, &playlist->pl_queue.q_cur, it);
playlist_current_set(playlist, it);
}
bool playlist_generic_can_select(struct playlist *playlist)
@ -194,8 +195,8 @@ bool playlist_generic_remove(struct playlist *playlist, struct track *track)
if (!playlist || !track)
return false;
while (queue_iter_val(&playlist->pl_queue.q_cur) == track)
queue_iter_prev(&playlist->pl_queue.q_cur);
while (playlist_current_track(playlist) == track)
playlist_current_previous(playlist);
count = g_queue_remove_all(&playlist->pl_queue.q_tracks, track);
playlist->pl_length -= (count * track->tr_length);
@ -253,14 +254,9 @@ struct track *playlist_generic_next(struct playlist *playlist)
else if (playlist->pl_random) {
pos = g_random_int_range(1, size);
pos += playlist->pl_queue.q_cur.it_pos;
queue_iter_set(&playlist->pl_queue,
&playlist->pl_queue.q_cur, pos % size);
} else {
queue_iter_next(&playlist->pl_queue.q_cur);
if (!playlist->pl_queue.q_cur.it_iter)
queue_iter_set(&playlist->pl_queue,
&playlist->pl_queue.q_cur, 0);
}
playlist_current_set(playlist, pos % size);
} else if (!playlist_current_next(playlist))
playlist_current_set(playlist, 0);
return queue_iter_val(&playlist->pl_queue.q_cur);
return playlist_current_track(playlist);
}

View File

@ -177,10 +177,10 @@ static bool pl_library_delete(struct playlist *playlist)
if (!library)
return false;
queue_for_each(&playlist->pl_queue, &it) {
pl_system_delete_track(queue_iter_val(&it));
pl_artist_delete_track(queue_iter_val(&it));
pl_user_delete_track(queue_iter_val(&it));
playlist_for_each(playlist, &it) {
pl_system_delete_track(playlist_iter_track(&it));
pl_artist_delete_track(playlist_iter_track(&it));
pl_user_delete_track(playlist_iter_track(&it));
}
__lib_pl_free(playlist);

View File

@ -201,7 +201,7 @@ static struct playlist_ops collection_ops = {
static bool sys_pl_history_add(struct playlist *playlist, struct track *track)
{
playlist_generic_add_front(playlist, track);
queue_iter_set(&playlist->pl_queue, &playlist->pl_queue.q_cur, 0);
playlist_current_set(playlist, 0);
return true;
}
@ -370,7 +370,6 @@ static void pl_system_selected(struct track *track)
{
unsigned int i;
queue_iter_prev(&pl_system_get(SYS_PL_QUEUED)->pl_queue.q_cur);
playlist_generic_remove(pl_system_get(SYS_PL_QUEUED), track);
for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++)
playlist_generic_update(pl_system_get(i), track);

View File

@ -22,10 +22,9 @@ static inline void __queue_deinit(struct queue *queue)
void queue_init(struct queue *queue, const struct queue_ops *ops, void *data)
{
queue->q_ops = ops;
g_queue_init(&queue->q_tracks);
queue_iter_init(queue, &queue->q_cur);
queue->q_cur.it_iter = NULL;
queue->q_cur.it_pos = -1;
queue->q_private = __queue_init(queue, data);
}

View File

@ -131,8 +131,7 @@ void gui_filter_path_load_track(GtkTreePath *path)
unsigned int index = gtk_tree_path_get_indices(path)[0];
audio_load(track);
queue_iter_set(&gui_model_get_playlist()->pl_queue,
&gui_model_get_playlist()->pl_queue.q_cur, index);
playlist_current_set(gui_model_get_playlist(), index);
}
unsigned int gui_filter_path_get_index(GtkTreePath *path)

View File

@ -3,6 +3,7 @@
*/
#ifndef OCARINA_CORE_PLAYLISTS_GENERIC_H
#define OCARINA_CORE_PLAYLISTS_GENERIC_H
#include <core/playlists/iterator.h>
#include <core/playlists/playlist.h>
enum playlist_save_flags {

View File

@ -0,0 +1,76 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_ITERATOR_H
#define OCARINA_CORE_PLAYLISTS_ITERATOR_H
#include <core/playlists/playlist.h>
#include <core/queue.h>
/* Called to set the playlist iterator to a specific position. */
static inline bool playlist_iter_set(struct playlist *playlist,
struct queue_iter *iter,
unsigned int n)
{
if (!playlist || !iter)
return false;
iter->it_iter = g_queue_peek_nth_link(&playlist->pl_queue.q_tracks, n);
iter->it_pos = n;
return iter->it_iter != NULL;
}
/* Called to advance the requested playlist iterator. */
static inline bool playlist_iter_next(struct queue_iter *iter)
{
if (!iter)
return false;
iter->it_iter = g_list_next(iter->it_iter);
iter->it_pos++;
return iter->it_iter != NULL;
}
/* Called to get a pointer to the track at the requested iterator. */
static inline struct track *playlist_iter_track(struct queue_iter *iter)
{
return (iter && iter->it_iter) ? iter->it_iter->data : NULL;
}
/* Called to iterate over the entire playlist. */
#define playlist_for_each(playlist, it) \
for (playlist_iter_set(playlist, it, 0); (it)->it_iter; \
playlist_iter_next(it))
/* Called to set the index of the current track. */
static inline bool playlist_current_set(struct playlist *playlist,
unsigned int n)
{
if (!playlist)
return false;
return playlist_iter_set(playlist, &playlist->pl_queue.q_cur, n);
}
/* Called to advance the current track. */
static inline bool playlist_current_next(struct playlist *playlist)
{
if (!playlist)
return false;
return playlist_iter_next(&playlist->pl_queue.q_cur);
}
/* Called to rewind the current track. */
static inline bool playlist_current_previous(struct playlist *playlist)
{
if (!playlist)
return false;
playlist->pl_queue.q_cur.it_iter = g_list_previous(playlist->pl_queue.q_cur.it_iter);
playlist->pl_queue.q_cur.it_pos--;
return playlist->pl_queue.q_cur.it_iter != NULL;
}
/* Called to get a pointer to the current track. */
static inline struct track *playlist_current_track(struct playlist *playlist)
{
return playlist ? playlist_iter_track(&playlist->pl_queue.q_cur) : NULL;
}
#endif /* OCARINA_CORE_PLAYLISTS_ITERATOR_H */

View File

@ -38,47 +38,6 @@ struct queue {
};
/* Called to initialize a queue iterator. */
static inline void queue_iter_init(struct queue *queue, struct queue_iter *it)
{
it->it_iter = g_queue_peek_head_link(&queue->q_tracks);
it->it_pos = g_queue_link_index(&queue->q_tracks, it->it_iter);
}
/* Called to advance a queue iterator by one step. */
static inline void queue_iter_next(struct queue_iter *it)
{
it->it_iter = g_list_next(it->it_iter);
it->it_pos++;
}
/* Called to rewind a queue iterator by one step. */
static inline void queue_iter_prev(struct queue_iter *it)
{
it->it_iter = g_list_previous(it->it_iter);
it->it_pos--;
}
/* Called to set a queue iterator to a specific position. */
static inline void queue_iter_set(struct queue *queue, struct queue_iter *it,
unsigned int pos)
{
it->it_iter = g_queue_peek_nth_link(&queue->q_tracks, pos);
it->it_pos = pos;
}
/* Called to access the value of a queue iterator. */
static inline struct track *queue_iter_val(struct queue_iter *it)
{
return (it->it_iter) ? it->it_iter->data : NULL;
}
#define queue_for_each(queue, it) \
for (queue_iter_init(queue, it); (it)->it_iter; queue_iter_next(it))
/* Called to initialize a queue. */
void queue_init(struct queue *, const struct queue_ops *, void *);

View File

@ -77,12 +77,22 @@ static void test_null()
playlist_generic_save(NULL, NULL, PL_SAVE_ALL);
playlist_generic_load(NULL, NULL, PL_SAVE_ALL);
g_assert_false(playlist_iter_set(NULL, NULL, 0));
g_assert_false(playlist_iter_next(NULL));
g_assert_null(playlist_iter_track(NULL));
g_assert_false(playlist_current_set(NULL, 0));
g_assert_false(playlist_current_next(NULL));
g_assert_false(playlist_current_previous(NULL));
g_assert_null(playlist_current_track(NULL));
}
static void test_playlist()
{
struct playlist p = DEFINE_PLAYLIST(PL_MAX_TYPE, "Test", 0, &test_ops);
unsigned int ex_length = 0;
struct queue_iter it;
unsigned int i;
g_assert_cmpuint(playlist_size(&p), ==, 0);
@ -102,17 +112,19 @@ static void test_playlist()
g_assert_false(playlist_generic_add_front(&p, NULL));
/* Trigger an update for each track. */
for (i = 0; i < 13; i++) {
playlist_generic_update(&p, track_get(i));
i = 13;
playlist_for_each(&p, &it) {
g_assert_cmpuint(playlist_iter_track(&it)->tr_track, ==, i--);
playlist_generic_update(&p, playlist_iter_track(&it));
g_assert(cb_playlist == &p);
g_assert(cb_track == track_get(i));
g_assert(cb_track == playlist_iter_track(&it));
}
playlist_generic_update(&p, NULL);
g_assert(cb_playlist == &p);
g_assert_null(cb_track);
/* Remove all tracks. */
queue_iter_set(&p.pl_queue, &p.pl_queue.q_cur, 12);
playlist_current_set(&p, 12);
for (i = 0; i < 13; i++) {
ex_length -= track_get(i)->tr_length;
g_assert_true(playlist_remove(&p, track_get(i)));
@ -148,7 +160,7 @@ static void test_playlist()
g_assert_cmpuint(p.pl_length, ==, ex_length);
/* Now clear the playlist. */
queue_iter_set(&p.pl_queue, &p.pl_queue.q_cur, 12);
playlist_current_set(&p, 12);
playlist_generic_clear(&p);
g_assert_cmpuint(playlist_size(&p), ==, 0);
g_assert_cmpuint(p.pl_length, ==, 0);
@ -332,7 +344,7 @@ static void test_save_load()
g_assert_false(s.pl_random);
g_assert_cmpuint(s.pl_queue.q_cur.it_pos, ==, 4);
g_assert(queue_iter_val(&s.pl_queue.q_cur) == queue_at(&q.pl_queue, 4));
g_assert(playlist_current_track(&s) == queue_at(&q.pl_queue, 4));
g_assert_cmpuint(g_slist_length(s.pl_sort), ==, 0);
g_assert_cmpuint(playlist_size(&s), ==, 13);

View File

@ -32,7 +32,6 @@ static const struct queue_ops test_ops = {
static void test_init()
{
struct queue q;
struct queue_iter it;
queue_init(&q, NULL, NULL);
g_assert_cmpuint(count_init, ==, 0);
@ -41,11 +40,6 @@ static void test_init()
g_assert_cmpuint(q.q_cur.it_pos, ==, (unsigned int)-1);
g_assert_null(q.q_ops);
queue_iter_init(&q, &it);
g_assert_null(it.it_iter);
g_assert_cmpuint(it.it_pos, ==, (unsigned int)-1);
g_assert_null(queue_iter_val(&it));
queue_deinit(&q);
g_assert_cmpuint(count_deinit, ==, 0);