2014-10-17 09:42:45 -04: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-09-09 09:00:17 -04:00
|
|
|
extern "C" {
|
2014-06-05 10:19:22 -04:00
|
|
|
#include <core/random.h>
|
2015-09-09 09:00:17 -04:00
|
|
|
}
|
2015-01-29 08:27:25 -05:00
|
|
|
#include <core/string.h>
|
2014-01-22 21:17:51 -05:00
|
|
|
|
2014-01-26 13:44:25 -05:00
|
|
|
#include <algorithm>
|
2014-01-22 21:17:51 -05:00
|
|
|
#include <sstream>
|
|
|
|
|
2013-12-31 15:44:44 -05:00
|
|
|
|
2015-04-03 10:30:46 -04:00
|
|
|
static class DefaultNotifier : public QNotifier {
|
|
|
|
public:
|
|
|
|
DefaultNotifier() {};
|
2015-04-03 12:24:26 -04:00
|
|
|
void on_track_removed(unsigned int pos) {};
|
2015-04-03 20:54:45 -04:00
|
|
|
void on_track_updated(unsigned int pos) {};
|
2015-04-03 10:30:46 -04:00
|
|
|
} def_notify;
|
|
|
|
|
|
|
|
|
2015-11-25 08:24:04 -05:00
|
|
|
static bool track_less_than(struct track *lhs, struct track *rhs,
|
|
|
|
std::vector<struct sort_info> &order)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < order.size(); i++) {
|
|
|
|
if (order[i].ascending == true)
|
|
|
|
res = track_compare(lhs, rhs, order[i].field);
|
|
|
|
else
|
|
|
|
res = track_compare(rhs, lhs, order[i].field);
|
|
|
|
if (res == 0)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return res < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-11-29 20:01:12 -05:00
|
|
|
static inline void __queue_removed(struct queue *queue,
|
|
|
|
struct track *track,
|
|
|
|
unsigned int pos)
|
|
|
|
{
|
|
|
|
queue->q_length -= track->tr_length;
|
|
|
|
if (queue->q_cur == pos)
|
|
|
|
queue->q_cur--;
|
|
|
|
if (queue->q_ops)
|
|
|
|
queue->q_ops->qop_removed(queue, pos);
|
|
|
|
}
|
|
|
|
|
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-25 08:24:04 -05:00
|
|
|
static unsigned int __queue_find_sorted_id(struct queue *queue, struct track *rhs)
|
|
|
|
{
|
|
|
|
struct track *lhs;
|
|
|
|
unsigned int mid, begin = 0, end = queue_size(queue) - 1;
|
|
|
|
|
|
|
|
if (queue_size(queue) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (end > begin) {
|
|
|
|
mid = begin + ((end - begin) / 2);
|
|
|
|
lhs = queue->q_tracks[mid];
|
|
|
|
if (track_less_than(lhs, rhs, queue->q_sort))
|
|
|
|
begin = mid + 1;
|
|
|
|
else {
|
|
|
|
if (mid == begin)
|
|
|
|
return begin;
|
|
|
|
else
|
|
|
|
end = mid - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lhs = queue->q_tracks[begin];
|
|
|
|
if (track_less_than(lhs, rhs, queue->q_sort))
|
|
|
|
return begin + 1;
|
|
|
|
return begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-23 08:36:29 -05:00
|
|
|
void queue_init(struct queue *queue, unsigned int flags,
|
|
|
|
const struct queue_ops *ops)
|
|
|
|
{
|
|
|
|
queue->q_cur = -1;
|
|
|
|
queue->q_flags = flags;
|
|
|
|
queue->q_length = 0;
|
|
|
|
queue->q_notify = &def_notify;
|
|
|
|
queue->q_ops = ops;
|
|
|
|
}
|
2013-12-31 15:44:44 -05:00
|
|
|
|
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-11-25 09:04:10 -05:00
|
|
|
unsigned int pos = queue_size(queue);
|
2015-11-25 08:24:04 -05:00
|
|
|
|
2015-11-25 09:04:10 -05:00
|
|
|
if (queue_has_flag(queue, Q_ADD_FRONT))
|
|
|
|
pos = 0;
|
|
|
|
else if (queue->q_sort.size() > 0)
|
|
|
|
pos = __queue_find_sorted_id(queue, track);
|
2015-11-25 08:24:04 -05:00
|
|
|
|
2015-11-25 09:04:10 -05:00
|
|
|
queue->q_tracks.insert(queue->q_tracks.begin() + pos, track);
|
2015-11-29 19:45:39 -05:00
|
|
|
return __queue_added(queue, track, pos);
|
2014-01-02 21:58:18 -05:00
|
|
|
}
|
|
|
|
|
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-11-29 20:01:12 -05:00
|
|
|
struct track *track = queue->q_tracks[index];
|
2015-11-28 15:24:03 -05:00
|
|
|
queue->q_tracks.erase(queue->q_tracks.begin() + index);
|
2015-11-29 20:01:12 -05:00
|
|
|
__queue_removed(queue, track, index);
|
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-11-29 16:34:51 -05:00
|
|
|
for (unsigned int i = 0; i < queue->q_tracks.size(); i++) {
|
|
|
|
while (i < queue->q_tracks.size() &&
|
|
|
|
queue->q_tracks[i] == track)
|
|
|
|
queue_remove(queue, i);
|
2014-12-09 08:48:27 -05:00
|
|
|
}
|
2014-01-16 22:05:36 -05:00
|
|
|
}
|
|
|
|
|
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-11-20 08:02:54 -05:00
|
|
|
for (unsigned int i = 0; i < queue_size(queue); i++) {
|
|
|
|
if (queue->q_tracks[i] == track)
|
|
|
|
queue->q_notify->on_track_updated(i);
|
2014-01-29 22:45:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-19 08:08:14 -05:00
|
|
|
void queue_selected(struct queue *queue, unsigned int index)
|
|
|
|
{
|
|
|
|
queue->q_cur = index;
|
2015-11-20 08:18:54 -05:00
|
|
|
if (queue_has_flag(queue, Q_REPEAT) == false)
|
2015-11-28 15:24:03 -05:00
|
|
|
queue_remove(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-11-19 13:48:59 -05:00
|
|
|
unsigned int size = queue_size(queue);
|
2015-10-24 19:34:45 -04:00
|
|
|
struct track *res;
|
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-11-19 08:25:53 -05:00
|
|
|
else if (size == 1)
|
|
|
|
queue->q_cur = 0;
|
2015-11-20 08:18:54 -05:00
|
|
|
else if (queue_has_flag(queue, Q_RANDOM))
|
2015-11-19 08:25:53 -05:00
|
|
|
queue->q_cur += random_range(1, size / 2);
|
2014-05-18 11:08:58 -04:00
|
|
|
else
|
2015-11-19 08:25:53 -05:00
|
|
|
queue->q_cur++;
|
2014-05-18 11:08:58 -04:00
|
|
|
|
2015-11-19 08:25:53 -05:00
|
|
|
queue->q_cur %= size;
|
|
|
|
res = queue->q_tracks[queue->q_cur];
|
|
|
|
queue_selected(queue, queue->q_cur);
|
2014-05-18 11:08:58 -04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-01-26 13:44:25 -05:00
|
|
|
class SortTracks {
|
|
|
|
public:
|
2014-05-18 14:11:21 -04:00
|
|
|
std::vector<struct sort_info> fields;
|
|
|
|
SortTracks(std::vector<sort_info> f) : fields(f) {}
|
2015-10-24 19:34:45 -04:00
|
|
|
bool operator()(struct track *lhs, struct track *rhs)
|
2014-01-26 13:44:25 -05:00
|
|
|
{
|
|
|
|
return track_less_than(lhs, rhs, fields);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-12-03 13:43:15 -05:00
|
|
|
void queue_sort(struct queue *queue, enum compare_t field, bool reset)
|
2014-01-26 12:12:01 -05:00
|
|
|
{
|
2014-05-18 14:11:21 -04:00
|
|
|
bool found = false;
|
|
|
|
struct sort_info info = { field, true };
|
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;
|
2014-05-18 14:11:21 -04:00
|
|
|
if (reset)
|
2015-12-03 13:43:15 -05:00
|
|
|
queue->q_sort.clear();
|
2014-05-18 14:11:21 -04:00
|
|
|
|
2015-12-03 13:43:15 -05:00
|
|
|
for (unsigned int i = 0; i < queue->q_sort.size(); i++) {
|
|
|
|
if (queue->q_sort[i].field == info.field) {
|
|
|
|
queue->q_sort[i].ascending = !queue->q_sort[i].ascending;
|
2014-05-18 14:11:21 -04:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
2015-12-03 13:43:15 -05:00
|
|
|
queue->q_sort.push_back(info);
|
2014-01-26 14:49:07 -05:00
|
|
|
|
2015-12-03 13:43:15 -05:00
|
|
|
std::stable_sort(queue->q_tracks.begin(),
|
|
|
|
queue->q_tracks.end(),
|
|
|
|
SortTracks(queue->q_sort));
|
2014-01-26 14:44:56 -05:00
|
|
|
|
2015-12-03 13:43:15 -05:00
|
|
|
for (unsigned int i = 0; i < queue->q_tracks.size(); i++)
|
|
|
|
queue->q_notify->on_track_updated(i);
|
|
|
|
__queue_save(queue, Q_SAVE_SORT);
|
2014-01-26 12:12:01 -05:00
|
|
|
}
|