New Upstream Release - ncmpc
Ready changes
Summary
Merged new upstream version: 0.49 (was: 0.48).
Resulting package
Built on 2023-08-05T15:45 (took 7m44s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases ncmpc-dbgsymapt install -t fresh-releases ncmpc-lyricsapt install -t fresh-releases ncmpc
Lintian Result
Diff
diff --git a/NEWS b/NEWS
index e8c2176b..81fb9bf7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+ncmpc 0.49 - (2023-08-04)
+* fix UI freeze if lyrics plugin is stuck
+* fix missing tags with libmpdclient 2.21
+* fix build failure on macOS
+
ncmpc 0.48 - (2023-04-06)
* drop support for ~/.ncmpc/; using only ~/.config/ncmpc/ (XDG)
* improve scroll-offset handling
diff --git a/debian/changelog b/debian/changelog
index 680fafdd..f795c9b4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,10 +1,14 @@
-ncmpc (0.48-1) UNRELEASED; urgency=medium
+ncmpc (0.49-1) UNRELEASED; urgency=medium
+ [ Geoffroy Youri Berret ]
* New upstream release
* Update copyright (upstream switched to spdx headers)
* Add NEWS.Debian regarding the new config location
- -- Geoffroy Youri Berret <kaliko@debian.org> Sun, 23 Apr 2023 15:40:46 +0200
+ [ Debian Janitor ]
+ * New upstream release.
+
+ -- Geoffroy Youri Berret <kaliko@debian.org> Sat, 05 Aug 2023 15:39:09 -0000
ncmpc (0.47-2) unstable; urgency=medium
diff --git a/doc/conf.py b/doc/conf.py
index a83b4016..65032693 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -38,7 +38,7 @@ author = 'Max Kellermann'
# built documents.
#
# The short X.Y version.
-version = '0.48'
+version = '0.49'
# The full version, including alpha/beta/rc tags.
release = version
diff --git a/meson.build b/meson.build
index fa59fe92..fa0eff94 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
project('ncmpc', 'cpp',
- version: '0.48',
+ version: '0.49',
meson_version: '>= 0.49',
default_options: [
'cpp_std=c++2a',
diff --git a/src/ConfigFile.cxx b/src/ConfigFile.cxx
index c00ec50a..31180d7c 100644
--- a/src/ConfigFile.cxx
+++ b/src/ConfigFile.cxx
@@ -34,17 +34,22 @@ IsFile(const char *path) noexcept
std::string
MakeKeysPath()
{
- return MakeUserConfigPath(KEYS_FILENAME);
+ const auto dir = GetUserConfigDirectory(PACKAGE);
+ if (dir.empty())
+ return {};
+
+ mkdir(dir.c_str(), 0777);
+ return BuildPath(dir, KEYS_FILENAME);
}
std::string
GetUserConfigPath() noexcept
{
- const auto dir = GetHomeConfigDirectory();
+ const auto dir = GetUserConfigDirectory(PACKAGE);
if (dir.empty())
return {};
- return BuildPath(dir, PACKAGE, CONFIG_FILENAME);
+ return BuildPath(dir, CONFIG_FILENAME);
}
std::string
@@ -65,30 +70,15 @@ GetSystemConfigPath() noexcept
#endif
}
-#ifndef _WIN32
-
-[[gnu::pure]]
-static std::string
-GetHomeKeysPath() noexcept
-{
- const char *home = GetHomeDirectory();
- if (home == nullptr)
- return {};
-
- return BuildPath(home, "." PACKAGE, KEYS_FILENAME);
-}
-
-#endif
-
[[gnu::pure]]
static std::string
GetUserKeysPath() noexcept
{
- const auto dir = GetHomeConfigDirectory();
+ const auto dir = GetUserConfigDirectory(PACKAGE);
if (dir.empty())
return {};
- return BuildPath(dir, PACKAGE, KEYS_FILENAME);
+ return BuildPath(dir, KEYS_FILENAME);
}
[[gnu::pure]]
@@ -142,13 +132,6 @@ find_keys_file() noexcept
if (!filename.empty() && IsFile(filename.c_str()))
return filename;
-#ifndef _WIN32
- /* check for user key bindings ~/.ncmpc/keys */
- filename = GetHomeKeysPath();
- if (!filename.empty() && IsFile(filename.c_str()))
- return filename;
-#endif
-
/* check for global key bindings SYSCONFDIR/ncmpc/keys */
filename = GetSystemKeysPath();
if (IsFile(filename.c_str()))
diff --git a/src/KeyDefPage.cxx b/src/KeyDefPage.cxx
index 583016f2..be638940 100644
--- a/src/KeyDefPage.cxx
+++ b/src/KeyDefPage.cxx
@@ -284,8 +284,6 @@ CommandKeysPage::OnCommand(struct mpdclient &c, Command cmd)
default:
return false;
}
-
- return false;
}
class CommandListPage final : public ListPage, ListText {
diff --git a/src/LyricsCache.cxx b/src/LyricsCache.cxx
index 77fae25a..d98a214f 100644
--- a/src/LyricsCache.cxx
+++ b/src/LyricsCache.cxx
@@ -13,7 +13,7 @@
static std::string
GetLyricsCacheDirectory() noexcept
{
- const auto ncmpc_cache_directory = GetHomeCacheDirectory(PACKAGE);
+ const auto ncmpc_cache_directory = GetUserCacheDirectory(PACKAGE);
if (ncmpc_cache_directory.empty())
return {};
diff --git a/src/TagMask.hxx b/src/TagMask.hxx
index e4fd9864..94da63b8 100644
--- a/src/TagMask.hxx
+++ b/src/TagMask.hxx
@@ -11,7 +11,11 @@
#include <stdint.h>
class TagMask {
- typedef uint_least32_t mask_t;
+ using mask_t = uint_least64_t;
+
+ static_assert(sizeof(mask_t) * 8 >= MPD_TAG_COUNT,
+ "The mask does not have enough bits for the tags supported by MPD");
+
mask_t value;
explicit constexpr TagMask(uint_least32_t _value) noexcept
diff --git a/src/XdgBaseDirectory.cxx b/src/XdgBaseDirectory.cxx
index 3eef4b7d..2d404793 100644
--- a/src/XdgBaseDirectory.cxx
+++ b/src/XdgBaseDirectory.cxx
@@ -2,34 +2,26 @@
// Copyright The Music Player Daemon Project
#include "XdgBaseDirectory.hxx"
-#include "config.h"
#include "io/Path.hxx"
#include <stdlib.h>
-#include <sys/stat.h>
-[[gnu::pure]]
-static bool
-IsDirectory(const char *path) noexcept
-{
- struct stat st;
- return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
-}
-
-const char *
-GetHomeDirectory() noexcept
+[[gnu::const]]
+static const char *
+GetUserDirectory() noexcept
{
return getenv("HOME");
}
-std::string
-GetHomeConfigDirectory() noexcept
+[[gnu::const]]
+static std::string
+GetUserConfigDirectory() noexcept
{
const char *config_home = getenv("XDG_CONFIG_HOME");
if (config_home != nullptr && *config_home != 0)
return config_home;
- const char *home = GetHomeDirectory();
+ const char *home = GetUserDirectory();
if (home != nullptr)
return BuildPath(home, ".config");
@@ -37,36 +29,24 @@ GetHomeConfigDirectory() noexcept
}
std::string
-GetHomeConfigDirectory(const char *package) noexcept
+GetUserConfigDirectory(std::string_view package) noexcept
{
- const auto dir = GetHomeConfigDirectory();
+ const auto dir = GetUserConfigDirectory();
if (dir.empty())
return {};
return BuildPath(dir, package);
}
-std::string
-MakeUserConfigPath(const char *filename) noexcept
-{
- const auto directory = GetHomeConfigDirectory(PACKAGE);
- if (directory.empty())
- return {};
-
- return IsDirectory(directory.c_str()) ||
- mkdir(directory.c_str(), 0755) == 0
- ? BuildPath(directory, filename)
- : std::string();
-}
-
-std::string
-GetHomeCacheDirectory() noexcept
+[[gnu::const]]
+static std::string
+GetUserCacheDirectory() noexcept
{
const char *cache_home = getenv("XDG_CACHE_HOME");
if (cache_home != nullptr && *cache_home != 0)
return cache_home;
- const char *home = GetHomeDirectory();
+ const char *home = GetUserDirectory();
if (home != nullptr)
return BuildPath(home, ".cache");
@@ -74,9 +54,9 @@ GetHomeCacheDirectory() noexcept
}
std::string
-GetHomeCacheDirectory(const char *package) noexcept
+GetUserCacheDirectory(std::string_view package) noexcept
{
- const auto dir = GetHomeCacheDirectory();
+ const auto dir = GetUserCacheDirectory();
if (dir.empty())
return {};
diff --git a/src/XdgBaseDirectory.hxx b/src/XdgBaseDirectory.hxx
index 7f775233..3888c2cf 100644
--- a/src/XdgBaseDirectory.hxx
+++ b/src/XdgBaseDirectory.hxx
@@ -1,38 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
-#ifndef XDG_BASE_DIRECTORY_HXX
-#define XDG_BASE_DIRECTORY_HXX
+#pragma once
#include <string>
+#include <string_view>
-[[gnu::const]]
-const char *
-GetHomeDirectory() noexcept;
-
-[[gnu::const]]
-std::string
-GetHomeConfigDirectory() noexcept;
-
+/**
+ * Returns the absolute path of the XDG config directory for the
+ * specified package (or an empty string on error).
+ */
[[gnu::pure]]
std::string
-GetHomeConfigDirectory(const char *package) noexcept;
+GetUserConfigDirectory(std::string_view package) noexcept;
/**
- * Find or create the directory for writing configuration files.
- *
- * @return the absolute path; an empty string indicates that no
- * directory could be created
+ * Returns the absolute path of the XDG cache directory for the
+ * specified package (or an empty string on error).
*/
-std::string
-MakeUserConfigPath(const char *filename) noexcept;
-
-[[gnu::const]]
-std::string
-GetHomeCacheDirectory() noexcept;
-
[[gnu::pure]]
std::string
-GetHomeCacheDirectory(const char *package) noexcept;
-
-#endif
+GetUserCacheDirectory(std::string_view package) noexcept;
diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx
index a5e54c98..12b9fdba 100644
--- a/src/event/Loop.cxx
+++ b/src/event/Loop.cxx
@@ -275,10 +275,8 @@ EventLoop::Run() noexcept
#endif
assert(IsInside());
- assert(!quit);
#ifdef HAVE_THREADED_EVENT_LOOP
- assert(!quit_injected);
- assert(alive);
+ assert(alive || quit_injected);
assert(busy);
wake_event.Schedule(SocketEvent::READ);
@@ -303,7 +301,7 @@ EventLoop::Run() noexcept
FlushClockCaches();
- do {
+ while (!quit) {
again = false;
/* invoke timers */
@@ -365,7 +363,7 @@ EventLoop::Run() noexcept
socket_event.Dispatch();
}
- } while (!quit);
+ }
#ifdef HAVE_THREADED_EVENT_LOOP
#ifndef NDEBUG
diff --git a/src/io/Path.hxx b/src/io/Path.hxx
index e8bbf367..4d042459 100644
--- a/src/io/Path.hxx
+++ b/src/io/Path.hxx
@@ -5,8 +5,7 @@
#define IO_PATH_HXX
#include <string>
-
-#include <string.h>
+#include <string_view>
namespace PathDetail {
@@ -16,93 +15,37 @@ static constexpr char SEPARATOR = '\\';
static constexpr char SEPARATOR = '/';
#endif
-[[gnu::pure]]
-inline size_t
-GetLength(const char *s) noexcept
-{
- return strlen(s);
-}
-
-[[gnu::pure]]
-inline size_t
-GetLength(const std::string &s) noexcept
+inline void
+AppendWithSeparator(std::string &dest, std::string_view src) noexcept
{
- return s.length();
+ dest.push_back(SEPARATOR);
+ dest.append(src);
}
template<typename... Args>
-inline size_t
-FillLengths(size_t *lengths, Args&&... args) noexcept;
-
-template<typename First, typename... Args>
-inline size_t
-FillLengths(size_t *lengths, First &&first, Args&&... args) noexcept
-{
- size_t length = GetLength(std::forward<First>(first));
- *lengths++ = length;
- return length + FillLengths(lengths, std::forward<Args>(args)...);
-}
-
-template<>
-inline size_t
-FillLengths(size_t *) noexcept
-{
- return 0;
-}
-
-inline std::string &
-Append(std::string &dest, const std::string &value, size_t length) noexcept
+std::string
+BuildPath(std::string_view first, Args&&... args) noexcept
{
- return dest.append(value, 0, length);
-}
+ constexpr size_t n = sizeof...(args);
-inline std::string &
-Append(std::string &dest, const char *value, size_t length) noexcept
-{
- return dest.append(value, length);
-}
+ const std::size_t total = first.size() + (args.size() + ...);
-template<typename... Args>
-inline std::string &
-AppendWithSeparators(std::string &dest, const size_t *lengths,
- Args&&... args) noexcept;
+ std::string result;
+ result.reserve(total + n);
-template<typename First, typename... Args>
-inline std::string &
-AppendWithSeparators(std::string &dest, const size_t *lengths,
- First &&first, Args&&... args) noexcept
-{
- dest.push_back(SEPARATOR);
- return AppendWithSeparators(Append(dest, std::forward<First>(first),
- *lengths),
- lengths + 1,
- std::forward<Args>(args)...);
-}
+ result.append(first);
+ (AppendWithSeparator(result, args), ...);
-template<>
-inline std::string &
-AppendWithSeparators(std::string &dest, const size_t *) noexcept
-{
- return dest;
+ return result;
}
} // namespace PathDetail
-template<typename First, typename... Args>
+template<typename... Args>
std::string
-BuildPath(First &&first, Args&&... args) noexcept
+BuildPath(std::string_view first, Args&&... args) noexcept
{
- constexpr size_t n = sizeof...(args);
-
- size_t lengths[n + 1];
- const size_t total = PathDetail::FillLengths(lengths, first, args...);
-
- std::string result;
- result.reserve(total + n);
- PathDetail::Append(result, std::forward<First>(first), lengths[0]);
- PathDetail::AppendWithSeparators(result, lengths + 1,
- std::forward<Args>(args)...);
- return result;
+ return PathDetail::BuildPath(first, static_cast<std::string_view>(args)...);
}
#endif
diff --git a/src/plugin.cxx b/src/plugin.cxx
index f1ee25db..719aeab0 100644
--- a/src/plugin.cxx
+++ b/src/plugin.cxx
@@ -6,6 +6,7 @@
#include "io/UniqueFileDescriptor.hxx"
#include "event/PipeEvent.hxx"
#include "event/CoarseTimerEvent.hxx"
+#include "event/Features.h" // for USE_SIGNALFD
#include "util/ScopeExit.hxx"
#include "util/UriUtil.hxx"
@@ -21,6 +22,10 @@
#include <sys/stat.h>
#include <sys/wait.h>
+#ifdef __APPLE__
+extern char **environ;
+#endif
+
struct PluginCycle;
class PluginPipe {
@@ -259,7 +264,15 @@ PluginCycle::LaunchPlugin(const char *plugin_path) noexcept
posix_spawn_file_actions_adddup2(&file_actions, stderr_w.Get(),
STDERR_FILENO);
- if (posix_spawn(&pid, plugin_path, &file_actions, nullptr,
+ posix_spawnattr_t attr;
+ posix_spawnattr_init(&attr);
+
+#ifdef USE_SIGNALFD
+ /* unblock all signals which may be blocked for signalfd */
+ posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK);
+#endif
+
+ if (posix_spawn(&pid, plugin_path, &file_actions, &attr,
argv.get(), environ) != 0)
return -1;
diff --git a/src/system/Error.hxx b/src/system/Error.hxx
index bce69f99..706c1dd8 100644
--- a/src/system/Error.hxx
+++ b/src/system/Error.hxx
@@ -6,23 +6,10 @@
#include <system_error> // IWYU pragma: export
#include <utility>
-#include <stdio.h>
-
-template<typename... Args>
-static inline std::system_error
-FormatSystemError(std::error_code code, const char *fmt,
- Args&&... args) noexcept
-{
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), fmt, std::forward<Args>(args)...);
- return std::system_error(code, buffer);
-}
-
#ifdef _WIN32
#include <errhandlingapi.h> // for GetLastError()
-#include <windef.h> // for HWND (needed by winbase.h)
-#include <winbase.h> // for FormatMessageA()
+#include <winerror.h>
/**
* Returns the error_category to be used to wrap WIN32 GetLastError()
@@ -59,38 +46,10 @@ MakeLastError(const char *msg) noexcept
return MakeLastError(GetLastError(), msg);
}
-template<typename... Args>
-static inline std::system_error
-FormatLastError(DWORD code, const char *fmt, Args&&... args) noexcept
-{
- char buffer[512];
- const auto end = buffer + sizeof(buffer);
- size_t length = snprintf(buffer, sizeof(buffer) - 128,
- fmt, std::forward<Args>(args)...);
- char *p = buffer + length;
- *p++ = ':';
- *p++ = ' ';
-
- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- nullptr, code, 0, p, end - p, nullptr);
- return MakeLastError(code, buffer);
-}
-
-template<typename... Args>
-static inline std::system_error
-FormatLastError(const char *fmt, Args&&... args) noexcept
-{
- return FormatLastError(GetLastError(), fmt,
- std::forward<Args>(args)...);
-}
-
#endif /* _WIN32 */
#include <cerrno> // IWYU pragma: export
-#include <string.h>
-
/**
* Returns the error_category to be used to wrap errno values. The
* C++ standard does not define this well, so this code is based on
@@ -127,35 +86,6 @@ MakeErrno(const char *msg) noexcept
return MakeErrno(errno, msg);
}
-template<typename... Args>
-static inline std::system_error
-FormatErrno(int code, const char *fmt, Args&&... args) noexcept
-{
- char buffer[512];
- snprintf(buffer, sizeof(buffer),
- fmt, std::forward<Args>(args)...);
- return MakeErrno(code, buffer);
-}
-
-template<typename... Args>
-static inline std::system_error
-FormatErrno(const char *fmt, Args&&... args) noexcept
-{
- return FormatErrno(errno, fmt, std::forward<Args>(args)...);
-}
-
-template<typename... Args>
-static inline std::system_error
-FormatFileNotFound(const char *fmt, Args&&... args) noexcept
-{
-#ifdef _WIN32
- return FormatLastError(ERROR_FILE_NOT_FOUND, fmt,
- std::forward<Args>(args)...);
-#else
- return FormatErrno(ENOENT, fmt, std::forward<Args>(args)...);
-#endif
-}
-
[[gnu::pure]]
inline bool
IsErrno(const std::system_error &e, int code) noexcept
diff --git a/src/util/Concepts.hxx b/src/util/Concepts.hxx
index 6439dd92..a741d690 100644
--- a/src/util/Concepts.hxx
+++ b/src/util/Concepts.hxx
@@ -5,33 +5,5 @@
#include <concepts>
-/**
- * Compatibility wrapper for std::invocable which is unavailable in
- * the Android NDK r25b and Apple Xcode.
- */
-#if !defined(ANDROID) && !defined(__APPLE__)
-template<typename F, typename... Args>
-concept Invocable = std::invocable<F, Args...>;
-#else
-template<typename F, typename... Args>
-concept Invocable = requires(F f, Args... args) {
- { f(args...) };
-};
-#endif
-
-/**
- * Compatibility wrapper for std::predicate which is unavailable in
- * the Android NDK r25b and Apple Xcode.
- */
-#if !defined(ANDROID) && !defined(__APPLE__)
-template<typename F, typename... Args>
-concept Predicate = std::predicate<F, Args...>;
-#else
-template<typename F, typename... Args>
-concept Predicate = requires(F f, Args... args) {
- { f(args...) } -> std::same_as<bool>;
-};
-#endif
-
template<typename F, typename T>
-concept Disposer = Invocable<F, T *>;
+concept Disposer = std::invocable<F, T *>;
diff --git a/src/util/IntrusiveList.hxx b/src/util/IntrusiveList.hxx
index f8b5116e..aa1c67e5 100644
--- a/src/util/IntrusiveList.hxx
+++ b/src/util/IntrusiveList.hxx
@@ -77,31 +77,26 @@ using SafeLinkIntrusiveListHook =
using AutoUnlinkIntrusiveListHook =
IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>;
-/**
- * Detect the hook type which is embedded in the given type as a base
- * class. This is a template to postpone the type checks, to allow
- * forward-declared types.
- */
-template<typename U>
-struct IntrusiveListHookDetection {
- /* TODO can this be simplified somehow, without checking for
- all possible enum values? */
- using type = std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::NORMAL>, U>,
- IntrusiveListHook<IntrusiveHookMode::NORMAL>,
- std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::TRACK>, U>,
- IntrusiveListHook<IntrusiveHookMode::TRACK>,
- std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>, U>,
- IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>,
- void>>>;
-};
-
/**
* For classes which embed #IntrusiveListHook as base class.
*/
template<typename T>
struct IntrusiveListBaseHookTraits {
+ /* a never-called helper function which is used by _Cast() */
+ template<IntrusiveHookMode mode>
+ static constexpr IntrusiveListHook<mode> _Identity(const IntrusiveListHook<mode> &) noexcept;
+
+ /* another never-called helper function which "calls"
+ _Identity(), implicitly casting the item to the
+ IntrusiveListHook specialization; we use this to detect
+ which IntrusiveListHook specialization is used */
+ template<typename U>
+ static constexpr auto _Cast(const U &u) noexcept {
+ return decltype(_Identity(u))();
+ }
+
template<typename U>
- using Hook = typename IntrusiveListHookDetection<U>::type;
+ using Hook = decltype(_Cast(std::declval<U>()));
static constexpr T *Cast(IntrusiveListNode *node) noexcept {
auto *hook = &Hook<T>::Cast(*node);
@@ -264,16 +259,14 @@ public:
void clear_and_dispose(Disposer<value_type> auto disposer) noexcept {
while (!empty()) {
- auto *item = &front();
- pop_front();
- disposer(item);
+ disposer(&pop_front());
}
}
/**
* @return the number of removed items
*/
- std::size_t remove_and_dispose_if(Predicate<const_reference> auto pred,
+ std::size_t remove_and_dispose_if(std::predicate<const_reference> auto pred,
Disposer<value_type> auto dispose) noexcept {
std::size_t result = 0;
@@ -302,15 +295,15 @@ public:
return *Cast(head.next);
}
- void pop_front() noexcept {
- ToHook(front()).unlink();
+ reference pop_front() noexcept {
+ auto &i = front();
+ ToHook(i).unlink();
--counter;
+ return i;
}
void pop_front_and_dispose(Disposer<value_type> auto disposer) noexcept {
- auto &i = front();
- ToHook(i).unlink();
- --counter;
+ auto &i = pop_front();
disposer(&i);
}
@@ -319,7 +312,8 @@ public:
}
void pop_back() noexcept {
- ToHook(back()).unlink();
+ auto &i = back();
+ ToHook(i).unlink();
--counter;
}
@@ -487,12 +481,18 @@ public:
insert(end(), t);
}
+ /**
+ * Insert a new item before the given position.
+ *
+ * @param p a valid iterator (end() is allowed)for this list
+ * describing the position where to insert
+ */
void insert(iterator p, reference t) noexcept {
static_assert(!constant_time_size ||
GetHookMode() < IntrusiveHookMode::AUTO_UNLINK,
"Can't use auto-unlink hooks with constant_time_size");
- auto &existing_node = ToNode(*p);
+ auto &existing_node = *p.cursor;
auto &new_node = ToNode(t);
IntrusiveListNode::Connect(*existing_node.prev,
@@ -502,6 +502,13 @@ public:
++counter;
}
+ /**
+ * Like insert(), but insert after the given position.
+ */
+ void insert_after(iterator p, reference t) noexcept {
+ insert(std::next(p), t);
+ }
+
/**
* Move one item of the given list to this one before the
* given position.
@@ -522,13 +529,13 @@ public:
if (_begin == _end)
return;
- auto &next_node = ToNode(*position);
- auto &prev_node = ToNode(*std::prev(position));
+ auto &next_node = *position.cursor;
+ auto &prev_node = *std::prev(position).cursor;
- auto &first_node = ToNode(*_begin);
- auto &before_first_node = ToNode(*std::prev(_begin));
- auto &last_node = ToNode(*std::prev(_end));
- auto &after_last_node = ToNode(*_end);
+ auto &first_node = *_begin.cursor;
+ auto &before_first_node = *std::prev(_begin).cursor;
+ auto &last_node = *std::prev(_end).cursor;
+ auto &after_last_node = *_end.cursor;
/* remove from the other list */
IntrusiveListNode::Connect(before_first_node, after_last_node);
diff --git a/src/util/ScopeExit.hxx b/src/util/ScopeExit.hxx
index 5c6fc9a7..9e1cc5dd 100644
--- a/src/util/ScopeExit.hxx
+++ b/src/util/ScopeExit.hxx
@@ -10,20 +10,27 @@
* Internal class. Do not use directly.
*/
template<typename F>
-class ScopeExitGuard : F {
+class ScopeExitGuard {
+ [[no_unique_address]]
+ F function;
+
bool enabled = true;
public:
- explicit ScopeExitGuard(F &&f):F(std::forward<F>(f)) {}
+ explicit ScopeExitGuard(F &&f) noexcept
+ :function(std::forward<F>(f)) {}
- ScopeExitGuard(ScopeExitGuard &&src)
- :F(std::move(src)), enabled(src.enabled) {
- src.enabled = false;
- }
+ ScopeExitGuard(ScopeExitGuard &&src) noexcept
+ :function(std::move(src.function)),
+ enabled(std::exchange(src.enabled, false)) {}
- ~ScopeExitGuard() {
+ /* destructors are "noexcept" by default; this explicit
+ "noexcept" declaration allows the destructor to throw if
+ the function can throw; without this, a throwing function
+ would std::terminate() */
+ ~ScopeExitGuard() noexcept(noexcept(std::declval<F>()())) {
if (enabled)
- F::operator()();
+ function();
}
ScopeExitGuard(const ScopeExitGuard &) = delete;
@@ -38,7 +45,7 @@ struct ScopeExitTag {
parantheses at the end of the expression AtScopeExit()
call */
template<typename F>
- ScopeExitGuard<F> operator+(F &&f) {
+ ScopeExitGuard<F> operator+(F &&f) noexcept {
return ScopeExitGuard<F>(std::forward<F>(f));
}
};
diff --git a/src/util/SortList.hxx b/src/util/SortList.hxx
index 6856872b..54a43745 100644
--- a/src/util/SortList.hxx
+++ b/src/util/SortList.hxx
@@ -3,10 +3,10 @@
#pragma once
-#include "Concepts.hxx"
#include "StaticVector.hxx"
#include <algorithm> // for std::find_if()
+#include <concepts>
/**
* Move all items from #src to #dest, keeping both sorted.
@@ -17,7 +17,7 @@
template<typename List>
constexpr void
MergeList(List &dest, List &src,
- Predicate<typename List::const_reference, typename List::const_reference> auto p) noexcept
+ std::predicate<typename List::const_reference, typename List::const_reference> auto p) noexcept
{
const auto dest_end = dest.end(), src_end = src.end();
@@ -59,7 +59,7 @@ MergeList(List &dest, List &src,
template<typename List>
constexpr void
SortList(List &list,
- Predicate <typename List::const_reference, typename List::const_reference> auto p) noexcept
+ std::predicate <typename List::const_reference, typename List::const_reference> auto p) noexcept
{
using std::swap;
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/lib/debug/.build-id/14/81cdff33f82d51ea07abe638a0fde3818bd3f7.debug
Files in first set of .debs but not in second
-rw-r--r-- root/root /usr/lib/debug/.build-id/58/71c31f6f8235a672262faa946908f60a6ba22d.debug
Control files of package ncmpc: lines which differ (wdiff format)
Depends: libc6 (>= 2.34), libgcc-s1 (>= 3.0), liblirc-client0, libmpdclient2 (>= 2.19), libncursesw6 (>= 6), libpcre2-8-0 (>= 10.22), libstdc++6 (>= 11), 13), libtinfo6 (>= 6)
Control files of package ncmpc-dbgsym: lines which differ (wdiff format)
Build-Ids: 5871c31f6f8235a672262faa946908f60a6ba22d 1481cdff33f82d51ea07abe638a0fde3818bd3f7
No differences were encountered between the control files of package ncmpc-lyrics