110 lines
2.5 KiB
C++
110 lines
2.5 KiB
C++
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
// Copyright The Music Player Daemon Project
|
|
|
|
#pragma once
|
|
|
|
#include "input/RemoteTagScanner.hxx"
|
|
#include "tag/Tag.hxx"
|
|
#include "event/InjectEvent.hxx"
|
|
#include "thread/Mutex.hxx"
|
|
#include "util/IntrusiveList.hxx"
|
|
#include "util/IntrusiveHashSet.hxx"
|
|
|
|
#include <array>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
class RemoteTagCacheHandler;
|
|
|
|
/**
|
|
* A cache for tags received via #RemoteTagScanner.
|
|
*/
|
|
class RemoteTagCache final {
|
|
static constexpr size_t MAX_SIZE = 4096;
|
|
|
|
RemoteTagCacheHandler &handler;
|
|
|
|
InjectEvent defer_invoke_handler;
|
|
|
|
Mutex mutex;
|
|
|
|
struct Item final
|
|
: public IntrusiveHashSetHook<>,
|
|
public IntrusiveListHook<>,
|
|
RemoteTagHandler
|
|
{
|
|
RemoteTagCache &parent;
|
|
|
|
const std::string uri;
|
|
|
|
std::unique_ptr<RemoteTagScanner> scanner;
|
|
|
|
Tag tag;
|
|
|
|
template<typename U>
|
|
Item(RemoteTagCache &_parent, U &&_uri) noexcept
|
|
:parent(_parent), uri(std::forward<U>(_uri)) {}
|
|
|
|
/* virtual methods from RemoteTagHandler */
|
|
void OnRemoteTag(Tag &&tag) noexcept override;
|
|
void OnRemoteTagError(std::exception_ptr e) noexcept override;
|
|
|
|
struct GetUri {
|
|
[[gnu::pure]]
|
|
std::string_view operator()(const Item &item) const noexcept {
|
|
return item.uri;
|
|
}
|
|
};
|
|
};
|
|
|
|
using ItemList = IntrusiveList<Item>;
|
|
|
|
/**
|
|
* These items have been resolved completely (successful or
|
|
* failed). All callbacks have been invoked. The oldest
|
|
* comes first in the list, and is the first one to be evicted
|
|
* if the cache is full.
|
|
*/
|
|
ItemList idle_list;
|
|
|
|
/**
|
|
* A #RemoteTagScanner instances is currently busy on fetching
|
|
* information, and we're waiting for our #RemoteTagHandler
|
|
* methods to be invoked.
|
|
*/
|
|
ItemList waiting_list;
|
|
|
|
/**
|
|
* These items have just been resolved, and the
|
|
* #RemoteTagCacheHandler is about to be invoked. After that,
|
|
* they will be moved to the #idle_list.
|
|
*/
|
|
ItemList invoke_list;
|
|
|
|
IntrusiveHashSet<
|
|
Item, 127,
|
|
IntrusiveHashSetOperators<std::hash<std::string_view>,
|
|
std::equal_to<std::string_view>,
|
|
Item::GetUri>,
|
|
IntrusiveHashSetBaseHookTraits<Item>,
|
|
IntrusiveHashSetOptions{.constant_time_size = true}> map;
|
|
|
|
public:
|
|
RemoteTagCache(EventLoop &event_loop,
|
|
RemoteTagCacheHandler &_handler) noexcept;
|
|
~RemoteTagCache() noexcept;
|
|
|
|
void Lookup(const std::string &uri) noexcept;
|
|
|
|
private:
|
|
void InvokeHandlers() noexcept;
|
|
|
|
void ScheduleInvokeHandlers() noexcept {
|
|
defer_invoke_handler.Schedule();
|
|
}
|
|
|
|
void ItemResolved(Item &item) noexcept;
|
|
};
|