diff options
author | Max Kellermann <max@duempel.org> | 2014-06-10 21:15:40 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-06-16 18:39:16 +0200 |
commit | 3ca0a39a357d9be9c85de4892ac02716f8af2ae8 (patch) | |
tree | 88c87573974f6609a1dc68cf20e5901600613280 | |
parent | 52594e64d0f48eb83c9bf54eb1ac95a6de881829 (diff) | |
download | mpd-3ca0a39a357d9be9c85de4892ac02716f8af2ae8.tar.gz mpd-3ca0a39a357d9be9c85de4892ac02716f8af2ae8.tar.xz mpd-3ca0a39a357d9be9c85de4892ac02716f8af2ae8.zip |
db/simple: use class boost::intrusive::list
Remove the C list_head library and use type-safe C++ instead.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/db/plugins/simple/Directory.cxx | 90 | ||||
-rw-r--r-- | src/db/plugins/simple/Directory.hxx | 60 | ||||
-rw-r--r-- | src/db/plugins/simple/DirectorySave.cxx | 14 | ||||
-rw-r--r-- | src/db/plugins/simple/Song.hxx | 20 | ||||
-rw-r--r-- | src/db/plugins/simple/SongSort.cxx | 29 | ||||
-rw-r--r-- | src/db/plugins/simple/SongSort.hxx | 4 | ||||
-rw-r--r-- | src/db/update/Editor.cxx | 17 | ||||
-rw-r--r-- | src/db/update/Walk.cxx | 61 | ||||
-rw-r--r-- | src/util/list.h | 607 | ||||
-rw-r--r-- | src/util/list_sort.c | 162 | ||||
-rw-r--r-- | src/util/list_sort.h | 33 |
12 files changed, 151 insertions, 948 deletions
diff --git a/Makefile.am b/Makefile.am index e0d00015f..15b392230 100644 --- a/Makefile.am +++ b/Makefile.am @@ -370,8 +370,6 @@ libutil_a_SOURCES = \ src/util/PeakBuffer.cxx src/util/PeakBuffer.hxx \ src/util/OptionParser.cxx src/util/OptionParser.hxx \ src/util/OptionDef.hxx \ - src/util/list.h \ - src/util/list_sort.c src/util/list_sort.h \ src/util/ByteReverse.cxx src/util/ByteReverse.hxx \ src/util/bit_reverse.c src/util/bit_reverse.h diff --git a/src/db/plugins/simple/Directory.cxx b/src/db/plugins/simple/Directory.cxx index 3ac2f96a2..6259df49f 100644 --- a/src/db/plugins/simple/Directory.cxx +++ b/src/db/plugins/simple/Directory.cxx @@ -33,10 +33,6 @@ #include "util/Alloc.hxx" #include "util/Error.hxx" -extern "C" { -#include "util/list_sort.h" -} - #include <assert.h> #include <string.h> #include <stdlib.h> @@ -47,21 +43,14 @@ Directory::Directory(std::string &&_path_utf8, Directory *_parent) path(std::move(_path_utf8)), mounted_database(nullptr) { - INIT_LIST_HEAD(&children); - INIT_LIST_HEAD(&songs); } Directory::~Directory() { delete mounted_database; - Song *song, *ns; - directory_for_each_song_safe(song, ns, *this) - song->Free(); - - Directory *child, *n; - directory_for_each_child_safe(child, n, *this) - delete child; + songs.clear_and_dispose(Song::Disposer()); + children.clear_and_dispose(Disposer()); } void @@ -70,8 +59,8 @@ Directory::Delete() assert(holding_db_lock()); assert(parent != nullptr); - list_del(&siblings); - delete this; + parent->children.erase_and_dispose(parent->children.iterator_to(*this), + Disposer()); } const char * @@ -94,7 +83,7 @@ Directory::CreateChild(const char *name_utf8) : PathTraitsUTF8::Build(GetPath(), name_utf8); Directory *child = new Directory(std::move(path_utf8), this); - list_add_tail(&child->siblings, &children); + children.push_back(*child); return child; } @@ -103,10 +92,9 @@ Directory::FindChild(const char *name) const { assert(holding_db_lock()); - const Directory *child; - directory_for_each_child(child, *this) - if (strcmp(child->GetName(), name) == 0) - return child; + for (const auto &child : children) + if (strcmp(child.GetName(), name) == 0) + return &child; return nullptr; } @@ -116,17 +104,14 @@ Directory::PruneEmpty() { assert(holding_db_lock()); - Directory *child, *n; - directory_for_each_child_safe(child, n, *this) { - if (child->IsMount()) - /* never prune mount points; they're always - empty by definition, but that's ok */ - continue; - + for (auto child = children.begin(), end = children.end(); + child != end;) { child->PruneEmpty(); if (child->IsEmpty()) - child->Delete(); + child = children.erase_and_dispose(child, Disposer()); + else + ++child; } } @@ -182,7 +167,7 @@ Directory::AddSong(Song *song) assert(song != nullptr); assert(song->parent == this); - list_add_tail(&song->siblings, &songs); + songs.push_back(*song); } void @@ -192,7 +177,7 @@ Directory::RemoveSong(Song *song) assert(song != nullptr); assert(song->parent == this); - list_del(&song->siblings); + songs.erase(songs.iterator_to(*song)); } const Song * @@ -201,25 +186,21 @@ Directory::FindSong(const char *name_utf8) const assert(holding_db_lock()); assert(name_utf8 != nullptr); - Song *song; - directory_for_each_song(song, *this) { - assert(song->parent == this); + for (auto &song : songs) { + assert(song.parent == this); - if (strcmp(song->uri, name_utf8) == 0) - return song; + if (strcmp(song.uri, name_utf8) == 0) + return &song; } return nullptr; } -static int -directory_cmp(gcc_unused void *priv, - struct list_head *_a, struct list_head *_b) +gcc_pure +static bool +directory_cmp(const Directory &a, const Directory &b) { - const Directory *a = (const Directory *)_a; - const Directory *b = (const Directory *)_b; - - return IcuCollate(a->path.c_str(), b->path.c_str()); + return IcuCollate(a.path.c_str(), b.path.c_str()) < 0; } void @@ -227,12 +208,11 @@ Directory::Sort() { assert(holding_db_lock()); - list_sort(nullptr, &children, directory_cmp); - song_list_sort(&songs); + children.sort(directory_cmp); + song_list_sort(songs); - Directory *child; - directory_for_each_child(child, *this) - child->Sort(); + for (auto &child : children) + child.Sort(); } bool @@ -260,9 +240,8 @@ Directory::Walk(bool recursive, const SongFilter *filter, } if (visit_song) { - Song *song; - directory_for_each_song(song, *this) { - const LightSong song2 = song->Export(); + for (auto &song : songs){ + const LightSong song2 = song.Export(); if ((filter == nullptr || filter->Match(song2)) && !visit_song(song2, error)) return false; @@ -275,16 +254,15 @@ Directory::Walk(bool recursive, const SongFilter *filter, return false; } - Directory *child; - directory_for_each_child(child, *this) { + for (auto &child : children) { if (visit_directory && - !visit_directory(child->Export(), error)) + !visit_directory(child.Export(), error)) return false; if (recursive && - !child->Walk(recursive, filter, - visit_directory, visit_song, visit_playlist, - error)) + !child.Walk(recursive, filter, + visit_directory, visit_song, visit_playlist, + error)) return false; } diff --git a/src/db/plugins/simple/Directory.hxx b/src/db/plugins/simple/Directory.hxx index 029815d95..80675bd21 100644 --- a/src/db/plugins/simple/Directory.hxx +++ b/src/db/plugins/simple/Directory.hxx @@ -21,10 +21,12 @@ #define MPD_DIRECTORY_HXX #include "check.h" -#include "util/list.h" #include "Compiler.h" #include "db/Visitor.hxx" #include "db/PlaylistVector.hxx" +#include "Song.hxx" + +#include <boost/intrusive/list.hpp> #include <string> @@ -41,25 +43,22 @@ static constexpr unsigned DEVICE_INARCHIVE = -1; */ static constexpr unsigned DEVICE_CONTAINER = -2; -#define directory_for_each_child(pos, directory) \ - list_for_each_entry(pos, &(directory).children, siblings) - -#define directory_for_each_child_safe(pos, n, directory) \ - list_for_each_entry_safe(pos, n, &(directory).children, siblings) - -#define directory_for_each_song(pos, directory) \ - list_for_each_entry(pos, &(directory).songs, siblings) - -#define directory_for_each_song_safe(pos, n, directory) \ - list_for_each_entry_safe(pos, n, &(directory).songs, siblings) - -struct Song; struct db_visitor; class SongFilter; class Error; class Database; struct Directory { + static constexpr auto link_mode = boost::intrusive::normal_link; + typedef boost::intrusive::link_mode<link_mode> LinkMode; + typedef boost::intrusive::list_member_hook<LinkMode> Hook; + + struct Disposer { + void operator()(Directory *directory) const { + delete directory; + } + }; + /** * Pointers to the siblings of this directory within the * parent directory. It is unused (undefined) in the root @@ -68,7 +67,12 @@ struct Directory { * This attribute is protected with the global #db_mutex. * Read access in the update thread does not need protection. */ - struct list_head siblings; + Hook siblings; + + typedef boost::intrusive::member_hook<Directory, Hook, + &Directory::siblings> SiblingsHook; + typedef boost::intrusive::list<Directory, SiblingsHook, + boost::intrusive::constant_time_size<false>> List; /** * A doubly linked list of child directories. @@ -76,7 +80,7 @@ struct Directory { * This attribute is protected with the global #db_mutex. * Read access in the update thread does not need protection. */ - struct list_head children; + List children; /** * A doubly linked list of songs within this directory. @@ -84,7 +88,7 @@ struct Directory { * This attribute is protected with the global #db_mutex. * Read access in the update thread does not need protection. */ - struct list_head songs; + SongList songs; PlaylistVector playlists; @@ -186,8 +190,8 @@ public: gcc_pure bool IsEmpty() const { - return list_empty(&children) && - list_empty(&songs) && + return children.empty() && + songs.empty() && playlists.empty(); } @@ -210,6 +214,24 @@ public: return parent == nullptr; } + template<typename T> + void ForEachChildSafe(T &&t) { + const auto end = children.end(); + for (auto i = children.begin(), next = i; i != end; i = next) { + next = std::next(i); + t(*i); + } + } + + template<typename T> + void ForEachSongSafe(T &&t) { + const auto end = songs.end(); + for (auto i = songs.begin(), next = i; i != end; i = next) { + next = std::next(i); + t(*i); + } + } + /** * Look up a song in this directory by its name. * diff --git a/src/db/plugins/simple/DirectorySave.cxx b/src/db/plugins/simple/DirectorySave.cxx index b5989dd06..9d3ebbac2 100644 --- a/src/db/plugins/simple/DirectorySave.cxx +++ b/src/db/plugins/simple/DirectorySave.cxx @@ -84,20 +84,18 @@ directory_save(FILE *fp, const Directory &directory) fprintf(fp, "%s%s\n", DIRECTORY_BEGIN, directory.GetPath()); } - Directory *cur; - directory_for_each_child(cur, directory) { - fprintf(fp, DIRECTORY_DIR "%s\n", cur->GetName()); + for (const auto &child : directory.children) { + fprintf(fp, DIRECTORY_DIR "%s\n", child.GetName()); - if (!cur->IsMount()) - directory_save(fp, *cur); + if (!child.IsMount()) + directory_save(fp, child); if (ferror(fp)) return; } - Song *song; - directory_for_each_song(song, directory) - song_save(fp, *song); + for (const auto &song : directory.songs) + song_save(fp, song); playlist_vector_save(fp, directory.playlists); diff --git a/src/db/plugins/simple/Song.hxx b/src/db/plugins/simple/Song.hxx index 75fce20e9..b2e85aa6b 100644 --- a/src/db/plugins/simple/Song.hxx +++ b/src/db/plugins/simple/Song.hxx @@ -20,10 +20,11 @@ #ifndef MPD_SONG_HXX #define MPD_SONG_HXX -#include "util/list.h" #include "tag/Tag.hxx" #include "Compiler.h" +#include <boost/intrusive/list.hpp> + #include <string> #include <assert.h> @@ -39,6 +40,16 @@ class Storage; * #SimpleDatabase class. */ struct Song { + static constexpr auto link_mode = boost::intrusive::normal_link; + typedef boost::intrusive::link_mode<link_mode> LinkMode; + typedef boost::intrusive::list_member_hook<LinkMode> Hook; + + struct Disposer { + void operator()(Song *song) const { + song->Free(); + } + }; + /** * Pointers to the siblings of this directory within the * parent directory. It is unused (undefined) if this song is @@ -47,7 +58,7 @@ struct Song { * This attribute is protected with the global #db_mutex. * Read access in the update thread does not need protection. */ - struct list_head siblings; + Hook siblings; Tag tag; @@ -110,4 +121,9 @@ struct Song { LightSong Export() const; }; +typedef boost::intrusive::list<Song, + boost::intrusive::member_hook<Song, Song::Hook, + &Song::siblings>, + boost::intrusive::constant_time_size<false>> SongList; + #endif diff --git a/src/db/plugins/simple/SongSort.cxx b/src/db/plugins/simple/SongSort.cxx index c5752f568..4b7144937 100644 --- a/src/db/plugins/simple/SongSort.cxx +++ b/src/db/plugins/simple/SongSort.cxx @@ -23,10 +23,6 @@ #include "tag/Tag.hxx" #include "lib/icu/Collate.hxx" -extern "C" { -#include "util/list_sort.h" -} - #include <stdlib.h> static int @@ -80,34 +76,33 @@ compare_tag_item(const Tag &a, const Tag &b, TagType type) } /* Only used for sorting/searchin a songvec, not general purpose compares */ -static int -song_cmp(gcc_unused void *priv, struct list_head *_a, struct list_head *_b) +gcc_pure +static bool +song_cmp(const Song &a, const Song &b) { - const Song *a = (const Song *)_a; - const Song *b = (const Song *)_b; int ret; /* first sort by album */ - ret = compare_string_tag_item(a->tag, b->tag, TAG_ALBUM); + ret = compare_string_tag_item(a.tag, b.tag, TAG_ALBUM); if (ret != 0) - return ret; + return ret < 0; /* then sort by disc */ - ret = compare_tag_item(a->tag, b->tag, TAG_DISC); + ret = compare_tag_item(a.tag, b.tag, TAG_DISC); if (ret != 0) - return ret; + return ret < 0; /* then by track number */ - ret = compare_tag_item(a->tag, b->tag, TAG_TRACK); + ret = compare_tag_item(a.tag, b.tag, TAG_TRACK); if (ret != 0) - return ret; + return ret < 0; /* still no difference? compare file name */ - return IcuCollate(a->uri, b->uri); + return IcuCollate(a.uri, b.uri) < 0; } void -song_list_sort(struct list_head *songs) +song_list_sort(SongList &songs) { - list_sort(nullptr, songs, song_cmp); + songs.sort(song_cmp); } diff --git a/src/db/plugins/simple/SongSort.hxx b/src/db/plugins/simple/SongSort.hxx index 28b903532..2a0c4383b 100644 --- a/src/db/plugins/simple/SongSort.hxx +++ b/src/db/plugins/simple/SongSort.hxx @@ -20,9 +20,11 @@ #ifndef MPD_SONG_SORT_HXX #define MPD_SONG_SORT_HXX +#include "Song.hxx" + struct list_head; void -song_list_sort(list_head *songs); +song_list_sort(SongList &songs); #endif diff --git a/src/db/update/Editor.cxx b/src/db/update/Editor.cxx index c3c1a23d6..4136ccdad 100644 --- a/src/db/update/Editor.cxx +++ b/src/db/update/Editor.cxx @@ -64,15 +64,14 @@ DatabaseEditor::LockDeleteSong(Directory &parent, Song *song) inline void DatabaseEditor::ClearDirectory(Directory &directory) { - Directory *child, *n; - directory_for_each_child_safe(child, n, directory) - DeleteDirectory(child); - - Song *song, *ns; - directory_for_each_song_safe(song, ns, directory) { - assert(song->parent == &directory); - DeleteSong(directory, song); - } + directory.ForEachChildSafe([this](Directory &child){ + DeleteDirectory(&child); + }); + + directory.ForEachSongSafe([this, &directory](Song &song){ + assert(song.parent == &directory); + DeleteSong(directory, &song); + }); } void diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx index c329865ff..afb67ab29 100644 --- a/src/db/update/Walk.cxx +++ b/src/db/update/Walk.cxx @@ -80,26 +80,25 @@ UpdateWalk::RemoveExcludedFromDirectory(Directory &directory, { db_lock(); - Directory *child, *n; - directory_for_each_child_safe(child, n, directory) { - const auto name_fs = AllocatedPath::FromUTF8(child->GetName()); + directory.ForEachChildSafe([&](Directory &child){ + const auto name_fs = + AllocatedPath::FromUTF8(child.GetName()); - if (name_fs.IsNull() || exclude_list.Check(name_fs)) { - editor.DeleteDirectory(child); - modified = true; - } - } + if (name_fs.IsNull() || exclude_list.Check(name_fs)) { + editor.DeleteDirectory(&child); + modified = true; + } + }); - Song *song, *ns; - directory_for_each_song_safe(song, ns, directory) { - assert(song->parent == &directory); + directory.ForEachSongSafe([&](Song &song){ + assert(song.parent == &directory); - const auto name_fs = AllocatedPath::FromUTF8(song->uri); - if (name_fs.IsNull() || exclude_list.Check(name_fs)) { - editor.DeleteSong(directory, song); - modified = true; - } - } + const auto name_fs = AllocatedPath::FromUTF8(song.uri); + if (name_fs.IsNull() || exclude_list.Check(name_fs)) { + editor.DeleteSong(directory, &song); + modified = true; + } + }); db_unlock(); } @@ -107,25 +106,23 @@ UpdateWalk::RemoveExcludedFromDirectory(Directory &directory, inline void UpdateWalk::PurgeDeletedFromDirectory(Directory &directory) { - Directory *child, *n; - directory_for_each_child_safe(child, n, directory) { - if (DirectoryExists(storage, *child)) - continue; + directory.ForEachChildSafe([&](Directory &child){ + if (DirectoryExists(storage, child)) + return; - editor.LockDeleteDirectory(child); + editor.LockDeleteDirectory(&child); - modified = true; - } + modified = true; + }); - Song *song, *ns; - directory_for_each_song_safe(song, ns, directory) { - if (!directory_child_is_regular(storage, directory, - song->uri)) { - editor.LockDeleteSong(directory, song); + directory.ForEachSongSafe([&](Song &song){ + if (!directory_child_is_regular(storage, directory, + song.uri)) { + editor.LockDeleteSong(directory, &song); - modified = true; - } - } + modified = true; + } + }); for (auto i = directory.playlists.begin(), end = directory.playlists.end(); diff --git a/src/util/list.h b/src/util/list.h deleted file mode 100644 index b02e8b96d..000000000 --- a/src/util/list.h +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright (C) 2003-2014 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* - * This code was imported from the Linux kernel. - * - */ - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#ifdef __clang__ -/* allow typeof() */ -#pragma GCC diagnostic ignored "-Wlanguage-extension-token" -#endif - -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) \ - ((type *)((uint8_t *)ptr - offsetof(type, member))) - -/* - * These are non-NULL pointers that will result in page faults - * under normal circumstances, used to verify that nobody uses - * non-initialized list entries. - */ -#define LIST_POISON1 ((struct list_head *)(void *) 0x00100100) -#define LIST_POISON2 ((struct list_head *)(void *) 0x00200200) - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_add(struct list_head *new_item, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new_item; - new_item->next = next; - new_item->prev = prev; - prev->next = new_item; -} -#else -extern void __list_add(struct list_head *new_item, - struct list_head *prev, - struct list_head *next); -#endif - -/** - * list_add - add a new entry - * @new_item: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new_item, struct list_head *head) -{ - __list_add(new_item, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new_item: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void -list_add_tail(struct list_head *new_item, struct list_head *head) -{ - __list_add(new_item, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_del_entry(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); -} - -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} -#else -extern void __list_del_entry(struct list_head *entry); -extern void list_del(struct list_head *entry); -#endif - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new_item : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new_item) -{ - new_item->next = old->next; - new_item->next->prev = new_item; - new_item->prev = old->prev; - new_item->prev->next = new_item; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new_item) -{ - list_replace(old, new_item); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del_entry(entry); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del_entry(list); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del_entry(list); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -/** - * list_rotate_left - rotate the list to the left - * @head: the head of the list - */ -static inline void list_rotate_left(struct list_head *head) -{ - struct list_head *first; - - if (!list_empty(head)) { - first = head->next; - list_move_tail(first, head); - } -} - -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} - -static inline void __list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - struct list_head *new_first = entry->next; - list->next = head->next; - list->next->prev = list; - list->prev = entry; - entry->next = list; - head->next = new_first; - new_first->prev = head; -} - -/** - * list_cut_position - cut a list into two - * @list: a new list to add all removed entries - * @head: a list with entries - * @entry: an entry within head, could be the head itself - * and if so we won't cut the list - * - * This helper moves the initial part of @head, up to and - * including @entry, from @head to @list. You should - * pass on @entry an element you know is on @head. @list - * should be an empty list or a list you do not care about - * losing its data. - * - */ -static inline void list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - if (list_empty(head)) - return; - if (list_is_singular(head) && - (head->next != entry && head != entry)) - return; - if (entry == head) - INIT_LIST_HEAD(list); - else - __list_cut_position(list, head, entry); -} - -static inline void __list_splice(const struct list_head *list, - struct list_head *prev, - struct list_head *next) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; -} - -/** - * list_splice - join two lists, this is designed for stacks - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head, head->next); -} - -/** - * list_splice_tail - join two lists, each list being a queue - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice_tail(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head->prev, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); - } -} - -/** - * list_splice_tail_init - join two lists and reinitialise the emptied list - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * Each of the lists is a queue. - * The list at @list is reinitialised - */ -static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant doesn't differ from list_for_each() any more. - * We don't do prefetching in either case. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - continue list iteration safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - iterate over list from current point safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -/** - * list_safe_reset_next - reset a stale list_for_each_entry_safe loop - * @pos: the loop cursor used in the list_for_each_entry_safe loop - * @n: temporary storage used in list_for_each_entry_safe - * @member: the name of the list_struct within the struct. - * - * list_safe_reset_next is not safe to use in general if the list may be - * modified concurrently (eg. the lock is dropped in the loop body). An - * exception to this is if the cursor element (pos) is pinned in the list, - * and list_safe_reset_next is called after re-taking the lock and before - * completing the current iteration of the loop body. - */ -#define list_safe_reset_next(pos, n, member) \ - n = list_entry(pos->member.next, typeof(*pos), member) - -#endif diff --git a/src/util/list_sort.c b/src/util/list_sort.c deleted file mode 100644 index d4eeb9b36..000000000 --- a/src/util/list_sort.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2003-2014 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* - * This code was imported from the Linux kernel. - * - */ - -#include "list_sort.h" -#include "list.h" -#include "Macros.hxx" -#include "Compiler.h" - -#include <string.h> - -#define unlikely gcc_unlikely - -#define MAX_LIST_LENGTH_BITS 20 - -/* - * Returns a list organized in an intermediate format suited - * to chaining of merge() calls: null-terminated, no reserved or - * sentinel head node, "prev" links not maintained. - */ -static struct list_head *merge(void *priv, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b), - struct list_head *a, struct list_head *b) -{ - struct list_head head, *tail = &head; - - while (a && b) { - /* if equal, take 'a' -- important for sort stability */ - if ((*cmp)(priv, a, b) <= 0) { - tail->next = a; - a = a->next; - } else { - tail->next = b; - b = b->next; - } - tail = tail->next; - } - tail->next = a?a:b; - return head.next; -} - -/* - * Combine final list merge with restoration of standard doubly-linked - * list structure. This approach duplicates code from merge(), but - * runs faster than the tidier alternatives of either a separate final - * prev-link restoration pass, or maintaining the prev links - * throughout. - */ -static void merge_and_restore_back_links(void *priv, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b), - struct list_head *head, - struct list_head *a, struct list_head *b) -{ - struct list_head *tail = head; - - while (a && b) { - /* if equal, take 'a' -- important for sort stability */ - if ((*cmp)(priv, a, b) <= 0) { - tail->next = a; - a->prev = tail; - a = a->next; - } else { - tail->next = b; - b->prev = tail; - b = b->next; - } - tail = tail->next; - } - tail->next = a ? a : b; - - do { - /* - * In worst cases this loop may run many iterations. - * Continue callbacks to the client even though no - * element comparison is needed, so the client's cmp() - * routine can invoke cond_resched() periodically. - */ - (*cmp)(priv, tail->next, tail->next); - - tail->next->prev = tail; - tail = tail->next; - } while (tail->next); - - tail->next = head; - head->prev = tail; -} - -/** - * list_sort - sort a list - * @priv: private data, opaque to list_sort(), passed to @cmp - * @head: the list to sort - * @cmp: the elements comparison function - * - * This function implements "merge sort", which has O(nlog(n)) - * complexity. - * - * The comparison function @cmp must return a negative value if @a - * should sort before @b, and a positive value if @a should sort after - * @b. If @a and @b are equivalent, and their original relative - * ordering is to be preserved, @cmp must return 0. - */ -void list_sort(void *priv, struct list_head *head, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b)) -{ - struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists - -- last slot is a sentinel */ - int lev; /* index into part[] */ - int max_lev = 0; - struct list_head *list; - - if (list_empty(head)) - return; - - memset(part, 0, sizeof(part)); - - head->prev->next = NULL; - list = head->next; - - while (list) { - struct list_head *cur = list; - list = list->next; - cur->next = NULL; - - for (lev = 0; part[lev]; lev++) { - cur = merge(priv, cmp, part[lev], cur); - part[lev] = NULL; - } - if (lev > max_lev) { - max_lev = lev; - } - part[lev] = cur; - } - - for (lev = 0; lev < max_lev; lev++) - if (part[lev]) - list = merge(priv, cmp, part[lev], list); - - merge_and_restore_back_links(priv, cmp, head, part[max_lev], list); -} diff --git a/src/util/list_sort.h b/src/util/list_sort.h deleted file mode 100644 index f0e6d7893..000000000 --- a/src/util/list_sort.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2003-2014 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* - * This code was imported from the Linux kernel. - * - */ - -#ifndef _LINUX_LIST_SORT_H -#define _LINUX_LIST_SORT_H - -struct list_head; - -void list_sort(void *priv, struct list_head *head, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b)); -#endif |