From 4486b2ededeecb595a3f51e40b94b302af02e65c Mon Sep 17 00:00:00 2001
From: Max Kellermann <max.kellermann@gmail.com>
Date: Thu, 11 Jul 2024 21:26:47 +0200
Subject: [PATCH] lib/alsa/NonBlock: add common base class

---
 src/lib/alsa/NonBlock.cxx | 59 +++++++++++++++++++--------------------
 src/lib/alsa/NonBlock.hxx | 18 ++++++++++--
 2 files changed, 45 insertions(+), 32 deletions(-)

diff --git a/src/lib/alsa/NonBlock.cxx b/src/lib/alsa/NonBlock.cxx
index 800bc4886..a20255bcc 100644
--- a/src/lib/alsa/NonBlock.cxx
+++ b/src/lib/alsa/NonBlock.cxx
@@ -7,6 +7,25 @@
 
 namespace Alsa {
 
+std::span<pollfd>
+NonBlock::CopyReturnedEvents(MultiSocketMonitor &m, std::size_t n) noexcept
+{
+	const auto pfds = buffer.Get(n), end = pfds + n;
+
+	auto *i = pfds;
+	m.ForEachReturnedEvent([&i, end](SocketDescriptor s, unsigned events){
+		if (i >= end)
+			return;
+
+		i->fd = s.Get();
+		i->events = i->revents = events;
+		++i;
+	});
+
+	return {pfds, static_cast<std::size_t>(i - pfds)};
+
+}
+
 Event::Duration
 NonBlockPcm::PrepareSockets(MultiSocketMonitor &m, snd_pcm_t *pcm)
 {
@@ -18,9 +37,9 @@ NonBlockPcm::PrepareSockets(MultiSocketMonitor &m, snd_pcm_t *pcm)
 			throw Alsa::MakeError(count, "snd_pcm_poll_descriptors_count() failed");
 	}
 
-	struct pollfd *pfds = pfd_buffer.Get(count);
+	const auto pfds = base.Allocate(count);
 
-	count = snd_pcm_poll_descriptors(pcm, pfds, count);
+	count = snd_pcm_poll_descriptors(pcm, pfds.data(), count);
 	if (count <= 0) {
 		if (count == 0)
 			throw std::runtime_error("snd_pcm_poll_descriptors() failed");
@@ -28,7 +47,7 @@ NonBlockPcm::PrepareSockets(MultiSocketMonitor &m, snd_pcm_t *pcm)
 			throw Alsa::MakeError(count, "snd_pcm_poll_descriptors() failed");
 	}
 
-	m.ReplaceSocketList({pfds, static_cast<std::size_t>(count)});
+	m.ReplaceSocketList(pfds.first(count));
 	return Event::Duration(-1);
 }
 
@@ -39,20 +58,10 @@ NonBlockPcm::DispatchSockets(MultiSocketMonitor &m, snd_pcm_t *pcm)
 	if (count <= 0)
 		return;
 
-	const auto pfds = pfd_buffer.Get(count), end = pfds + count;
-
-	auto *i = pfds;
-	m.ForEachReturnedEvent([&i, end](SocketDescriptor s, unsigned events){
-		if (i >= end)
-			return;
-
-		i->fd = s.Get();
-		i->events = i->revents = events;
-		++i;
-	});
+	const auto pfds = base.CopyReturnedEvents(m, count);
 
 	unsigned short dummy;
-	int err = snd_pcm_poll_descriptors_revents(pcm, pfds, i - pfds, &dummy);
+	int err = snd_pcm_poll_descriptors_revents(pcm, pfds.data(), pfds.size(), &dummy);
 	if (err < 0)
 		throw Alsa::MakeError(err, "snd_pcm_poll_descriptors_revents() failed");
 }
@@ -66,13 +75,13 @@ NonBlockMixer::PrepareSockets(MultiSocketMonitor &m, snd_mixer_t *mixer) noexcep
 		return Event::Duration(-1);
 	}
 
-	struct pollfd *pfds = pfd_buffer.Get(count);
+	const auto pfds = base.Allocate(count);
 
-	count = snd_mixer_poll_descriptors(mixer, pfds, count);
+	count = snd_mixer_poll_descriptors(mixer, pfds.data(), count);
 	if (count < 0)
 		count = 0;
 
-	m.ReplaceSocketList({pfds, static_cast<std::size_t>(count)});
+	m.ReplaceSocketList(pfds.first(count));
 	return Event::Duration(-1);
 }
 
@@ -83,20 +92,10 @@ NonBlockMixer::DispatchSockets(MultiSocketMonitor &m, snd_mixer_t *mixer) noexce
 	if (count <= 0)
 		return;
 
-	const auto pfds = pfd_buffer.Get(count), end = pfds + count;
-
-	auto *i = pfds;
-	m.ForEachReturnedEvent([&i, end](SocketDescriptor s, unsigned events){
-		if (i >= end)
-			return;
-
-		i->fd = s.Get();
-		i->events = i->revents = events;
-		++i;
-	});
+	const auto pfds = base.CopyReturnedEvents(m, count);
 
 	unsigned short dummy;
-	snd_mixer_poll_descriptors_revents(mixer, pfds, i - pfds, &dummy);
+	snd_mixer_poll_descriptors_revents(mixer, pfds.data(), pfds.size(), &dummy);
 }
 
 } // namespace Alsa
diff --git a/src/lib/alsa/NonBlock.hxx b/src/lib/alsa/NonBlock.hxx
index aae992f50..16cfb3102 100644
--- a/src/lib/alsa/NonBlock.hxx
+++ b/src/lib/alsa/NonBlock.hxx
@@ -8,16 +8,30 @@
 
 #include <alsa/asoundlib.h>
 
+#include <span>
+
 class MultiSocketMonitor;
 
 namespace Alsa {
 
+class NonBlock {
+	ReusableArray<pollfd> buffer;
+
+public:
+	std::span<pollfd> Allocate(std::size_t n) noexcept {
+		return {buffer.Get(n), n};
+	}
+
+	std::span<pollfd> CopyReturnedEvents(MultiSocketMonitor &m,
+					     std::size_t n) noexcept;
+};
+
 /**
  * Helper class for #MultiSocketMonitor's virtual methods which
  * manages the file descriptors for a #snd_pcm_t.
  */
 class NonBlockPcm {
-	ReusableArray<pollfd> pfd_buffer;
+	NonBlock base;
 
 public:
 	/**
@@ -40,7 +54,7 @@ public:
  * manages the file descriptors for a #snd_mixer_t.
  */
 class NonBlockMixer {
-	ReusableArray<pollfd> pfd_buffer;
+	NonBlock base;
 
 public:
 	Event::Duration PrepareSockets(MultiSocketMonitor &m,