Commit 10824204 authored by Max Kellermann's avatar Max Kellermann

queue: convert all functions to methods

parent 70652abf
...@@ -36,7 +36,7 @@ extern "C" { ...@@ -36,7 +36,7 @@ extern "C" {
void void
playlist_increment_version_all(struct playlist *playlist) playlist_increment_version_all(struct playlist *playlist)
{ {
queue_modify_all(&playlist->queue); playlist->queue.ModifyAll();
idle_add(IDLE_PLAYLIST); idle_add(IDLE_PLAYLIST);
} }
...@@ -48,7 +48,7 @@ playlist_tag_changed(struct playlist *playlist) ...@@ -48,7 +48,7 @@ playlist_tag_changed(struct playlist *playlist)
assert(playlist->current >= 0); assert(playlist->current >= 0);
queue_modify(&playlist->queue, playlist->current); playlist->queue.ModifyAtOrder(playlist->current);
idle_add(IDLE_PLAYLIST); idle_add(IDLE_PLAYLIST);
} }
...@@ -61,12 +61,12 @@ playlist_queue_song_order(struct playlist *playlist, struct player_control *pc, ...@@ -61,12 +61,12 @@ playlist_queue_song_order(struct playlist *playlist, struct player_control *pc,
{ {
char *uri; char *uri;
assert(queue_valid_order(&playlist->queue, order)); assert(playlist->queue.IsValidOrder(order));
playlist->queued = order; playlist->queued = order;
struct song *song = struct song *song =
song_dup_detached(queue_get_order(&playlist->queue, order)); song_dup_detached(playlist->queue.GetOrder(order));
uri = song_get_uri(song); uri = song_get_uri(song);
g_debug("queue song %i:\"%s\"", playlist->queued, uri); g_debug("queue song %i:\"%s\"", playlist->queued, uri);
...@@ -93,8 +93,7 @@ playlist_song_started(struct playlist *playlist, struct player_control *pc) ...@@ -93,8 +93,7 @@ playlist_song_started(struct playlist *playlist, struct player_control *pc)
if(playlist->queue.consume) if(playlist->queue.consume)
playlist_delete(playlist, pc, playlist_delete(playlist, pc,
queue_order_to_position(&playlist->queue, playlist->queue.OrderToPosition(current));
current));
idle_add(IDLE_PLAYER); idle_add(IDLE_PLAYER);
} }
...@@ -105,7 +104,7 @@ playlist_get_queued_song(struct playlist *playlist) ...@@ -105,7 +104,7 @@ playlist_get_queued_song(struct playlist *playlist)
if (!playlist->playing || playlist->queued < 0) if (!playlist->playing || playlist->queued < 0)
return NULL; return NULL;
return queue_get_order(&playlist->queue, playlist->queued); return playlist->queue.GetOrder(playlist->queued);
} }
void void
...@@ -119,11 +118,11 @@ playlist_update_queued_song(struct playlist *playlist, ...@@ -119,11 +118,11 @@ playlist_update_queued_song(struct playlist *playlist,
if (!playlist->playing) if (!playlist->playing)
return; return;
assert(!queue_is_empty(&playlist->queue)); assert(!playlist->queue.IsEmpty());
assert((playlist->queued < 0) == (prev == NULL)); assert((playlist->queued < 0) == (prev == NULL));
next_order = playlist->current >= 0 next_order = playlist->current >= 0
? queue_next_order(&playlist->queue, playlist->current) ? playlist->queue.GetNextOrder(playlist->current)
: 0; : 0;
if (next_order == 0 && playlist->queue.random && if (next_order == 0 && playlist->queue.random &&
...@@ -132,21 +131,19 @@ playlist_update_queued_song(struct playlist *playlist, ...@@ -132,21 +131,19 @@ playlist_update_queued_song(struct playlist *playlist,
order each time the playlist is played order each time the playlist is played
completely */ completely */
unsigned current_position = unsigned current_position =
queue_order_to_position(&playlist->queue, playlist->queue.OrderToPosition(playlist->current);
playlist->current);
queue_shuffle_order(&playlist->queue); playlist->queue.ShuffleOrder();
/* make sure that the playlist->current still points to /* make sure that the playlist->current still points to
the current song, after the song order has been the current song, after the song order has been
shuffled */ shuffled */
playlist->current = playlist->current =
queue_position_to_order(&playlist->queue, playlist->queue.PositionToOrder(current_position);
current_position);
} }
if (next_order >= 0) if (next_order >= 0)
next_song = queue_get_order(&playlist->queue, next_order); next_song = playlist->queue.GetOrder(next_order);
else else
next_song = NULL; next_song = NULL;
...@@ -174,7 +171,7 @@ playlist_play_order(struct playlist *playlist, struct player_control *pc, ...@@ -174,7 +171,7 @@ playlist_play_order(struct playlist *playlist, struct player_control *pc,
playlist->queued = -1; playlist->queued = -1;
struct song *song = struct song *song =
song_dup_detached(queue_get_order(&playlist->queue, orderNum)); song_dup_detached(playlist->queue.GetOrder(orderNum));
uri = song_get_uri(song); uri = song_get_uri(song);
g_debug("play %i:\"%s\"", orderNum, uri); g_debug("play %i:\"%s\"", orderNum, uri);
...@@ -247,7 +244,7 @@ playlist_resume_playback(struct playlist *playlist, struct player_control *pc) ...@@ -247,7 +244,7 @@ playlist_resume_playback(struct playlist *playlist, struct player_control *pc)
if ((playlist->stop_on_error && error != PLAYER_ERROR_NONE) || if ((playlist->stop_on_error && error != PLAYER_ERROR_NONE) ||
error == PLAYER_ERROR_OUTPUT || error == PLAYER_ERROR_OUTPUT ||
playlist->error_count >= queue_length(&playlist->queue)) playlist->error_count >= playlist->queue.GetLength())
/* too many errors, or critical error: stop /* too many errors, or critical error: stop
playback */ playback */
playlist_stop(playlist, pc); playlist_stop(playlist, pc);
...@@ -306,10 +303,9 @@ playlist_order(struct playlist *playlist) ...@@ -306,10 +303,9 @@ playlist_order(struct playlist *playlist)
{ {
if (playlist->current >= 0) if (playlist->current >= 0)
/* update playlist.current, order==position now */ /* update playlist.current, order==position now */
playlist->current = queue_order_to_position(&playlist->queue, playlist->current = playlist->queue.OrderToPosition(playlist->current);
playlist->current);
queue_restore_order(&playlist->queue); playlist->queue.RestoreOrder();
} }
void void
...@@ -362,20 +358,18 @@ playlist_set_random(struct playlist *playlist, struct player_control *pc, ...@@ -362,20 +358,18 @@ playlist_set_random(struct playlist *playlist, struct player_control *pc,
int current_position = int current_position =
playlist->playing && playlist->current >= 0 playlist->playing && playlist->current >= 0
? (int)queue_order_to_position(&playlist->queue, ? (int)playlist->queue.OrderToPosition(playlist->current)
playlist->current)
: -1; : -1;
queue_shuffle_order(&playlist->queue); playlist->queue.ShuffleOrder();
if (current_position >= 0) { if (current_position >= 0) {
/* make sure the current song is the first in /* make sure the current song is the first in
the order list, so the whole rest of the the order list, so the whole rest of the
playlist is played after that */ playlist is played after that */
unsigned current_order = unsigned current_order =
queue_position_to_order(&playlist->queue, playlist->queue.PositionToOrder(current_position);
current_position); playlist->queue.SwapOrders(0, current_order);
queue_swap_order(&playlist->queue, 0, current_order);
playlist->current = 0; playlist->current = 0;
} else } else
playlist->current = -1; playlist->current = -1;
...@@ -391,8 +385,7 @@ int ...@@ -391,8 +385,7 @@ int
playlist_get_current_song(const struct playlist *playlist) playlist_get_current_song(const struct playlist *playlist)
{ {
if (playlist->current >= 0) if (playlist->current >= 0)
return queue_order_to_position(&playlist->queue, return playlist->queue.OrderToPosition(playlist->current);
playlist->current);
return -1; return -1;
} }
...@@ -403,13 +396,11 @@ playlist_get_next_song(const struct playlist *playlist) ...@@ -403,13 +396,11 @@ playlist_get_next_song(const struct playlist *playlist)
if (playlist->current >= 0) if (playlist->current >= 0)
{ {
if (playlist->queue.single == 1 && playlist->queue.repeat == 1) if (playlist->queue.single == 1 && playlist->queue.repeat == 1)
return queue_order_to_position(&playlist->queue, return playlist->queue.OrderToPosition(playlist->current);
playlist->current); else if (playlist->current + 1 < (int)playlist->queue.GetLength())
else if (playlist->current + 1 < (int)queue_length(&playlist->queue)) return playlist->queue.OrderToPosition(playlist->current + 1);
return queue_order_to_position(&playlist->queue,
playlist->current + 1);
else if (playlist->queue.repeat == 1) else if (playlist->queue.repeat == 1)
return queue_order_to_position(&playlist->queue, 0); return playlist->queue.OrderToPosition(0);
} }
return -1; return -1;
...@@ -424,11 +415,11 @@ playlist_get_version(const struct playlist *playlist) ...@@ -424,11 +415,11 @@ playlist_get_version(const struct playlist *playlist)
int int
playlist_get_length(const struct playlist *playlist) playlist_get_length(const struct playlist *playlist)
{ {
return queue_length(&playlist->queue); return playlist->queue.GetLength();
} }
unsigned unsigned
playlist_get_song_id(const struct playlist *playlist, unsigned song) playlist_get_song_id(const struct playlist *playlist, unsigned song)
{ {
return queue_position_to_id(&playlist->queue, song); return playlist->queue.PositionToId(song);
} }
...@@ -50,16 +50,14 @@ playlist_stop(struct playlist *playlist, struct player_control *pc) ...@@ -50,16 +50,14 @@ playlist_stop(struct playlist *playlist, struct player_control *pc)
result in a new random order */ result in a new random order */
unsigned current_position = unsigned current_position =
queue_order_to_position(&playlist->queue, playlist->queue.OrderToPosition(playlist->current);
playlist->current);
queue_shuffle_order(&playlist->queue); playlist->queue.ShuffleOrder();
/* make sure that "current" stays valid, and the next /* make sure that "current" stays valid, and the next
"play" command plays the same song again */ "play" command plays the same song again */
playlist->current = playlist->current =
queue_position_to_order(&playlist->queue, playlist->queue.PositionToOrder(current_position);
current_position);
} }
} }
...@@ -74,7 +72,7 @@ playlist_play(struct playlist *playlist, struct player_control *pc, ...@@ -74,7 +72,7 @@ playlist_play(struct playlist *playlist, struct player_control *pc,
if (song == -1) { if (song == -1) {
/* play any song ("current" song, or the first song */ /* play any song ("current" song, or the first song */
if (queue_is_empty(&playlist->queue)) if (playlist->queue.IsEmpty())
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
if (playlist->playing) { if (playlist->playing) {
...@@ -88,7 +86,7 @@ playlist_play(struct playlist *playlist, struct player_control *pc, ...@@ -88,7 +86,7 @@ playlist_play(struct playlist *playlist, struct player_control *pc,
i = playlist->current >= 0 i = playlist->current >= 0
? playlist->current ? playlist->current
: 0; : 0;
} else if (!queue_valid_position(&playlist->queue, song)) } else if (!playlist->queue.IsValidPosition(song))
return PLAYLIST_RESULT_BAD_RANGE; return PLAYLIST_RESULT_BAD_RANGE;
if (playlist->queue.random) { if (playlist->queue.random) {
...@@ -97,15 +95,14 @@ playlist_play(struct playlist *playlist, struct player_control *pc, ...@@ -97,15 +95,14 @@ playlist_play(struct playlist *playlist, struct player_control *pc,
would be equal to the order number in would be equal to the order number in
no-random mode); convert it to a order no-random mode); convert it to a order
number, because random mode is enabled */ number, because random mode is enabled */
i = queue_position_to_order(&playlist->queue, song); i = playlist->queue.PositionToOrder(song);
if (!playlist->playing) if (!playlist->playing)
playlist->current = 0; playlist->current = 0;
/* swap the new song with the previous "current" one, /* swap the new song with the previous "current" one,
so playback continues as planned */ so playback continues as planned */
queue_swap_order(&playlist->queue, playlist->queue.SwapOrders(i, playlist->current);
i, playlist->current);
i = playlist->current; i = playlist->current;
} }
...@@ -126,7 +123,7 @@ playlist_play_id(struct playlist *playlist, struct player_control *pc, ...@@ -126,7 +123,7 @@ playlist_play_id(struct playlist *playlist, struct player_control *pc,
return playlist_play(playlist, pc, id); return playlist_play(playlist, pc, id);
} }
song = queue_id_to_position(&playlist->queue, id); song = playlist->queue.IdToPosition(id);
if (song < 0) if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
...@@ -142,15 +139,15 @@ playlist_next(struct playlist *playlist, struct player_control *pc) ...@@ -142,15 +139,15 @@ playlist_next(struct playlist *playlist, struct player_control *pc)
if (!playlist->playing) if (!playlist->playing)
return; return;
assert(!queue_is_empty(&playlist->queue)); assert(!playlist->queue.IsEmpty());
assert(queue_valid_order(&playlist->queue, playlist->current)); assert(playlist->queue.IsValidOrder(playlist->current));
current = playlist->current; current = playlist->current;
playlist->stop_on_error = false; playlist->stop_on_error = false;
/* determine the next song from the queue's order list */ /* determine the next song from the queue's order list */
next_order = queue_next_order(&playlist->queue, playlist->current); next_order = playlist->queue.GetNextOrder(playlist->current);
if (next_order < 0) { if (next_order < 0) {
/* no song after this one: stop playback */ /* no song after this one: stop playback */
playlist_stop(playlist, pc); playlist_stop(playlist, pc);
...@@ -167,7 +164,7 @@ playlist_next(struct playlist *playlist, struct player_control *pc) ...@@ -167,7 +164,7 @@ playlist_next(struct playlist *playlist, struct player_control *pc)
songs in a different than before */ songs in a different than before */
assert(playlist->queue.repeat); assert(playlist->queue.repeat);
queue_shuffle_order(&playlist->queue); playlist->queue.ShuffleOrder();
/* note that playlist->current and playlist->queued are /* note that playlist->current and playlist->queued are
now invalid, but playlist_play_order() will now invalid, but playlist_play_order() will
...@@ -180,8 +177,7 @@ playlist_next(struct playlist *playlist, struct player_control *pc) ...@@ -180,8 +177,7 @@ playlist_next(struct playlist *playlist, struct player_control *pc)
/* Consume mode removes each played songs. */ /* Consume mode removes each played songs. */
if(playlist->queue.consume) if(playlist->queue.consume)
playlist_delete(playlist, pc, playlist_delete(playlist, pc,
queue_order_to_position(&playlist->queue, playlist->queue.OrderToPosition(current));
current));
} }
void void
...@@ -190,7 +186,7 @@ playlist_previous(struct playlist *playlist, struct player_control *pc) ...@@ -190,7 +186,7 @@ playlist_previous(struct playlist *playlist, struct player_control *pc)
if (!playlist->playing) if (!playlist->playing)
return; return;
assert(queue_length(&playlist->queue) > 0); assert(playlist->queue.GetLength() > 0);
if (playlist->current > 0) { if (playlist->current > 0) {
/* play the preceding song */ /* play the preceding song */
...@@ -199,7 +195,7 @@ playlist_previous(struct playlist *playlist, struct player_control *pc) ...@@ -199,7 +195,7 @@ playlist_previous(struct playlist *playlist, struct player_control *pc)
} else if (playlist->queue.repeat) { } else if (playlist->queue.repeat) {
/* play the last song in "repeat" mode */ /* play the last song in "repeat" mode */
playlist_play_order(playlist, pc, playlist_play_order(playlist, pc,
queue_length(&playlist->queue) - 1); playlist->queue.GetLength() - 1);
} else { } else {
/* re-start playing the current song if it's /* re-start playing the current song if it's
the first one */ the first one */
...@@ -215,13 +211,13 @@ playlist_seek_song(struct playlist *playlist, struct player_control *pc, ...@@ -215,13 +211,13 @@ playlist_seek_song(struct playlist *playlist, struct player_control *pc,
unsigned i; unsigned i;
bool success; bool success;
if (!queue_valid_position(&playlist->queue, song)) if (!playlist->queue.IsValidPosition(song))
return PLAYLIST_RESULT_BAD_RANGE; return PLAYLIST_RESULT_BAD_RANGE;
queued = playlist_get_queued_song(playlist); queued = playlist_get_queued_song(playlist);
if (playlist->queue.random) if (playlist->queue.random)
i = queue_position_to_order(&playlist->queue, song); i = playlist->queue.PositionToOrder(song);
else else
i = song; i = song;
...@@ -240,7 +236,7 @@ playlist_seek_song(struct playlist *playlist, struct player_control *pc, ...@@ -240,7 +236,7 @@ playlist_seek_song(struct playlist *playlist, struct player_control *pc,
} }
struct song *the_song = struct song *the_song =
song_dup_detached(queue_get_order(&playlist->queue, i)); song_dup_detached(playlist->queue.GetOrder(i));
success = pc_seek(pc, the_song, seek_time); success = pc_seek(pc, the_song, seek_time);
if (!success) { if (!success) {
playlist_update_queued_song(playlist, pc, queued); playlist_update_queued_song(playlist, pc, queued);
...@@ -258,7 +254,7 @@ enum playlist_result ...@@ -258,7 +254,7 @@ enum playlist_result
playlist_seek_song_id(struct playlist *playlist, struct player_control *pc, playlist_seek_song_id(struct playlist *playlist, struct player_control *pc,
unsigned id, float seek_time) unsigned id, float seek_time)
{ {
int song = queue_id_to_position(&playlist->queue, id); int song = playlist->queue.IdToPosition(id);
if (song < 0) if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
......
...@@ -41,7 +41,7 @@ playlist_print_uris(Client *client, const struct playlist *playlist) ...@@ -41,7 +41,7 @@ playlist_print_uris(Client *client, const struct playlist *playlist)
{ {
const struct queue *queue = &playlist->queue; const struct queue *queue = &playlist->queue;
queue_print_uris(client, queue, 0, queue_length(queue)); queue_print_uris(client, queue, 0, queue->GetLength());
} }
bool bool
...@@ -50,9 +50,9 @@ playlist_print_info(Client *client, const struct playlist *playlist, ...@@ -50,9 +50,9 @@ playlist_print_info(Client *client, const struct playlist *playlist,
{ {
const struct queue *queue = &playlist->queue; const struct queue *queue = &playlist->queue;
if (end > queue_length(queue)) if (end > queue->GetLength())
/* correct the "end" offset */ /* correct the "end" offset */
end = queue_length(queue); end = queue->GetLength();
if (start > end) if (start > end)
/* an invalid "start" offset is fatal */ /* an invalid "start" offset is fatal */
...@@ -69,7 +69,7 @@ playlist_print_id(Client *client, const struct playlist *playlist, ...@@ -69,7 +69,7 @@ playlist_print_id(Client *client, const struct playlist *playlist,
const struct queue *queue = &playlist->queue; const struct queue *queue = &playlist->queue;
int position; int position;
position = queue_id_to_position(queue, id); position = queue->IdToPosition(id);
if (position < 0) if (position < 0)
/* no such song */ /* no such song */
return false; return false;
......
...@@ -98,8 +98,8 @@ spl_save_queue(const char *name_utf8, const struct queue *queue) ...@@ -98,8 +98,8 @@ spl_save_queue(const char *name_utf8, const struct queue *queue)
if (file == NULL) if (file == NULL)
return PLAYLIST_RESULT_ERRNO; return PLAYLIST_RESULT_ERRNO;
for (unsigned i = 0; i < queue_length(queue); i++) for (unsigned i = 0; i < queue->GetLength(); i++)
playlist_print_song(file, queue_get(queue, i)); playlist_print_song(file, queue->Get(i));
fclose(file); fclose(file);
......
...@@ -74,8 +74,7 @@ playlist_state_save(FILE *fp, const struct playlist *playlist, ...@@ -74,8 +74,7 @@ playlist_state_save(FILE *fp, const struct playlist *playlist,
fputs(PLAYLIST_STATE_FILE_STATE_PLAY "\n", fp); fputs(PLAYLIST_STATE_FILE_STATE_PLAY "\n", fp);
} }
fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n", fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n",
queue_order_to_position(&playlist->queue, playlist->queue.OrderToPosition(playlist->current));
playlist->current));
fprintf(fp, PLAYLIST_STATE_FILE_TIME "%i\n", fprintf(fp, PLAYLIST_STATE_FILE_TIME "%i\n",
(int)player_status.elapsed_time); (int)player_status.elapsed_time);
} else { } else {
...@@ -83,8 +82,7 @@ playlist_state_save(FILE *fp, const struct playlist *playlist, ...@@ -83,8 +82,7 @@ playlist_state_save(FILE *fp, const struct playlist *playlist,
if (playlist->current >= 0) if (playlist->current >= 0)
fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n", fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n",
queue_order_to_position(&playlist->queue, playlist->queue.OrderToPosition(playlist->current));
playlist->current));
} }
fprintf(fp, PLAYLIST_STATE_FILE_RANDOM "%i\n", playlist->queue.random); fprintf(fp, PLAYLIST_STATE_FILE_RANDOM "%i\n", playlist->queue.random);
...@@ -123,7 +121,7 @@ playlist_state_load(TextFile &file, struct playlist *playlist) ...@@ -123,7 +121,7 @@ playlist_state_load(TextFile &file, struct playlist *playlist)
} }
} }
queue_increment_version(&playlist->queue); playlist->queue.IncrementVersion();
} }
bool bool
...@@ -195,8 +193,8 @@ playlist_state_restore(const char *line, TextFile &file, ...@@ -195,8 +193,8 @@ playlist_state_restore(const char *line, TextFile &file,
playlist_set_random(playlist, pc, random_mode); playlist_set_random(playlist, pc, random_mode);
if (!queue_is_empty(&playlist->queue)) { if (!playlist->queue.IsEmpty()) {
if (!queue_valid_position(&playlist->queue, current)) if (!playlist->queue.IsValidPosition(current))
current = 0; current = 0;
if (state == PLAYER_STATE_PLAY && if (state == PLAYER_STATE_PLAY &&
...@@ -239,8 +237,7 @@ playlist_state_get_hash(const struct playlist *playlist, ...@@ -239,8 +237,7 @@ playlist_state_get_hash(const struct playlist *playlist,
? ((int)player_status.elapsed_time << 8) ? ((int)player_status.elapsed_time << 8)
: 0) ^ : 0) ^
(playlist->current >= 0 (playlist->current >= 0
? (queue_order_to_position(&playlist->queue, ? (playlist->queue.OrderToPosition(playlist->current) << 16)
playlist->current) << 16)
: 0) ^ : 0) ^
((int)pc_get_cross_fade(pc) << 20) ^ ((int)pc_get_cross_fade(pc) << 20) ^
(player_status.state << 24) ^ (player_status.state << 24) ^
......
...@@ -20,10 +20,11 @@ ...@@ -20,10 +20,11 @@
#ifndef MPD_QUEUE_HXX #ifndef MPD_QUEUE_HXX
#define MPD_QUEUE_HXX #define MPD_QUEUE_HXX
#include "gcc.h"
#include <glib.h> #include <glib.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
enum { enum {
...@@ -110,169 +111,141 @@ struct queue { ...@@ -110,169 +111,141 @@ struct queue {
queue(const queue &other) = delete; queue(const queue &other) = delete;
queue &operator=(const queue &other) = delete; queue &operator=(const queue &other) = delete;
};
static inline unsigned unsigned GetLength() const {
queue_length(const struct queue *queue) assert(length <= max_length);
{
assert(queue->length <= queue->max_length);
return queue->length; return length;
} }
/** /**
* Determine if the queue is empty, i.e. there are no songs. * Determine if the queue is empty, i.e. there are no songs.
*/ */
static inline bool bool IsEmpty() const {
queue_is_empty(const struct queue *queue) return length == 0;
{ }
return queue->length == 0;
}
/** /**
* Determine if the maximum number of songs has been reached. * Determine if the maximum number of songs has been reached.
*/ */
static inline bool bool IsFull() const {
queue_is_full(const struct queue *queue) assert(length <= max_length);
{
assert(queue->length <= queue->max_length);
return queue->length >= queue->max_length; return length >= max_length;
} }
/** /**
* Is that a valid position number? * Is that a valid position number?
*/ */
static inline bool bool IsValidPosition(unsigned position) const {
queue_valid_position(const struct queue *queue, unsigned position) return position < length;
{ }
return position < queue->length;
}
/** /**
* Is that a valid order number? * Is that a valid order number?
*/ */
static inline bool bool IsValidOrder(unsigned _order) const {
queue_valid_order(const struct queue *queue, unsigned order) return _order < length;
{ }
return order < queue->length;
} int IdToPosition(unsigned id) const {
if (id >= max_length * QUEUE_HASH_MULT)
static inline int
queue_id_to_position(const struct queue *queue, unsigned id)
{
if (id >= queue->max_length * QUEUE_HASH_MULT)
return -1; return -1;
assert(queue->id_to_position[id] >= -1); assert(id_to_position[id] >= -1);
assert(queue->id_to_position[id] < (int)queue->length); assert(id_to_position[id] < (int)length);
return queue->id_to_position[id]; return id_to_position[id];
} }
static inline int int PositionToId(unsigned position) const
queue_position_to_id(const struct queue *queue, unsigned position) {
{ assert(position < length);
assert(position < queue->length);
return queue->items[position].id; return items[position].id;
} }
static inline unsigned gcc_pure
queue_order_to_position(const struct queue *queue, unsigned order) unsigned OrderToPosition(unsigned _order) const {
{ assert(_order < length);
assert(order < queue->length);
return queue->order[order]; return order[_order];
} }
static inline unsigned gcc_pure
queue_position_to_order(const struct queue *queue, unsigned position) unsigned PositionToOrder(unsigned position) const {
{ assert(position < length);
assert(position < queue->length);
for (unsigned i = 0;; ++i) { for (unsigned i = 0;; ++i) {
assert(i < queue->length); assert(i < length);
if (queue->order[i] == position) if (order[i] == position)
return i; return i;
} }
} }
G_GNUC_PURE G_GNUC_PURE
static inline uint8_t uint8_t GetPriorityAtPosition(unsigned position) const {
queue_get_priority_at_position(const struct queue *queue, unsigned position) assert(position < length);
{
assert(position < queue->length);
return queue->items[position].priority; return items[position].priority;
} }
/** /**
* Returns the song at the specified position. * Returns the song at the specified position.
*/ */
static inline struct song * struct song *Get(unsigned position) const {
queue_get(const struct queue *queue, unsigned position) assert(position < length);
{
assert(position < queue->length);
return queue->items[position].song; return items[position].song;
} }
/** /**
* Returns the song at the specified order number. * Returns the song at the specified order number.
*/ */
static inline struct song * struct song *GetOrder(unsigned _order) const {
queue_get_order(const struct queue *queue, unsigned order) return Get(OrderToPosition(_order));
{ }
return queue_get(queue, queue_order_to_position(queue, order));
}
/** /**
* Is the song at the specified position newer than the specified * Is the song at the specified position newer than the specified
* version? * version?
*/ */
static inline bool bool IsNewerAtPosition(unsigned position, uint32_t _version) const {
queue_song_newer(const struct queue *queue, unsigned position, assert(position < length);
uint32_t version)
{
assert(position < queue->length);
return version > queue->version || return _version > version ||
queue->items[position].version >= version || items[position].version >= _version ||
queue->items[position].version == 0; items[position].version == 0;
} }
/** /**
* Returns the order number following the specified one. This takes * Returns the order number following the specified one. This takes
* end of queue and "repeat" mode into account. * end of queue and "repeat" mode into account.
* *
* @return the next order number, or -1 to stop playback * @return the next order number, or -1 to stop playback
*/ */
int gcc_pure
queue_next_order(const struct queue *queue, unsigned order); int GetNextOrder(unsigned order) const;
/** /**
* Increments the queue's version number. This handles integer * Increments the queue's version number. This handles integer
* overflow well. * overflow well.
*/ */
void void IncrementVersion();
queue_increment_version(struct queue *queue);
/** /**
* Marks the specified song as "modified" and increments the version * Marks the specified song as "modified" and increments the version
* number. * number.
*/ */
void void ModifyAtOrder(unsigned order);
queue_modify(struct queue *queue, unsigned order);
/** /**
* Marks all songs as "modified" and increments the version number. * Marks all songs as "modified" and increments the version number.
*/ */
void void ModifyAll();
queue_modify_all(struct queue *queue);
/** /**
* Appends a song to the queue and returns its position. Prior to * Appends a song to the queue and returns its position. Prior to
* that, the caller must check if the queue is already full. * that, the caller must check if the queue is already full.
* *
...@@ -281,97 +254,79 @@ queue_modify_all(struct queue *queue); ...@@ -281,97 +254,79 @@ queue_modify_all(struct queue *queue);
* *
* @param priority the priority of this new queue item * @param priority the priority of this new queue item
*/ */
unsigned unsigned Append(struct song *song, uint8_t priority);
queue_append(struct queue *queue, struct song *song, uint8_t priority);
/** /**
* Swaps two songs, addressed by their position. * Swaps two songs, addressed by their position.
*/ */
void void SwapPositions(unsigned position1, unsigned position2);
queue_swap(struct queue *queue, unsigned position1, unsigned position2);
/** /**
* Swaps two songs, addressed by their order number. * Swaps two songs, addressed by their order number.
*/ */
static inline void void SwapOrders(unsigned order1, unsigned order2) {
queue_swap_order(struct queue *queue, unsigned order1, unsigned order2) unsigned tmp = order[order1];
{ order[order1] = order[order2];
unsigned tmp = queue->order[order1]; order[order2] = tmp;
queue->order[order1] = queue->order[order2]; }
queue->order[order2] = tmp;
}
/** /**
* Moves a song to a new position. * Moves a song to a new position.
*/ */
void void MovePostion(unsigned from, unsigned to);
queue_move(struct queue *queue, unsigned from, unsigned to);
/** /**
* Moves a range of songs to a new position. * Moves a range of songs to a new position.
*/ */
void void MoveRange(unsigned start, unsigned end, unsigned to);
queue_move_range(struct queue *queue, unsigned start, unsigned end, unsigned to);
/** /**
* Removes a song from the playlist. * Removes a song from the playlist.
*/ */
void void DeletePosition(unsigned position);
queue_delete(struct queue *queue, unsigned position);
/** /**
* Removes all songs from the playlist. * Removes all songs from the playlist.
*/ */
void void Clear();
queue_clear(struct queue *queue);
/** /**
* Initializes the "order" array, and restores "normal" order. * Initializes the "order" array, and restores "normal" order.
*/ */
static inline void void RestoreOrder() {
queue_restore_order(struct queue *queue) for (unsigned i = 0; i < length; ++i)
{ order[i] = i;
for (unsigned i = 0; i < queue->length; ++i) }
queue->order[i] = i;
}
/** /**
* Shuffle the order of items in the specified range, taking their * Shuffle the order of items in the specified range, taking their
* priorities into account. * priorities into account.
*/ */
void void ShuffleOrderRangeWithPriority(unsigned start, unsigned end);
queue_shuffle_order_range_with_priority(struct queue *queue,
unsigned start, unsigned end);
/** /**
* Shuffles the virtual order of songs, but does not move them * Shuffles the virtual order of songs, but does not move them
* physically. This is used in random mode. * physically. This is used in random mode.
*/ */
void void ShuffleOrder();
queue_shuffle_order(struct queue *queue);
/** /**
* Shuffles the virtual order of the last song in the specified * Shuffles the virtual order of the last song in the specified
* (order) range. This is used in random mode after a song has been * (order) range. This is used in random mode after a song has been
* appended by queue_append(). * appended by queue_append().
*/ */
void void ShuffleOrderLast(unsigned start, unsigned end);
queue_shuffle_order_last(struct queue *queue, unsigned start, unsigned end);
/** /**
* Shuffles a (position) range in the queue. The songs are physically * Shuffles a (position) range in the queue. The songs are physically
* shuffled, not by using the "order" mapping. * shuffled, not by using the "order" mapping.
*/ */
void void ShuffleRange(unsigned start, unsigned end);
queue_shuffle_range(struct queue *queue, unsigned start, unsigned end);
bool bool SetPriority(unsigned position, uint8_t priority, int after_order);
queue_set_priority(struct queue *queue, unsigned position,
uint8_t priority, int after_order);
bool bool SetPriorityRange(unsigned start_position, unsigned end_position,
queue_set_priority_range(struct queue *queue,
unsigned start_position, unsigned end_position,
uint8_t priority, int after_order); uint8_t priority, int after_order);
};
#endif #endif
...@@ -171,7 +171,7 @@ enum command_return ...@@ -171,7 +171,7 @@ enum command_return
handle_shuffle(G_GNUC_UNUSED Client *client, handle_shuffle(G_GNUC_UNUSED Client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{ {
unsigned start = 0, end = queue_length(&client->playlist.queue); unsigned start = 0, end = client->playlist.queue.GetLength();
if (argc == 2 && !check_range(client, &start, &end, argv[1])) if (argc == 2 && !check_range(client, &start, &end, argv[1]))
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
......
...@@ -41,11 +41,11 @@ static void ...@@ -41,11 +41,11 @@ static void
queue_print_song_info(Client *client, const struct queue *queue, queue_print_song_info(Client *client, const struct queue *queue,
unsigned position) unsigned position)
{ {
song_print_info(client, queue_get(queue, position)); song_print_info(client, queue->Get(position));
client_printf(client, "Pos: %u\nId: %u\n", client_printf(client, "Pos: %u\nId: %u\n",
position, queue_position_to_id(queue, position)); position, queue->PositionToId(position));
uint8_t priority = queue_get_priority_at_position(queue, position); uint8_t priority = queue->GetPriorityAtPosition(position);
if (priority != 0) if (priority != 0)
client_printf(client, "Prio: %u\n", priority); client_printf(client, "Prio: %u\n", priority);
} }
...@@ -55,7 +55,7 @@ queue_print_info(Client *client, const struct queue *queue, ...@@ -55,7 +55,7 @@ queue_print_info(Client *client, const struct queue *queue,
unsigned start, unsigned end) unsigned start, unsigned end)
{ {
assert(start <= end); assert(start <= end);
assert(end <= queue_length(queue)); assert(end <= queue->GetLength());
for (unsigned i = start; i < end; ++i) for (unsigned i = start; i < end; ++i)
queue_print_song_info(client, queue, i); queue_print_song_info(client, queue, i);
...@@ -66,11 +66,11 @@ queue_print_uris(Client *client, const struct queue *queue, ...@@ -66,11 +66,11 @@ queue_print_uris(Client *client, const struct queue *queue,
unsigned start, unsigned end) unsigned start, unsigned end)
{ {
assert(start <= end); assert(start <= end);
assert(end <= queue_length(queue)); assert(end <= queue->GetLength());
for (unsigned i = start; i < end; ++i) { for (unsigned i = start; i < end; ++i) {
client_printf(client, "%i:", i); client_printf(client, "%i:", i);
song_print_uri(client, queue_get(queue, i)); song_print_uri(client, queue->Get(i));
} }
} }
...@@ -78,8 +78,8 @@ void ...@@ -78,8 +78,8 @@ void
queue_print_changes_info(Client *client, const struct queue *queue, queue_print_changes_info(Client *client, const struct queue *queue,
uint32_t version) uint32_t version)
{ {
for (unsigned i = 0; i < queue_length(queue); i++) { for (unsigned i = 0; i < queue->GetLength(); i++) {
if (queue_song_newer(queue, i, version)) if (queue->IsNewerAtPosition(i, version))
queue_print_song_info(client, queue, i); queue_print_song_info(client, queue, i);
} }
} }
...@@ -88,18 +88,18 @@ void ...@@ -88,18 +88,18 @@ void
queue_print_changes_position(Client *client, const struct queue *queue, queue_print_changes_position(Client *client, const struct queue *queue,
uint32_t version) uint32_t version)
{ {
for (unsigned i = 0; i < queue_length(queue); i++) for (unsigned i = 0; i < queue->GetLength(); i++)
if (queue_song_newer(queue, i, version)) if (queue->IsNewerAtPosition(i, version))
client_printf(client, "cpos: %i\nId: %i\n", client_printf(client, "cpos: %i\nId: %i\n",
i, queue_position_to_id(queue, i)); i, queue->PositionToId(i));
} }
void void
queue_find(Client *client, const struct queue *queue, queue_find(Client *client, const struct queue *queue,
const SongFilter &filter) const SongFilter &filter)
{ {
for (unsigned i = 0; i < queue_length(queue); i++) { for (unsigned i = 0; i < queue->GetLength(); i++) {
const struct song *song = queue_get(queue, i); const struct song *song = queue->Get(i);
if (filter.Match(*song)) if (filter.Match(*song))
queue_print_song_info(client, queue, i); queue_print_song_info(client, queue, i);
......
...@@ -61,19 +61,19 @@ queue_save_song(FILE *fp, int idx, const struct song *song) ...@@ -61,19 +61,19 @@ queue_save_song(FILE *fp, int idx, const struct song *song)
void void
queue_save(FILE *fp, const struct queue *queue) queue_save(FILE *fp, const struct queue *queue)
{ {
for (unsigned i = 0; i < queue_length(queue); i++) { for (unsigned i = 0; i < queue->GetLength(); i++) {
uint8_t prio = queue_get_priority_at_position(queue, i); uint8_t prio = queue->GetPriorityAtPosition(i);
if (prio != 0) if (prio != 0)
fprintf(fp, PRIO_LABEL "%u\n", prio); fprintf(fp, PRIO_LABEL "%u\n", prio);
queue_save_song(fp, i, queue_get(queue, i)); queue_save_song(fp, i, queue->Get(i));
} }
} }
void void
queue_load_song(TextFile &file, const char *line, queue *queue) queue_load_song(TextFile &file, const char *line, queue *queue)
{ {
if (queue_is_full(queue)) if (queue->IsFull())
return; return;
uint8_t priority = 0; uint8_t priority = 0;
...@@ -123,7 +123,7 @@ queue_load_song(TextFile &file, const char *line, queue *queue) ...@@ -123,7 +123,7 @@ queue_load_song(TextFile &file, const char *line, queue *queue)
} }
} }
queue_append(queue, song, priority); queue->Append(song, priority);
if (db != nullptr) if (db != nullptr)
db->ReturnSong(song); db->ReturnSong(song);
......
...@@ -23,21 +23,21 @@ G_GNUC_UNUSED ...@@ -23,21 +23,21 @@ G_GNUC_UNUSED
static void static void
dump_order(const struct queue *queue) dump_order(const struct queue *queue)
{ {
g_printerr("queue length=%u, order:\n", queue_length(queue)); g_printerr("queue length=%u, order:\n", queue->GetLength());
for (unsigned i = 0; i < queue_length(queue); ++i) for (unsigned i = 0; i < queue->GetLength(); ++i)
g_printerr(" [%u] -> %u (prio=%u)\n", i, queue->order[i], g_printerr(" [%u] -> %u (prio=%u)\n", i, queue->order[i],
queue->items[queue->order[i]].priority); queue->items[queue->order[i]].priority);
} }
static void static void
check_descending_priority(G_GNUC_UNUSED const struct queue *queue, check_descending_priority(const struct queue *queue,
unsigned start_order) unsigned start_order)
{ {
assert(start_order < queue_length(queue)); assert(start_order < queue->GetLength());
uint8_t last_priority = 0xff; uint8_t last_priority = 0xff;
for (unsigned order = start_order; order < queue_length(queue); ++order) { for (unsigned order = start_order; order < queue->GetLength(); ++order) {
unsigned position = queue_order_to_position(queue, order); unsigned position = queue->OrderToPosition(order);
uint8_t priority = queue->items[position].priority; uint8_t priority = queue->items[position].priority;
assert(priority <= last_priority); assert(priority <= last_priority);
(void)last_priority; (void)last_priority;
...@@ -48,74 +48,74 @@ check_descending_priority(G_GNUC_UNUSED const struct queue *queue, ...@@ -48,74 +48,74 @@ check_descending_priority(G_GNUC_UNUSED const struct queue *queue,
int int
main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
{ {
struct song songs[16]; static struct song songs[16];
struct queue queue(32); struct queue queue(32);
for (unsigned i = 0; i < G_N_ELEMENTS(songs); ++i) for (unsigned i = 0; i < G_N_ELEMENTS(songs); ++i)
queue_append(&queue, &songs[i], 0); queue.Append(&songs[i], 0);
assert(queue_length(&queue) == G_N_ELEMENTS(songs)); assert(queue.GetLength() == G_N_ELEMENTS(songs));
/* priority=10 for 4 items */ /* priority=10 for 4 items */
queue_set_priority_range(&queue, 4, 8, 10, -1); queue.SetPriorityRange(4, 8, 10, -1);
queue.random = true; queue.random = true;
queue_shuffle_order(&queue); queue.ShuffleOrder();
check_descending_priority(&queue, 0); check_descending_priority(&queue, 0);
for (unsigned i = 0; i < 4; ++i) { for (unsigned i = 0; i < 4; ++i) {
assert(queue_position_to_order(&queue, i) >= 4); assert(queue.PositionToOrder(i) >= 4);
} }
for (unsigned i = 4; i < 8; ++i) { for (unsigned i = 4; i < 8; ++i) {
assert(queue_position_to_order(&queue, i) < 4); assert(queue.PositionToOrder(i) < 4);
} }
for (unsigned i = 8; i < G_N_ELEMENTS(songs); ++i) { for (unsigned i = 8; i < G_N_ELEMENTS(songs); ++i) {
assert(queue_position_to_order(&queue, i) >= 4); assert(queue.PositionToOrder(i) >= 4);
} }
/* priority=50 one more item */ /* priority=50 one more item */
queue_set_priority_range(&queue, 15, 16, 50, -1); queue.SetPriorityRange(15, 16, 50, -1);
check_descending_priority(&queue, 0); check_descending_priority(&queue, 0);
assert(queue_position_to_order(&queue, 15) == 0); assert(queue.PositionToOrder(15) == 0);
for (unsigned i = 0; i < 4; ++i) { for (unsigned i = 0; i < 4; ++i) {
assert(queue_position_to_order(&queue, i) >= 4); assert(queue.PositionToOrder(i) >= 4);
} }
for (unsigned i = 4; i < 8; ++i) { for (unsigned i = 4; i < 8; ++i) {
assert(queue_position_to_order(&queue, i) >= 1 && assert(queue.PositionToOrder(i) >= 1 &&
queue_position_to_order(&queue, i) < 5); queue.PositionToOrder(i) < 5);
} }
for (unsigned i = 8; i < 15; ++i) { for (unsigned i = 8; i < 15; ++i) {
assert(queue_position_to_order(&queue, i) >= 5); assert(queue.PositionToOrder(i) >= 5);
} }
/* priority=20 for one of the 4 priority=10 items */ /* priority=20 for one of the 4 priority=10 items */
queue_set_priority_range(&queue, 3, 4, 20, -1); queue.SetPriorityRange(3, 4, 20, -1);
check_descending_priority(&queue, 0); check_descending_priority(&queue, 0);
assert(queue_position_to_order(&queue, 3) == 1); assert(queue.PositionToOrder(3) == 1);
assert(queue_position_to_order(&queue, 15) == 0); assert(queue.PositionToOrder(15) == 0);
for (unsigned i = 0; i < 3; ++i) { for (unsigned i = 0; i < 3; ++i) {
assert(queue_position_to_order(&queue, i) >= 5); assert(queue.PositionToOrder(i) >= 5);
} }
for (unsigned i = 4; i < 8; ++i) { for (unsigned i = 4; i < 8; ++i) {
assert(queue_position_to_order(&queue, i) >= 2 && assert(queue.PositionToOrder(i) >= 2 &&
queue_position_to_order(&queue, i) < 6); queue.PositionToOrder(i) < 6);
} }
for (unsigned i = 8; i < 15; ++i) { for (unsigned i = 8; i < 15; ++i) {
assert(queue_position_to_order(&queue, i) >= 6); assert(queue.PositionToOrder(i) >= 6);
} }
/* priority=20 for another one of the 4 priority=10 items; /* priority=20 for another one of the 4 priority=10 items;
...@@ -124,17 +124,17 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) ...@@ -124,17 +124,17 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
unsigned current_order = 4; unsigned current_order = 4;
unsigned current_position = unsigned current_position =
queue_order_to_position(&queue, current_order); queue.OrderToPosition(current_order);
unsigned a_order = 3; unsigned a_order = 3;
unsigned a_position = queue_order_to_position(&queue, a_order); unsigned a_position = queue.OrderToPosition(a_order);
assert(queue.items[a_position].priority == 10); assert(queue.items[a_position].priority == 10);
queue_set_priority(&queue, a_position, 20, current_order); queue.SetPriority(a_position, 20, current_order);
current_order = queue_position_to_order(&queue, current_position); current_order = queue.PositionToOrder(current_position);
assert(current_order == 3); assert(current_order == 3);
a_order = queue_position_to_order(&queue, a_position); a_order = queue.PositionToOrder(a_position);
assert(a_order == 4); assert(a_order == 4);
check_descending_priority(&queue, current_order + 1); check_descending_priority(&queue, current_order + 1);
...@@ -144,14 +144,14 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) ...@@ -144,14 +144,14 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
just created */ just created */
unsigned b_order = 10; unsigned b_order = 10;
unsigned b_position = queue_order_to_position(&queue, b_order); unsigned b_position = queue.OrderToPosition(b_order);
assert(queue.items[b_position].priority == 0); assert(queue.items[b_position].priority == 0);
queue_set_priority(&queue, b_position, 70, current_order); queue.SetPriority(b_position, 70, current_order);
current_order = queue_position_to_order(&queue, current_position); current_order = queue.PositionToOrder(current_position);
assert(current_order == 3); assert(current_order == 3);
b_order = queue_position_to_order(&queue, b_position); b_order = queue.PositionToOrder(b_position);
assert(b_order == 4); assert(b_order == 4);
check_descending_priority(&queue, current_order + 1); check_descending_priority(&queue, current_order + 1);
...@@ -161,27 +161,26 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) ...@@ -161,27 +161,26 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
hasn't changed (it was already higher before) */ hasn't changed (it was already higher before) */
unsigned c_order = 0; unsigned c_order = 0;
unsigned c_position = queue_order_to_position(&queue, c_order); unsigned c_position = queue.OrderToPosition(c_order);
assert(queue.items[c_position].priority == 50); assert(queue.items[c_position].priority == 50);
queue_set_priority(&queue, c_position, 60, current_order); queue.SetPriority(c_position, 60, current_order);
current_order = queue_position_to_order(&queue, current_position); current_order = queue.PositionToOrder(current_position);
assert(current_order == 3); assert(current_order == 3);
c_order = queue_position_to_order(&queue, c_position); c_order = queue.PositionToOrder(c_position);
assert(c_order == 0); assert(c_order == 0);
/* move the prio=20 item back */ /* move the prio=20 item back */
a_order = queue_position_to_order(&queue, a_position); a_order = queue.PositionToOrder(a_position);
assert(a_order == 5); assert(a_order == 5);
assert(queue.items[a_position].priority == 20); assert(queue.items[a_position].priority == 20);
queue_set_priority(&queue, a_position, 5, current_order); queue.SetPriority(a_position, 5, current_order);
current_order = queue.PositionToOrder(current_position);
current_order = queue_position_to_order(&queue, current_position);
assert(current_order == 3); assert(current_order == 3);
a_order = queue_position_to_order(&queue, a_position); a_order = queue.PositionToOrder(a_position);
assert(a_order == 6); assert(a_order == 6);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment