From f6d67ac260ad12a6465378d93d03d98fea857ec8 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Mon, 21 Oct 2013 22:14:08 +0200
Subject: DecoderThread: simplify the decoder lookup loop

Merge the two loops into one, and eliminate the GSList.
---
 src/DecoderList.hxx   |  11 ++++++
 src/DecoderThread.cxx | 106 ++++++++++++++++++++------------------------------
 2 files changed, 53 insertions(+), 64 deletions(-)

diff --git a/src/DecoderList.hxx b/src/DecoderList.hxx
index 51aeb1d71..fd4b22c63 100644
--- a/src/DecoderList.hxx
+++ b/src/DecoderList.hxx
@@ -61,6 +61,17 @@ decoder_plugins_find(F f)
 	return nullptr;
 }
 
+template<typename F>
+static inline bool
+decoder_plugins_try(F f)
+{
+	for (unsigned i = 0; decoder_plugins[i] != nullptr; ++i)
+		if (decoder_plugins_enabled[i] && f(*decoder_plugins[i]))
+			return true;
+
+	return false;
+}
+
 template<typename F>
 static inline void
 decoder_plugins_for_each(F f)
diff --git a/src/DecoderThread.cxx b/src/DecoderThread.cxx
index f70b7c34f..556ab327e 100644
--- a/src/DecoderThread.cxx
+++ b/src/DecoderThread.cxx
@@ -179,74 +179,58 @@ deconst_plugin(const struct DecoderPlugin *plugin)
 	return const_cast<struct DecoderPlugin *>(plugin);
 }
 
-/**
- * Try decoding a stream, using plugins matching the stream's MIME type.
- *
- * @param tried_r a list of plugins which were tried
- */
+gcc_pure
 static bool
-decoder_run_stream_mime_type(Decoder &decoder, struct input_stream *is,
-			     GSList **tried_r)
+decoder_check_plugin_mime(const DecoderPlugin &plugin, const input_stream &is)
 {
-	assert(tried_r != nullptr);
-
-	const struct DecoderPlugin *plugin;
-	unsigned int next = 0;
-
-	if (is->mime.empty())
-		return false;
-
-	while ((plugin = decoder_plugin_from_mime_type(is->mime.c_str(),
-						       next++))) {
-		if (plugin->stream_decode == nullptr)
-			continue;
-
-		if (g_slist_find(*tried_r, plugin) != nullptr)
-			/* don't try a plugin twice */
-			continue;
+	assert(plugin.stream_decode != nullptr);
 
-		if (decoder_stream_decode(*plugin, decoder, is))
-			return true;
+	return !is.mime.empty() && plugin.SupportsMimeType(is.mime.c_str());
+}
 
-		*tried_r = g_slist_prepend(*tried_r, deconst_plugin(plugin));
-	}
+gcc_pure
+static bool
+decoder_check_plugin_suffix(const DecoderPlugin &plugin, const char *suffix)
+{
+	assert(plugin.stream_decode != nullptr);
 
-	return false;
+	return suffix != nullptr && plugin.SupportsSuffix(suffix);
 }
 
-/**
- * Try decoding a stream, using plugins matching the stream's URI
- * suffix.
- *
- * @param tried_r a list of plugins which were tried
- */
+gcc_pure
 static bool
-decoder_run_stream_suffix(Decoder &decoder, struct input_stream *is,
-			  const char *uri, GSList **tried_r)
+decoder_check_plugin(const DecoderPlugin &plugin, const input_stream &is,
+		     const char *suffix)
 {
-	assert(tried_r != nullptr);
-
-	const char *suffix = uri_get_suffix(uri);
-	const struct DecoderPlugin *plugin = nullptr;
+	return plugin.stream_decode != nullptr &&
+		(decoder_check_plugin_mime(plugin, is) ||
+		 decoder_check_plugin_suffix(plugin, suffix));
+}
 
-	if (suffix == nullptr)
+static bool
+decoder_run_stream_plugin(Decoder &decoder, input_stream &is,
+			  const char *suffix,
+			  const DecoderPlugin &plugin,
+			  bool &tried_r)
+{
+	if (!decoder_check_plugin(plugin, is, suffix))
 		return false;
 
-	while ((plugin = decoder_plugin_from_suffix(suffix, plugin)) != nullptr) {
-		if (plugin->stream_decode == nullptr)
-			continue;
-
-		if (g_slist_find(*tried_r, plugin) != nullptr)
-			/* don't try a plugin twice */
-			continue;
-
-		if (decoder_stream_decode(*plugin, decoder, is))
-			return true;
+	tried_r = true;
+	return decoder_stream_decode(plugin, decoder, &is);
+}
 
-		*tried_r = g_slist_prepend(*tried_r, deconst_plugin(plugin));
-	}
+static bool
+decoder_run_stream_locked(Decoder &decoder, input_stream &is,
+			  const char *uri, bool &tried_r)
+{
+	const char *const suffix = uri_get_suffix(uri);
 
-	return false;
+	using namespace std::placeholders;
+	const auto f = std::bind(decoder_run_stream_plugin,
+				 std::ref(decoder), std::ref(is), suffix,
+				 _1, std::ref(tried_r));
+	return decoder_plugins_try(f);
 }
 
 /**
@@ -282,21 +266,15 @@ decoder_run_stream(Decoder &decoder, const char *uri)
 
 	dc.Lock();
 
-	GSList *tried = nullptr;
-
+	bool tried = false;
 	success = dc.command == DecoderCommand::STOP ||
-		/* first we try mime types: */
-		decoder_run_stream_mime_type(decoder, input_stream, &tried) ||
-		/* if that fails, try suffix matching the URL: */
-		decoder_run_stream_suffix(decoder, input_stream, uri,
-					  &tried) ||
+		decoder_run_stream_locked(decoder, *input_stream, uri,
+					  tried) ||
 		/* fallback to mp3: this is needed for bastard streams
 		   that don't have a suffix or set the mimeType */
-		(tried == nullptr &&
+		(!tried &&
 		 decoder_run_stream_fallback(decoder, input_stream));
 
-	g_slist_free(tried);
-
 	dc.Unlock();
 	input_stream->Close();
 	dc.Lock();
-- 
cgit v1.2.3