From 1ac16516a1cd6c47008dc307623bb2d01fdab37c Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Wed, 17 Feb 2021 20:07:50 +0100
Subject: [PATCH] event/TimerList: add option to avoid the Boost dependency

---
 src/event/FineTimerEvent.hxx | 21 ++++++++++++++++++---
 src/event/TimerList.cxx      | 16 ++++++++++++++++
 src/event/TimerList.hxx      | 10 ++++++++++
 3 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/src/event/FineTimerEvent.hxx b/src/event/FineTimerEvent.hxx
index e4639deda..2eebde4d4 100644
--- a/src/event/FineTimerEvent.hxx
+++ b/src/event/FineTimerEvent.hxx
@@ -33,9 +33,14 @@
 #pragma once
 
 #include "Chrono.hxx"
+#include "event/Features.h"
 #include "util/BindMethod.hxx"
 
+#ifdef NO_BOOST
+#include "util/IntrusiveList.hxx"
+#else
 #include <boost/intrusive/set_hook.hpp>
+#endif
 
 class EventLoop;
 
@@ -50,10 +55,17 @@ class EventLoop;
  * thread that runs the #EventLoop, except where explicitly documented
  * as thread-safe.
  */
-class FineTimerEvent final
-	: public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>
+class FineTimerEvent final :
+#ifdef NO_BOOST
+	AutoUnlinkIntrusiveListHook
+#else
+	public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>
+#endif
 {
 	friend class TimerList;
+#ifdef NO_BOOST
+	friend class IntrusiveList<FineTimerEvent>;
+#endif
 
 	EventLoop &loop;
 
@@ -91,7 +103,10 @@ public:
 	void ScheduleEarlier(Event::Duration d) noexcept;
 
 	void Cancel() noexcept {
-		unlink();
+#ifdef NO_BOOST
+		if (IsPending())
+#endif
+			unlink();
 	}
 
 private:
diff --git a/src/event/TimerList.cxx b/src/event/TimerList.cxx
index d2f3bef8d..6801081ae 100644
--- a/src/event/TimerList.cxx
+++ b/src/event/TimerList.cxx
@@ -33,6 +33,10 @@
 #include "Loop.hxx"
 #include "FineTimerEvent.hxx"
 
+#ifdef NO_BOOST
+#include <algorithm>
+#endif
+
 constexpr bool
 TimerList::Compare::operator()(const FineTimerEvent &a,
 			       const FineTimerEvent &b) const noexcept
@@ -50,7 +54,15 @@ TimerList::~TimerList() noexcept
 void
 TimerList::Insert(FineTimerEvent &t) noexcept
 {
+#ifdef NO_BOOST
+	auto i = std::find_if(timers.begin(), timers.end(), [due = t.GetDue()](const auto &other){
+		return other.GetDue() >= due;
+	});
+
+	timers.insert(i, t);
+#else
 	timers.insert(t);
+#endif
 }
 
 Event::Duration
@@ -66,7 +78,11 @@ TimerList::Run(const Event::TimePoint now) noexcept
 		if (timeout > timeout.zero())
 			return timeout;
 
+#ifdef NO_BOOST
+		t.Cancel();
+#else
 		timers.erase(i);
+#endif
 
 		t.Run();
 	}
diff --git a/src/event/TimerList.hxx b/src/event/TimerList.hxx
index 36b97f101..458b2f4a9 100644
--- a/src/event/TimerList.hxx
+++ b/src/event/TimerList.hxx
@@ -33,9 +33,12 @@
 #pragma once
 
 #include "Chrono.hxx"
+#include "event/Features.h"
 #include "util/IntrusiveList.hxx"
 
+#ifndef NO_BOOST
 #include <boost/intrusive/set.hpp>
+#endif
 
 class FineTimerEvent;
 
@@ -48,10 +51,17 @@ class TimerList final {
 					  const FineTimerEvent &b) const noexcept;
 	};
 
+#ifdef NO_BOOST
+	/* when building without Boost, then this is just a sorted
+	   doubly-linked list - this doesn't scale well, but is good
+	   enough for most programs */
+	IntrusiveList<FineTimerEvent> timers;
+#else
 	boost::intrusive::multiset<FineTimerEvent,
 				   boost::intrusive::base_hook<boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>>,
 				   boost::intrusive::compare<Compare>,
 				   boost::intrusive::constant_time_size<false>> timers;
+#endif
 
 public:
 	TimerList();