mpd: make Iterator more flexible
This commit is contained in:
@@ -29,6 +29,58 @@
|
|||||||
|
|
||||||
MPD::Connection Mpd;
|
MPD::Connection Mpd;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool fetchItem(MPD::ItemIterator::State &state)
|
||||||
|
{
|
||||||
|
auto src = mpd_recv_entity(state.connection());
|
||||||
|
if (src != nullptr)
|
||||||
|
{
|
||||||
|
state.setObject(src);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fetchPlaylist(MPD::PlaylistIterator::State &state)
|
||||||
|
{
|
||||||
|
auto src = mpd_recv_playlist(state.connection());
|
||||||
|
if (src != nullptr)
|
||||||
|
{
|
||||||
|
state.setObject(src);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fetchSong(MPD::SongIterator::State &state)
|
||||||
|
{
|
||||||
|
auto src = mpd_recv_song(state.connection());
|
||||||
|
if (src != nullptr)
|
||||||
|
{
|
||||||
|
state.setObject(src);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fetchOutput(MPD::OutputIterator::State &state)
|
||||||
|
{
|
||||||
|
auto src = mpd_recv_output(state.connection());
|
||||||
|
if (src != nullptr)
|
||||||
|
{
|
||||||
|
state.setObject(src);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace MPD {
|
namespace MPD {
|
||||||
|
|
||||||
Connection::Connection() : m_connection(nullptr),
|
Connection::Connection() : m_connection(nullptr),
|
||||||
@@ -295,7 +347,7 @@ SongIterator Connection::GetPlaylistChanges(unsigned version)
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_queue_changes_meta(m_connection.get(), version);
|
mpd_send_queue_changes_meta(m_connection.get(), version);
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return SongIterator(m_connection.get(), mpd_recv_song);
|
return SongIterator(m_connection.get(), fetchSong);
|
||||||
}
|
}
|
||||||
|
|
||||||
Song Connection::GetCurrentSong()
|
Song Connection::GetCurrentSong()
|
||||||
@@ -322,7 +374,7 @@ SongIterator Connection::GetPlaylistContent(const std::string &path)
|
|||||||
{
|
{
|
||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_playlist_meta(m_connection.get(), path.c_str());
|
mpd_send_list_playlist_meta(m_connection.get(), path.c_str());
|
||||||
SongIterator result(m_connection.get(), mpd_recv_song);
|
SongIterator result(m_connection.get(), fetchSong);
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -331,7 +383,7 @@ SongIterator Connection::GetPlaylistContentNoInfo(const std::string &path)
|
|||||||
{
|
{
|
||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_playlist(m_connection.get(), path.c_str());
|
mpd_send_list_playlist(m_connection.get(), path.c_str());
|
||||||
SongIterator result(m_connection.get(), mpd_recv_song);
|
SongIterator result(m_connection.get(), fetchSong);
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -609,7 +661,7 @@ PlaylistIterator Connection::GetPlaylists()
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_playlists(m_connection.get());
|
mpd_send_list_playlists(m_connection.get());
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return PlaylistIterator(m_connection.get(), mpd_recv_playlist);
|
return PlaylistIterator(m_connection.get(), fetchPlaylist);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::GetList(mpd_tag_type type, StringConsumer f)
|
void Connection::GetList(mpd_tag_type type, StringConsumer f)
|
||||||
@@ -661,7 +713,7 @@ SongIterator Connection::CommitSearchSongs()
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_search_commit(m_connection.get());
|
mpd_search_commit(m_connection.get());
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return SongIterator(m_connection.get(), mpd_recv_song);
|
return SongIterator(m_connection.get(), fetchSong);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::CommitSearchTags(StringConsumer f)
|
void Connection::CommitSearchTags(StringConsumer f)
|
||||||
@@ -682,7 +734,7 @@ ItemIterator Connection::GetDirectory(const std::string &directory)
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_meta(m_connection.get(), directory.c_str());
|
mpd_send_list_meta(m_connection.get(), directory.c_str());
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return ItemIterator(m_connection.get(), mpd_recv_entity);
|
return ItemIterator(m_connection.get(), fetchItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemIterator Connection::GetDirectoryRecursive(const std::string &directory)
|
ItemIterator Connection::GetDirectoryRecursive(const std::string &directory)
|
||||||
@@ -690,7 +742,7 @@ ItemIterator Connection::GetDirectoryRecursive(const std::string &directory)
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_all_meta(m_connection.get(), directory.c_str());
|
mpd_send_list_all_meta(m_connection.get(), directory.c_str());
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return ItemIterator(m_connection.get(), mpd_recv_entity);
|
return ItemIterator(m_connection.get(), fetchItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::GetDirectories(const std::string &directory, StringConsumer f)
|
void Connection::GetDirectories(const std::string &directory, StringConsumer f)
|
||||||
@@ -711,7 +763,7 @@ SongIterator Connection::GetSongs(const std::string &directory)
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_meta(m_connection.get(), directory.c_str());
|
mpd_send_list_meta(m_connection.get(), directory.c_str());
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return SongIterator(m_connection.get(), mpd_recv_song);
|
return SongIterator(m_connection.get(), fetchSong);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputIterator Connection::GetOutputs()
|
OutputIterator Connection::GetOutputs()
|
||||||
@@ -719,7 +771,7 @@ OutputIterator Connection::GetOutputs()
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_outputs(m_connection.get());
|
mpd_send_outputs(m_connection.get());
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return OutputIterator(m_connection.get(), mpd_recv_output);
|
return OutputIterator(m_connection.get(), fetchOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::EnableOutput(int id)
|
void Connection::EnableOutput(int id)
|
||||||
|
|||||||
136
src/mpdpp.h
136
src/mpdpp.h
@@ -329,16 +329,75 @@ typedef std::vector<Item> ItemList;
|
|||||||
typedef std::vector<std::string> StringList;
|
typedef std::vector<std::string> StringList;
|
||||||
typedef std::vector<Output> OutputList;
|
typedef std::vector<Output> OutputList;
|
||||||
|
|
||||||
template <typename DestT, typename SourceT>
|
template <typename ObjectT>
|
||||||
struct Iterator: std::iterator<std::input_iterator_tag, DestT>
|
struct Iterator: std::iterator<std::input_iterator_tag, ObjectT>
|
||||||
{
|
{
|
||||||
typedef SourceT *(*SourceFetcher)(mpd_connection *);
|
// shared state of the iterator
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
friend Iterator;
|
||||||
|
|
||||||
|
typedef bool (*Fetcher)(State &);
|
||||||
|
|
||||||
|
State(mpd_connection *connection, Fetcher fetcher)
|
||||||
|
: m_connection(connection)
|
||||||
|
, m_fetcher(fetcher)
|
||||||
|
{
|
||||||
|
assert(m_connection != nullptr);
|
||||||
|
assert(m_fetcher != nullptr);
|
||||||
|
}
|
||||||
|
~State()
|
||||||
|
{
|
||||||
|
mpd_response_finish(m_connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
mpd_connection *connection() const
|
||||||
|
{
|
||||||
|
return m_connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setObject(ObjectT object)
|
||||||
|
{
|
||||||
|
if (hasObject())
|
||||||
|
*m_object = std::move(object);
|
||||||
|
else
|
||||||
|
m_object.reset(new ObjectT(std::move(object)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool operator==(const State &rhs) const
|
||||||
|
{
|
||||||
|
return m_connection == rhs.m_connection
|
||||||
|
&& m_object == m_object;
|
||||||
|
}
|
||||||
|
bool operator!=(const State &rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fetch()
|
||||||
|
{
|
||||||
|
return m_fetcher(*this);
|
||||||
|
}
|
||||||
|
ObjectT &getObject() const
|
||||||
|
{
|
||||||
|
return *m_object;
|
||||||
|
}
|
||||||
|
bool hasObject() const
|
||||||
|
{
|
||||||
|
return m_object.get() != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpd_connection *m_connection;
|
||||||
|
Fetcher m_fetcher;
|
||||||
|
std::unique_ptr<ObjectT> m_object;
|
||||||
|
};
|
||||||
|
|
||||||
Iterator()
|
Iterator()
|
||||||
: m_state(nullptr)
|
: m_state(nullptr)
|
||||||
{ }
|
{ }
|
||||||
Iterator(mpd_connection *connection, SourceFetcher fetch_source)
|
Iterator(mpd_connection *connection, typename State::Fetcher fetcher)
|
||||||
: m_state(std::make_shared<State>(connection, fetch_source))
|
: m_state(std::make_shared<State>(connection, std::move(fetcher)))
|
||||||
{
|
{
|
||||||
// get the first element
|
// get the first element
|
||||||
++*this;
|
++*this;
|
||||||
@@ -350,14 +409,14 @@ struct Iterator: std::iterator<std::input_iterator_tag, DestT>
|
|||||||
m_state = nullptr;
|
m_state = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DestT &operator*() const
|
ObjectT &operator*() const
|
||||||
{
|
{
|
||||||
if (!m_state)
|
if (!m_state)
|
||||||
throw std::runtime_error("no object associated with the iterator");
|
throw std::runtime_error("no object associated with the iterator");
|
||||||
assert(m_state->hasObject());
|
assert(m_state->hasObject());
|
||||||
return m_state->getObject();
|
return m_state->getObject();
|
||||||
}
|
}
|
||||||
DestT *operator->() const
|
ObjectT *operator->() const
|
||||||
{
|
{
|
||||||
return &**this;
|
return &**this;
|
||||||
}
|
}
|
||||||
@@ -365,10 +424,7 @@ struct Iterator: std::iterator<std::input_iterator_tag, DestT>
|
|||||||
Iterator &operator++()
|
Iterator &operator++()
|
||||||
{
|
{
|
||||||
assert(m_state);
|
assert(m_state);
|
||||||
auto src = m_state->fetchSource();
|
if (!m_state->fetch())
|
||||||
if (src != nullptr)
|
|
||||||
m_state->setObject(src);
|
|
||||||
else
|
|
||||||
finish();
|
finish();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -389,63 +445,13 @@ struct Iterator: std::iterator<std::input_iterator_tag, DestT>
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct State
|
|
||||||
{
|
|
||||||
State(mpd_connection *conn, SourceFetcher fetch_source)
|
|
||||||
: m_connection(conn)
|
|
||||||
, m_fetch_source(fetch_source)
|
|
||||||
{
|
|
||||||
assert(m_connection != nullptr);
|
|
||||||
assert(m_fetch_source != nullptr);
|
|
||||||
}
|
|
||||||
~State()
|
|
||||||
{
|
|
||||||
mpd_response_finish(m_connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const State &rhs) const
|
|
||||||
{
|
|
||||||
return m_connection == rhs.m_connection
|
|
||||||
&& m_object == m_object;
|
|
||||||
}
|
|
||||||
bool operator!=(const State &rhs) const
|
|
||||||
{
|
|
||||||
return !(*this == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceT *fetchSource() const
|
|
||||||
{
|
|
||||||
return m_fetch_source(m_connection);
|
|
||||||
}
|
|
||||||
DestT &getObject() const
|
|
||||||
{
|
|
||||||
return *m_object;
|
|
||||||
}
|
|
||||||
bool hasObject() const
|
|
||||||
{
|
|
||||||
return m_object.get() != nullptr;
|
|
||||||
}
|
|
||||||
void setObject(DestT object)
|
|
||||||
{
|
|
||||||
if (hasObject())
|
|
||||||
*m_object = std::move(object);
|
|
||||||
else
|
|
||||||
m_object.reset(new DestT(std::move(object)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mpd_connection *m_connection;
|
|
||||||
SourceFetcher m_fetch_source;
|
|
||||||
std::unique_ptr<DestT> m_object;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<State> m_state;
|
std::shared_ptr<State> m_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Iterator<Item, mpd_entity> ItemIterator;
|
typedef Iterator<Item> ItemIterator;
|
||||||
typedef Iterator<Output, mpd_output> OutputIterator;
|
typedef Iterator<Output> OutputIterator;
|
||||||
typedef Iterator<Playlist, mpd_playlist> PlaylistIterator;
|
typedef Iterator<Playlist> PlaylistIterator;
|
||||||
typedef Iterator<Song, mpd_song> SongIterator;
|
typedef Iterator<Song> SongIterator;
|
||||||
|
|
||||||
class Connection
|
class Connection
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user