diff --git a/src/mpdpp.cpp b/src/mpdpp.cpp index 1eeeed36..20f86cd8 100644 --- a/src/mpdpp.cpp +++ b/src/mpdpp.cpp @@ -29,6 +29,58 @@ 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 { Connection::Connection() : m_connection(nullptr), @@ -295,7 +347,7 @@ SongIterator Connection::GetPlaylistChanges(unsigned version) prechecksNoCommandsList(); mpd_send_queue_changes_meta(m_connection.get(), version); checkErrors(); - return SongIterator(m_connection.get(), mpd_recv_song); + return SongIterator(m_connection.get(), fetchSong); } Song Connection::GetCurrentSong() @@ -322,7 +374,7 @@ SongIterator Connection::GetPlaylistContent(const std::string &path) { prechecksNoCommandsList(); 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(); return result; } @@ -331,7 +383,7 @@ SongIterator Connection::GetPlaylistContentNoInfo(const std::string &path) { prechecksNoCommandsList(); 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(); return result; } @@ -609,7 +661,7 @@ PlaylistIterator Connection::GetPlaylists() prechecksNoCommandsList(); mpd_send_list_playlists(m_connection.get()); checkErrors(); - return PlaylistIterator(m_connection.get(), mpd_recv_playlist); + return PlaylistIterator(m_connection.get(), fetchPlaylist); } void Connection::GetList(mpd_tag_type type, StringConsumer f) @@ -661,7 +713,7 @@ SongIterator Connection::CommitSearchSongs() prechecksNoCommandsList(); mpd_search_commit(m_connection.get()); checkErrors(); - return SongIterator(m_connection.get(), mpd_recv_song); + return SongIterator(m_connection.get(), fetchSong); } void Connection::CommitSearchTags(StringConsumer f) @@ -682,7 +734,7 @@ ItemIterator Connection::GetDirectory(const std::string &directory) prechecksNoCommandsList(); mpd_send_list_meta(m_connection.get(), directory.c_str()); checkErrors(); - return ItemIterator(m_connection.get(), mpd_recv_entity); + return ItemIterator(m_connection.get(), fetchItem); } ItemIterator Connection::GetDirectoryRecursive(const std::string &directory) @@ -690,7 +742,7 @@ ItemIterator Connection::GetDirectoryRecursive(const std::string &directory) prechecksNoCommandsList(); mpd_send_list_all_meta(m_connection.get(), directory.c_str()); checkErrors(); - return ItemIterator(m_connection.get(), mpd_recv_entity); + return ItemIterator(m_connection.get(), fetchItem); } void Connection::GetDirectories(const std::string &directory, StringConsumer f) @@ -711,7 +763,7 @@ SongIterator Connection::GetSongs(const std::string &directory) prechecksNoCommandsList(); mpd_send_list_meta(m_connection.get(), directory.c_str()); checkErrors(); - return SongIterator(m_connection.get(), mpd_recv_song); + return SongIterator(m_connection.get(), fetchSong); } OutputIterator Connection::GetOutputs() @@ -719,7 +771,7 @@ OutputIterator Connection::GetOutputs() prechecksNoCommandsList(); mpd_send_outputs(m_connection.get()); checkErrors(); - return OutputIterator(m_connection.get(), mpd_recv_output); + return OutputIterator(m_connection.get(), fetchOutput); } void Connection::EnableOutput(int id) diff --git a/src/mpdpp.h b/src/mpdpp.h index 70e58550..972159c6 100644 --- a/src/mpdpp.h +++ b/src/mpdpp.h @@ -329,16 +329,75 @@ typedef std::vector ItemList; typedef std::vector StringList; typedef std::vector OutputList; -template -struct Iterator: std::iterator +template +struct Iterator: std::iterator { - 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 m_object; + }; Iterator() : m_state(nullptr) { } - Iterator(mpd_connection *connection, SourceFetcher fetch_source) - : m_state(std::make_shared(connection, fetch_source)) + Iterator(mpd_connection *connection, typename State::Fetcher fetcher) + : m_state(std::make_shared(connection, std::move(fetcher))) { // get the first element ++*this; @@ -350,14 +409,14 @@ struct Iterator: std::iterator m_state = nullptr; } - DestT &operator*() const + ObjectT &operator*() const { if (!m_state) throw std::runtime_error("no object associated with the iterator"); assert(m_state->hasObject()); return m_state->getObject(); } - DestT *operator->() const + ObjectT *operator->() const { return &**this; } @@ -365,10 +424,7 @@ struct Iterator: std::iterator Iterator &operator++() { assert(m_state); - auto src = m_state->fetchSource(); - if (src != nullptr) - m_state->setObject(src); - else + if (!m_state->fetch()) finish(); return *this; } @@ -389,63 +445,13 @@ struct Iterator: std::iterator } 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 m_object; - }; - std::shared_ptr m_state; }; -typedef Iterator ItemIterator; -typedef Iterator OutputIterator; -typedef Iterator PlaylistIterator; -typedef Iterator SongIterator; +typedef Iterator ItemIterator; +typedef Iterator OutputIterator; +typedef Iterator PlaylistIterator; +typedef Iterator SongIterator; class Connection {