aboutsummaryrefslogtreecommitdiff
path: root/src/queue.h
blob: e4bfcdffaacc80d0dd5aa3d4811addc77aa753c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/*
 * Copyright (C) 2003-2011 The Music Player Daemon Project
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef QUEUE_H
#define QUEUE_H

#include <glib.h>

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>

enum {
	/**
	 * reserve max_length * QUEUE_HASH_MULT elements in the id
	 * number space
	 */
	QUEUE_HASH_MULT = 4,
};

/**
 * One element of the queue: basically a song plus some queue specific
 * information attached.
 */
struct queue_item {
	struct song *song;

	/** the unique id of this item in the queue */
	unsigned id;

	/** when was this item last changed? */
	uint32_t version;

	/**
	 * The priority of this item, between 0 and 255.  High
	 * priority value means that this song gets played first in
	 * "random" mode.
	 */
	uint8_t priority;
};

/**
 * A queue of songs.  This is the backend of the playlist: it contains
 * an ordered list of songs.
 *
 * Songs can be addressed in three possible ways:
 *
 * - the position in the queue
 * - the unique id (which stays the same, regardless of moves)
 * - the order number (which only differs from "position" in random mode)
 */
struct queue {
	/** configured maximum length of the queue */
	unsigned max_length;

	/** number of songs in the queue */
	unsigned length;

	/** the current version number */
	uint32_t version;

	/** all songs in "position" order */
	struct queue_item *items;

	/** map order numbers to positions */
	unsigned *order;

	/** map song ids to positions */
	int *id_to_position;

	/** repeat playback when the end of the queue has been
	    reached? */
	bool repeat;

	/** play only current song. */
	bool single;

	/** remove each played files. */
	bool consume;

	/** play back songs in random order? */
	bool random;

	/** random number generator for shuffle and random mode */
	GRand *rand;
};

static inline unsigned
queue_length(const struct queue *queue)
{
	assert(queue->length <= queue->max_length);

	return queue->length;
}

/**
 * Determine if the queue is empty, i.e. there are no songs.
 */
static inline bool
queue_is_empty(const struct queue *queue)
{
	return queue->length == 0;
}

/**
 * Determine if the maximum number of songs has been reached.
 */
static inline bool
queue_is_full(const struct queue *queue)
{
	assert(queue->length <= queue->max_length);

	return queue->length >= queue->max_length;
}

/**
 * Is that a valid position number?
 */
static inline bool
queue_valid_position(const struct queue *queue, unsigned position)
{
	return position < queue->length;
}

/**
 * Is that a valid order number?
 */
static inline bool
queue_valid_order(const struct queue *queue, unsigned order)
{
	return order < queue->length;
}

static inline int
queue_id_to_position(const struct queue *queue, unsigned id)
{
	if (id >= queue->max_length * QUEUE_HASH_MULT)
		return -1;

	assert(queue->id_to_position[id] >= -1);
	assert(queue->id_to_position[id] < (int)queue->length);

	return queue->id_to_position[id];
}

static inline int
queue_position_to_id(const struct queue *queue, unsigned position)
{
	assert(position < queue->length);

	return queue->items[position].id;
}

static inline unsigned
queue_order_to_position(const struct queue *queue, unsigned order)
{
	assert(order < queue->length);

	return queue->order[order];
}

static inline unsigned
queue_position_to_order(const struct queue *queue, unsigned position)
{
	assert(position < queue->length);

	for (unsigned i = 0;; ++i) {
		assert(i < queue->length);

		if (queue->order[i] == position)
			return i;
	}
}

G_GNUC_PURE
static inline uint8_t
queue_get_priority_at_position(const struct queue *queue, unsigned position)
{
	assert(position < queue->length);

	return queue->items[position].priority;
}

/**
 * Returns the song at the specified position.
 */
static inline struct song *
queue_get(const struct queue *queue, unsigned position)
{
	assert(position < queue->length);

	return queue->items[position].song;
}

/**
 * Returns the song at the specified order number.
 */
static inline struct song *
queue_get_order(const struct queue *queue, unsigned order)
{
	return queue_get(queue, queue_order_to_position(queue, order));
}

/**
 * Is the song at the specified position newer than the specified
 * version?
 */
static inline bool
queue_song_newer(const struct queue *queue, unsigned position,
		 uint32_t version)
{
	assert(position < queue->length);

	return version > queue->version ||
		queue->items[position].version >= version ||
		queue->items[position].version == 0;
}

/**
 * Initialize a queue object.
 */
void
queue_init(struct queue *queue, unsigned max_length);

/**
 * Deinitializes a queue object.  It does not free the queue pointer
 * itself.
 */
void
queue_finish(struct queue *queue);

/**
 * Returns the order number following the specified one.  This takes
 * end of queue and "repeat" mode into account.
 *
 * @return the next order number, or -1 to stop playback
 */
int
queue_next_order(const struct queue *queue, unsigned order);

/**
 * Increments the queue's version number.  This handles integer
 * overflow well.
 */
void
queue_increment_version(struct queue *queue);

/**
 * Marks the specified song as "modified" and increments the version
 * number.
 */
void
queue_modify(struct queue *queue, unsigned order);

/**
 * Marks all songs as "modified" and increments the version number.
 */
void
queue_modify_all(struct queue *queue);

/**
 * Appends a song to the queue and returns its position.  Prior to
 * that, the caller must check if the queue is already full.
 *
 * If a song is not in the database (determined by
 * song_in_database()), it is freed when removed from the queue.
 *
 * @param priority the priority of this new queue item
 */
unsigned
queue_append(struct queue *queue, struct song *song, uint8_t priority);

/**
 * Swaps two songs, addressed by their position.
 */
void
queue_swap(struct queue *queue, unsigned position1, unsigned position2);

/**
 * Swaps two songs, addressed by their order number.
 */
static inline void
queue_swap_order(struct queue *queue, unsigned order1, unsigned order2)
{
	unsigned tmp = queue->order[order1];
	queue->order[order1] = queue->order[order2];
	queue->order[order2] = tmp;
}

/**
 * Moves a song to a new position.
 */
void
queue_move(struct queue *queue, unsigned from, unsigned to);

/**
 * Moves a range of songs to a new position.
 */
void
queue_move_range(struct queue *queue, unsigned start, unsigned end, unsigned to);

/**
 * Removes a song from the playlist.
 */
void
queue_delete(struct queue *queue, unsigned position);

/**
 * Removes all songs from the playlist.
 */
void
queue_clear(struct queue *queue);

/**
 * Initializes the "order" array, and restores "normal" order.
 */
static inline void
queue_restore_order(struct queue *queue)
{
	for (unsigned i = 0; i < queue->length; ++i)
		queue->order[i] = i;
}

/**
 * Shuffle the order of items in the specified range, taking their
 * priorities into account.
 */
void
queue_shuffle_order_range_with_priority(struct queue *queue,
					unsigned start, unsigned end);

/**
 * Shuffles the virtual order of songs, but does not move them
 * physically.  This is used in random mode.
 */
void
queue_shuffle_order(struct queue *queue);

/**
 * Shuffles the virtual order of the last song in the specified
 * (order) range.  This is used in random mode after a song has been
 * appended by queue_append().
 */
void
queue_shuffle_order_last(struct queue *queue, unsigned start, unsigned end);

/**
 * Shuffles a (position) range in the queue.  The songs are physically
 * shuffled, not by using the "order" mapping.
 */
void
queue_shuffle_range(struct queue *queue, unsigned start, unsigned end);

bool
queue_set_priority(struct queue *queue, unsigned position,
		   uint8_t priority, int after_order);

bool
queue_set_priority_range(struct queue *queue,
			 unsigned start_position, unsigned end_position,
			 uint8_t priority, int after_order);

#endif