From 847ae7dd7c947eef2c00de972eabe8bc32f56f83 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max.kellermann@gmail.com>
Date: Mon, 11 Sep 2023 20:57:51 +0200
Subject: [PATCH] util/IntrusiveHashSet: add insert_check_if()

---
 src/util/IntrusiveHashSet.hxx | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/util/IntrusiveHashSet.hxx b/src/util/IntrusiveHashSet.hxx
index 07fe3ccaf..69603ab1c 100644
--- a/src/util/IntrusiveHashSet.hxx
+++ b/src/util/IntrusiveHashSet.hxx
@@ -276,6 +276,25 @@ public:
 		return {bucket.end(), true};
 	}
 
+	/**
+	 * Like insert_check(), but existing items are only considered
+	 * conflicting if they match the given predicate.
+	 */
+	[[nodiscard]] [[gnu::pure]]
+	constexpr std::pair<bucket_iterator, bool> insert_check_if(const auto &key,
+								   std::predicate<const_reference> auto pred) noexcept {
+		auto &bucket = GetBucket(key);
+		for (auto &i : bucket)
+			if (ops.equal(key, ops.get_key(i)) && pred(i))
+				return {bucket.iterator_to(i), false};
+
+		/* bucket.end() is a pointer to the bucket's list
+		   head, a stable value that is guaranteed to be still
+		   valid when insert_commit() gets called
+		   eventually */
+		return {bucket.end(), true};
+	}
+
 	/**
 	 * Finish the insertion if insert_check() has returned true.
 	 *