use SongIterator

This commit is contained in:
Andrzej Rybczak
2014-11-01 19:45:19 +01:00
parent 485e6ee4a3
commit 4ad5c33f32
10 changed files with 138 additions and 100 deletions

View File

@@ -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);

View File

@@ -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)

View File

@@ -350,14 +350,15 @@ void MediaLibrary::update()
Mpd.StartSearch(true);
Mpd.AddSearch(Config.media_lib_primary_tag, primary_tag);
std::map<std::tuple<std::string, std::string>, 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));

View File

@@ -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<Song &>(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<mpd_connection> 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<std::string> &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<std::string> 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)

View File

@@ -152,8 +152,10 @@ struct SongIterator : std::iterator<std::forward_iterator_tag, Song>
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<std::forward_iterator_tag, Song>
}
private:
SongIterator(std::shared_ptr<mpd_connection> conn) : m_connection(std::move(conn)) { }
SongIterator(std::shared_ptr<mpd_connection> conn);
std::shared_ptr<mpd_connection> 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<void(Item)> ItemConsumer;
typedef std::function<void(Output)> OutputConsumer;
typedef std::function<void(Song)> 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<std::string> &);
@@ -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);

View File

@@ -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));
});
}
}

View File

@@ -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;
}

View File

@@ -44,6 +44,14 @@ struct 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;
virtual std::string getURI(unsigned idx = 0) const;

View File

@@ -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();

View File

@@ -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();