diff --git a/src/actions.cpp b/src/actions.cpp index 93d9c214..97b59b6e 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -1319,30 +1319,31 @@ void EditLibraryTag::run() if (!new_tag.empty() && new_tag != myLibrary->Tags.current().value().tag()) { Statusbar::print("Updating tags..."); - Mpd.StartSearch(1); + Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, myLibrary->Tags.current().value().tag()); MPD::MutableSong::SetFunction set = tagTypeToSetFunction(Config.media_lib_primary_tag); assert(set); bool success = true; std::string dir_to_update; - Mpd.CommitSearchSongs([set, &dir_to_update, &new_tag, &success](MPD::Song s) { - if (!success) - return; - MPD::MutableSong ms = s; + for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s) + { + MPD::MutableSong ms = std::move(*s); ms.setTags(set, new_tag, Config.tags_separator); Statusbar::printf("Updating tags in \"%1%\"...", ms.getName()); std::string path = Config.mpd_music_dir + ms.getURI(); if (!Tags::write(ms)) { + success = false; const char msg[] = "Error while updating tags in \"%1%\""; Statusbar::printf(msg, wideShorten(ms.getURI(), COLS-const_strlen(msg))); - success = false; + s.finish(); + break; } if (dir_to_update.empty()) - dir_to_update = s.getURI(); + dir_to_update = ms.getURI(); else - dir_to_update = getSharedDirectory(dir_to_update, s.getURI()); - }); + dir_to_update = getSharedDirectory(dir_to_update, ms.getURI()); + }; if (success) { Mpd.UpdateDirectory(dir_to_update); diff --git a/src/browser.cpp b/src/browser.cpp index 41c1d956..8ff2cc32 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -139,8 +139,10 @@ void Browser::enterPressed() } case itPlaylist: { - MPD::SongList list; - Mpd.GetPlaylistContentNoInfo(item.name, vectorMoveInserter(list)); + MPD::SongList list( + std::make_move_iterator(Mpd.GetPlaylistContentNoInfo(item.name)), + std::make_move_iterator(MPD::SongIterator()) + ); bool success = addSongsToPlaylist(list.begin(), list.end(), true, -1); Statusbar::printf("Playlist \"%1%\" loaded%2%", item.name, withErrors(success) @@ -366,7 +368,11 @@ MPD::SongList Browser::getSelectedSongs() result.push_back(*item.song); else if (item.type == itPlaylist) { - Mpd.GetPlaylistContent(item.name, vectorMoveInserter(result)); + std::copy( + std::make_move_iterator(Mpd.GetPlaylistContent(item.name)), + std::make_move_iterator(MPD::SongIterator()), + std::back_inserter(result) + ); } }; for (auto it = w.begin(); it != w.end(); ++it) diff --git a/src/media_library.cpp b/src/media_library.cpp index 496cc3a6..12d26711 100644 --- a/src/media_library.cpp +++ b/src/media_library.cpp @@ -350,14 +350,15 @@ void MediaLibrary::update() Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, primary_tag); std::map, time_t> albums; - Mpd.CommitSearchSongs([&albums](MPD::Song s) { - auto key = std::make_tuple(s.getAlbum(), s.getDate()); + for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s) + { + auto key = std::make_tuple(s->getAlbum(), s->getDate()); auto it = albums.find(key); if (it == albums.end()) - albums[key] = s.getMTime(); + albums[key] = s->getMTime(); else - it->second = s.getMTime(); - }); + it->second = s->getMTime(); + }; withUnfilteredMenuReapplyFilter(Albums, [this, &albums, &primary_tag]() { size_t idx = 0; for (auto it = albums.begin(); it != albums.end(); ++it, ++idx) @@ -404,17 +405,17 @@ void MediaLibrary::update() } withUnfilteredMenuReapplyFilter(Songs, [this, &album]() { size_t idx = 0; - Mpd.CommitSearchSongs([this, &idx](MPD::Song s) { - bool is_playlist = myPlaylist->checkForSong(s); + for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s, ++idx) + { + bool is_playlist = myPlaylist->checkForSong(*s); if (idx < Songs.size()) { - Songs[idx].value() = s; + Songs[idx].value() = std::move(*s); Songs[idx].setBold(is_playlist); } else - Songs.addItem(s, is_playlist); - ++idx; - }); + Songs.addItem(std::move(*s), is_playlist); + }; if (idx < Songs.size()) Songs.resizeList(idx); std::sort(Songs.begin(), Songs.end(), SortSongs(!album.isAllTracksEntry())); @@ -738,7 +739,11 @@ MPD::SongList MediaLibrary::getSelectedSongs() auto tag_handler = [&result](const std::string &tag) { Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, tag); - Mpd.CommitSearchSongs(vectorMoveInserter(result)); + std::copy( + std::make_move_iterator(Mpd.CommitSearchSongs()), + std::make_move_iterator(MPD::SongIterator()), + std::back_inserter(result) + ); }; bool any_selected = false; for (auto &e : Tags) @@ -771,7 +776,11 @@ MPD::SongList MediaLibrary::getSelectedSongs() Mpd.AddSearch(MPD_TAG_ALBUM, sc.entry().album()); Mpd.AddSearch(MPD_TAG_DATE, sc.entry().date()); size_t begin = result.size(); - Mpd.CommitSearchSongs(vectorMoveInserter(result)); + std::copy( + std::make_move_iterator(Mpd.CommitSearchSongs()), + std::make_move_iterator(MPD::SongIterator()), + std::back_inserter(result) + ); std::sort(result.begin()+begin, result.end(), SortSongs(false)); } } @@ -1046,10 +1055,12 @@ void MediaLibrary::AddToPlaylist(bool add_n_play) if ((!Tags.empty() && isActiveWindow(Tags)) || (isActiveWindow(Albums) && Albums.current().value().isAllTracksEntry())) { - MPD::SongList list; Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value().tag()); - Mpd.CommitSearchSongs(vectorMoveInserter(list)); + MPD::SongList list( + std::make_move_iterator(Mpd.CommitSearchSongs()), + std::make_move_iterator(MPD::SongIterator()) + ); bool success = addSongsToPlaylist(list.begin(), list.end(), add_n_play, -1); std::string tag_type = boost::locale::to_lower( tagTypeToString(Config.media_lib_primary_tag)); diff --git a/src/mpdpp.cpp b/src/mpdpp.cpp index 7f7fa358..f15e8eb2 100644 --- a/src/mpdpp.cpp +++ b/src/mpdpp.cpp @@ -33,37 +33,43 @@ namespace MPD { SongIterator::~SongIterator() { - // if iterator wasn't fully traversed, clean up - if (m_connection.get() != nullptr) - mpd_response_finish(m_connection.get()); + if (m_connection) + finish(); } -Song &SongIterator::operator*() +void SongIterator::finish() { - assert(m_connection.get() != nullptr); - assert(!m_song.empty()); - return m_song; + // clean up + assert(m_connection); + mpd_response_finish(m_connection.get()); + m_song = Song(); + m_connection = nullptr; } -Song *SongIterator::operator->() +Song &SongIterator::operator*() const { - assert(m_connection.get() != nullptr); + assert(m_connection); assert(!m_song.empty()); - return &m_song; + // 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.get() != nullptr); + assert(m_connection); mpd_song *s = mpd_recv_song(m_connection.get()); if (s != nullptr) m_song = Song(s); else - { - mpd_response_finish(m_connection.get()); - m_song = Song(); - m_connection = nullptr; - } + finish(); return *this; } @@ -74,6 +80,13 @@ SongIterator SongIterator::operator++(int) 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), @@ -336,14 +349,12 @@ void Connection::Rename(const std::string &from, const std::string &to) checkErrors(); } -void Connection::GetPlaylistChanges(unsigned version, SongConsumer f) +SongIterator Connection::GetPlaylistChanges(unsigned version) { prechecksNoCommandsList(); mpd_send_queue_changes_meta(m_connection.get(), version); - while (mpd_song *s = mpd_recv_song(m_connection.get())) - f(Song(s)); - mpd_response_finish(m_connection.get()); checkErrors(); + return SongIterator(m_connection); } Song Connection::GetCurrentSong() @@ -366,24 +377,22 @@ Song Connection::GetSong(const std::string &path) return Song(s); } -void Connection::GetPlaylistContent(const std::string &path, SongConsumer f) +SongIterator Connection::GetPlaylistContent(const std::string &path) { prechecksNoCommandsList(); mpd_send_list_playlist_meta(m_connection.get(), path.c_str()); - while (mpd_song *s = mpd_recv_song(m_connection.get())) - f(Song(s)); - mpd_response_finish(m_connection.get()); + SongIterator result(m_connection); checkErrors(); + return result; } -void Connection::GetPlaylistContentNoInfo(const std::string &path, SongConsumer f) +SongIterator Connection::GetPlaylistContentNoInfo(const std::string &path) { prechecksNoCommandsList(); mpd_send_list_playlist(m_connection.get(), path.c_str()); - while (mpd_song *s = mpd_recv_song(m_connection.get())) - f(Song(s)); - mpd_response_finish(m_connection.get()); + SongIterator result(m_connection); checkErrors(); + return result; } void Connection::GetSupportedExtensions(std::set &acc) @@ -546,15 +555,15 @@ bool Connection::AddRandomTag(mpd_tag_type tag, size_t number) auto it = tags.begin()+rand()%(tags.size()-number); for (size_t i = 0; i < number && it != tags.end(); ++i) { - StartSearch(1); + StartSearch(true); AddSearch(tag, *it++); - SongList songs; - CommitSearchSongs([&songs](MPD::Song s) { - songs.push_back(s); - }); + std::vector paths; + MPD::SongIterator s = CommitSearchSongs(), end; + for (; s != end; ++s) + paths.push_back(s->getURI()); StartCommandsList(); - for (auto s = songs.begin(); s != songs.end(); ++s) - AddSong(*s); + for (const auto &path : paths) + AddSong(path); CommitCommandsList(); } } @@ -706,14 +715,12 @@ void Connection::AddSearchURI(const std::string &str) const mpd_search_add_uri_constraint(m_connection.get(), MPD_OPERATOR_DEFAULT, str.c_str()); } -void Connection::CommitSearchSongs(SongConsumer f) +SongIterator Connection::CommitSearchSongs() { prechecksNoCommandsList(); mpd_search_commit(m_connection.get()); - while (mpd_song *s = mpd_recv_song(m_connection.get())) - f(Song(s)); - mpd_response_finish(m_connection.get()); checkErrors(); + return SongIterator(m_connection); } void Connection::CommitSearchTags(StringConsumer f) @@ -786,14 +793,12 @@ void Connection::GetDirectories(const std::string &directory, StringConsumer f) checkErrors(); } -void Connection::GetSongs(const std::string &directory, SongConsumer f) +SongIterator Connection::GetSongs(const std::string &directory) { prechecksNoCommandsList(); mpd_send_list_meta(m_connection.get(), directory.c_str()); - while (mpd_song *s = mpd_recv_song(m_connection.get())) - f(Song(s)); - mpd_response_finish(m_connection.get()); checkErrors(); + return SongIterator(m_connection); } void Connection::GetOutputs(OutputConsumer f) diff --git a/src/mpdpp.h b/src/mpdpp.h index edee3f63..35618cc2 100644 --- a/src/mpdpp.h +++ b/src/mpdpp.h @@ -152,8 +152,10 @@ struct SongIterator : std::iterator SongIterator() : m_connection(nullptr) { } ~SongIterator(); - Song &operator*(); - Song *operator->(); + void finish(); + + Song &operator*() const; + Song *operator->() const; SongIterator &operator++(); SongIterator operator++(int); @@ -167,7 +169,7 @@ struct SongIterator : std::iterator } private: - SongIterator(std::shared_ptr conn) : m_connection(std::move(conn)) { } + SongIterator(std::shared_ptr conn); std::shared_ptr m_connection; Song m_song; @@ -175,8 +177,6 @@ private: class Connection : private boost::noncopyable { - typedef void (*ErrorHandler) (Connection *, int, const char *, void *); - typedef std::function ItemConsumer; typedef std::function OutputConsumer; typedef std::function SongConsumer; @@ -221,12 +221,12 @@ public: void Shuffle(); void ClearMainPlaylist(); - void GetPlaylistChanges(unsigned, SongConsumer f); + SongIterator GetPlaylistChanges(unsigned); Song GetCurrentSong(); Song GetSong(const std::string &); - void GetPlaylistContent(const std::string &name, SongConsumer f); - void GetPlaylistContentNoInfo(const std::string &name, SongConsumer f); + SongIterator GetPlaylistContent(const std::string &name); + SongIterator GetPlaylistContentNoInfo(const std::string &name); void GetSupportedExtensions(std::set &); @@ -266,14 +266,14 @@ public: void AddSearch(mpd_tag_type item, const std::string &str) const; void AddSearchAny(const std::string &str) const; void AddSearchURI(const std::string &str) const; - void CommitSearchSongs(SongConsumer f); + SongIterator CommitSearchSongs(); void CommitSearchTags(StringConsumer f); void GetPlaylists(StringConsumer f); void GetList(mpd_tag_type type, StringConsumer f); void GetDirectory(const std::string &directory, ItemConsumer f); void GetDirectoryRecursive(const std::string &directory, SongConsumer f); - void GetSongs(const std::string &directory, SongConsumer f); + SongIterator GetSongs(const std::string &directory); void GetDirectories(const std::string &directory, StringConsumer f); void GetOutputs(OutputConsumer f); diff --git a/src/playlist_editor.cpp b/src/playlist_editor.cpp index dcc118f0..86feb7c9 100644 --- a/src/playlist_editor.cpp +++ b/src/playlist_editor.cpp @@ -167,16 +167,18 @@ void PlaylistEditor::update() Content.clearSearchResults(); withUnfilteredMenuReapplyFilter(Content, [this]() { size_t idx = 0; - Mpd.GetPlaylistContent(Playlists.current().value(), [this, &idx](MPD::Song s) { + MPD::SongIterator s = Mpd.GetPlaylistContent(Playlists.current().value()), end; + for (; s != end; ++s, ++idx) + { + bool is_bold = myPlaylist->checkForSong(*s); if (idx < Content.size()) { - Content[idx].value() = s; - Content[idx].setBold(myPlaylist->checkForSong(s)); + Content[idx].setBold(is_bold); + Content[idx].value() = std::move(*s); } else - Content.addItem(s, myPlaylist->checkForSong(s)); - ++idx; - }); + Content.addItem(std::move(*s), is_bold); + } if (idx < Content.size()) Content.resizeList(idx); std::string title; @@ -484,14 +486,18 @@ MPD::SongList PlaylistEditor::getSelectedSongs() if (e.isSelected()) { any_selected = true; - Mpd.GetPlaylistContent(e.value(), vectorMoveInserter(result)); + std::copy( + std::make_move_iterator(Mpd.GetPlaylistContent(e.value())), + std::make_move_iterator(MPD::SongIterator()), + std::back_inserter(result) + ); } } // if no item is selected, add songs from right column if (!any_selected && !Content.empty()) { withUnfilteredMenu(Content, [this, &result]() { - result.insert(result.end(), Content.beginV(), Content.endV()); + std::copy(Content.beginV(), Content.endV(), std::back_inserter(result)); }); } } diff --git a/src/search_engine.cpp b/src/search_engine.cpp index 6c5b817b..6235c4d2 100644 --- a/src/search_engine.cpp +++ b/src/search_engine.cpp @@ -439,9 +439,8 @@ void SearchEngine::Search() Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[9]); if (!itsConstraints[10].empty()) Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[10]); - Mpd.CommitSearchSongs([this](MPD::Song s) { - w.addItem(s); - }); + for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s) + w.addItem(std::move(*s)); return; } diff --git a/src/song.h b/src/song.h index 7e280132..58a05b50 100644 --- a/src/song.h +++ b/src/song.h @@ -43,6 +43,14 @@ struct Song virtual ~Song() { } Song(mpd_song *s); + + Song(const Song &rhs) : m_song(rhs.m_song), m_hash(rhs.m_hash) { } + Song(Song &&rhs) : m_song(std::move(rhs.m_song)), m_hash(rhs.m_hash) { } + Song &operator=(Song rhs) { + m_song = std::move(rhs.m_song); + m_hash = rhs.m_hash; + return *this; + } std::string get(mpd_tag_type type, unsigned idx = 0) const; diff --git a/src/status.cpp b/src/status.cpp index b57f25f0..1a7dc353 100644 --- a/src/status.cpp +++ b/src/status.cpp @@ -398,19 +398,21 @@ void Status::Changes::playlist(unsigned previous_version) myPlaylist->main().resizeList(m_playlist_length); } - Mpd.GetPlaylistChanges(previous_version, [](MPD::Song s) { - size_t pos = s.getPosition(); + MPD::SongIterator s = Mpd.GetPlaylistChanges(previous_version), end; + for (; s != end; ++s) + { + size_t pos = s->getPosition(); + myPlaylist->registerSong(*s); if (pos < myPlaylist->main().size()) { // if song's already in playlist, replace it with a new one MPD::Song &old_s = myPlaylist->main()[pos].value(); myPlaylist->unregisterSong(old_s); - old_s = s; + old_s = std::move(*s); } else // otherwise just add it to playlist - myPlaylist->main().addItem(s); - myPlaylist->registerSong(s); - }); + myPlaylist->main().addItem(std::move(*s)); + } }); myPlaylist->reloadTotalLength(); diff --git a/src/tag_editor.cpp b/src/tag_editor.cpp index 62b1a6a0..bfe30aa6 100644 --- a/src/tag_editor.cpp +++ b/src/tag_editor.cpp @@ -252,9 +252,9 @@ void TagEditor::update() if (Tags->reallyEmpty()) { Tags->reset(); - Mpd.GetSongs(Dirs->current().value().second, [this](MPD::Song s) { - Tags->addItem(s); - }); + MPD::SongIterator s = Mpd.GetSongs(Dirs->current().value().second), end; + for (; s != end; ++s) + Tags->addItem(std::move(*s)); std::sort(Tags->beginV(), Tags->endV(), LocaleBasedSorting(std::locale(), Config.ignore_leading_the)); Tags->refresh();