From 057922d2a610fc0b7a49fb12560b1c7f3a4726f1 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Sat, 8 Sep 2012 03:35:52 +0200 Subject: [PATCH] make use of std::locale based strings comparison --- src/media_library.cpp | 75 +++++++++++++++++++------------------ src/playlist.cpp | 4 +- src/search_engine.cpp | 6 +-- src/utility/comparators.cpp | 24 +++++++----- src/utility/comparators.h | 22 ++++------- 5 files changed, 63 insertions(+), 68 deletions(-) diff --git a/src/media_library.cpp b/src/media_library.cpp index ca2eaeae..25f9eb6a 100644 --- a/src/media_library.cpp +++ b/src/media_library.cpp @@ -71,8 +71,41 @@ void DisplayAlbums(NC::Menu &menu); void DisplayPrimaryTags(NC::Menu &menu); bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b); -bool SortAllTracks(const MPD::Song &a, const MPD::Song &b); -bool SortSearchConstraints(const SearchConstraints &a, const SearchConstraints &b); + +struct SortAllTracks { + const std::array m_gets; + LocaleStringComparison m_cmp; +public: + SortAllTracks() : m_gets({{ + &MPD::Song::getDate, + &MPD::Song::getAlbum, + &MPD::Song::getDisc + }}), m_cmp(std::locale(""), Config.ignore_leading_the) { } + bool operator()(const MPD::Song &a, const MPD::Song &b) { + for (auto get = m_gets.begin(); get != m_gets.end(); ++get) { + int ret = m_cmp(a.getTags(*get), b.getTags(*get)); + if (ret != 0) + return ret < 0; + } + return a.getTrack() < b.getTrack(); + } +}; + +class SortSearchConstraints { + LocaleStringComparison m_cmp; +public: + SortSearchConstraints() : m_cmp(std::locale(""), Config.ignore_leading_the) { } + bool operator()(const SearchConstraints &a, const SearchConstraints &b) const { + int result; + result = m_cmp(a.PrimaryTag, b.PrimaryTag); + if (result != 0) + return result < 0; + result = m_cmp(a.Date, b.Date); + if (result != 0) + return result < 0; + return m_cmp(a.Album, b.Album) < 0; + } +}; } @@ -257,7 +290,7 @@ void MediaLibrary::Update() Albums->addItem(SearchConstraints(*album, "")); } if (!Albums->empty()) - std::sort(Albums->beginV(), Albums->endV(), SortSearchConstraints); + std::sort(Albums->beginV(), Albums->endV(), SortSearchConstraints()); if (Albums->size() > 1) { Albums->addSeparator(); @@ -300,7 +333,7 @@ void MediaLibrary::Update() } Mpd.BlockIdle(0); if (!Albums->empty()) - std::sort(Albums->beginV(), Albums->endV(), SortSearchConstraints); + std::sort(Albums->beginV(), Albums->endV(), SortSearchConstraints()); Albums->refresh(); } @@ -328,7 +361,7 @@ void MediaLibrary::Update() Songs->addItem(*s, myPlaylist->checkForSong(*s)); if (Albums->current().value().Date == AllTracksMarker) - std::sort(Songs->beginV(), Songs->endV(), SortAllTracks); + std::sort(Songs->beginV(), Songs->endV(), SortAllTracks()); else std::sort(Songs->beginV(), Songs->endV(), SortSongsByTrack); @@ -572,7 +605,7 @@ MPD::SongList MediaLibrary::getSelectedSongs() Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, tag); auto songs = Mpd.CommitSearchSongs(); - std::sort(songs.begin(), songs.end(), SortAllTracks); + std::sort(songs.begin(), songs.end(), SortAllTracks()); result.insert(result.end(), songs.begin(), songs.end()); }; for (auto it = Tags->begin(); it != Tags->end(); ++it) @@ -915,34 +948,4 @@ bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b) return a.getTrack() < b.getTrack(); } -bool SortAllTracks(const MPD::Song &a, const MPD::Song &b) -{ - const std::array gets = {{ - &MPD::Song::getDate, - &MPD::Song::getAlbum, - &MPD::Song::getDisc - }}; - CaseInsensitiveStringComparison cmp(Config.ignore_leading_the); - for (auto get = gets.begin(); get != gets.end(); ++get) - { - int ret = cmp(a.getTags(*get), b.getTags(*get)); - if (ret != 0) - return ret < 0; - } - return a.getTrack() < b.getTrack(); -} - -bool SortSearchConstraints(const SearchConstraints &a, const SearchConstraints &b) -{ - int result; - CaseInsensitiveStringComparison cmp(Config.ignore_leading_the); - result = cmp(a.PrimaryTag, b.PrimaryTag); - if (result != 0) - return result < 0; - result = cmp(a.Date, b.Date); - if (result != 0) - return result < 0; - return cmp(a.Album, b.Album) < 0; -} - } diff --git a/src/playlist.cpp b/src/playlist.cpp index dfba954b..ffba208c 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -197,9 +197,9 @@ void Playlist::EnterPressed() for (; begin != end; ++begin) playlist.push_back(begin->value()); + LocaleStringComparison cmp(std::locale(""), Config.ignore_leading_the); std::function iter_swap, quick_sort; - auto song_cmp = [](const MPD::Song &a, const MPD::Song &b) -> bool { - CaseInsensitiveStringComparison cmp(Config.ignore_leading_the); + auto song_cmp = [&cmp](const MPD::Song &a, const MPD::Song &b) -> bool { for (size_t i = 0; i < SortOptions; ++i) if (int ret = cmp(a.getTags((*SortDialog)[i].value().second), b.getTags((*SortDialog)[i].value().second))) return ret < 0; diff --git a/src/search_engine.cpp b/src/search_engine.cpp index 2a060b17..410981e8 100644 --- a/src/search_engine.cpp +++ b/src/search_engine.cpp @@ -448,6 +448,7 @@ void SearchEngine::Search() bool any_found = 1; bool found = 1; + LocaleStringComparison cmp(std::locale(""), Config.ignore_leading_the); for (auto it = list.begin(); it != list.end(); ++it) { if (SearchMode != &SearchModes[2]) // match to pattern @@ -535,8 +536,6 @@ void SearchEngine::Search() } else // match only if values are equal { - CaseInsensitiveStringComparison cmp(Config.ignore_leading_the); - if (!itsConstraints[0].empty()) any_found = !cmp(it->getArtist(), itsConstraints[0]) @@ -573,10 +572,7 @@ void SearchEngine::Search() } if (found && any_found) - { w->addItem(*it); - list[it-list.begin()] = 0; - } found = 1; any_found = 1; } diff --git a/src/utility/comparators.cpp b/src/utility/comparators.cpp index 9deeb71c..5c5e65db 100644 --- a/src/utility/comparators.cpp +++ b/src/utility/comparators.cpp @@ -18,33 +18,37 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include #include "comparators.h" #include "settings.h" -bool CaseInsensitiveStringComparison::hasTheWord(const char *s) const +bool LocaleStringComparison::hasTheWord(const std::string &s) const { - return (s[0] == 't' || s[0] == 'T') + return s.length() >= 4 + && (s[0] == 't' || s[0] == 'T') && (s[1] == 'h' || s[1] == 'H') && (s[2] == 'e' || s[2] == 'E') && (s[3] == ' '); } -int CaseInsensitiveStringComparison::operator()(const char *a, const char *b) const +int LocaleStringComparison::operator()(const std::string &a, const std::string &b) const { + const char *ac = a.c_str(); + const char *bc = b.c_str(); + size_t ac_off = 0, bc_off = 0; if (m_ignore_the) { if (hasTheWord(a)) - a += 4; + ac_off += 4; if (hasTheWord(b)) - b += 4; + bc_off += 4; } - int dist; - while (!(dist = tolower(*a)-tolower(*b)) && *b) - ++a, ++b; - return dist; + return std::use_facet< std::collate >(m_locale).compare( + ac+ac_off, ac+a.length(), bc+bc_off, bc+b.length() + ); } -CaseInsensitiveSorting::CaseInsensitiveSorting(): cmp(Config.ignore_leading_the) { } +CaseInsensitiveSorting::CaseInsensitiveSorting(): cmp(std::locale(""), Config.ignore_leading_the) { } bool CaseInsensitiveSorting::operator()(const MPD::Item &a, const MPD::Item &b) const { diff --git a/src/utility/comparators.h b/src/utility/comparators.h index 87ddad80..02f24379 100644 --- a/src/utility/comparators.h +++ b/src/utility/comparators.h @@ -24,31 +24,23 @@ #include #include "mpdpp.h" -class CaseInsensitiveStringComparison +class LocaleStringComparison { + std::locale m_locale; bool m_ignore_the; - bool hasTheWord(const char *s) const; + bool hasTheWord(const std::string &s) const; public: - CaseInsensitiveStringComparison(bool ignore_the) : m_ignore_the(ignore_the) { } + LocaleStringComparison(const std::locale &loc, bool ignore_the) + : m_locale(loc), m_ignore_the(ignore_the) { } - int operator()(const char *a, const char *b) const; - - int operator()(const char *a, const std::string &b) const { - return (*this)(a, b.c_str()); - } - int operator()(const std::string &a, const char *b) const { - return (*this)(a.c_str(), b); - } - int operator()(const std::string &a, const std::string &b) const { - return (*this)(a.c_str(), b.c_str()); - } + int operator()(const std::string &a, const std::string &b) const; }; class CaseInsensitiveSorting { - CaseInsensitiveStringComparison cmp; + LocaleStringComparison cmp; public: CaseInsensitiveSorting();