diff options
Diffstat (limited to 'src/playlist/include')
| -rw-r--r-- | src/playlist/include/shuffler.hpp | 68 | ||||
| -rw-r--r-- | src/playlist/include/source.hpp | 105 |
2 files changed, 173 insertions, 0 deletions
diff --git a/src/playlist/include/shuffler.hpp b/src/playlist/include/shuffler.hpp new file mode 100644 index 00000000..affc6301 --- /dev/null +++ b/src/playlist/include/shuffler.hpp @@ -0,0 +1,68 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <deque> +#include <memory> +#include <mutex> +#include <variant> +#include <vector> + +#include "bloom_filter.hpp" +#include "database.hpp" +#include "future_fetcher.hpp" +#include "random.hpp" +#include "source.hpp" +#include "track.hpp" + +namespace playlist { + +/* + * A source composes of other sources and/or specific extra tracks. Supports + * iteration over its contents in a random order. + */ +class Shuffler : public ISource { + public: + static auto Create() -> Shuffler*; + + explicit Shuffler( + util::IRandom* random, + std::unique_ptr<util::BloomFilter<database::TrackId>> filter); + + auto Current() -> std::optional<database::TrackId> override; + auto Advance() -> std::optional<database::TrackId> override; + auto Peek(std::size_t, std::vector<database::TrackId>*) + -> std::size_t override; + + typedef std::variant<database::TrackId, std::shared_ptr<IResetableSource>> + Item; + auto Add(Item) -> void; + + /* + * Returns the enqueued items, starting from the current item, in their + * original insertion order. + */ + auto Unshuffle() -> std::vector<Item>; + + // Not copyable or movable. + + Shuffler(const Shuffler&) = delete; + Shuffler& operator=(const Shuffler&) = delete; + + private: + auto RefillBuffer() -> void; + + util::IRandom* random_; + + std::unique_ptr<util::BloomFilter<database::TrackId>> already_played_; + bool out_of_items_; + + std::deque<Item> ordered_items_; + std::deque<database::TrackId> shuffled_items_buffer_; +}; + +} // namespace playlist diff --git a/src/playlist/include/source.hpp b/src/playlist/include/source.hpp new file mode 100644 index 00000000..069c1e93 --- /dev/null +++ b/src/playlist/include/source.hpp @@ -0,0 +1,105 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <deque> +#include <memory> +#include <mutex> +#include <variant> +#include <vector> + +#include "bloom_filter.hpp" +#include "database.hpp" +#include "future_fetcher.hpp" +#include "random.hpp" +#include "track.hpp" + +namespace playlist { + +/* + * Stateful interface for iterating over a collection of tracks by id. + */ +class ISource { + public: + virtual ~ISource() {} + + virtual auto Current() -> std::optional<database::TrackId> = 0; + + /* + * Discards the current track id and continues to the next in this source. + * Returns the new current track id. + */ + virtual auto Advance() -> std::optional<database::TrackId> = 0; + + /* + * Repeatedly advances until a track with the given id is the current track. + * Returns false if this source ran out of tracks before the requested id + * was encounted, true otherwise. + */ + virtual auto AdvanceTo(database::TrackId id) -> bool { + for (auto t = Current(); t.has_value(); t = Advance()) { + if (*t == id) { + return true; + } + } + return false; + } + + /* + * Places the next n tracks into the given vector, in order. Does not change + * the value returned by Current(). + */ + virtual auto Peek(std::size_t n, std::vector<database::TrackId>*) + -> std::size_t = 0; +}; + +/* + * A Source that supports restarting iteration from its original initial + * value. + */ +class IResetableSource : public ISource { + public: + virtual ~IResetableSource() {} + + virtual auto Previous() -> std::optional<database::TrackId> = 0; + + /* + * Restarts iteration from this source's initial value. + */ + virtual auto Reset() -> void = 0; +}; + +class IndexRecordSource : public IResetableSource { + public: + IndexRecordSource(std::weak_ptr<database::Database> db, + std::shared_ptr<database::Result<database::IndexRecord>>); + + IndexRecordSource(std::weak_ptr<database::Database> db, + std::shared_ptr<database::Result<database::IndexRecord>>, + std::size_t, + std::shared_ptr<database::Result<database::IndexRecord>>, + std::size_t); + + auto Current() -> std::optional<database::TrackId> override; + auto Advance() -> std::optional<database::TrackId> override; + auto Peek(std::size_t n, std::vector<database::TrackId>*) + -> std::size_t override; + + auto Previous() -> std::optional<database::TrackId> override; + auto Reset() -> void override; + + private: + std::weak_ptr<database::Database> db_; + + std::shared_ptr<database::Result<database::IndexRecord>> initial_page_; + ssize_t initial_item_; + + std::shared_ptr<database::Result<database::IndexRecord>> current_page_; + ssize_t current_item_; +}; + +} // namespace playlist |
