You need to sign in or sign up before continuing.
Queue.hxx 8.4 KB
Newer Older
1
/*
2
 * Copyright (C) 2003-2013 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13
 * 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.
14 15 16 17
 *
 * 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.
18 19
 */

20 21
#ifndef MPD_QUEUE_HXX
#define MPD_QUEUE_HXX
22

23
#include "Compiler.h"
24
#include "IdTable.hxx"
25
#include "util/LazyRandomEngine.hxx"
26

Max Kellermann's avatar
Max Kellermann committed
27 28
#include <algorithm>

29 30 31
#include <assert.h>
#include <stdint.h>

32 33
struct Song;

34 35 36 37 38 39 40 41 42 43 44
/**
 * 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 {
45
	/**
46
	 * reserve max_length * HASH_MULT elements in the id
47 48
	 * number space
	 */
49
	static constexpr unsigned HASH_MULT = 4;
50 51 52 53 54

	/**
	 * One element of the queue: basically a song plus some queue specific
	 * information attached.
	 */
55
	struct Item {
56
		Song *song;
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

		/** 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;
	};

72 73 74 75 76 77 78 79 80 81
	/** 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 */
82
	Item *items;
83 84 85 86

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

Max Kellermann's avatar
Max Kellermann committed
87
	/** map song ids to positions */
88
	IdTable id_table;
89 90 91 92 93

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

94 95
	/** play only current song. */
	bool single;
96

97 98 99
	/** remove each played files. */
	bool consume;

100 101 102 103
	/** play back songs in random order? */
	bool random;

	/** random number generator for shuffle and random mode */
104
	LazyRandomEngine rand;
105 106 107 108 109 110 111 112 113 114 115

	queue(unsigned max_length);

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

	queue(const queue &other) = delete;
	queue &operator=(const queue &other) = delete;
116

117 118
	unsigned GetLength() const {
		assert(length <= max_length);
119

120 121
		return length;
	}
122

123 124 125 126 127 128
	/**
	 * Determine if the queue is empty, i.e. there are no songs.
	 */
	bool IsEmpty() const {
		return length == 0;
	}
129

130 131 132 133 134
	/**
	 * Determine if the maximum number of songs has been reached.
	 */
	bool IsFull() const {
		assert(length <= max_length);
135

136 137
		return length >= max_length;
	}
138

139 140 141 142 143 144
	/**
	 * Is that a valid position number?
	 */
	bool IsValidPosition(unsigned position) const {
		return position < length;
	}
145

146 147 148 149 150
	/**
	 * Is that a valid order number?
	 */
	bool IsValidOrder(unsigned _order) const {
		return _order < length;
151 152
	}

153
	int IdToPosition(unsigned id) const {
154
		return id_table.IdToPosition(id);
155
	}
156

157 158 159
	int PositionToId(unsigned position) const
	{
		assert(position < length);
160

161 162
		return items[position].id;
	}
163

164 165 166
	gcc_pure
	unsigned OrderToPosition(unsigned _order) const {
		assert(_order < length);
167

168 169
		return order[_order];
	}
170

171 172 173
	gcc_pure
	unsigned PositionToOrder(unsigned position) const {
		assert(position < length);
174

175 176
		for (unsigned i = 0;; ++i) {
			assert(i < length);
177

178 179 180 181
			if (order[i] == position)
				return i;
		}
	}
182

183
	gcc_pure
184 185
	uint8_t GetPriorityAtPosition(unsigned position) const {
		assert(position < length);
186

187 188
		return items[position].priority;
	}
189

190
	const Item &GetOrderItem(unsigned i) const {
191 192 193 194 195 196 197 198 199
		assert(IsValidOrder(i));

		return items[OrderToPosition(i)];
	}

	uint8_t GetOrderPriority(unsigned i) const {
		return GetOrderItem(i).priority;
	}

200 201 202
	/**
	 * Returns the song at the specified position.
	 */
203
	Song &Get(unsigned position) const {
204
		assert(position < length);
205

206
		return *items[position].song;
207
	}
208

209 210 211
	/**
	 * Returns the song at the specified order number.
	 */
212
	Song &GetOrder(unsigned _order) const {
213 214
		return Get(OrderToPosition(_order));
	}
215

216 217 218 219 220 221
	/**
	 * Is the song at the specified position newer than the specified
	 * version?
	 */
	bool IsNewerAtPosition(unsigned position, uint32_t _version) const {
		assert(position < length);
222

223 224 225 226
		return _version > version ||
			items[position].version >= _version ||
			items[position].version == 0;
	}
227

228 229 230 231 232 233 234 235
	/**
	 * 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
	 */
	gcc_pure
	int GetNextOrder(unsigned order) const;
236

237 238 239 240 241
	/**
	 * Increments the queue's version number.  This handles integer
	 * overflow well.
	 */
	void IncrementVersion();
242

243 244 245 246 247 248 249 250 251 252 253
	/**
	 * Marks the specified song as "modified".  Call
	 * IncrementVersion() after all modifications have been made.
	 * number.
	 */
	void ModifyAtPosition(unsigned position) {
		assert(position < length);

		items[position].version = version;
	}

254
	/**
255 256
	 * Marks the specified song as "modified".  Call
	 * IncrementVersion() after all modifications have been made.
257 258 259
	 * number.
	 */
	void ModifyAtOrder(unsigned order);
260

261 262 263 264 265
	/**
	 * 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
266 267
	 * Song::IsInDatabase()), it is freed when removed from the
	 * queue.
268 269 270
	 *
	 * @param priority the priority of this new queue item
	 */
271
	unsigned Append(Song *song, uint8_t priority);
272

273 274 275 276
	/**
	 * Swaps two songs, addressed by their position.
	 */
	void SwapPositions(unsigned position1, unsigned position2);
277

278 279 280 281
	/**
	 * Swaps two songs, addressed by their order number.
	 */
	void SwapOrders(unsigned order1, unsigned order2) {
Max Kellermann's avatar
Max Kellermann committed
282
		std::swap(order[order1], order[order2]);
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
	/**
	 * Moves a song to a new position.
	 */
	void MovePostion(unsigned from, unsigned to);

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

	/**
	 * Removes a song from the playlist.
	 */
	void DeletePosition(unsigned position);

	/**
	 * Removes all songs from the playlist.
	 */
	void Clear();

	/**
	 * Initializes the "order" array, and restores "normal" order.
	 */
	void RestoreOrder() {
		for (unsigned i = 0; i < length; ++i)
			order[i] = i;
	}

313 314 315 316 317 318
	/**
	 * Shuffle the order of items in the specified range, ignoring
	 * their priorities.
	 */
	void ShuffleOrderRange(unsigned start, unsigned end);

319 320 321 322 323 324 325 326 327 328 329 330
	/**
	 * Shuffle the order of items in the specified range, taking their
	 * priorities into account.
	 */
	void ShuffleOrderRangeWithPriority(unsigned start, unsigned end);

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

331 332
	void ShuffleOrderFirst(unsigned start, unsigned end);

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
	/**
	 * 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 ShuffleOrderLast(unsigned start, unsigned end);

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

	bool SetPriority(unsigned position, uint8_t priority, int after_order);

	bool SetPriorityRange(unsigned start_position, unsigned end_position,
			      uint8_t priority, int after_order);
350 351 352 353 354 355 356 357 358 359 360 361

private:
	/**
	 * Moves a song to a new position in the "order" list.
	 */
	void MoveOrder(unsigned from_order, unsigned to_order);

	void MoveItemTo(unsigned from, unsigned to) {
		unsigned from_id = items[from].id;

		items[to] = items[from];
		items[to].version = version;
362
		id_table.Move(from_id, to);
363 364 365 366 367 368 369 370 371 372 373 374 375
	}

	/**
	 * Find the first item that has this specified priority or
	 * higher.
	 */
	gcc_pure
	unsigned FindPriorityOrder(unsigned start_order, uint8_t priority,
				   unsigned exclude_order) const;

	gcc_pure
	unsigned CountSamePriority(unsigned start_order,
				   uint8_t priority) const;
376
};
377

378
#endif