2015-12-02 10:22:11 -05:00
|
|
|
/*
|
2013-12-31 15:44:44 -05:00
|
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
|
|
*/
|
2014-06-05 10:19:22 -04:00
|
|
|
#include <core/queue.h>
|
2015-01-29 08:27:25 -05:00
|
|
|
#include <core/string.h>
|
2015-12-02 10:22:11 -05:00
|
|
|
#include <stdlib.h>
|
2014-01-22 21:17:51 -05:00
|
|
|
|
2013-12-31 15:44:44 -05:00
|
|
|
|
2015-12-01 11:17:25 -05:00
|
|
|
static int track_less_than(const void *a, const void *b, void *data)
|
2015-11-25 08:24:04 -05:00
|
|
|
{
|
2015-12-01 11:17:25 -05:00
|
|
|
struct track *lhs = (struct track *)a;
|
|
|
|
struct track *rhs = (struct track *)b;
|
2015-12-02 09:18:10 -05:00
|
|
|
GSList *cur = (GSList *)data;
|
|
|
|
int res, field;
|
2015-11-25 08:24:04 -05:00
|
|
|
|
2015-12-02 09:18:10 -05:00
|
|
|
while (cur) {
|
|
|
|
field = GPOINTER_TO_INT(cur->data);
|
|
|
|
if (field > 0)
|
2015-12-02 10:22:11 -05:00
|
|
|
res = track_compare(lhs, rhs, field);
|
2015-11-25 08:24:04 -05:00
|
|
|
else
|
2015-12-02 10:22:11 -05:00
|
|
|
res = track_compare(rhs, lhs, abs(field));
|
2015-12-02 09:18:10 -05:00
|
|
|
if (res == 0) {
|
|
|
|
cur = g_slist_next(cur);
|
2015-11-25 08:24:04 -05:00
|
|
|
continue;
|
2015-12-02 09:18:10 -05:00
|
|
|
}
|
2015-11-25 08:24:04 -05:00
|
|
|
break;
|
2015-12-02 09:18:10 -05:00
|
|
|
};
|
2015-12-01 11:17:25 -05:00
|
|
|
return res;
|
2015-11-25 08:24:04 -05:00
|
|
|
}
|
|
|
|
|
2016-01-12 08:02:28 -05:00
|
|
|
static inline void *__queue_init(struct queue *queue)
|
|
|
|
{
|
|
|
|
if (queue->q_ops)
|
|
|
|
return queue->q_ops->qop_init(queue);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-01-13 08:18:03 -05:00
|
|
|
static inline void __queue_deinit(struct queue *queue)
|
|
|
|
{
|
|
|
|
if (queue->q_ops)
|
|
|
|
queue->q_ops->qop_deinit(queue);
|
|
|
|
}
|
|
|
|
|
2015-11-29 19:45:39 -05:00
|
|
|
static inline unsigned int __queue_added(struct queue *queue,
|
|
|
|
struct track *track,
|
|
|
|
unsigned int pos)
|
|
|
|
{
|
|
|
|
queue->q_length += track->tr_length;
|
|
|
|
if (queue->q_ops)
|
|
|
|
queue->q_ops->qop_added(queue, pos);
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
2016-01-22 08:11:09 -05:00
|
|
|
static inline bool __queue_erase(struct queue *queue, struct _q_iter *it)
|
|
|
|
{
|
|
|
|
struct track *track = (struct track *)_q_iter_val(it);
|
|
|
|
|
|
|
|
if (queue->q_ops)
|
|
|
|
return queue->q_ops->qop_erase(queue, track);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-12-01 11:17:25 -05:00
|
|
|
static inline void __queue_remove(struct queue *queue, struct _q_iter *it)
|
2015-11-29 20:01:12 -05:00
|
|
|
{
|
2015-12-01 11:17:25 -05:00
|
|
|
unsigned int pos = it->it_pos;
|
|
|
|
struct track *track = (struct track *)_q_remove_it(&queue->q_tracks, it);
|
|
|
|
|
2015-11-29 20:01:12 -05:00
|
|
|
queue->q_length -= track->tr_length;
|
2015-12-01 15:44:18 -05:00
|
|
|
if (queue->q_cur.it_pos == pos)
|
|
|
|
_q_iter_prev(&queue->q_cur);
|
2015-11-29 20:01:12 -05:00
|
|
|
if (queue->q_ops)
|
|
|
|
queue->q_ops->qop_removed(queue, pos);
|
|
|
|
}
|
|
|
|
|
2016-01-29 10:12:09 -05:00
|
|
|
static inline void __queue_clear(struct queue *queue, unsigned int n)
|
|
|
|
{
|
|
|
|
queue->q_length = 0;
|
|
|
|
if (queue->q_ops)
|
|
|
|
queue->q_ops->qop_cleared(queue, n);
|
|
|
|
}
|
|
|
|
|
2015-11-29 20:10:15 -05:00
|
|
|
static inline void __queue_updated(struct queue *queue, unsigned int pos)
|
|
|
|
{
|
|
|
|
if (queue->q_ops)
|
|
|
|
queue->q_ops->qop_updated(queue, pos);
|
|
|
|
}
|
|
|
|
|
2016-06-04 17:10:05 -04:00
|
|
|
static inline struct track *__queue_selected(struct queue *queue, unsigned int pos)
|
2015-12-01 15:44:18 -05:00
|
|
|
{
|
|
|
|
struct track *track = (struct track *)_q_iter_val(&queue->q_cur);
|
|
|
|
|
|
|
|
if (queue_has_flag(queue, Q_REPEAT) == false)
|
|
|
|
__queue_remove(queue, &queue->q_cur);
|
2016-06-04 17:10:05 -04:00
|
|
|
else
|
|
|
|
__queue_updated(queue, pos);
|
2015-12-01 15:44:18 -05:00
|
|
|
return track;
|
|
|
|
}
|
|
|
|
|
2015-11-23 08:36:29 -05:00
|
|
|
static inline void __queue_save(struct queue *queue, enum queue_flags flag)
|
|
|
|
{
|
|
|
|
if (queue->q_ops && queue_has_flag(queue, flag))
|
|
|
|
queue->q_ops->qop_save(queue, flag);
|
|
|
|
}
|
2014-12-09 08:39:04 -05:00
|
|
|
|
2015-11-23 08:36:29 -05:00
|
|
|
void queue_init(struct queue *queue, unsigned int flags,
|
|
|
|
const struct queue_ops *ops)
|
|
|
|
{
|
|
|
|
queue->q_flags = flags;
|
|
|
|
queue->q_length = 0;
|
2015-12-02 09:18:10 -05:00
|
|
|
queue->q_sort = NULL;
|
2015-11-23 08:36:29 -05:00
|
|
|
queue->q_ops = ops;
|
2015-12-01 11:17:25 -05:00
|
|
|
|
2015-12-01 15:44:18 -05:00
|
|
|
queue->q_cur.it_pos = -1;
|
|
|
|
queue->q_cur.it_iter = NULL;
|
2015-12-01 11:17:25 -05:00
|
|
|
_q_init(&queue->q_tracks);
|
2016-01-12 08:02:28 -05:00
|
|
|
|
|
|
|
queue->q_private = __queue_init(queue);
|
2015-11-23 08:36:29 -05:00
|
|
|
}
|
2013-12-31 15:44:44 -05:00
|
|
|
|
2015-12-07 10:00:19 -05:00
|
|
|
void queue_deinit(struct queue *queue)
|
|
|
|
{
|
2016-01-29 10:12:09 -05:00
|
|
|
queue_clear(queue);
|
2016-01-13 08:18:03 -05:00
|
|
|
__queue_deinit(queue);
|
2015-12-07 10:00:19 -05:00
|
|
|
g_slist_free(queue->q_sort);
|
|
|
|
queue->q_sort = NULL;
|
|
|
|
}
|
|
|
|
|
2015-12-03 13:41:39 -05:00
|
|
|
void queue_set_flag(struct queue *queue, enum queue_flags flag)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2015-12-03 13:41:39 -05:00
|
|
|
queue->q_flags |= flag;
|
|
|
|
__queue_save(queue, Q_SAVE_FLAGS);
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2015-12-03 13:41:39 -05:00
|
|
|
void queue_unset_flag(struct queue *queue, enum queue_flags flag)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2015-12-03 13:41:39 -05:00
|
|
|
queue->q_flags &= ~flag;
|
|
|
|
__queue_save(queue, Q_SAVE_FLAGS);
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2015-11-25 08:24:04 -05:00
|
|
|
unsigned int queue_add(struct queue *queue, struct track *track)
|
2014-01-02 21:58:18 -05:00
|
|
|
{
|
2015-12-01 11:17:25 -05:00
|
|
|
unsigned int pos;
|
2015-11-25 08:24:04 -05:00
|
|
|
|
2015-11-25 09:04:10 -05:00
|
|
|
if (queue_has_flag(queue, Q_ADD_FRONT))
|
2015-12-01 11:17:25 -05:00
|
|
|
pos = _q_add_head(&queue->q_tracks, track);
|
2015-12-02 09:18:10 -05:00
|
|
|
else if (queue->q_sort)
|
|
|
|
pos = _q_add_sorted(&queue->q_tracks, track,
|
|
|
|
track_less_than, queue->q_sort);
|
2015-12-01 11:17:25 -05:00
|
|
|
else
|
|
|
|
pos = _q_add_tail(&queue->q_tracks, track);
|
2015-11-25 08:24:04 -05:00
|
|
|
|
2015-11-29 19:45:39 -05:00
|
|
|
return __queue_added(queue, track, pos);
|
2014-01-02 21:58:18 -05:00
|
|
|
}
|
|
|
|
|
2016-01-22 08:11:09 -05:00
|
|
|
void queue_erase(struct queue *queue, unsigned int index)
|
|
|
|
{
|
|
|
|
struct _q_iter it;
|
|
|
|
|
|
|
|
_q_iter_set(&queue->q_tracks, &it, index);
|
|
|
|
if (__queue_erase(queue, &it))
|
|
|
|
__queue_remove(queue, &it);
|
|
|
|
}
|
|
|
|
|
2015-11-28 15:24:03 -05:00
|
|
|
void queue_remove(struct queue *queue, unsigned int index)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2015-12-01 11:17:25 -05:00
|
|
|
struct _q_iter it;
|
|
|
|
|
|
|
|
_q_iter_set(&queue->q_tracks, &it, index);
|
|
|
|
__queue_remove(queue, &it);
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2015-11-29 16:34:51 -05:00
|
|
|
void queue_remove_all(struct queue *queue, struct track *track)
|
2014-01-16 22:05:36 -05:00
|
|
|
{
|
2015-12-01 11:17:25 -05:00
|
|
|
struct _q_iter it;
|
|
|
|
|
|
|
|
while (queue_at(queue, 0) == track)
|
|
|
|
queue_remove(queue, 0);
|
|
|
|
|
|
|
|
_q_for_each(&queue->q_tracks, &it) {
|
|
|
|
if (_q_iter_val(&it) == track)
|
|
|
|
__queue_remove(queue, &it);
|
2014-12-09 08:48:27 -05:00
|
|
|
}
|
2014-01-16 22:05:36 -05:00
|
|
|
}
|
|
|
|
|
2016-01-29 10:12:09 -05:00
|
|
|
void queue_clear(struct queue *queue)
|
|
|
|
{
|
|
|
|
unsigned int n = queue_size(queue);
|
|
|
|
|
|
|
|
_q_clear(&queue->q_tracks);
|
|
|
|
__queue_clear(queue, n);
|
|
|
|
}
|
|
|
|
|
2015-11-20 08:02:54 -05:00
|
|
|
void queue_updated(struct queue *queue, struct track *track)
|
2014-01-29 22:45:01 -05:00
|
|
|
{
|
2015-12-01 11:17:25 -05:00
|
|
|
struct _q_iter it;
|
|
|
|
|
|
|
|
_q_for_each(&queue->q_tracks, &it) {
|
|
|
|
if (_q_iter_val(&it) == track)
|
|
|
|
__queue_updated(queue, it.it_pos);
|
2014-01-29 22:45:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-27 12:19:28 -04:00
|
|
|
struct track *queue_selected(struct queue *queue, unsigned int index)
|
2015-11-19 08:08:14 -05:00
|
|
|
{
|
2016-03-27 12:19:28 -04:00
|
|
|
if (index > queue_size(queue))
|
|
|
|
return NULL;
|
2015-12-01 15:44:18 -05:00
|
|
|
if (queue->q_cur.it_pos != index)
|
|
|
|
_q_iter_set(&queue->q_tracks, &queue->q_cur, index);
|
2016-06-04 17:10:05 -04:00
|
|
|
return __queue_selected(queue, index);
|
2015-11-19 08:08:14 -05:00
|
|
|
}
|
|
|
|
|
2015-11-19 08:25:53 -05:00
|
|
|
struct track *queue_next(struct queue *queue)
|
2014-05-18 11:08:58 -04:00
|
|
|
{
|
2015-12-01 15:44:18 -05:00
|
|
|
unsigned int pos, size = queue_size(queue);
|
2014-05-18 11:08:58 -04:00
|
|
|
|
2015-11-20 08:18:54 -05:00
|
|
|
if (!queue_has_flag(queue, Q_ENABLED))
|
2015-11-13 11:14:40 -05:00
|
|
|
return NULL;
|
2015-11-19 08:25:53 -05:00
|
|
|
else if (size == 0)
|
2014-05-18 11:08:58 -04:00
|
|
|
return NULL;
|
|
|
|
|
2015-12-01 15:44:18 -05:00
|
|
|
if (size == 1)
|
|
|
|
_q_iter_set(&queue->q_tracks, &queue->q_cur, 0);
|
|
|
|
else if (queue_has_flag(queue, Q_RANDOM)) {
|
2016-03-11 14:56:44 -05:00
|
|
|
pos = g_random_int_range(1, (size < 15) ? size : size / 3);
|
2016-03-23 11:33:22 -04:00
|
|
|
pos += queue->q_cur.it_pos;
|
2015-12-01 15:44:18 -05:00
|
|
|
_q_iter_set(&queue->q_tracks, &queue->q_cur, pos % size);
|
|
|
|
} else {
|
|
|
|
_q_iter_next(&queue->q_cur);
|
|
|
|
if (!queue->q_cur.it_iter)
|
|
|
|
_q_iter_set(&queue->q_tracks, &queue->q_cur, 0);
|
|
|
|
}
|
|
|
|
|
2016-06-04 17:10:05 -04:00
|
|
|
return __queue_selected(queue, queue->q_cur.it_pos);
|
2014-05-18 11:08:58 -04:00
|
|
|
}
|
|
|
|
|
2015-12-03 10:03:52 -05:00
|
|
|
void queue_resort(struct queue *queue)
|
|
|
|
{
|
|
|
|
_q_sort(&queue->q_tracks, track_less_than, queue->q_sort);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < queue_size(queue); i++)
|
|
|
|
__queue_updated(queue, i);
|
|
|
|
}
|
|
|
|
|
2015-12-02 09:18:10 -05:00
|
|
|
void queue_sort(struct queue *queue, enum compare_t sort, bool reset)
|
2014-01-26 12:12:01 -05:00
|
|
|
{
|
2015-12-02 09:18:10 -05:00
|
|
|
GSList *cur = NULL;
|
|
|
|
int field;
|
2014-01-26 14:44:56 -05:00
|
|
|
|
2015-12-03 13:43:15 -05:00
|
|
|
if (queue_has_flag(queue, Q_NO_SORT))
|
2014-01-26 14:49:07 -05:00
|
|
|
return;
|
2015-12-02 09:18:10 -05:00
|
|
|
if (reset) {
|
|
|
|
g_slist_free(queue->q_sort);
|
|
|
|
queue->q_sort = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = queue->q_sort;
|
|
|
|
while (cur) {
|
|
|
|
field = GPOINTER_TO_INT(cur->data);
|
|
|
|
if (abs(field) == sort) {
|
|
|
|
cur->data = GINT_TO_POINTER(-field);
|
|
|
|
goto out_sort;
|
2014-05-18 14:11:21 -04:00
|
|
|
}
|
2015-12-02 09:18:10 -05:00
|
|
|
cur = g_slist_next(cur);
|
2014-05-18 14:11:21 -04:00
|
|
|
}
|
|
|
|
|
2015-12-02 09:18:10 -05:00
|
|
|
queue->q_sort = g_slist_append(queue->q_sort, GINT_TO_POINTER(sort));
|
2014-01-26 14:49:07 -05:00
|
|
|
|
2015-12-02 09:18:10 -05:00
|
|
|
out_sort:
|
2015-12-03 10:03:52 -05:00
|
|
|
queue_resort(queue);
|
2015-12-03 13:43:15 -05:00
|
|
|
__queue_save(queue, Q_SAVE_SORT);
|
2014-01-26 12:12:01 -05:00
|
|
|
}
|