ocarina/core/queue.cpp

222 lines
4.9 KiB
C++
Raw Normal View History

/**
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/queue.h>
extern "C" {
#include <core/random.h>
}
#include <core/string.h>
#include <algorithm>
#include <sstream>
static class DefaultNotifier : public QNotifier {
public:
DefaultNotifier() {};
void on_track_removed(unsigned int pos) {};
void on_track_updated(unsigned int pos) {};
} def_notify;
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;
}
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 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);
}
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);
}
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;
}
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;
}
void queue_set_flag(struct queue *queue, enum queue_flags flag)
{
queue->q_flags |= flag;
__queue_save(queue, Q_SAVE_FLAGS);
}
void queue_unset_flag(struct queue *queue, enum queue_flags flag)
{
queue->q_flags &= ~flag;
__queue_save(queue, Q_SAVE_FLAGS);
}
unsigned int queue_add(struct queue *queue, struct track *track)
{
unsigned int pos = queue_size(queue);
if (queue_has_flag(queue, Q_ADD_FRONT))
pos = 0;
else if (queue->q_sort.size() > 0)
pos = __queue_find_sorted_id(queue, track);
queue->q_tracks.insert(queue->q_tracks.begin() + pos, track);
return __queue_added(queue, track, pos);
}
void queue_remove(struct queue *queue, unsigned int index)
{
struct track *track = queue->q_tracks[index];
queue->q_tracks.erase(queue->q_tracks.begin() + index);
__queue_removed(queue, track, index);
}
void queue_remove_all(struct queue *queue, struct track *track)
{
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);
}
}
void queue_updated(struct queue *queue, struct track *track)
{
for (unsigned int i = 0; i < queue_size(queue); i++) {
if (queue->q_tracks[i] == track)
queue->q_notify->on_track_updated(i);
}
}
void queue_selected(struct queue *queue, unsigned int index)
{
queue->q_cur = index;
if (queue_has_flag(queue, Q_REPEAT) == false)
queue_remove(queue, index);
}
struct track *queue_next(struct queue *queue)
{
unsigned int size = queue_size(queue);
struct track *res;
if (!queue_has_flag(queue, Q_ENABLED))
return NULL;
else if (size == 0)
return NULL;
else if (size == 1)
queue->q_cur = 0;
else if (queue_has_flag(queue, Q_RANDOM))
queue->q_cur += random_range(1, size / 2);
else
queue->q_cur++;
queue->q_cur %= size;
res = queue->q_tracks[queue->q_cur];
queue_selected(queue, queue->q_cur);
return res;
}
class SortTracks {
public:
std::vector<struct sort_info> fields;
SortTracks(std::vector<sort_info> f) : fields(f) {}
bool operator()(struct track *lhs, struct track *rhs)
{
return track_less_than(lhs, rhs, fields);
}
};
void queue_sort(struct queue *queue, enum compare_t field, bool reset)
{
bool found = false;
struct sort_info info = { field, true };
if (queue_has_flag(queue, Q_NO_SORT))
return;
if (reset)
queue->q_sort.clear();
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;
found = true;
break;
}
}
if (!found)
queue->q_sort.push_back(info);
std::stable_sort(queue->q_tracks.begin(),
queue->q_tracks.end(),
SortTracks(queue->q_sort));
for (unsigned int i = 0; i < queue->q_tracks.size(); i++)
queue->q_notify->on_track_updated(i);
__queue_save(queue, Q_SAVE_SORT);
}