/* * Copyright 2013 (c) Anna Schumaker. */ #include #include #include static int track_less_than(const void *a, const void *b, void *data) { struct track *lhs = (struct track *)a; struct track *rhs = (struct track *)b; GSList *cur = (GSList *)data; int res, field; while (cur) { field = GPOINTER_TO_INT(cur->data); if (field > 0) res = track_compare(lhs, rhs, field); else res = track_compare(rhs, lhs, abs(field)); if (res == 0) { cur = g_slist_next(cur); continue; } break; }; return res; } static inline void *__queue_init(struct queue *queue, void *data) { if (queue->q_ops) return queue->q_ops->qop_init(queue, data); return NULL; } static inline void __queue_deinit(struct queue *queue) { if (queue->q_ops) queue->q_ops->qop_deinit(queue); } 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; } static inline unsigned int __queue_add_head(struct queue *queue, struct track *track) { g_queue_push_head(&queue->q_tracks, track); return __queue_added(queue, track, 0); } static inline unsigned int __queue_add_tail(struct queue *queue, struct track *track) { g_queue_push_tail(&queue->q_tracks, track); return __queue_added(queue, track, queue_size(queue) - 1); } static inline unsigned int __queue_add_sorted(struct queue *queue, struct track *track) { struct queue_iter it; queue_for_each(queue, &it) { if (track_less_than(queue_iter_val(&it), track, queue->q_sort) > 0) { g_queue_insert_before(&queue->q_tracks, it.it_iter, track); return __queue_added(queue, track, it.it_pos); } } return __queue_add_tail(queue, track); } static inline void __queue_remove(struct queue *queue, struct queue_iter *it) { struct track *track = queue_iter_val(it); unsigned int pos = it->it_pos; GList *link = it->it_iter; queue_iter_prev(it); g_queue_delete_link(&queue->q_tracks, link); queue->q_length -= track->tr_length; if (queue->q_ops) queue->q_ops->qop_removed(queue, pos); } 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); } static inline void __queue_updated(struct queue *queue, unsigned int pos) { if (queue->q_ops) queue->q_ops->qop_updated(queue, pos); } static inline struct track *__queue_selected(struct queue *queue, unsigned int pos) { struct track *track = queue_iter_val(&queue->q_cur); __queue_updated(queue, pos); return track; } void queue_init(struct queue *queue, const struct queue_ops *ops, void *data) { queue->q_length = 0; queue->q_sort = NULL; queue->q_ops = ops; g_queue_init(&queue->q_tracks); queue_iter_init(queue, &queue->q_cur); queue->q_private = __queue_init(queue, data); } void queue_deinit(struct queue *queue) { queue_clear(queue); __queue_deinit(queue); g_slist_free(queue->q_sort); queue->q_sort = NULL; } unsigned int queue_add(struct queue *queue, struct track *track) { if (queue->q_sort) return __queue_add_sorted(queue, track); return __queue_add_tail(queue, track); } unsigned int queue_add_front(struct queue *queue, struct track *track) { return __queue_add_head(queue, track); } void queue_remove(struct queue *queue, unsigned int index) { struct queue_iter it; queue_iter_set(queue, &it, index); __queue_remove(queue, &it); } unsigned int queue_remove_all(struct queue *queue, struct track *track) { unsigned int count = 0; struct queue_iter it; while (queue_at(queue, 0) == track) { queue_remove(queue, 0); count++; } queue_for_each(queue, &it) { if (queue_iter_val(&it) == track) { __queue_remove(queue, &it); count++; } } return count; } void queue_clear(struct queue *queue) { unsigned int n = queue_size(queue); g_queue_clear(&queue->q_tracks); __queue_clear(queue, n); } bool queue_has(struct queue *queue, struct track *track) { struct queue_iter it; queue_for_each(queue, &it) { if (queue_iter_val(&it) == track) return true; } return false; } void queue_updated(struct queue *queue, struct track *track) { struct queue_iter it; queue_for_each(queue, &it) { if (queue_iter_val(&it) == track) __queue_updated(queue, it.it_pos); } } struct track *queue_selected(struct queue *queue, unsigned int index) { if (index > queue_size(queue)) return NULL; if (queue->q_cur.it_pos != index) queue_iter_set(queue, &queue->q_cur, index); return __queue_selected(queue, index); }