Compare commits

...

70 Commits

Author SHA1 Message Date
Max Kellermann
b4c9d9c2a7 release v0.20.7 2017-05-15 22:51:08 +02:00
Max Kellermann
fa2b59df4b Main: cap buffer_before_play at 80% to prevent deadlock
Closes #34
2017-05-15 22:49:31 +02:00
Max Kellermann
f41a169460 Main: enforce a reasonable minimum audio_buffer_size setting 2017-05-15 22:44:18 +02:00
Max Kellermann
f567083006 Main: refactor DEFAULT_BUFFER_SIZE to represent bytes 2017-05-15 22:40:23 +02:00
Max Kellermann
a2a677e539 doc/developer.xml: change git URIs to GitHub 2017-05-15 21:49:18 +02:00
Max Kellermann
9123c0b733 doc, README.md: update bug tracker URL
Closes #43
2017-05-15 21:48:03 +02:00
Max Kellermann
788e3b31e1 *: remove "pure" and "const" attributes from throwing functions
The "pure" and "const" attributes are not so well-defined, and a
recent clang version implements an optimization which pushes the
definition's boundary beyond what I believed it was.  clang now
assumes that functions declared "pure" cannot throw exceptions, even
if they lack the "noexcept" specification.

When compiled with this new clang version, MPD will crash randomly if
an exception happens to get thrown by such as "pure" function
(https://github.com/MusicPlayerDaemon/MPD/issues/41).

This commit removes all such misplaced "pure" and "const" attributes,
closing #41.
2017-05-08 17:25:06 +02:00
Max Kellermann
71f0ed8b74 *: add "noexcept" to many, many function prototypes
This eliminates some overhead, because the compiler doesn't need to
consider these functions throwing.
2017-05-08 14:44:49 +02:00
Max Kellermann
ac2e4e593d python/libs: upgrade Boost to 1.64 2017-04-24 20:43:04 +02:00
Max Kellermann
edaa7d7748 python/build/libs: upgrade CURL to 7.54.0 2017-04-24 20:42:28 +02:00
Max Kellermann
3cdf965fba python/build/libs: upgrade FFmpeg to 3.3 2017-04-24 20:41:08 +02:00
Max Kellermann
6b60d1e71f decoder/pcm: add missing nullptr check
Fixes a potential crash bug which is actually unreachable, because the
"pcm" plugin is never invoked when there is no (matching) MIME type.
2017-04-24 20:36:55 +02:00
Max Kellermann
7b7fb5acd5 decoder/pcm: fix potential assertion failure in FillBuffer()
After a seek failure, the buffer may still be full, and then
FillBuffer() aborts with assertion failure.
2017-04-24 11:20:37 +02:00
Bart Nagel
0a7d612f41 Remove some redundant code 2017-04-18 16:10:38 +02:00
Max Kellermann
38da76bbe0 util/ScopeExit: copy enabled tag in move constructor 2017-04-12 13:11:43 +02:00
martinarielhartmann
a13e045742 Update libs.py
upgrade zlib to 1.2.11
2017-04-11 13:31:34 +02:00
cotko
811620c0a0 Fix typo 2017-04-11 13:31:15 +02:00
Max Kellermann
504f5f7bdd storage/FileInfo, db/simple/Directory: use 64 bit for device/inode
An ino_t is usually a 64 bit integer, and some file systems (such as
Linux's kernel NFS client) really uses the upper 32 bit.  This can
lead to false positives in the directory loop detection in
FindAncestorLoop().  Increasing these two attributes (in
StorageFileInfo and Directory) to 64 bit adds little overhead, but
makes the check a lot safer.
2017-04-06 09:58:25 +02:00
Max Kellermann
32bcad51b8 configure.ac: prepare for 0.20.7 2017-03-16 10:50:12 +01:00
Max Kellermann
a40510c241 release v0.20.6 2017-03-10 16:57:59 +01:00
Max Kellermann
ac8dce6599 lib/curl/Request: "ICY 200 OK" is a response boundary header 2017-03-10 16:28:02 +01:00
Max Kellermann
190d525099 lib/curl/Request: move code to IsResponseBoundaryHeader() 2017-03-10 16:24:30 +01:00
Max Kellermann
1b6666fa39 Partition: handle SYNC_WITH_PLAYER before TAG_MODIFIED
The TAG_MODIFIED handler (i.e. playlist::TagModified()) works only if
the modified song is the current song - something that is not updated
until SYNC_WITH_PLAYER is finished.  This fixes tag updates right
after a new song is started.
2017-03-10 16:11:34 +01:00
Max Kellermann
1dd01c99e8 decoder/sidplay: make compatible with libsidplayfp < 1.8
https://bugs.musicpd.org/view.php?id=4665
2017-03-10 13:48:52 +01:00
Thomas Zander
d50b30a498 Add missing include for cstdlib, otherwise free() is undefined 2017-03-07 20:02:36 +01:00
Max Kellermann
42a3a87f13 util/HugeAllocator: paranoid check for sysconf()<0
Just in case.
2017-03-01 21:50:26 +01:00
Ben Boeckel
9dfedbe619 ReusableArray: fix build error on GCC7
GCC7 outputs the following error without this change:

    src/util/ReusableArray.hxx:61:35: error: no matching function for call to ‘swap(size_t&, const size_t&)’
       std::swap(capacity, src.capacity);

which can be resolved by just using an rvalue-reference rather than a
const rvalue-reference.

Signed-off-by: Ben Boeckel <mathstuf@gmail.com>
2017-03-01 19:38:41 +01:00
Max Kellermann
88957b4c9d android/build.py: build with libc++ instead of GNU libstdc++
Android is migrating away from GCC, and libstdc++ will disappear
eventually.
2017-03-01 17:31:26 +01:00
Max Kellermann
b2f2c9322b db/simple/Mount: workaround for libc++ 2017-03-01 17:31:26 +01:00
Max Kellermann
3be2051808 decoder/Thread: check ENABLE_FFMPEG, not HAVE_FFMPEG
This repairs the damage to commit 74dbaade6f done by commit
b3f5b4932c
2017-03-01 17:06:23 +01:00
Max Kellermann
ff32b0dc9b input/curl: use %lu instead of %llu
Fixes a GCC warning because %llu appears to be unsupported by the
Windows standard library.
2017-03-01 16:44:11 +01:00
Max Kellermann
c1869a11af input/curl: format Range offset as unsigned 2017-03-01 16:44:08 +01:00
Max Kellermann
e22a4fdba4 command/Error: improve libstdc++ 4.9.x detection for std::rethrow_if_nested() workaround 2017-03-01 16:38:22 +01:00
Max Kellermann
29a7b2c5b5 decoder/mpcdec: ignore empty frames
https://bugs.musicpd.org/view.php?id=4656 describes a crash due to
division by zero because frame.samples==0.  This should never happen,
but apparently can happen after seeking.  The best we can do is to
just ignore this frame.
2017-03-01 16:13:21 +01:00
Max Kellermann
3b6c285c2a configure.ac: prepare for 0.20.6 2017-03-01 16:13:21 +01:00
Max Kellermann
575d1786af release v0.20.5 2017-02-20 21:51:31 +01:00
Max Kellermann
bc1c927952 util/TimeFormat: suppress -Wunused on Windows 2017-02-20 21:44:01 +01:00
Max Kellermann
f95bc85f91 python/build/libs: upgrade FFmpeg to 3.2.4 2017-02-20 21:13:43 +01:00
Max Kellermann
4015195314 doc/user: instructions to compile the Windows binary 2017-02-20 21:06:43 +01:00
Max Kellermann
c3d883c6cb win32/build.py: default to x64 build 2017-02-20 21:06:43 +01:00
Max Kellermann
097e30321b win32/build.py: add option --32 2017-02-20 21:06:31 +01:00
Max Kellermann
b6ddeaacf2 win32/build.py: convert argument parser to loop
Allow multiple arguments.
2017-02-20 21:06:21 +01:00
Max Kellermann
b0c60ec124 win32/build.py: add variable "x64", assign host_arch later 2017-02-20 21:04:34 +01:00
Max Kellermann
f3b788703e tag/Handler: improve snprintf() return value check 2017-02-19 19:34:13 +01:00
Max Kellermann
4bb83781e8 output/httpd/IcyMetaDataServer: cast length to unsigned
Fixes another buffer overflow: if the stream has a very long title or
URL, resulting in a metadata string of more than 2 kB, icy_string[0]
is a negative value, which gets casted to size_t - ouch!

 https://bugs.musicpd.org/view.php?id=4652
2017-02-19 19:28:52 +01:00
Max Kellermann
a73195b7cc output/httpd/IcyMetaDataServer: pad the string with 15 spaces
Fixes a buffer overflow due to the bad formula rounding the buffer
size up.  At the same time, remove the "+1" from the meta_length
calculation, which takes the padding into account and at the same time
implements proper rounding.
2017-02-19 19:27:37 +01:00
Max Kellermann
1bd00b8a9a output/httpd/IcyMetaDataServer: remove the int cast
Why did this cast exist??
2017-02-19 19:27:37 +01:00
Max Kellermann
d84eaeafc5 doc/include/tags.xml: clarify that track/disc are decimal 2017-02-18 19:01:04 +01:00
Max Kellermann
20ae84bff9 {input,mixer}/alsa: cancel the DeferredMonitor in the destructor
Yet another potential crash bug fix.
2017-02-10 15:05:49 +01:00
Max Kellermann
7372c931b3 event/Loop: make IsInsideOrNull() available in the NDEBUG build
Fixes build breakage by commit 4e5271fcdf7; and this method does make
sense in non-debug builds.
2017-02-09 21:21:49 +01:00
Max Kellermann
29e1b6e465 mixer/alsa: reset the MultiSocketMonitor in the destructor
Fixes potential crash bug.
2017-02-09 21:13:19 +01:00
Max Kellermann
eda06993f8 event/MultiSocketMonitor: add method Reset() 2017-02-09 21:12:23 +01:00
Max Kellermann
4b30ef1cf2 event/MultiSocketMonitor: use C++11 initializer 2017-02-09 21:12:23 +01:00
Max Kellermann
e92e5e8eb8 event/MultiSocketMonitor: more API documentation
Now ClearSocketList() may only be called from PrepareSockets().
Calling it before destroying the object doesn't work properly, because
it doesn't unregister the TimeoutMonitor and the IdleMonitor.  Some of
its callers need to be fixed.
2017-02-09 21:12:23 +01:00
Max Kellermann
4e5271fcdf event/Call: allow usage during shutdown
Change EventLoop::IsInside() call to EventLoop::IsInsideOrNull().
This means that BlockingCall() may be used during shutdown, after the
main EventLoop::Run() has finished.  This is important because mixers
are currently registered in the main EventLoop.
2017-02-09 21:12:23 +01:00
Max Kellermann
3c55487a16 configure.ac: don't require libsidutils when building with libsidplayfp
The libsidplayfp fork has merged libsidutils into the main library.
The libsidutils we used to link with was part of the original
libsidplay project.
2017-02-09 13:09:03 +01:00
Max Kellermann
76a1cae5d8 {input,mixer}/alsa: fix off-by-one bug in count check
Doesn't make a practical difference - but it's more correct this way.
2017-02-09 12:46:49 +01:00
Max Kellermann
81a97315e3 NEWS: mention ID3 memory leak fix 2017-02-08 08:44:47 +01:00
Max Kellermann
53c14d97a6 lib/nfs/FileReader: remove debug line 2017-02-08 08:43:56 +01:00
Max Kellermann
69a82eec17 tag/TagId3: use AtScopeExit() for exception-safety 2017-02-06 23:32:07 +01:00
Max Kellermann
45cadef22f configure.ac: prepare for 0.20.5 2017-02-06 23:28:36 +01:00
Max Kellermann
0a033fb10a release v0.20.4 2017-02-01 21:59:36 +01:00
Max Kellermann
591afa0647 lib/nfs/Connection: detect socket hangup and unregister from epoll
Fixes race condition when epoll_ctl() gets called after the socket has
been closed, which may affect a different socket created by another
thread meanwhile.
2017-02-01 21:44:20 +01:00
Max Kellermann
05eac20ffe lib/nfs/Connection: detect libnfs reconnect
When rpc_reconnect_requeue() gets called from inside nfs_service(),
the NfsInputStream can stall completely because the old socket has
been unregistered from epoll automatically, but the new one has never
been registered.  Therefore, nfs_service() will never be called again.

This kludge attempts to detect this condition by checking
nfs_which_events()==POLLOUT.

https://bugs.musicpd.org/view.php?id=4081
2017-02-01 21:36:58 +01:00
Max Kellermann
38d263ac19 output/sndio: work around a libroar C++ incompatibility
Same as in commit e02d8ad8d2, but this time for the sndio plugin
which can be emulated by libroar.
2017-02-01 19:53:23 +01:00
Thomas Zander
f71c204eef Correct method types to match Interface.hxx 2017-01-31 21:22:02 +01:00
Thomas Zander
51147203be free() require cstdlib to be included 2017-01-31 21:21:37 +01:00
Max Kellermann
a931686317 pcm/SampleFormat: workaround for GCC 4.9 "constexpr" bug
GCC 4.9 has incomplete C++14 support.  Specifically, it doesn't allow
switch/case in "constexpr" functions.
2017-01-27 11:02:58 +01:00
Max Kellermann
5bd322bdcf python/libs: upgrade Opus to 1.1.4 2017-01-27 08:47:58 +01:00
Max Kellermann
bb097109f0 configure.ac: prepare for 0.20.4 2017-01-27 08:47:36 +01:00
318 changed files with 1303 additions and 1036 deletions

35
NEWS
View File

@@ -1,3 +1,38 @@
ver 0.20.7 (2017/05/15)
* database
- simple: fix false positive directory loop detection with NFS
* enforce a reasonable minimum audio_buffer_size setting
* cap buffer_before_play at 80% to prevent deadlock
* fix random crashes when compiled with clang
ver 0.20.6 (2017/03/10)
* input
- curl: fix headers after HTTP redirect to Shoutcast server
* decoder
- ffmpeg: re-enable as fallback
- mpcdec: fix crash (division by zero) after seeking
- sidplay: make compatible with libsidplayfp < 1.8
* fix stream tags after automatic song change
* workaround for GCC 4.9.4 / libstdc++ bug (build failure)
ver 0.20.5 (2017/02/20)
* tags
- id3: fix memory leak on corrupt ID3 tags
* decoder
- sidplay: don't require libsidutils when building with libsidplayfp
* output
- httpd: fix two buffer overflows in IcyMetaData length calculation
* mixer
- alsa: fix crash bug
ver 0.20.4 (2017/02/01)
* input
- nfs: fix freeze after reconnect
* output
- sndio: work around a libroar C++ incompatibility
* workaround for GCC 4.9 "constexpr" bug
* fix FreeBSD build failure
ver 0.20.3 (2017/01/25) ver 0.20.3 (2017/01/25)
* protocol * protocol
- "playlistadd" creates new playlist if it does not exist, as documented - "playlistadd" creates new playlist if it does not exist, as documented

View File

@@ -14,7 +14,7 @@ For basic installation information see the INSTALL file.
- [Manual](http://www.musicpd.org/doc/user/) - [Manual](http://www.musicpd.org/doc/user/)
- [Forum](http://forum.musicpd.org/) - [Forum](http://forum.musicpd.org/)
- [IRC](irc://chat.freenode.net/#mpd) - [IRC](irc://chat.freenode.net/#mpd)
- [Bug tracker](http://bugs.musicpd.org/) - [Bug tracker](https://github.com/MusicPlayerDaemon/MPD/issues/)
# Developers # Developers

View File

@@ -87,9 +87,14 @@ class AndroidNdkToolchain:
self.is_armv7 = self.is_arm and 'armv7' in self.cflags self.is_armv7 = self.is_arm and 'armv7' in self.cflags
self.is_windows = False self.is_windows = False
libstdcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/gnu-libstdc++', gcc_version) libcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/llvm-libc++')
libstdcxx_cppflags = '-isystem ' + os.path.join(libstdcxx_path, 'include') + ' -isystem ' + os.path.join(libstdcxx_path, 'libs', android_abi, 'include') libcxx_libs_path = os.path.join(libcxx_path, 'libs', android_abi)
libstdcxx_ldadd = os.path.join(libstdcxx_path, 'libs', android_abi, 'libgnustl_static.a')
libstdcxx_cppflags = '-nostdinc++ -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
libstdcxx_ldadd = os.path.join(libcxx_libs_path, 'libc++_static.a') + ' ' + os.path.join(libcxx_libs_path, 'libc++abi.a')
if self.is_armv7:
libstdcxx_ldadd += ' ' + os.path.join(libcxx_libs_path, 'libunwind.a')
if use_cxx: if use_cxx:
self.libs += ' ' + libstdcxx_ldadd self.libs += ' ' + libstdcxx_ldadd

View File

@@ -1,10 +1,10 @@
AC_PREREQ(2.60) AC_PREREQ(2.60)
AC_INIT(mpd, 0.20.3, musicpd-dev-team@lists.sourceforge.net) AC_INIT(mpd, 0.20.7, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0 VERSION_MAJOR=0
VERSION_MINOR=20 VERSION_MINOR=20
VERSION_REVISION=3 VERSION_REVISION=7
VERSION_EXTRA=0 VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx]) AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -992,7 +992,7 @@ AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enab
dnl --------------------------------- sidplay --------------------------------- dnl --------------------------------- sidplay ---------------------------------
if test x$enable_sidplay != xno; then if test x$enable_sidplay != xno; then
dnl Check for libsidplayfp first dnl Check for libsidplayfp first
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp libsidutils], PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp],
[found_sidplayfp=yes], [found_sidplayfp=yes],
[found_sidplayfp=no]) [found_sidplayfp=no])
found_sidplay=$found_sidplayfp found_sidplay=$found_sidplayfp

View File

@@ -97,20 +97,20 @@ Foo(const char *abc, int xyz)
<para> <para>
MPD sources are managed in a git repository on <ulink MPD sources are managed in a git repository on <ulink
url="http://git.musicpd.org/">git.musicpd.org</ulink>. url="https://github.com/MusicPlayerDaemon/">GitHub</ulink>.
</para> </para>
<para> <para>
Always write your code against the latest git: Always write your code against the latest git:
</para> </para>
<programlisting>git clone git://git.musicpd.org/master/mpd.git</programlisting> <programlisting>git clone git://github.com/MusicPlayerDaemon/MPD</programlisting>
<para> <para>
If you already have a clone, update it: If you already have a clone, update it:
</para> </para>
<programlisting>git pull --rebase git://git.musicpd.org/master/mpd.git master</programlisting> <programlisting>git pull --rebase git://github.com/MusicPlayerDaemon/MPD master</programlisting>
<para> <para>
You can do without "--rebase", but we recommend that you rebase You can do without "--rebase", but we recommend that you rebase
@@ -188,17 +188,7 @@ Foo(const char *abc, int xyz)
</para> </para>
<para> <para>
<command>git pull</command> requests are preferred. Regular <command>git pull</command> requests are preferred.
contributors can get <ulink
url="http://git.musicpd.org/account-policy.html">an account on
git.musicpd.org</ulink>, but any public git repository will do.
</para>
<para>
There is <ulink url="https://github.com/MaxKellermann/MPD">a
mirror of the <application>MPD</application> git repository on
GitHub</ulink>, and you can use that as well to submit pull
requests.
</para> </para>
</chapter> </chapter>

View File

@@ -55,7 +55,8 @@
<listitem> <listitem>
<para> <para>
<varname>track</varname>: the track number within the album. <varname>track</varname>: the decimal track number within the
album.
</para> </para>
</listitem> </listitem>
@@ -103,7 +104,8 @@
<listitem> <listitem>
<para> <para>
<varname>disc</varname>: the disc number in a multi-disc album. <varname>disc</varname>: the decimal disc number in a multi-disc
album.
</para> </para>
</listitem> </listitem>

View File

@@ -48,7 +48,7 @@ mpd.conf(5), mpc(1)
.SH BUGS .SH BUGS
If you find a bug, please report it at If you find a bug, please report it at
.br .br
<\fBhttp://bugs.musicpd.org/bug_report_page.php\fP>. <\fBhttps://github.com/MusicPlayerDaemon/MPD/issues/\fP>.
.SH AUTHORS .SH AUTHORS
Max Kellermann <max.kellermann@gmail.com> Max Kellermann <max.kellermann@gmail.com>

View File

@@ -135,6 +135,91 @@ apt-get install g++ \
</para> </para>
<programlisting>make install</programlisting> <programlisting>make install</programlisting>
<section id="windows_build">
<title>Compiling for Windows</title>
<para>
Even though it does not "feel" like a Windows application,
<application>MPD</application> works well under Windows.
Its build process follows the "Linux style", and may seem
awkward for Windows people (who are not used to compiling
their software, anyway).
</para>
<para>
Basically, there are three ways to compile
<application>MPD</application> for Windows:
</para>
<orderedlist>
<listitem>
<para>
Build on Windows for Windows. All you need to do is
described above already: configure and make.
</para>
<para>
For Windows users, this is kind of unusual, because few
Windows users have a GNU toolchain and a UNIX shell
installed.
</para>
</listitem>
<listitem>
<para>
Build on Linux for Windows. This is described above
already: configure and make. You need the <ulink
url="https://mingw-w64.org/"><application>mingw-w64</application>
cross compiler</ulink>. Pass
<parameter>--host=i686-w64-mingw32</parameter> (32 bit)
or <parameter>--host=x86_64-w64-mingw32</parameter> (64
bit) to configure.
</para>
<para>
This is somewhat natural for Linux users. Many
distributions have <application>mingw-w64</application>
packages. The remaining difficulty here is installing
all the external libraries. And
<application>MPD</application> usually needs many,
making this method cumbersome for the casual user.
</para>
</listitem>
<listitem>
<para>
Build on Linux for Windows using the
<application>MPD</application>'s library build script.
</para>
</listitem>
</orderedlist>
<para>
This section is about the latter.
</para>
<para>
Just like with the native build, unpack the
<application>MPD</application> source tarball and change
into the directory. Then, instead of
<command>./configure</command>, type:
</para>
<programlisting>./win32/build.py --64</programlisting>
<para>
This downloads various library sources, and then configures
and builds <application>MPD</application> (for x64; to build
a 32 bit binary, pass <parameter>--32</parameter>). The
resulting EXE files is linked statically, i.e. it contains
all the libraries already, and you do not need carry DLLs
around. It is large, but easy to use. If you wish to have
a small <filename>mpd.exe</filename> with DLLs, you need to
compile manually, without the <filename>build.py</filename>
script.
</para>
</section>
</section> </section>
<section id="systemd_socket"> <section id="systemd_socket">
@@ -1662,7 +1747,7 @@ buffer_size: 16384</programlisting>
<para> <para>
If you believe you found a bug in If you believe you found a bug in
<application>MPD</application>, report it on <ulink <application>MPD</application>, report it on <ulink
url="https://bugs.musicpd.org/my_view_page.php">the bug url="https://github.com/MusicPlayerDaemon/MPD/issues/">the bug
tracker</ulink>. tracker</ulink>.
</para> </para>
@@ -3995,7 +4080,7 @@ run</programlisting>
(logical "and") can be used to select portions of (logical "and") can be used to select portions of
the format string depending on the existing tag the format string depending on the existing tag
values. Example: values. Example:
<parameter>~/.mpd/recorder/[%title|%name%].ogg</parameter> <parameter>~/.mpd/recorder/[%title%|%name%].ogg</parameter>
(use the "name" tag if no title exists) (use the "name" tag if no title exists)
</para> </para>
</entry> </entry>

View File

@@ -19,8 +19,8 @@ libvorbis = AutotoolsProject(
) )
opus = AutotoolsProject( opus = AutotoolsProject(
'http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz', 'http://downloads.xiph.org/releases/opus/opus-1.1.4.tar.gz',
'32bbb6b557fe1b6066adc0ae1f08b629', '9122b6b380081dd2665189f97bfd777f04f92dc3ab6698eea1dbb27ad59d8692',
'lib/libopus.a', 'lib/libopus.a',
['--disable-shared', '--enable-static'], ['--disable-shared', '--enable-static'],
) )
@@ -36,8 +36,8 @@ flac = AutotoolsProject(
) )
zlib = ZlibProject( zlib = ZlibProject(
'http://zlib.net/zlib-1.2.8.tar.xz', 'http://zlib.net/zlib-1.2.11.tar.xz',
'28f1205d8dd2001f26fec1e8c2cebe37', '4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066',
'lib/libz.a', 'lib/libz.a',
) )
@@ -58,8 +58,8 @@ libmad = AutotoolsProject(
) )
ffmpeg = FfmpegProject( ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-3.2.2.tar.xz', 'http://ffmpeg.org/releases/ffmpeg-3.3.tar.xz',
'3f01bd1fe1a17a277f8c84869e5d9192b4b978cb660872aa2b54c3cc8a2fedfc', '599e7f7c017221c22011c4037b88bdcd1c47cd40c1e466838bc3c465f3e9569d',
'lib/libavcodec.a', 'lib/libavcodec.a',
[ [
'--disable-shared', '--enable-static', '--disable-shared', '--enable-static',
@@ -82,8 +82,8 @@ ffmpeg = FfmpegProject(
) )
curl = AutotoolsProject( curl = AutotoolsProject(
'http://curl.haxx.se/download/curl-7.52.1.tar.lzma', 'http://curl.haxx.se/download/curl-7.54.0.tar.lzma',
'44286d4b825936e2430fc44ad730ce899afb736a5d328cbb8b5d42462f3f2365', 'cd6aa6039f13e0b06e0a93e1b93754f6dc07f444812bb6c32be75a8f28c4070a',
'lib/libcurl.a', 'lib/libcurl.a',
[ [
'--disable-shared', '--enable-static', '--disable-shared', '--enable-static',
@@ -103,7 +103,7 @@ curl = AutotoolsProject(
) )
boost = BoostProject( boost = BoostProject(
'http://downloads.sourceforge.net/project/boost/boost/1.63.0/boost_1_63_0.tar.bz2', 'http://downloads.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2',
'beae2529f759f6b3bf3f4969a19c2e9d6f0c503edcb2de4a61d1428519fcb3b0', '7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332',
'include/boost/version.hpp', 'include/boost/version.hpp',
) )

View File

@@ -24,7 +24,7 @@
#include <stdio.h> #include <stdio.h>
void void
AudioFormat::ApplyMask(AudioFormat mask) AudioFormat::ApplyMask(AudioFormat mask) noexcept
{ {
assert(IsValid()); assert(IsValid());
assert(mask.IsMaskValid()); assert(mask.IsMaskValid());
@@ -42,7 +42,7 @@ AudioFormat::ApplyMask(AudioFormat mask)
} }
StringBuffer<24> StringBuffer<24>
ToString(const AudioFormat af) ToString(const AudioFormat af) noexcept
{ {
StringBuffer<24> buffer; StringBuffer<24> buffer;

View File

@@ -124,7 +124,7 @@ struct AudioFormat {
return !(*this == other); return !(*this == other);
} }
void ApplyMask(AudioFormat mask); void ApplyMask(AudioFormat mask) noexcept;
gcc_pure gcc_pure
AudioFormat WithMask(AudioFormat mask) const { AudioFormat WithMask(AudioFormat mask) const {
@@ -223,6 +223,6 @@ AudioFormat::GetTimeToSize() const
*/ */
gcc_const gcc_const
StringBuffer<24> StringBuffer<24>
ToString(AudioFormat af); ToString(AudioFormat af) noexcept;
#endif #endif

View File

@@ -25,8 +25,6 @@
#ifndef MPD_AUDIO_PARSER_HXX #ifndef MPD_AUDIO_PARSER_HXX
#define MPD_AUDIO_PARSER_HXX #define MPD_AUDIO_PARSER_HXX
#include "Compiler.h"
struct AudioFormat; struct AudioFormat;
/** /**
@@ -38,7 +36,6 @@ struct AudioFormat;
* @param src the input string * @param src the input string
* @param mask if true, then "*" is allowed for any number of items * @param mask if true, then "*" is allowed for any number of items
*/ */
gcc_pure
AudioFormat AudioFormat
ParseAudioFormat(const char *src, bool mask); ParseAudioFormat(const char *src, bool mask);

View File

@@ -37,19 +37,19 @@ DetachedSong::~DetachedSong()
} }
bool bool
DetachedSong::IsRemote() const DetachedSong::IsRemote() const noexcept
{ {
return uri_has_scheme(GetRealURI()); return uri_has_scheme(GetRealURI());
} }
bool bool
DetachedSong::IsAbsoluteFile() const DetachedSong::IsAbsoluteFile() const noexcept
{ {
return PathTraitsUTF8::IsAbsolute(GetRealURI()); return PathTraitsUTF8::IsAbsolute(GetRealURI());
} }
bool bool
DetachedSong::IsInDatabase() const DetachedSong::IsInDatabase() const noexcept
{ {
/* here, we use GetURI() and not GetRealURI() because /* here, we use GetURI() and not GetRealURI() because
GetRealURI() is never relative */ GetRealURI() is never relative */
@@ -59,7 +59,7 @@ DetachedSong::IsInDatabase() const
} }
SignedSongTime SignedSongTime
DetachedSong::GetDuration() const DetachedSong::GetDuration() const noexcept
{ {
SongTime a = start_time, b = end_time; SongTime a = start_time, b = end_time;
if (!b.IsPositive()) { if (!b.IsPositive()) {

View File

@@ -100,7 +100,7 @@ public:
~DetachedSong(); ~DetachedSong();
gcc_pure gcc_pure
const char *GetURI() const { const char *GetURI() const noexcept {
return uri.c_str(); return uri.c_str();
} }
@@ -114,7 +114,7 @@ public:
* displayed URI? * displayed URI?
*/ */
gcc_pure gcc_pure
bool HasRealURI() const { bool HasRealURI() const noexcept {
return !real_uri.empty(); return !real_uri.empty();
} }
@@ -123,7 +123,7 @@ public:
* GetURI(). * GetURI().
*/ */
gcc_pure gcc_pure
const char *GetRealURI() const { const char *GetRealURI() const noexcept {
return (HasRealURI() ? real_uri : uri).c_str(); return (HasRealURI() ? real_uri : uri).c_str();
} }
@@ -137,19 +137,19 @@ public:
* song. * song.
*/ */
gcc_pure gcc_pure
bool IsSame(const DetachedSong &other) const { bool IsSame(const DetachedSong &other) const noexcept {
return uri == other.uri && return uri == other.uri &&
start_time == other.start_time && start_time == other.start_time &&
end_time == other.end_time; end_time == other.end_time;
} }
gcc_pure gcc_nonnull_all gcc_pure gcc_nonnull_all
bool IsURI(const char *other_uri) const { bool IsURI(const char *other_uri) const noexcept {
return uri == other_uri; return uri == other_uri;
} }
gcc_pure gcc_pure
bool IsRemote() const; bool IsRemote() const noexcept;
gcc_pure gcc_pure
bool IsFile() const { bool IsFile() const {
@@ -157,10 +157,10 @@ public:
} }
gcc_pure gcc_pure
bool IsAbsoluteFile() const; bool IsAbsoluteFile() const noexcept;
gcc_pure gcc_pure
bool IsInDatabase() const; bool IsInDatabase() const noexcept;
const Tag &GetTag() const { const Tag &GetTag() const {
return tag; return tag;
@@ -215,7 +215,7 @@ public:
} }
gcc_pure gcc_pure
SignedSongTime GetDuration() const; SignedSongTime GetDuration() const noexcept;
/** /**
* Update the #tag and #mtime. * Update the #tag and #mtime.

View File

@@ -96,7 +96,7 @@ io_thread_deinit(void)
} }
EventLoop & EventLoop &
io_thread_get() io_thread_get() noexcept
{ {
assert(io.loop != nullptr); assert(io.loop != nullptr);
@@ -104,7 +104,7 @@ io_thread_get()
} }
bool bool
io_thread_inside(void) io_thread_inside() noexcept
{ {
return io.thread.IsInside(); return io.thread.IsInside();
} }

View File

@@ -51,13 +51,13 @@ io_thread_deinit();
gcc_const gcc_const
EventLoop & EventLoop &
io_thread_get(); io_thread_get() noexcept;
/** /**
* Is the current thread the I/O thread? * Is the current thread the I/O thread?
*/ */
gcc_pure gcc_pure
bool bool
io_thread_inside(); io_thread_inside() noexcept;
#endif #endif

View File

@@ -46,13 +46,13 @@ static const char *const idle_names[] = {
}; };
const char*const* const char*const*
idle_get_names(void) idle_get_names() noexcept
{ {
return idle_names; return idle_names;
} }
unsigned unsigned
idle_parse_name(const char *name) idle_parse_name(const char *name) noexcept
{ {
#if !CLANG_CHECK_VERSION(3,6) #if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */ /* disabled on clang due to -Wtautological-pointer-compare */

View File

@@ -70,8 +70,9 @@ static constexpr unsigned IDLE_MOUNT = 0x1000;
/** /**
* Get idle names * Get idle names
*/ */
gcc_const
const char*const* const char*const*
idle_get_names(); idle_get_names() noexcept;
/** /**
* Parse an idle name and return its mask. Returns 0 if the given * Parse an idle name and return its mask. Returns 0 if the given
@@ -79,6 +80,6 @@ idle_get_names();
*/ */
gcc_nonnull_all gcc_pure gcc_nonnull_all gcc_pure
unsigned unsigned
idle_parse_name(const char *name); idle_parse_name(const char *name) noexcept;
#endif #endif

View File

@@ -117,7 +117,6 @@ struct Instance final
* DatabaseError if this MPD configuration has no database (no * DatabaseError if this MPD configuration has no database (no
* music_directory was configured). * music_directory was configured).
*/ */
gcc_pure
const Database &GetDatabaseOrThrow() const; const Database &GetDatabaseOrThrow() const;
#endif #endif

View File

@@ -117,7 +117,13 @@
#include <limits.h> #include <limits.h>
static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096; static constexpr size_t KILOBYTE = 1024;
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
static constexpr size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
64 * KILOBYTE);
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10; static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
#ifdef ANDROID #ifdef ANDROID
@@ -130,7 +136,6 @@ struct Config {
ReplayGainConfig replay_gain; ReplayGainConfig replay_gain;
}; };
gcc_const
static Config static Config
LoadConfig() LoadConfig()
{ {
@@ -307,12 +312,17 @@ initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
FormatFatalError("buffer size \"%s\" is not a " FormatFatalError("buffer size \"%s\" is not a "
"positive integer, line %i", "positive integer, line %i",
param->value.c_str(), param->line); param->value.c_str(), param->line);
buffer_size = tmp; buffer_size = tmp * KILOBYTE;
if (buffer_size < MIN_BUFFER_SIZE) {
FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
(unsigned long)buffer_size,
(unsigned long)MIN_BUFFER_SIZE);
buffer_size = MIN_BUFFER_SIZE;
}
} else } else
buffer_size = DEFAULT_BUFFER_SIZE; buffer_size = DEFAULT_BUFFER_SIZE;
buffer_size *= 1024;
const unsigned buffered_chunks = buffer_size / CHUNK_SIZE; const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
if (buffered_chunks >= 1 << 15) if (buffered_chunks >= 1 << 15)
@@ -330,6 +340,19 @@ initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
"than 100 percent, line %i", "than 100 percent, line %i",
param->value.c_str(), param->line); param->value.c_str(), param->line);
} }
if (perc > 80) {
/* this upper limit should avoid deadlocks
which can occur because the DecoderThread
cannot ever fill the music buffer to
exactly 100%; a few chunks always need to
be available to generate silence in
Player::SendSilence() */
FormatError(config_domain,
"buffer_before_play is too large (%f%%), capping at 80%%; please fix your configuration",
perc);
perc = 80;
}
} else } else
perc = DEFAULT_BUFFER_BEFORE_PLAY; perc = DEFAULT_BUFFER_BEFORE_PLAY;

View File

@@ -59,14 +59,14 @@ mapper_init(AllocatedPath &&_playlist_dir)
} }
void void
mapper_finish() mapper_finish() noexcept
{ {
} }
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
AllocatedPath AllocatedPath
map_uri_fs(const char *uri) map_uri_fs(const char *uri) noexcept
{ {
assert(uri != nullptr); assert(uri != nullptr);
assert(*uri != '/'); assert(*uri != '/');
@@ -86,7 +86,7 @@ map_uri_fs(const char *uri)
} }
std::string std::string
map_fs_to_utf8(Path path_fs) map_fs_to_utf8(Path path_fs) noexcept
{ {
if (path_fs.IsAbsolute()) { if (path_fs.IsAbsolute()) {
if (instance->storage == nullptr) if (instance->storage == nullptr)
@@ -109,13 +109,13 @@ map_fs_to_utf8(Path path_fs)
#endif #endif
const AllocatedPath & const AllocatedPath &
map_spl_path() map_spl_path() noexcept
{ {
return playlist_dir_fs; return playlist_dir_fs;
} }
AllocatedPath AllocatedPath
map_spl_utf8_to_fs(const char *name) map_spl_utf8_to_fs(const char *name) noexcept
{ {
if (playlist_dir_fs.IsNull()) if (playlist_dir_fs.IsNull())
return AllocatedPath::Null(); return AllocatedPath::Null();

View File

@@ -37,7 +37,7 @@ void
mapper_init(AllocatedPath &&playlist_dir); mapper_init(AllocatedPath &&playlist_dir);
void void
mapper_finish(); mapper_finish() noexcept;
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
@@ -48,7 +48,7 @@ mapper_finish();
*/ */
gcc_pure gcc_pure
AllocatedPath AllocatedPath
map_uri_fs(const char *uri); map_uri_fs(const char *uri) noexcept;
/** /**
* Maps a file system path (relative to the music directory or * Maps a file system path (relative to the music directory or
@@ -60,7 +60,7 @@ map_uri_fs(const char *uri);
*/ */
gcc_pure gcc_pure
std::string std::string
map_fs_to_utf8(Path path_fs); map_fs_to_utf8(Path path_fs) noexcept;
#endif #endif
@@ -69,7 +69,7 @@ map_fs_to_utf8(Path path_fs);
*/ */
gcc_const gcc_const
const AllocatedPath & const AllocatedPath &
map_spl_path(); map_spl_path() noexcept;
/** /**
* Maps a playlist name (without the ".m3u" suffix) to a file system * Maps a playlist name (without the ".m3u" suffix) to a file system
@@ -79,6 +79,6 @@ map_spl_path();
*/ */
gcc_pure gcc_pure
AllocatedPath AllocatedPath
map_spl_utf8_to_fs(const char *name); map_spl_utf8_to_fs(const char *name) noexcept;
#endif #endif

View File

@@ -23,19 +23,19 @@
#include <assert.h> #include <assert.h>
MusicBuffer::MusicBuffer(unsigned num_chunks) MusicBuffer::MusicBuffer(unsigned num_chunks) noexcept
:buffer(num_chunks) { :buffer(num_chunks) {
} }
MusicChunk * MusicChunk *
MusicBuffer::Allocate() MusicBuffer::Allocate() noexcept
{ {
const std::lock_guard<Mutex> protect(mutex); const std::lock_guard<Mutex> protect(mutex);
return buffer.Allocate(); return buffer.Allocate();
} }
void void
MusicBuffer::Return(MusicChunk *chunk) MusicBuffer::Return(MusicChunk *chunk) noexcept
{ {
assert(chunk != nullptr); assert(chunk != nullptr);

View File

@@ -41,7 +41,7 @@ public:
* @param num_chunks the number of #MusicChunk reserved in * @param num_chunks the number of #MusicChunk reserved in
* this buffer * this buffer
*/ */
MusicBuffer(unsigned num_chunks); MusicBuffer(unsigned num_chunks) noexcept;
#ifndef NDEBUG #ifndef NDEBUG
/** /**
@@ -71,13 +71,13 @@ public:
* @return an empty chunk or nullptr if there are no chunks * @return an empty chunk or nullptr if there are no chunks
* available * available
*/ */
MusicChunk *Allocate(); MusicChunk *Allocate() noexcept;
/** /**
* Returns a chunk to the buffer. It can be reused by * Returns a chunk to the buffer. It can be reused by
* Allocate() then. * Allocate() then.
*/ */
void Return(MusicChunk *chunk); void Return(MusicChunk *chunk) noexcept;
}; };
#endif #endif

View File

@@ -31,7 +31,7 @@ MusicChunk::~MusicChunk()
#ifndef NDEBUG #ifndef NDEBUG
bool bool
MusicChunk::CheckFormat(const AudioFormat other_format) const MusicChunk::CheckFormat(const AudioFormat other_format) const noexcept
{ {
assert(other_format.IsValid()); assert(other_format.IsValid());
@@ -41,7 +41,7 @@ MusicChunk::CheckFormat(const AudioFormat other_format) const
WritableBuffer<void> WritableBuffer<void>
MusicChunk::Write(const AudioFormat af, MusicChunk::Write(const AudioFormat af,
SongTime data_time, uint16_t _bit_rate) SongTime data_time, uint16_t _bit_rate) noexcept
{ {
assert(CheckFormat(af)); assert(CheckFormat(af));
assert(length == 0 || audio_format.IsValid()); assert(length == 0 || audio_format.IsValid());
@@ -64,7 +64,7 @@ MusicChunk::Write(const AudioFormat af,
} }
bool bool
MusicChunk::Expand(const AudioFormat af, size_t _length) MusicChunk::Expand(const AudioFormat af, size_t _length) noexcept
{ {
const size_t frame_size = af.GetFrameSize(); const size_t frame_size = af.GetFrameSize();

View File

@@ -111,7 +111,7 @@ struct MusicChunk {
* specified audio_format. * specified audio_format.
*/ */
gcc_pure gcc_pure
bool CheckFormat(AudioFormat audio_format) const; bool CheckFormat(AudioFormat audio_format) const noexcept;
#endif #endif
/** /**
@@ -127,7 +127,7 @@ struct MusicChunk {
*/ */
WritableBuffer<void> Write(AudioFormat af, WritableBuffer<void> Write(AudioFormat af,
SongTime data_time, SongTime data_time,
uint16_t bit_rate); uint16_t bit_rate) noexcept;
/** /**
* Increases the length of the chunk after the caller has written to * Increases the length of the chunk after the caller has written to
@@ -138,7 +138,7 @@ struct MusicChunk {
* @param length the number of bytes which were appended * @param length the number of bytes which were appended
* @return true if the chunk is full * @return true if the chunk is full
*/ */
bool Expand(AudioFormat af, size_t length); bool Expand(AudioFormat af, size_t length) noexcept;
}; };
#endif #endif

View File

@@ -25,7 +25,7 @@
#ifndef NDEBUG #ifndef NDEBUG
bool bool
MusicPipe::Contains(const MusicChunk *chunk) const MusicPipe::Contains(const MusicChunk *chunk) const noexcept
{ {
const std::lock_guard<Mutex> protect(mutex); const std::lock_guard<Mutex> protect(mutex);

View File

@@ -86,7 +86,7 @@ public:
* Checks if the specified chunk is enqueued in the music pipe. * Checks if the specified chunk is enqueued in the music pipe.
*/ */
gcc_pure gcc_pure
bool Contains(const MusicChunk *chunk) const; bool Contains(const MusicChunk *chunk) const noexcept;
#endif #endif
/** /**

View File

@@ -141,9 +141,9 @@ Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
void void
Partition::OnGlobalEvent(unsigned mask) Partition::OnGlobalEvent(unsigned mask)
{ {
if ((mask & TAG_MODIFIED) != 0)
TagModified();
if ((mask & SYNC_WITH_PLAYER) != 0) if ((mask & SYNC_WITH_PLAYER) != 0)
SyncWithPlayer(); SyncWithPlayer();
if ((mask & TAG_MODIFIED) != 0)
TagModified();
} }

View File

@@ -200,7 +200,6 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
*/ */
const Database *GetDatabase() const; const Database *GetDatabase() const;
gcc_pure
const Database &GetDatabaseOrThrow() const; const Database &GetDatabaseOrThrow() const;
/** /**

View File

@@ -49,7 +49,6 @@ static std::map<std::string, unsigned> permission_passwords;
static unsigned permission_default; static unsigned permission_default;
gcc_pure
static unsigned static unsigned
ParsePermission(const char *p) ParsePermission(const char *p)
{ {

View File

@@ -24,7 +24,7 @@
#include <math.h> #include <math.h>
float float
ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
{ {
float scale; float scale;

View File

@@ -40,23 +40,23 @@ struct ReplayGainTuple {
} }
gcc_pure gcc_pure
float CalculateScale(const ReplayGainConfig &config) const; float CalculateScale(const ReplayGainConfig &config) const noexcept;
}; };
struct ReplayGainInfo { struct ReplayGainInfo {
ReplayGainTuple track, album; ReplayGainTuple track, album;
constexpr bool IsDefined() const { constexpr bool IsDefined() const noexcept {
return track.IsDefined() || album.IsDefined(); return track.IsDefined() || album.IsDefined();
} }
const ReplayGainTuple &Get(ReplayGainMode mode) const { const ReplayGainTuple &Get(ReplayGainMode mode) const noexcept {
return mode == ReplayGainMode::ALBUM return mode == ReplayGainMode::ALBUM
? (album.IsDefined() ? album : track) ? (album.IsDefined() ? album : track)
: (track.IsDefined() ? track : album); : (track.IsDefined() ? track : album);
} }
void Clear() { void Clear() noexcept {
track.Clear(); track.Clear();
album.Clear(); album.Clear();
} }

View File

@@ -25,7 +25,7 @@
#include <string.h> #include <string.h>
const char * const char *
ToString(ReplayGainMode mode) ToString(ReplayGainMode mode) noexcept
{ {
switch (mode) { switch (mode) {
case ReplayGainMode::AUTO: case ReplayGainMode::AUTO:

View File

@@ -36,13 +36,12 @@ enum class ReplayGainMode : uint8_t {
*/ */
gcc_pure gcc_pure
const char * const char *
ToString(ReplayGainMode mode); ToString(ReplayGainMode mode) noexcept;
/** /**
* Parse a string to a #ReplayGainMode. Throws std::runtime_error on * Parse a string to a #ReplayGainMode. Throws std::runtime_error on
* error. * error.
*/ */
gcc_pure
ReplayGainMode ReplayGainMode
FromString(const char *s); FromString(const char *s);

View File

@@ -39,7 +39,7 @@
#define LOCATE_TAG_ANY_KEY "any" #define LOCATE_TAG_ANY_KEY "any"
unsigned unsigned
locate_parse_type(const char *str) locate_parse_type(const char *str) noexcept
{ {
if (StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY) || if (StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY) ||
StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY_OLD)) StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY_OLD))
@@ -57,7 +57,6 @@ locate_parse_type(const char *str)
return tag_name_parse_i(str); return tag_name_parse_i(str);
} }
gcc_pure
static AllocatedString<> static AllocatedString<>
ImportString(const char *p, bool fold_case) ImportString(const char *p, bool fold_case)
{ {
@@ -78,7 +77,7 @@ SongFilter::Item::Item(unsigned _tag, time_t _time)
} }
bool bool
SongFilter::Item::StringMatch(const char *s) const SongFilter::Item::StringMatch(const char *s) const noexcept
{ {
#if !CLANG_CHECK_VERSION(3,6) #if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */ /* disabled on clang due to -Wtautological-pointer-compare */
@@ -97,14 +96,14 @@ SongFilter::Item::StringMatch(const char *s) const
} }
bool bool
SongFilter::Item::Match(const TagItem &item) const SongFilter::Item::Match(const TagItem &item) const noexcept
{ {
return (tag == LOCATE_TAG_ANY_TYPE || (unsigned)item.type == tag) && return (tag == LOCATE_TAG_ANY_TYPE || (unsigned)item.type == tag) &&
StringMatch(item.value); StringMatch(item.value);
} }
bool bool
SongFilter::Item::Match(const Tag &_tag) const SongFilter::Item::Match(const Tag &_tag) const noexcept
{ {
bool visited_types[TAG_NUM_OF_ITEM_TYPES]; bool visited_types[TAG_NUM_OF_ITEM_TYPES];
std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false); std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false);
@@ -140,7 +139,7 @@ SongFilter::Item::Match(const Tag &_tag) const
} }
bool bool
SongFilter::Item::Match(const DetachedSong &song) const SongFilter::Item::Match(const DetachedSong &song) const noexcept
{ {
if (tag == LOCATE_TAG_BASE_TYPE) if (tag == LOCATE_TAG_BASE_TYPE)
return uri_is_child_or_same(value.c_str(), song.GetURI()); return uri_is_child_or_same(value.c_str(), song.GetURI());
@@ -155,7 +154,7 @@ SongFilter::Item::Match(const DetachedSong &song) const
} }
bool bool
SongFilter::Item::Match(const LightSong &song) const SongFilter::Item::Match(const LightSong &song) const noexcept
{ {
if (tag == LOCATE_TAG_BASE_TYPE) { if (tag == LOCATE_TAG_BASE_TYPE) {
const auto uri = song.GetURI(); const auto uri = song.GetURI();
@@ -185,7 +184,7 @@ SongFilter::~SongFilter()
gcc_pure gcc_pure
static time_t static time_t
ParseTimeStamp(const char *s) ParseTimeStamp(const char *s) noexcept
{ {
assert(s != nullptr); assert(s != nullptr);
@@ -246,7 +245,7 @@ SongFilter::Parse(ConstBuffer<const char *> args, bool fold_case)
} }
bool bool
SongFilter::Match(const DetachedSong &song) const SongFilter::Match(const DetachedSong &song) const noexcept
{ {
for (const auto &i : items) for (const auto &i : items)
if (!i.Match(song)) if (!i.Match(song))
@@ -256,7 +255,7 @@ SongFilter::Match(const DetachedSong &song) const
} }
bool bool
SongFilter::Match(const LightSong &song) const SongFilter::Match(const LightSong &song) const noexcept
{ {
for (const auto &i : items) for (const auto &i : items)
if (!i.Match(song)) if (!i.Match(song))
@@ -266,7 +265,7 @@ SongFilter::Match(const LightSong &song) const
} }
bool bool
SongFilter::HasOtherThanBase() const SongFilter::HasOtherThanBase() const noexcept
{ {
for (const auto &i : items) for (const auto &i : items)
if (i.GetTag() != LOCATE_TAG_BASE_TYPE) if (i.GetTag() != LOCATE_TAG_BASE_TYPE)
@@ -276,7 +275,7 @@ SongFilter::HasOtherThanBase() const
} }
const char * const char *
SongFilter::GetBase() const SongFilter::GetBase() const noexcept
{ {
for (const auto &i : items) for (const auto &i : items)
if (i.GetTag() == LOCATE_TAG_BASE_TYPE) if (i.GetTag() == LOCATE_TAG_BASE_TYPE)

View File

@@ -80,19 +80,19 @@ public:
} }
gcc_pure gcc_nonnull(2) gcc_pure gcc_nonnull(2)
bool StringMatch(const char *s) const; bool StringMatch(const char *s) const noexcept;
gcc_pure gcc_pure
bool Match(const TagItem &tag_item) const; bool Match(const TagItem &tag_item) const noexcept;
gcc_pure gcc_pure
bool Match(const Tag &tag) const; bool Match(const Tag &tag) const noexcept;
gcc_pure gcc_pure
bool Match(const DetachedSong &song) const; bool Match(const DetachedSong &song) const noexcept;
gcc_pure gcc_pure
bool Match(const LightSong &song) const; bool Match(const LightSong &song) const noexcept;
}; };
private: private:
@@ -112,20 +112,20 @@ public:
bool Parse(ConstBuffer<const char *> args, bool fold_case=false); bool Parse(ConstBuffer<const char *> args, bool fold_case=false);
gcc_pure gcc_pure
bool Match(const Tag &tag) const; bool Match(const Tag &tag) const noexcept;
gcc_pure gcc_pure
bool Match(const DetachedSong &song) const; bool Match(const DetachedSong &song) const noexcept;
gcc_pure gcc_pure
bool Match(const LightSong &song) const; bool Match(const LightSong &song) const noexcept;
const std::list<Item> &GetItems() const { const std::list<Item> &GetItems() const noexcept {
return items; return items;
} }
gcc_pure gcc_pure
bool IsEmpty() const { bool IsEmpty() const noexcept {
return items.empty(); return items.empty();
} }
@@ -133,7 +133,7 @@ public:
* Is there at least one item with "fold case" enabled? * Is there at least one item with "fold case" enabled?
*/ */
gcc_pure gcc_pure
bool HasFoldCase() const { bool HasFoldCase() const noexcept {
for (const auto &i : items) for (const auto &i : items)
if (i.GetFoldCase()) if (i.GetFoldCase())
return true; return true;
@@ -145,14 +145,14 @@ public:
* Does this filter contain constraints other than "base"? * Does this filter contain constraints other than "base"?
*/ */
gcc_pure gcc_pure
bool HasOtherThanBase() const; bool HasOtherThanBase() const noexcept;
/** /**
* Returns the "base" specification (if there is one) or * Returns the "base" specification (if there is one) or
* nullptr. * nullptr.
*/ */
gcc_pure gcc_pure
const char *GetBase() const; const char *GetBase() const noexcept;
}; };
/** /**
@@ -160,6 +160,6 @@ public:
*/ */
gcc_pure gcc_pure
unsigned unsigned
locate_parse_type(const char *str); locate_parse_type(const char *str) noexcept;
#endif #endif

View File

@@ -50,7 +50,7 @@ StateFile::StateFile(AllocatedPath &&_path,
} }
void void
StateFile::RememberVersions() StateFile::RememberVersions() noexcept
{ {
prev_volume_version = sw_volume_state_get_hash(); prev_volume_version = sw_volume_state_get_hash();
prev_output_version = audio_output_state_get_version(); prev_output_version = audio_output_state_get_version();
@@ -59,7 +59,7 @@ StateFile::RememberVersions()
} }
bool bool
StateFile::IsModified() const StateFile::IsModified() const noexcept
{ {
return prev_volume_version != sw_volume_state_get_hash() || return prev_volume_version != sw_volume_state_get_hash() ||
prev_output_version != audio_output_state_get_version() || prev_output_version != audio_output_state_get_version() ||

View File

@@ -67,14 +67,14 @@ private:
/** /**
* Save the current state versions for use with IsModified(). * Save the current state versions for use with IsModified().
*/ */
void RememberVersions(); void RememberVersions() noexcept;
/** /**
* Check if MPD's state was modified since the last * Check if MPD's state was modified since the last
* RememberVersions() call. * RememberVersions() call.
*/ */
gcc_pure gcc_pure
bool IsModified() const; bool IsModified() const noexcept;
/* virtual methods from TimeoutMonitor */ /* virtual methods from TimeoutMonitor */
void OnTimeout() override; void OnTimeout() override;

View File

@@ -40,7 +40,7 @@
gcc_pure gcc_pure
static bool static bool
CheckDecoderPlugin(const DecoderPlugin &plugin, CheckDecoderPlugin(const DecoderPlugin &plugin,
const char *suffix, const char *mime) const char *suffix, const char *mime) noexcept
{ {
return (mime != nullptr && plugin.SupportsMimeType(mime)) || return (mime != nullptr && plugin.SupportsMimeType(mime)) ||
(suffix != nullptr && plugin.SupportsSuffix(suffix)); (suffix != nullptr && plugin.SupportsSuffix(suffix));

View File

@@ -28,7 +28,7 @@
gcc_pure gcc_pure
static char * static char *
FindSlash(char *p, size_t i) FindSlash(char *p, size_t i) noexcept
{ {
for (; i > 0; --i) for (; i > 0; --i)
if (p[i] == '/') if (p[i] == '/')
@@ -39,7 +39,7 @@ FindSlash(char *p, size_t i)
gcc_pure gcc_pure
static const char * static const char *
FindSuffix(const char *p, const char *i) FindSuffix(const char *p, const char *i) noexcept
{ {
for (; i > p; --i) { for (; i > p; --i) {
if (*i == '.') if (*i == '.')

View File

@@ -93,7 +93,7 @@ public:
~Bzip2InputStream(); ~Bzip2InputStream();
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() override; bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(void *ptr, size_t size) override;
private: private:
@@ -205,7 +205,7 @@ Bzip2InputStream::Read(void *ptr, size_t length)
} }
bool bool
Bzip2InputStream::IsEOF() Bzip2InputStream::IsEOF() noexcept
{ {
return eof; return eof;
} }

View File

@@ -162,7 +162,7 @@ public:
} }
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() override; bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(void *ptr, size_t size) override;
}; };
@@ -213,7 +213,7 @@ Iso9660InputStream::Read(void *ptr, size_t read_size)
} }
bool bool
Iso9660InputStream::IsEOF() Iso9660InputStream::IsEOF() noexcept
{ {
return offset == size; return offset == size;
} }

View File

@@ -116,7 +116,7 @@ struct ZzipInputStream final : public InputStream {
} }
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() override; bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(void *ptr, size_t size) override;
void Seek(offset_type offset) override; void Seek(offset_type offset) override;
}; };
@@ -147,7 +147,7 @@ ZzipInputStream::Read(void *ptr, size_t read_size)
} }
bool bool
ZzipInputStream::IsEOF() ZzipInputStream::IsEOF() noexcept
{ {
return offset_type(zzip_tell(file)) == size; return offset_type(zzip_tell(file)) == size;
} }

View File

@@ -28,7 +28,7 @@ const Domain client_domain("client");
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
const Database * const Database *
Client::GetDatabase() const Client::GetDatabase() const noexcept
{ {
return partition.instance.GetDatabase(); return partition.instance.GetDatabase();
} }
@@ -40,7 +40,7 @@ Client::GetDatabaseOrThrow() const
} }
const Storage * const Storage *
Client::GetStorage() const Client::GetStorage() const noexcept
{ {
return partition.instance.storage; return partition.instance.storage;
} }

View File

@@ -160,7 +160,7 @@ public:
}; };
gcc_pure gcc_pure
bool IsSubscribed(const char *channel_name) const { bool IsSubscribed(const char *channel_name) const noexcept {
return subscriptions.find(channel_name) != subscriptions.end(); return subscriptions.find(channel_name) != subscriptions.end();
} }
@@ -186,16 +186,15 @@ public:
* Wrapper for Instance::GetDatabase(). * Wrapper for Instance::GetDatabase().
*/ */
gcc_pure gcc_pure
const Database *GetDatabase() const; const Database *GetDatabase() const noexcept;
/** /**
* Wrapper for Instance::GetDatabaseOrThrow(). * Wrapper for Instance::GetDatabaseOrThrow().
*/ */
gcc_pure
const Database &GetDatabaseOrThrow() const; const Database &GetDatabaseOrThrow() const;
gcc_pure gcc_pure
const Storage *GetStorage() const; const Storage *GetStorage() const noexcept;
private: private:
/* virtual methods from class BufferedSocket */ /* virtual methods from class BufferedSocket */

View File

@@ -23,14 +23,14 @@
gcc_const gcc_const
static bool static bool
valid_channel_char(const char ch) valid_channel_char(const char ch) noexcept
{ {
return IsAlphaNumericASCII(ch) || return IsAlphaNumericASCII(ch) ||
ch == '_' || ch == '-' || ch == '.' || ch == ':'; ch == '_' || ch == '-' || ch == '.' || ch == ':';
} }
bool bool
client_message_valid_channel_name(const char *name) client_message_valid_channel_name(const char *name) noexcept
{ {
do { do {
if (!valid_channel_char(*name)) if (!valid_channel_char(*name))

View File

@@ -53,6 +53,6 @@ public:
gcc_pure gcc_pure
bool bool
client_message_valid_channel_name(const char *name); client_message_valid_channel_name(const char *name) noexcept;
#endif #endif

View File

@@ -29,9 +29,32 @@
#include <assert.h> #include <assert.h>
#define GLIBCXX_490 20140422
#define GLIBCXX_491 20140716
#define GLIBCXX_492 20141030
#define GLIBCXX_492_Debian_9 20141220
#define GLIBCXX_493 20150626
#define GLIBCXX_494 20160803
#define GLIBCXX_49X_NDK_r13b 20150123
/* the big mess attempts to detect whether we're compiling with
libstdc++ 4.9.x; __GLIBCXX__ is a date tag and cannot be used to
check the major version; and just checking the compiler version
isn't enough, because somebody could use an old libstdc++ with
clang - SIGH! */
#if GCC_OLDER_THAN(5,0) || (defined(__GLIBCXX__) && \
(__GLIBCXX__ == GLIBCXX_490 || __GLIBCXX__ == GLIBCXX_491 || \
__GLIBCXX__ == GLIBCXX_492 || \
__GLIBCXX__ == GLIBCXX_492_Debian_9 || \
__GLIBCXX__ == GLIBCXX_493 || \
__GLIBCXX__ == GLIBCXX_494 || \
__GLIBCXX__ == GLIBCXX_49X_NDK_r13b))
#define GLIBCXX_49X
#endif
gcc_const gcc_const
static enum ack static enum ack
ToAck(PlaylistResult result) ToAck(PlaylistResult result) noexcept
{ {
switch (result) { switch (result) {
case PlaylistResult::SUCCESS: case PlaylistResult::SUCCESS:
@@ -67,7 +90,7 @@ ToAck(PlaylistResult result)
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
gcc_const gcc_const
static enum ack static enum ack
ToAck(DatabaseErrorCode code) ToAck(DatabaseErrorCode code) noexcept
{ {
switch (code) { switch (code) {
case DatabaseErrorCode::DISABLED: case DatabaseErrorCode::DISABLED:
@@ -84,7 +107,7 @@ ToAck(DatabaseErrorCode code)
gcc_pure gcc_pure
static enum ack static enum ack
ToAck(std::exception_ptr ep) ToAck(std::exception_ptr ep) noexcept
{ {
try { try {
std::rethrow_exception(ep); std::rethrow_exception(ep);
@@ -100,13 +123,13 @@ ToAck(std::exception_ptr ep)
return ACK_ERROR_SYSTEM; return ACK_ERROR_SYSTEM;
} catch (const std::invalid_argument &e) { } catch (const std::invalid_argument &e) {
return ACK_ERROR_ARG; return ACK_ERROR_ARG;
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204 #ifdef GLIBCXX_49X
} catch (const std::exception &e) { } catch (const std::exception &e) {
#else #else
} catch (...) { } catch (...) {
#endif #endif
try { try {
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204 #ifdef GLIBCXX_49X
/* workaround for g++ 4.x: no overload for /* workaround for g++ 4.x: no overload for
rethrow_exception(exception_ptr) */ rethrow_exception(exception_ptr) */
std::rethrow_if_nested(e); std::rethrow_if_nested(e);

View File

@@ -44,7 +44,7 @@
gcc_pure gcc_pure
static bool static bool
SkipNameFS(PathTraitsFS::const_pointer_type name_fs) SkipNameFS(PathTraitsFS::const_pointer_type name_fs) noexcept
{ {
return name_fs[0] == '.' && return name_fs[0] == '.' &&
(name_fs[1] == 0 || (name_fs[1] == 0 ||
@@ -53,7 +53,7 @@ SkipNameFS(PathTraitsFS::const_pointer_type name_fs)
gcc_pure gcc_pure
static bool static bool
skip_path(Path name_fs) skip_path(Path name_fs) noexcept
{ {
return name_fs.HasNewline(); return name_fs.HasNewline();
} }
@@ -107,7 +107,7 @@ handle_listfiles_local(Response &r, Path path_fs)
gcc_pure gcc_pure
static bool static bool
IsValidName(const char *p) IsValidName(const char *p) noexcept
{ {
if (!IsAlphaASCII(*p)) if (!IsAlphaASCII(*p))
return false; return false;
@@ -123,7 +123,7 @@ IsValidName(const char *p)
gcc_pure gcc_pure
static bool static bool
IsValidValue(const char *p) IsValidValue(const char *p) noexcept
{ {
while (*p) { while (*p) {
const char ch = *p++; const char ch = *p++;

View File

@@ -30,7 +30,7 @@
#include <string> #include <string>
bool bool
neighbor_commands_available(const Instance &instance) neighbor_commands_available(const Instance &instance) noexcept
{ {
return instance.neighbors != nullptr; return instance.neighbors != nullptr;
} }

View File

@@ -30,7 +30,7 @@ class Response;
gcc_pure gcc_pure
bool bool
neighbor_commands_available(const Instance &instance); neighbor_commands_available(const Instance &instance) noexcept;
CommandResult CommandResult
handle_listneighbors(Client &client, Request request, Response &response); handle_listneighbors(Client &client, Request request, Response &response);

View File

@@ -39,7 +39,7 @@
#include "util/ConstBuffer.hxx" #include "util/ConstBuffer.hxx"
bool bool
playlist_commands_available() playlist_commands_available() noexcept
{ {
return !map_spl_path().IsNull(); return !map_spl_path().IsNull();
} }

View File

@@ -29,7 +29,7 @@ class Response;
gcc_const gcc_const
bool bool
playlist_commands_available(); playlist_commands_available() noexcept;
CommandResult CommandResult
handle_save(Client &client, Request request, Response &response); handle_save(Client &client, Request request, Response &response);

View File

@@ -45,7 +45,7 @@
gcc_pure gcc_pure
static bool static bool
skip_path(const char *name_utf8) skip_path(const char *name_utf8) noexcept
{ {
return strchr(name_utf8, '\n') != nullptr; return strchr(name_utf8, '\n') != nullptr;
} }

View File

@@ -68,7 +68,7 @@ ConfigBlock::~ConfigBlock()
} }
const BlockParam * const BlockParam *
ConfigBlock::GetBlockParam(const char *name) const ConfigBlock::GetBlockParam(const char *name) const noexcept
{ {
for (const auto &i : block_params) { for (const auto &i : block_params) {
if (i.name == name) { if (i.name == name) {
@@ -81,7 +81,8 @@ ConfigBlock::GetBlockParam(const char *name) const
} }
const char * const char *
ConfigBlock::GetBlockValue(const char *name, const char *default_value) const ConfigBlock::GetBlockValue(const char *name,
const char *default_value) const noexcept
{ {
const BlockParam *bp = GetBlockParam(name); const BlockParam *bp = GetBlockParam(name);
if (bp == nullptr) if (bp == nullptr)
@@ -128,7 +129,6 @@ ConfigBlock::GetBlockValue(const char *name, unsigned default_value) const
return bp->GetUnsignedValue(); return bp->GetUnsignedValue();
} }
gcc_pure
bool bool
ConfigBlock::GetBlockValue(const char *name, bool default_value) const ConfigBlock::GetBlockValue(const char *name, bool default_value) const
{ {

View File

@@ -44,13 +44,10 @@ struct BlockParam {
BlockParam(const char *_name, const char *_value, int _line=-1) BlockParam(const char *_name, const char *_value, int _line=-1)
:name(_name), value(_value), line(_line), used(false) {} :name(_name), value(_value), line(_line), used(false) {}
gcc_pure
int GetIntValue() const; int GetIntValue() const;
gcc_pure
unsigned GetUnsignedValue() const; unsigned GetUnsignedValue() const;
gcc_pure
bool GetBoolValue() const; bool GetBoolValue() const;
}; };
@@ -101,11 +98,11 @@ struct ConfigBlock {
} }
gcc_nonnull_all gcc_pure gcc_nonnull_all gcc_pure
const BlockParam *GetBlockParam(const char *_name) const; const BlockParam *GetBlockParam(const char *_name) const noexcept;
gcc_pure gcc_pure
const char *GetBlockValue(const char *name, const char *GetBlockValue(const char *name,
const char *default_value=nullptr) const; const char *default_value=nullptr) const noexcept;
/** /**
* Same as config_get_path(), but looks up the setting in the * Same as config_get_path(), but looks up the setting in the
@@ -116,13 +113,10 @@ struct ConfigBlock {
AllocatedPath GetPath(const char *name, AllocatedPath GetPath(const char *name,
const char *default_value=nullptr) const; const char *default_value=nullptr) const;
gcc_pure
int GetBlockValue(const char *name, int default_value) const; int GetBlockValue(const char *name, int default_value) const;
gcc_pure
unsigned GetBlockValue(const char *name, unsigned default_value) const; unsigned GetBlockValue(const char *name, unsigned default_value) const;
gcc_pure
bool GetBlockValue(const char *name, bool default_value) const; bool GetBlockValue(const char *name, bool default_value) const;
}; };

View File

@@ -75,7 +75,7 @@ void config_global_check(void)
} }
const ConfigParam * const ConfigParam *
config_get_param(ConfigOption option) config_get_param(ConfigOption option) noexcept
{ {
auto *param = config_data.params[unsigned(option)]; auto *param = config_data.params[unsigned(option)];
if (param != nullptr) if (param != nullptr)
@@ -84,7 +84,7 @@ config_get_param(ConfigOption option)
} }
const ConfigBlock * const ConfigBlock *
config_get_block(ConfigBlockOption option) config_get_block(ConfigBlockOption option) noexcept
{ {
ConfigBlock *block = config_data.blocks[unsigned(option)]; ConfigBlock *block = config_data.blocks[unsigned(option)];
if (block != nullptr) if (block != nullptr)
@@ -110,7 +110,7 @@ config_find_block(ConfigBlockOption option, const char *key, const char *value)
} }
const char * const char *
config_get_string(ConfigOption option, const char *default_value) config_get_string(ConfigOption option, const char *default_value) noexcept
{ {
const auto *param = config_get_param(option); const auto *param = config_get_param(option);

View File

@@ -48,11 +48,11 @@ ReadConfigFile(Path path);
gcc_pure gcc_pure
const ConfigParam * const ConfigParam *
config_get_param(enum ConfigOption option); config_get_param(enum ConfigOption option) noexcept;
gcc_pure gcc_pure
const ConfigBlock * const ConfigBlock *
config_get_block(enum ConfigBlockOption option); config_get_block(enum ConfigBlockOption option) noexcept;
/** /**
* Find a block with a matching attribute. * Find a block with a matching attribute.
@@ -61,20 +61,12 @@ config_get_block(enum ConfigBlockOption option);
* @param key the attribute name * @param key the attribute name
* @param value the expected attribute value * @param value the expected attribute value
*/ */
gcc_pure
const ConfigBlock * const ConfigBlock *
config_find_block(ConfigBlockOption option, const char *key, const char *value); config_find_block(ConfigBlockOption option, const char *key, const char *value);
/* Note on gcc_pure: Some of the functions declared pure are not
really pure in strict sense. They have side effect such that they
validate parameter's value and signal an error if it's invalid.
However, if the argument was already validated or we don't care
about the argument at all, this may be ignored so in the end, we
should be fine with calling those functions pure. */
gcc_pure
const char * const char *
config_get_string(enum ConfigOption option, const char *default_value=nullptr); config_get_string(enum ConfigOption option,
const char *default_value=nullptr) noexcept;
/** /**
* Returns an optional configuration variable which contains an * Returns an optional configuration variable which contains an
@@ -86,11 +78,9 @@ config_get_string(enum ConfigOption option, const char *default_value=nullptr);
AllocatedPath AllocatedPath
config_get_path(enum ConfigOption option); config_get_path(enum ConfigOption option);
gcc_pure
unsigned unsigned
config_get_unsigned(enum ConfigOption option, unsigned default_value); config_get_unsigned(enum ConfigOption option, unsigned default_value);
gcc_pure
static inline std::chrono::steady_clock::duration static inline std::chrono::steady_clock::duration
config_get_unsigned(ConfigOption option, config_get_unsigned(ConfigOption option,
std::chrono::steady_clock::duration default_value) std::chrono::steady_clock::duration default_value)
@@ -100,11 +90,9 @@ config_get_unsigned(ConfigOption option,
return std::chrono::steady_clock::duration(u); return std::chrono::steady_clock::duration(u);
} }
gcc_pure
unsigned unsigned
config_get_positive(enum ConfigOption option, unsigned default_value); config_get_positive(enum ConfigOption option, unsigned default_value);
gcc_pure
static inline std::chrono::steady_clock::duration static inline std::chrono::steady_clock::duration
config_get_positive(ConfigOption option, config_get_positive(ConfigOption option,
std::chrono::steady_clock::duration default_value) std::chrono::steady_clock::duration default_value)
@@ -114,7 +102,6 @@ config_get_positive(ConfigOption option,
return std::chrono::steady_clock::duration(u); return std::chrono::steady_clock::duration(u);
} }
gcc_pure
bool config_get_bool(enum ConfigOption option, bool default_value); bool config_get_bool(enum ConfigOption option, bool default_value);
#endif #endif

View File

@@ -102,13 +102,13 @@ enum class ConfigBlockOption {
*/ */
gcc_pure gcc_pure
enum ConfigOption enum ConfigOption
ParseConfigOptionName(const char *name); ParseConfigOptionName(const char *name) noexcept;
/** /**
* @return #ConfigOption::MAX if not found * @return #ConfigOption::MAX if not found
*/ */
gcc_pure gcc_pure
enum ConfigBlockOption enum ConfigBlockOption
ParseConfigBlockOptionName(const char *name); ParseConfigBlockOptionName(const char *name) noexcept;
#endif #endif

View File

@@ -101,7 +101,7 @@ static_assert(n_config_block_templates == unsigned(ConfigBlockOption::MAX),
gcc_pure gcc_pure
static inline unsigned static inline unsigned
ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count, ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
const char *name) const char *name) noexcept
{ {
unsigned i = 0; unsigned i = 0;
for (; i < count; ++i) for (; i < count; ++i)
@@ -112,7 +112,7 @@ ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
} }
ConfigOption ConfigOption
ParseConfigOptionName(const char *name) ParseConfigOptionName(const char *name) noexcept
{ {
return ConfigOption(ParseConfigTemplateName(config_param_templates, return ConfigOption(ParseConfigTemplateName(config_param_templates,
n_config_param_templates, n_config_param_templates,
@@ -120,7 +120,7 @@ ParseConfigOptionName(const char *name)
} }
ConfigBlockOption ConfigBlockOption
ParseConfigBlockOptionName(const char *name) ParseConfigBlockOptionName(const char *name) noexcept
{ {
return ConfigBlockOption(ParseConfigTemplateName(config_block_templates, return ConfigBlockOption(ParseConfigTemplateName(config_block_templates,
n_config_block_templates, n_config_block_templates,

View File

@@ -71,7 +71,6 @@ struct ConfigParam {
* *
* Throws #std::runtime_error on error. * Throws #std::runtime_error on error.
*/ */
gcc_pure
AllocatedPath GetPath() const; AllocatedPath GetPath() const;
}; };

View File

@@ -62,7 +62,7 @@ Print(Response &r, TagType group, const TagCountMap &m)
} }
} }
static bool static void
stats_visitor_song(SearchStats &stats, const LightSong &song) stats_visitor_song(SearchStats &stats, const LightSong &song)
{ {
stats.n_songs++; stats.n_songs++;
@@ -70,8 +70,6 @@ stats_visitor_song(SearchStats &stats, const LightSong &song)
const auto duration = song.GetDuration(); const auto duration = song.GetDuration();
if (!duration.IsNegative()) if (!duration.IsNegative())
stats.total_duration += duration; stats.total_duration += duration;
return true;
} }
static bool static bool
@@ -94,7 +92,7 @@ CollectGroupCounts(TagCountMap &map, TagType group, const Tag &tag)
return found; return found;
} }
static bool static void
GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song) GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
{ {
assert(song.tag != nullptr); assert(song.tag != nullptr);
@@ -103,8 +101,6 @@ GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
if (!CollectGroupCounts(map, group, tag) && group == TAG_ALBUM_ARTIST) if (!CollectGroupCounts(map, group, tag) && group == TAG_ALBUM_ARTIST)
/* fall back to "Artist" if no "AlbumArtist" was found */ /* fall back to "Artist" if no "AlbumArtist" was found */
CollectGroupCounts(map, TAG_ARTIST, tag); CollectGroupCounts(map, TAG_ARTIST, tag);
return true;
} }
void void

View File

@@ -45,7 +45,7 @@ extern ThreadId db_mutex_holder;
*/ */
gcc_pure gcc_pure
static inline bool static inline bool
holding_db_lock(void) holding_db_lock() noexcept
{ {
return db_mutex_holder.IsInside(); return db_mutex_holder.IsInside();
} }

View File

@@ -27,13 +27,12 @@
#include <functional> #include <functional>
static bool static void
AddSong(const Storage &storage, const char *playlist_path_utf8, AddSong(const Storage &storage, const char *playlist_path_utf8,
const LightSong &song) const LightSong &song)
{ {
spl_append_song(playlist_path_utf8, spl_append_song(playlist_path_utf8,
DatabaseDetachSong(storage, song)); DatabaseDetachSong(storage, song));
return true;
} }
void void

View File

@@ -49,16 +49,14 @@ PrintDirectoryURI(Response &r, bool base, const LightDirectory &directory)
ApplyBaseFlag(directory.GetPath(), base)); ApplyBaseFlag(directory.GetPath(), base));
} }
static bool static void
PrintDirectoryBrief(Response &r, bool base, const LightDirectory &directory) PrintDirectoryBrief(Response &r, bool base, const LightDirectory &directory)
{ {
if (!directory.IsRoot()) if (!directory.IsRoot())
PrintDirectoryURI(r, base, directory); PrintDirectoryURI(r, base, directory);
return true;
} }
static bool static void
PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory) PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
{ {
if (!directory.IsRoot()) { if (!directory.IsRoot()) {
@@ -67,8 +65,6 @@ PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
if (directory.mtime > 0) if (directory.mtime > 0)
time_print(r, "Last-Modified", directory.mtime); time_print(r, "Last-Modified", directory.mtime);
} }
return true;
} }
static void static void
@@ -96,7 +92,7 @@ print_playlist_in_directory(Response &r, bool base,
directory->GetPath(), name_utf8); directory->GetPath(), name_utf8);
} }
static bool static void
PrintSongBrief(Response &r, Partition &partition, PrintSongBrief(Response &r, Partition &partition,
bool base, const LightSong &song) bool base, const LightSong &song)
{ {
@@ -106,11 +102,9 @@ PrintSongBrief(Response &r, Partition &partition,
/* this song file has an embedded CUE sheet */ /* this song file has an embedded CUE sheet */
print_playlist_in_directory(r, base, print_playlist_in_directory(r, base,
song.directory, song.uri); song.directory, song.uri);
return true;
} }
static bool static void
PrintSongFull(Response &r, Partition &partition, PrintSongFull(Response &r, Partition &partition,
bool base, const LightSong &song) bool base, const LightSong &song)
{ {
@@ -120,21 +114,18 @@ PrintSongFull(Response &r, Partition &partition,
/* this song file has an embedded CUE sheet */ /* this song file has an embedded CUE sheet */
print_playlist_in_directory(r, base, print_playlist_in_directory(r, base,
song.directory, song.uri); song.directory, song.uri);
return true;
} }
static bool static void
PrintPlaylistBrief(Response &r, bool base, PrintPlaylistBrief(Response &r, bool base,
const PlaylistInfo &playlist, const PlaylistInfo &playlist,
const LightDirectory &directory) const LightDirectory &directory)
{ {
print_playlist_in_directory(r, base, print_playlist_in_directory(r, base,
&directory, playlist.name.c_str()); &directory, playlist.name.c_str());
return true;
} }
static bool static void
PrintPlaylistFull(Response &r, bool base, PrintPlaylistFull(Response &r, bool base,
const PlaylistInfo &playlist, const PlaylistInfo &playlist,
const LightDirectory &directory) const LightDirectory &directory)
@@ -144,8 +135,6 @@ PrintPlaylistFull(Response &r, bool base,
if (playlist.mtime > 0) if (playlist.mtime > 0)
time_print(r, "Last-Modified", playlist.mtime); time_print(r, "Last-Modified", playlist.mtime);
return true;
} }
void void
@@ -191,15 +180,13 @@ db_selection_print(Response &r, Partition &partition,
0, std::numeric_limits<int>::max()); 0, std::numeric_limits<int>::max());
} }
static bool static void
PrintSongURIVisitor(Response &r, Partition &partition, const LightSong &song) PrintSongURIVisitor(Response &r, Partition &partition, const LightSong &song)
{ {
song_print_uri(r, partition, song); song_print_uri(r, partition, song);
return true;
} }
static bool static void
PrintUniqueTag(Response &r, TagType tag_type, PrintUniqueTag(Response &r, TagType tag_type,
const Tag &tag) const Tag &tag)
{ {
@@ -211,8 +198,6 @@ PrintUniqueTag(Response &r, TagType tag_type,
if (item.type != tag_type) if (item.type != tag_type)
r.Format("%s: %s\n", r.Format("%s: %s\n",
tag_item_names[item.type], item.value); tag_item_names[item.type], item.value);
return true;
} }
void void

View File

@@ -27,14 +27,13 @@
#include <functional> #include <functional>
static bool static void
AddToQueue(Partition &partition, const LightSong &song) AddToQueue(Partition &partition, const LightSong &song)
{ {
const Storage &storage = *partition.instance.storage; const Storage &storage = *partition.instance.storage;
partition.playlist.AppendSong(partition.pc, partition.playlist.AppendSong(partition.pc,
DatabaseDetachSong(storage, DatabaseDetachSong(storage,
song)); song));
return true;
} }
void void

View File

@@ -31,7 +31,6 @@ class DetachedSong;
* "Detach" the #Song object, i.e. convert it to a #DetachedSong * "Detach" the #Song object, i.e. convert it to a #DetachedSong
* instance. * instance.
*/ */
gcc_pure
DetachedSong DetachedSong
DatabaseDetachSong(const Storage &storage, const LightSong &song); DatabaseDetachSong(const Storage &storage, const LightSong &song);

View File

@@ -67,15 +67,13 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
} }
} }
static bool static void
StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums, StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums,
const LightSong &song) const LightSong &song)
{ {
++stats.song_count; ++stats.song_count;
StatsVisitTag(stats, artists, albums, *song.tag); StatsVisitTag(stats, artists, albums, *song.tag);
return true;
} }
DatabaseStats DatabaseStats

View File

@@ -21,7 +21,7 @@
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
SignedSongTime SignedSongTime
LightSong::GetDuration() const LightSong::GetDuration() const noexcept
{ {
SongTime a = start_time, b = end_time; SongTime a = start_time, b = end_time;
if (!b.IsPositive()) { if (!b.IsPositive()) {

View File

@@ -76,7 +76,7 @@ struct LightSong {
SongTime end_time; SongTime end_time;
gcc_pure gcc_pure
std::string GetURI() const { std::string GetURI() const noexcept {
if (directory == nullptr) if (directory == nullptr)
return std::string(uri); return std::string(uri);
@@ -87,7 +87,7 @@ struct LightSong {
} }
gcc_pure gcc_pure
SignedSongTime GetDuration() const; SignedSongTime GetDuration() const noexcept;
}; };
#endif #endif

View File

@@ -26,7 +26,7 @@
#include <assert.h> #include <assert.h>
PlaylistVector::iterator PlaylistVector::iterator
PlaylistVector::find(const char *name) PlaylistVector::find(const char *name) noexcept
{ {
assert(holding_db_lock()); assert(holding_db_lock());
assert(name != nullptr); assert(name != nullptr);

View File

@@ -31,7 +31,7 @@ protected:
* Caller must lock the #db_mutex. * Caller must lock the #db_mutex.
*/ */
gcc_pure gcc_pure
iterator find(const char *name); iterator find(const char *name) noexcept;
public: public:
using std::list<PlaylistInfo>::empty; using std::list<PlaylistInfo>::empty;

View File

@@ -38,7 +38,7 @@ const DatabasePlugin *const database_plugins[] = {
}; };
const DatabasePlugin * const DatabasePlugin *
GetDatabasePluginByName(const char *name) GetDatabasePluginByName(const char *name) noexcept
{ {
for (auto i = database_plugins; *i != nullptr; ++i) for (auto i = database_plugins; *i != nullptr; ++i)
if (strcmp((*i)->name, name) == 0) if (strcmp((*i)->name, name) == 0)

View File

@@ -32,6 +32,6 @@ extern const DatabasePlugin *const database_plugins[];
gcc_pure gcc_pure
const DatabasePlugin * const DatabasePlugin *
GetDatabasePluginByName(const char *name); GetDatabasePluginByName(const char *name) noexcept;
#endif #endif

View File

@@ -34,19 +34,19 @@ DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
} }
bool bool
DatabaseSelection::IsEmpty() const DatabaseSelection::IsEmpty() const noexcept
{ {
return uri.empty() && (filter == nullptr || filter->IsEmpty()); return uri.empty() && (filter == nullptr || filter->IsEmpty());
} }
bool bool
DatabaseSelection::HasOtherThanBase() const DatabaseSelection::HasOtherThanBase() const noexcept
{ {
return filter != nullptr && filter->HasOtherThanBase(); return filter != nullptr && filter->HasOtherThanBase();
} }
bool bool
DatabaseSelection::Match(const LightSong &song) const DatabaseSelection::Match(const LightSong &song) const noexcept
{ {
return filter == nullptr || filter->Match(song); return filter == nullptr || filter->Match(song);
} }

View File

@@ -45,16 +45,16 @@ struct DatabaseSelection {
const SongFilter *_filter=nullptr); const SongFilter *_filter=nullptr);
gcc_pure gcc_pure
bool IsEmpty() const; bool IsEmpty() const noexcept;
/** /**
* Does this selection contain constraints other than "base"? * Does this selection contain constraints other than "base"?
*/ */
gcc_pure gcc_pure
bool HasOtherThanBase() const; bool HasOtherThanBase() const noexcept;
gcc_pure gcc_pure
bool Match(const LightSong &song) const; bool Match(const LightSong &song) const noexcept;
}; };
#endif #endif

View File

@@ -216,7 +216,7 @@ ProxySong::ProxySong(const mpd_song *song)
gcc_const gcc_const
static enum mpd_tag_type static enum mpd_tag_type
Convert(TagType tag_type) Convert(TagType tag_type) noexcept
{ {
for (auto i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i) for (auto i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
if (i->d == tag_type) if (i->d == tag_type)
@@ -574,7 +574,7 @@ Visit(struct mpd_connection *connection,
gcc_pure gcc_pure
static bool static bool
Match(const SongFilter *filter, const LightSong &song) Match(const SongFilter *filter, const LightSong &song) noexcept
{ {
return filter == nullptr || filter->Match(song); return filter == nullptr || filter->Match(song);
} }
@@ -717,7 +717,7 @@ SearchSongs(struct mpd_connection *connection,
*/ */
gcc_pure gcc_pure
static bool static bool
ServerSupportsSearchBase(const struct mpd_connection *connection) ServerSupportsSearchBase(const struct mpd_connection *connection) noexcept
{ {
#if LIBMPDCLIENT_CHECK_VERSION(2,9,0) #if LIBMPDCLIENT_CHECK_VERSION(2,9,0)
return mpd_connection_cmp_server_version(connection, 0, 18, 0) >= 0; return mpd_connection_cmp_server_version(connection, 0, 18, 0) >= 0;

View File

@@ -65,7 +65,7 @@ Directory::Delete()
} }
const char * const char *
Directory::GetName() const Directory::GetName() const noexcept
{ {
assert(!IsRoot()); assert(!IsRoot());
@@ -89,7 +89,7 @@ Directory::CreateChild(const char *name_utf8)
} }
const Directory * const Directory *
Directory::FindChild(const char *name) const Directory::FindChild(const char *name) const noexcept
{ {
assert(holding_db_lock()); assert(holding_db_lock());
@@ -101,7 +101,7 @@ Directory::FindChild(const char *name) const
} }
void void
Directory::PruneEmpty() Directory::PruneEmpty() noexcept
{ {
assert(holding_db_lock()); assert(holding_db_lock());
@@ -118,7 +118,7 @@ Directory::PruneEmpty()
} }
Directory::LookupResult Directory::LookupResult
Directory::LookupDirectory(const char *uri) Directory::LookupDirectory(const char *uri) noexcept
{ {
assert(holding_db_lock()); assert(holding_db_lock());
assert(uri != nullptr); assert(uri != nullptr);
@@ -173,7 +173,7 @@ Directory::AddSong(Song *song)
} }
void void
Directory::RemoveSong(Song *song) Directory::RemoveSong(Song *song) noexcept
{ {
assert(holding_db_lock()); assert(holding_db_lock());
assert(song != nullptr); assert(song != nullptr);
@@ -183,7 +183,7 @@ Directory::RemoveSong(Song *song)
} }
const Song * const Song *
Directory::FindSong(const char *name_utf8) const Directory::FindSong(const char *name_utf8) const noexcept
{ {
assert(holding_db_lock()); assert(holding_db_lock());
assert(name_utf8 != nullptr); assert(name_utf8 != nullptr);
@@ -200,13 +200,13 @@ Directory::FindSong(const char *name_utf8) const
gcc_pure gcc_pure
static bool static bool
directory_cmp(const Directory &a, const Directory &b) directory_cmp(const Directory &a, const Directory &b) noexcept
{ {
return IcuCollate(a.path.c_str(), b.path.c_str()) < 0; return IcuCollate(a.path.c_str(), b.path.c_str()) < 0;
} }
void void
Directory::Sort() Directory::Sort() noexcept
{ {
assert(holding_db_lock()); assert(holding_db_lock());
@@ -261,7 +261,7 @@ Directory::Walk(bool recursive, const SongFilter *filter,
} }
LightDirectory LightDirectory
Directory::Export() const Directory::Export() const noexcept
{ {
return LightDirectory(GetPath(), mtime); return LightDirectory(GetPath(), mtime);
} }

View File

@@ -86,7 +86,7 @@ struct Directory {
Directory *parent; Directory *parent;
time_t mtime; time_t mtime;
unsigned inode, device; uint64_t inode, device;
std::string path; std::string path;
@@ -134,10 +134,10 @@ public:
* Caller must lock the #db_mutex. * Caller must lock the #db_mutex.
*/ */
gcc_pure gcc_pure
const Directory *FindChild(const char *name) const; const Directory *FindChild(const char *name) const noexcept;
gcc_pure gcc_pure
Directory *FindChild(const char *name) { Directory *FindChild(const char *name) noexcept {
const Directory *cthis = this; const Directory *cthis = this;
return const_cast<Directory *>(cthis->FindChild(name)); return const_cast<Directory *>(cthis->FindChild(name));
} }
@@ -177,10 +177,10 @@ public:
* @return the Directory, or nullptr if none was found * @return the Directory, or nullptr if none was found
*/ */
gcc_pure gcc_pure
LookupResult LookupDirectory(const char *uri); LookupResult LookupDirectory(const char *uri) noexcept;
gcc_pure gcc_pure
bool IsEmpty() const { bool IsEmpty() const noexcept {
return children.empty() && return children.empty() &&
songs.empty() && songs.empty() &&
playlists.empty(); playlists.empty();
@@ -195,13 +195,13 @@ public:
* Returns the base name of the directory. * Returns the base name of the directory.
*/ */
gcc_pure gcc_pure
const char *GetName() const; const char *GetName() const noexcept;
/** /**
* Is this the root directory of the music database? * Is this the root directory of the music database?
*/ */
gcc_pure gcc_pure
bool IsRoot() const { bool IsRoot() const noexcept {
return parent == nullptr; return parent == nullptr;
} }
@@ -229,10 +229,10 @@ public:
* Caller must lock the #db_mutex. * Caller must lock the #db_mutex.
*/ */
gcc_pure gcc_pure
const Song *FindSong(const char *name_utf8) const; const Song *FindSong(const char *name_utf8) const noexcept;
gcc_pure gcc_pure
Song *FindSong(const char *name_utf8) { Song *FindSong(const char *name_utf8) noexcept {
const Directory *cthis = this; const Directory *cthis = this;
return const_cast<Song *>(cthis->FindSong(name_utf8)); return const_cast<Song *>(cthis->FindSong(name_utf8));
} }
@@ -248,19 +248,19 @@ public:
* invalidates the song object, because the "parent" attribute becomes * invalidates the song object, because the "parent" attribute becomes
* stale), but does not free it. * stale), but does not free it.
*/ */
void RemoveSong(Song *song); void RemoveSong(Song *song) noexcept;
/** /**
* Caller must lock the #db_mutex. * Caller must lock the #db_mutex.
*/ */
void PruneEmpty(); void PruneEmpty() noexcept;
/** /**
* Sort all directory entries recursively. * Sort all directory entries recursively.
* *
* Caller must lock the #db_mutex. * Caller must lock the #db_mutex.
*/ */
void Sort(); void Sort() noexcept;
/** /**
* Caller must lock #db_mutex. * Caller must lock #db_mutex.
@@ -270,7 +270,7 @@ public:
VisitPlaylist visit_playlist) const; VisitPlaylist visit_playlist) const;
gcc_pure gcc_pure
LightDirectory Export() const; LightDirectory Export() const noexcept;
}; };
#endif #endif

View File

@@ -40,7 +40,7 @@
gcc_const gcc_const
static const char * static const char *
DeviceToTypeString(unsigned device) DeviceToTypeString(unsigned device) noexcept
{ {
switch (device) { switch (device) {
case DEVICE_INARCHIVE: case DEVICE_INARCHIVE:
@@ -56,7 +56,7 @@ DeviceToTypeString(unsigned device)
gcc_pure gcc_pure
static unsigned static unsigned
ParseTypeString(const char *type) ParseTypeString(const char *type) noexcept
{ {
if (strcmp(type, "archive") == 0) if (strcmp(type, "archive") == 0)
return DEVICE_INARCHIVE; return DEVICE_INARCHIVE;

View File

@@ -25,6 +25,13 @@
#include "db/Interface.hxx" #include "db/Interface.hxx"
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
#ifdef _LIBCPP_VERSION
/* workaround for "error: incomplete type 'PlaylistInfo' used in type
trait expression" with libc++ version 3900 (from Android NDK
r13b) */
#include "db/PlaylistInfo.hxx"
#endif
#include <string> #include <string>
struct PrefixedLightDirectory : LightDirectory { struct PrefixedLightDirectory : LightDirectory {

View File

@@ -77,7 +77,7 @@ Song::Free()
} }
std::string std::string
Song::GetURI() const Song::GetURI() const noexcept
{ {
assert(*uri); assert(*uri);
@@ -96,7 +96,7 @@ Song::GetURI() const
} }
LightSong LightSong
Song::Export() const Song::Export() const noexcept
{ {
LightSong dest; LightSong dest;
dest.directory = parent->IsRoot() dest.directory = parent->IsRoot()

View File

@@ -123,10 +123,10 @@ struct Song {
* location within the music directory. * location within the music directory.
*/ */
gcc_pure gcc_pure
std::string GetURI() const; std::string GetURI() const noexcept;
gcc_pure gcc_pure
LightSong Export() const; LightSong Export() const noexcept;
}; };
typedef boost::intrusive::list<Song, typedef boost::intrusive::list<Song,

View File

@@ -26,7 +26,7 @@
#include <stdlib.h> #include <stdlib.h>
static int static int
compare_utf8_string(const char *a, const char *b) compare_utf8_string(const char *a, const char *b) noexcept
{ {
if (a == nullptr) if (a == nullptr)
return b == nullptr ? 0 : -1; return b == nullptr ? 0 : -1;
@@ -42,8 +42,7 @@ compare_utf8_string(const char *a, const char *b)
* nullptr. * nullptr.
*/ */
static int static int
compare_string_tag_item(const Tag &a, const Tag &b, compare_string_tag_item(const Tag &a, const Tag &b, TagType type) noexcept
TagType type)
{ {
return compare_utf8_string(a.GetValue(type), return compare_utf8_string(a.GetValue(type),
b.GetValue(type)); b.GetValue(type));
@@ -54,7 +53,7 @@ compare_string_tag_item(const Tag &a, const Tag &b,
* (e.g. disc or track number). Either one may be nullptr. * (e.g. disc or track number). Either one may be nullptr.
*/ */
static int static int
compare_number_string(const char *a, const char *b) compare_number_string(const char *a, const char *b) noexcept
{ {
long ai = a == nullptr ? 0 : strtol(a, nullptr, 10); long ai = a == nullptr ? 0 : strtol(a, nullptr, 10);
long bi = b == nullptr ? 0 : strtol(b, nullptr, 10); long bi = b == nullptr ? 0 : strtol(b, nullptr, 10);
@@ -69,7 +68,7 @@ compare_number_string(const char *a, const char *b)
} }
static int static int
compare_tag_item(const Tag &a, const Tag &b, TagType type) compare_tag_item(const Tag &a, const Tag &b, TagType type) noexcept
{ {
return compare_number_string(a.GetValue(type), return compare_number_string(a.GetValue(type),
b.GetValue(type)); b.GetValue(type));
@@ -78,7 +77,7 @@ compare_tag_item(const Tag &a, const Tag &b, TagType type)
/* Only used for sorting/searchin a songvec, not general purpose compares */ /* Only used for sorting/searchin a songvec, not general purpose compares */
gcc_pure gcc_pure
static bool static bool
song_cmp(const Song &a, const Song &b) song_cmp(const Song &a, const Song &b) noexcept
{ {
int ret; int ret;
@@ -102,7 +101,7 @@ song_cmp(const Song &a, const Song &b)
} }
void void
song_list_sort(SongList &songs) song_list_sort(SongList &songs) noexcept
{ {
songs.sort(song_cmp); songs.sort(song_cmp);
} }

View File

@@ -23,6 +23,6 @@
#include "Song.hxx" #include "Song.hxx"
void void
song_list_sort(SongList &songs); song_list_sort(SongList &songs) noexcept;
#endif #endif

View File

@@ -39,7 +39,7 @@ UPnPDirContent::~UPnPDirContent()
gcc_pure gcc_pure
static UPnPDirObject::ItemClass static UPnPDirObject::ItemClass
ParseItemClass(StringView name) ParseItemClass(StringView name) noexcept
{ {
if (name.EqualsLiteral("object.item.audioItem.musicTrack")) if (name.EqualsLiteral("object.item.audioItem.musicTrack"))
return UPnPDirObject::ItemClass::MUSIC; return UPnPDirObject::ItemClass::MUSIC;
@@ -51,7 +51,7 @@ ParseItemClass(StringView name)
gcc_pure gcc_pure
static SignedSongTime static SignedSongTime
ParseDuration(const char *duration) ParseDuration(const char *duration) noexcept
{ {
char *endptr; char *endptr;
@@ -81,7 +81,7 @@ ParseDuration(const char *duration)
*/ */
gcc_pure gcc_pure
static std::string && static std::string &&
TitleToPathSegment(std::string &&s) TitleToPathSegment(std::string &&s) noexcept
{ {
std::replace(s.begin(), s.end(), '/', '_'); std::replace(s.begin(), s.end(), '/', '_');
return std::move(s); return std::move(s);

View File

@@ -40,7 +40,7 @@ public:
~UPnPDirContent(); ~UPnPDirContent();
gcc_pure gcc_pure
UPnPDirObject *FindObject(const char *name) { UPnPDirObject *FindObject(const char *name) noexcept {
for (auto &o : objects) for (auto &o : objects)
if (o.name == name) if (o.name == name)
return &o; return &o;

View File

@@ -56,7 +56,7 @@ InotifyQueue::OnTimeout()
gcc_pure gcc_pure
static bool static bool
path_in(const char *path, const char *possible_parent) path_in(const char *path, const char *possible_parent) noexcept
{ {
if (StringIsEmpty(path)) if (StringIsEmpty(path))
return true; return true;

View File

@@ -62,10 +62,10 @@ struct WatchDirectory {
WatchDirectory &operator=(const WatchDirectory &) = delete; WatchDirectory &operator=(const WatchDirectory &) = delete;
gcc_pure gcc_pure
unsigned GetDepth() const; unsigned GetDepth() const noexcept;
gcc_pure gcc_pure
AllocatedPath GetUriFS() const; AllocatedPath GetUriFS() const noexcept;
}; };
static InotifySource *inotify_source; static InotifySource *inotify_source;
@@ -132,7 +132,7 @@ remove_watch_directory(WatchDirectory *directory)
} }
AllocatedPath AllocatedPath
WatchDirectory::GetUriFS() const WatchDirectory::GetUriFS() const noexcept
{ {
if (parent == nullptr) if (parent == nullptr)
return AllocatedPath::Null(); return AllocatedPath::Null();
@@ -225,7 +225,7 @@ recursive_watch_subdirectories(WatchDirectory *directory,
gcc_pure gcc_pure
unsigned unsigned
WatchDirectory::GetDepth() const WatchDirectory::GetDepth() const noexcept
{ {
const WatchDirectory *d = this; const WatchDirectory *d = this;
unsigned depth = 0; unsigned depth = 0;
@@ -331,7 +331,7 @@ mpd_inotify_init(EventLoop &loop, Storage &storage, UpdateService &update,
} }
void void
mpd_inotify_finish(void) mpd_inotify_finish(void) noexcept
{ {
if (inotify_source == nullptr) if (inotify_source == nullptr)
return; return;

View File

@@ -32,6 +32,6 @@ mpd_inotify_init(EventLoop &loop, Storage &storage, UpdateService &update,
unsigned max_depth); unsigned max_depth);
void void
mpd_inotify_finish(); mpd_inotify_finish() noexcept;
#endif #endif

View File

@@ -32,7 +32,7 @@
#include <errno.h> #include <errno.h>
bool bool
GetInfo(Storage &storage, const char *uri_utf8, StorageFileInfo &info) GetInfo(Storage &storage, const char *uri_utf8, StorageFileInfo &info) noexcept
try { try {
info = storage.GetInfo(uri_utf8, true); info = storage.GetInfo(uri_utf8, true);
return true; return true;
@@ -42,7 +42,7 @@ try {
} }
bool bool
GetInfo(StorageDirectoryReader &reader, StorageFileInfo &info) GetInfo(StorageDirectoryReader &reader, StorageFileInfo &info) noexcept
try { try {
info = reader.GetInfo(true); info = reader.GetInfo(true);
return true; return true;
@@ -52,7 +52,7 @@ try {
} }
bool bool
DirectoryExists(Storage &storage, const Directory &directory) DirectoryExists(Storage &storage, const Directory &directory) noexcept
{ {
StorageFileInfo info; StorageFileInfo info;
@@ -79,7 +79,7 @@ GetDirectoryChildInfo(Storage &storage, const Directory &directory,
bool bool
directory_child_is_regular(Storage &storage, const Directory &directory, directory_child_is_regular(Storage &storage, const Directory &directory,
const char *name_utf8) const char *name_utf8) noexcept
try { try {
return GetDirectoryChildInfo(storage, directory, name_utf8) return GetDirectoryChildInfo(storage, directory, name_utf8)
.IsRegular(); .IsRegular();
@@ -89,7 +89,7 @@ try {
bool bool
directory_child_access(Storage &storage, const Directory &directory, directory_child_access(Storage &storage, const Directory &directory,
const char *name, int mode) const char *name, int mode) noexcept
{ {
#ifdef WIN32 #ifdef WIN32
/* CheckAccess() is useless on WIN32 */ /* CheckAccess() is useless on WIN32 */

View File

@@ -33,23 +33,23 @@ class StorageDirectoryReader;
* returning them. * returning them.
*/ */
bool bool
GetInfo(Storage &storage, const char *uri_utf8, StorageFileInfo &info); GetInfo(Storage &storage, const char *uri_utf8, StorageFileInfo &info) noexcept;
/** /**
* Wrapper for LocalDirectoryReader::GetInfo() that logs errors * Wrapper for LocalDirectoryReader::GetInfo() that logs errors
* instead of returning them. * instead of returning them.
*/ */
bool bool
GetInfo(StorageDirectoryReader &reader, StorageFileInfo &info); GetInfo(StorageDirectoryReader &reader, StorageFileInfo &info) noexcept;
gcc_pure gcc_pure
bool bool
DirectoryExists(Storage &storage, const Directory &directory); DirectoryExists(Storage &storage, const Directory &directory) noexcept;
gcc_pure gcc_pure
bool bool
directory_child_is_regular(Storage &storage, const Directory &directory, directory_child_is_regular(Storage &storage, const Directory &directory,
const char *name_utf8); const char *name_utf8) noexcept;
/** /**
* Checks if the given permissions on the mapped file are given. * Checks if the given permissions on the mapped file are given.
@@ -57,6 +57,6 @@ directory_child_is_regular(Storage &storage, const Directory &directory,
gcc_pure gcc_pure
bool bool
directory_child_access(Storage &storage, const Directory &directory, directory_child_access(Storage &storage, const Directory &directory,
const char *name, int mode); const char *name, int mode) noexcept;
#endif #endif

View File

@@ -248,7 +248,7 @@ try {
/* we don't look at "." / ".." nor files with newlines in their name */ /* we don't look at "." / ".." nor files with newlines in their name */
gcc_pure gcc_pure
static bool static bool
skip_path(const char *name_utf8) skip_path(const char *name_utf8) noexcept
{ {
return strchr(name_utf8, '\n') != nullptr; return strchr(name_utf8, '\n') != nullptr;
} }
@@ -256,7 +256,7 @@ skip_path(const char *name_utf8)
gcc_pure gcc_pure
bool bool
UpdateWalk::SkipSymlink(const Directory *directory, UpdateWalk::SkipSymlink(const Directory *directory,
const char *utf8_name) const const char *utf8_name) const noexcept
{ {
#ifndef WIN32 #ifndef WIN32
const auto path_fs = storage.MapChildFS(directory->GetPath(), const auto path_fs = storage.MapChildFS(directory->GetPath(),

View File

@@ -78,7 +78,7 @@ public:
private: private:
gcc_pure gcc_pure
bool SkipSymlink(const Directory *directory, bool SkipSymlink(const Directory *directory,
const char *utf8_name) const; const char *utf8_name) const noexcept;
void RemoveExcludedFromDirectory(Directory &directory, void RemoveExcludedFromDirectory(Directory &directory,
const ExcludeList &exclude_list); const ExcludeList &exclude_list);

View File

@@ -54,7 +54,7 @@ DecoderBridge::~DecoderBridge()
} }
bool bool
DecoderBridge::CheckCancelRead() const DecoderBridge::CheckCancelRead() const noexcept
{ {
if (error) if (error)
/* this translates to DecoderCommand::STOP */ /* this translates to DecoderCommand::STOP */
@@ -78,7 +78,7 @@ DecoderBridge::CheckCancelRead() const
* one. * one.
*/ */
static DecoderCommand static DecoderCommand
need_chunks(DecoderControl &dc) need_chunks(DecoderControl &dc) noexcept
{ {
if (dc.command == DecoderCommand::NONE) if (dc.command == DecoderCommand::NONE)
dc.Wait(); dc.Wait();
@@ -87,14 +87,14 @@ need_chunks(DecoderControl &dc)
} }
static DecoderCommand static DecoderCommand
LockNeedChunks(DecoderControl &dc) LockNeedChunks(DecoderControl &dc) noexcept
{ {
const std::lock_guard<Mutex> protect(dc.mutex); const std::lock_guard<Mutex> protect(dc.mutex);
return need_chunks(dc); return need_chunks(dc);
} }
MusicChunk * MusicChunk *
DecoderBridge::GetChunk() DecoderBridge::GetChunk() noexcept
{ {
DecoderCommand cmd; DecoderCommand cmd;
@@ -177,7 +177,7 @@ DecoderBridge::PrepareInitialSeek()
} }
DecoderCommand DecoderCommand
DecoderBridge::GetVirtualCommand() DecoderBridge::GetVirtualCommand() noexcept
{ {
if (error) if (error)
/* an error has occurred: stop the decoder plugin */ /* an error has occurred: stop the decoder plugin */
@@ -192,7 +192,7 @@ DecoderBridge::GetVirtualCommand()
} }
DecoderCommand DecoderCommand
DecoderBridge::LockGetVirtualCommand() DecoderBridge::LockGetVirtualCommand() noexcept
{ {
const std::lock_guard<Mutex> protect(dc.mutex); const std::lock_guard<Mutex> protect(dc.mutex);
return GetVirtualCommand(); return GetVirtualCommand();

View File

@@ -114,7 +114,7 @@ public:
* Caller must lock the #DecoderControl object. * Caller must lock the #DecoderControl object.
*/ */
gcc_pure gcc_pure
bool CheckCancelRead() const; bool CheckCancelRead() const noexcept;
/** /**
* Returns the current chunk the decoder writes to, or allocates a new * Returns the current chunk the decoder writes to, or allocates a new
@@ -122,7 +122,7 @@ public:
* *
* @return the chunk, or NULL if we have received a decoder command * @return the chunk, or NULL if we have received a decoder command
*/ */
MusicChunk *GetChunk(); MusicChunk *GetChunk() noexcept;
/** /**
* Flushes the current chunk. * Flushes the current chunk.
@@ -161,8 +161,8 @@ private:
* "virtual" synthesized command, e.g. to seek to the * "virtual" synthesized command, e.g. to seek to the
* beginning of the CUE track. * beginning of the CUE track.
*/ */
DecoderCommand GetVirtualCommand(); DecoderCommand GetVirtualCommand() noexcept;
DecoderCommand LockGetVirtualCommand(); DecoderCommand LockGetVirtualCommand() noexcept;
/** /**
* Sends a #Tag as-is to the #MusicPipe. Flushes the current * Sends a #Tag as-is to the #MusicPipe. Flushes the current

View File

@@ -74,7 +74,7 @@ DecoderControl::SetReady(const AudioFormat audio_format,
} }
bool bool
DecoderControl::IsCurrentSong(const DetachedSong &_song) const DecoderControl::IsCurrentSong(const DetachedSong &_song) const noexcept
{ {
switch (state) { switch (state) {
case DecoderState::STOP: case DecoderState::STOP:

View File

@@ -305,10 +305,10 @@ struct DecoderControl {
* Caller must lock the object. * Caller must lock the object.
*/ */
gcc_pure gcc_pure
bool IsCurrentSong(const DetachedSong &_song) const; bool IsCurrentSong(const DetachedSong &_song) const noexcept;
gcc_pure gcc_pure
bool LockIsCurrentSong(const DetachedSong &_song) const { bool LockIsCurrentSong(const DetachedSong &_song) const noexcept {
const std::lock_guard<Mutex> protect(mutex); const std::lock_guard<Mutex> protect(mutex);
return IsCurrentSong(_song); return IsCurrentSong(_song);
} }

View File

@@ -118,7 +118,7 @@ static constexpr unsigned num_decoder_plugins =
bool decoder_plugins_enabled[num_decoder_plugins]; bool decoder_plugins_enabled[num_decoder_plugins];
const struct DecoderPlugin * const struct DecoderPlugin *
decoder_plugin_from_name(const char *name) decoder_plugin_from_name(const char *name) noexcept
{ {
return decoder_plugins_find([=](const DecoderPlugin &plugin){ return decoder_plugins_find([=](const DecoderPlugin &plugin){
return strcmp(plugin.name, name) == 0; return strcmp(plugin.name, name) == 0;
@@ -154,7 +154,7 @@ void decoder_plugin_deinit_all(void)
} }
bool bool
decoder_plugins_supports_suffix(const char *suffix) decoder_plugins_supports_suffix(const char *suffix) noexcept
{ {
return decoder_plugins_try([suffix](const DecoderPlugin &plugin){ return decoder_plugins_try([suffix](const DecoderPlugin &plugin){
return plugin.SupportsSuffix(suffix); return plugin.SupportsSuffix(suffix);

Some files were not shown because too many files have changed in this diff Show More