From 72726831ca640965ae81cc0d2fcc9c478f886d5d Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Sat, 1 Nov 2014 21:05:15 +0100 Subject: [PATCH] mpd: add OutputIterator --- src/mpdpp.cpp | 75 +++---------------------- src/mpdpp.h | 136 ++++++++++++++++++++++++++++++++++++++------- src/outputs.cpp | 10 ++-- src/visualizer.cpp | 14 +++-- 4 files changed, 136 insertions(+), 99 deletions(-) diff --git a/src/mpdpp.cpp b/src/mpdpp.cpp index f15e8eb2..a39a51bd 100644 --- a/src/mpdpp.cpp +++ b/src/mpdpp.cpp @@ -31,62 +31,6 @@ MPD::Connection Mpd; namespace MPD { -SongIterator::~SongIterator() -{ - if (m_connection) - finish(); -} - -void SongIterator::finish() -{ - // clean up - assert(m_connection); - mpd_response_finish(m_connection.get()); - m_song = Song(); - m_connection = nullptr; -} - -Song &SongIterator::operator*() const -{ - assert(m_connection); - assert(!m_song.empty()); - // we could make m_song a pointer to a Song and dereference here, - // but it's retarded as Song itself is essentially wrapper to - // std::shared_ptr. on the other hand, we need constness for the - // iterator to be able to play along with std::move_iterator. - return const_cast(m_song); -} - -Song *SongIterator::operator->() const -{ - return &**this; -} - -SongIterator &SongIterator::operator++() -{ - assert(m_connection); - mpd_song *s = mpd_recv_song(m_connection.get()); - if (s != nullptr) - m_song = Song(s); - else - finish(); - return *this; -} - -SongIterator SongIterator::operator++(int) -{ - SongIterator it(*this); - ++*this; - return it; -} - -SongIterator::SongIterator(std::shared_ptr conn) -: m_connection(std::move(conn)) -{ - // get the first element - ++*this; -} - Connection::Connection() : m_connection(nullptr), m_command_list_active(false), m_idle(false), @@ -354,7 +298,7 @@ SongIterator Connection::GetPlaylistChanges(unsigned version) prechecksNoCommandsList(); mpd_send_queue_changes_meta(m_connection.get(), version); checkErrors(); - return SongIterator(m_connection); + return SongIterator(m_connection, mpd_recv_song); } Song Connection::GetCurrentSong() @@ -381,7 +325,7 @@ SongIterator Connection::GetPlaylistContent(const std::string &path) { prechecksNoCommandsList(); mpd_send_list_playlist_meta(m_connection.get(), path.c_str()); - SongIterator result(m_connection); + SongIterator result(m_connection, mpd_recv_song); checkErrors(); return result; } @@ -390,7 +334,7 @@ SongIterator Connection::GetPlaylistContentNoInfo(const std::string &path) { prechecksNoCommandsList(); mpd_send_list_playlist(m_connection.get(), path.c_str()); - SongIterator result(m_connection); + SongIterator result(m_connection, mpd_recv_song); checkErrors(); return result; } @@ -720,7 +664,7 @@ SongIterator Connection::CommitSearchSongs() prechecksNoCommandsList(); mpd_search_commit(m_connection.get()); checkErrors(); - return SongIterator(m_connection); + return SongIterator(m_connection, mpd_recv_song); } void Connection::CommitSearchTags(StringConsumer f) @@ -798,20 +742,15 @@ SongIterator Connection::GetSongs(const std::string &directory) prechecksNoCommandsList(); mpd_send_list_meta(m_connection.get(), directory.c_str()); checkErrors(); - return SongIterator(m_connection); + return SongIterator(m_connection, mpd_recv_song); } -void Connection::GetOutputs(OutputConsumer f) +OutputIterator Connection::GetOutputs() { prechecksNoCommandsList(); mpd_send_outputs(m_connection.get()); - while (mpd_output *output = mpd_recv_output(m_connection.get())) - { - f(Output(mpd_output_get_name(output), mpd_output_get_enabled(output))); - mpd_output_free(output); - } - mpd_response_finish(m_connection.get()); checkErrors(); + return OutputIterator(m_connection, mpd_recv_output); } void Connection::EnableOutput(int id) diff --git a/src/mpdpp.h b/src/mpdpp.h index 35618cc2..8be0eb9a 100644 --- a/src/mpdpp.h +++ b/src/mpdpp.h @@ -131,50 +131,144 @@ struct Item struct Output { - Output(const std::string &name_, bool enabled) : m_name(name_), m_enabled(enabled) { } - - const std::string &name() const { return m_name; } - bool isEnabled() const { return m_enabled; } - + Output() { } + Output(mpd_output *output) : m_output(output, mpd_output_free) { } + + Output(const Output &rhs) : m_output(rhs.m_output) { } + Output(Output &&rhs) : m_output(std::move(rhs.m_output)) { } + Output &operator=(Output rhs) + { + m_output = std::move(rhs.m_output); + return *this; + } + + bool operator==(const Output &rhs) const + { + if (empty() && rhs.empty()) + return true; + else if (!empty() && !rhs.empty()) + return id() == rhs.id() + && std::strcmp(name(), rhs.name()) == 0 + && enabled() == rhs.enabled(); + else + return false; + } + bool operator!=(const Output &rhs) const + { + return !(*this == rhs); + } + + unsigned id() const + { + checkNonEmpty(); + return mpd_output_get_id(m_output.get()); + } + const char *name() const + { + checkNonEmpty(); + return mpd_output_get_name(m_output.get()); + } + bool enabled() const + { + checkNonEmpty(); + return mpd_output_get_enabled(m_output.get()); + } + + bool empty() const { return m_output.get() == nullptr; } + private: - std::string m_name; - bool m_enabled; + void checkNonEmpty() const + { + if (empty()) + throw std::runtime_error("No associated mpd_output object"); + } + + std::shared_ptr m_output; }; typedef std::vector ItemList; typedef std::vector StringList; typedef std::vector OutputList; -struct SongIterator : std::iterator +template +struct Iterator : std::iterator { + typedef SourceT *(*SourceFetcher)(mpd_connection *); + friend class Connection; - SongIterator() : m_connection(nullptr) { } - ~SongIterator(); + Iterator() : m_connection(nullptr), m_fetch_source(nullptr) { } + ~Iterator() + { + if (m_connection) + finish(); + } - void finish(); + void finish() + { + // clean up + assert(m_connection); + mpd_response_finish(m_connection.get()); + m_object = DestT(); + m_connection = nullptr; + } - Song &operator*() const; - Song *operator->() const; + DestT &operator*() const + { + assert(m_connection); + if (m_object.empty()) + throw std::runtime_error("empty object"); + return const_cast(m_object); + } + DestT *operator->() const + { + return &**this; + } - SongIterator &operator++(); - SongIterator operator++(int); + Iterator &operator++() + { + assert(m_connection); + assert(m_fetch_source != nullptr); + auto src = m_fetch_source(m_connection.get()); + if (src != nullptr) + m_object = DestT(src); + else + finish(); + return *this; + } + Iterator operator++(int) + { + Iterator it(*this); + ++*this; + return it; + } - bool operator==(const SongIterator &rhs) { + bool operator==(const Iterator &rhs) + { return m_connection == rhs.m_connection - && m_song == rhs.m_song; + && m_object == rhs.m_object; } - bool operator!=(const SongIterator &rhs) { + bool operator!=(const Iterator &rhs) + { return !(*this == rhs); } private: - SongIterator(std::shared_ptr conn); + Iterator(std::shared_ptr conn, SourceFetcher fetch_source) + : m_connection(std::move(conn)), m_fetch_source(fetch_source) + { + // get the first element + ++*this; + } std::shared_ptr m_connection; - Song m_song; + SourceFetcher m_fetch_source; + DestT m_object; }; +typedef Iterator SongIterator; +typedef Iterator OutputIterator; + class Connection : private boost::noncopyable { typedef std::function ItemConsumer; @@ -276,7 +370,7 @@ public: SongIterator GetSongs(const std::string &directory); void GetDirectories(const std::string &directory, StringConsumer f); - void GetOutputs(OutputConsumer f); + OutputIterator GetOutputs(); void EnableOutput(int id); void DisableOutput(int id); diff --git a/src/outputs.cpp b/src/outputs.cpp index f420238c..07b21b7b 100644 --- a/src/outputs.cpp +++ b/src/outputs.cpp @@ -70,7 +70,7 @@ std::wstring Outputs::title() void Outputs::enterPressed() { - if (w.current().value().isEnabled()) + if (w.current().value().enabled()) { Mpd.DisableOutput(w.choice()); Statusbar::printf("Output \"%s\" disabled", w.current().value().name()); @@ -99,9 +99,11 @@ void Outputs::mouseButtonPressed(MEVENT me) void Outputs::FetchList() { w.clear(); - Mpd.GetOutputs([this](MPD::Output output) { - w.addItem(output, output.isEnabled()); - }); + for (MPD::OutputIterator out = Mpd.GetOutputs(), end; out != end; ++out) + { + bool enabled = out->enabled(); + w.addItem(std::move(*out), enabled); + } if (myScreen == this) w.refresh(); } diff --git a/src/visualizer.cpp b/src/visualizer.cpp index fa4accbe..1e6d6850 100644 --- a/src/visualizer.cpp +++ b/src/visualizer.cpp @@ -458,12 +458,14 @@ void Visualizer::FindOutputID() m_output_id = -1; if (!Config.visualizer_output_name.empty()) { - size_t idx = 0; - Mpd.GetOutputs([this, &idx](MPD::Output output) { - if (output.name() == Config.visualizer_output_name) - m_output_id = idx; - ++idx; - }); + for (MPD::OutputIterator out = Mpd.GetOutputs(), end; out != end; ++out) + { + if (out->name() == Config.visualizer_output_name) + { + m_output_id = out->id(); + break; + } + } if (m_output_id == -1) Statusbar::printf("There is no output named \"%s\"", Config.visualizer_output_name); }