From 5f12ed9f259a825efc7c2354230932712273fab6 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Sun, 23 Mar 2025 15:25:03 +0000
Subject: Use otherObjects where possible for find

---
 lib/collection.h         | 32 ++++++++++++++++++++++++++------
 test/test-collection.cpp | 29 +++++++++++++++++++++++++++--
 2 files changed, 53 insertions(+), 8 deletions(-)

diff --git a/lib/collection.h b/lib/collection.h
index 98f043b..6ee6c82 100644
--- a/lib/collection.h
+++ b/lib/collection.h
@@ -54,12 +54,19 @@ public:
 	T *
 	find()
 	{
-		if (auto i = std::find_if(objects.begin(), objects.end(),
-					[](auto && o) {
-						return (dynamic_cast<T *>(o.get()));
-					});
-				i != objects.end()) {
-			return static_cast<T *>(i->get());
+		const auto & srcObjects = containerFor<T>();
+		if constexpr (std::is_convertible_v<typename std::remove_reference_t<decltype(srcObjects)>::value_type, T *>) {
+			if (srcObjects.empty()) {
+				return nullptr;
+			}
+			return srcObjects.front();
+		}
+		else if (auto i = std::find_if(srcObjects.begin(), srcObjects.end(),
+						 [](auto && o) {
+							 return dynamic_cast<T *>(std::to_address(o)) != nullptr;
+						 });
+				i != srcObjects.end()) {
+			return static_cast<T *>(std::to_address(*i));
 		}
 		return nullptr;
 	}
@@ -224,6 +231,19 @@ protected:
 				...);
 	}
 
+	template<typename T>
+	[[nodiscard]]
+	const auto &
+	containerFor() const
+	{
+		if constexpr ((std::is_convertible_v<T *, Others *> || ...)) {
+			return std::get<OtherObjects<T>>(otherObjects);
+		}
+		else {
+			return objects;
+		}
+	}
+
 	template<typename T = Object, typename... Params>
 	auto
 	apply_internal(const auto begin, const auto end, const auto & m, Params &&... params) const
diff --git a/test/test-collection.cpp b/test/test-collection.cpp
index 13df95c..7fadcf9 100644
--- a/test/test-collection.cpp
+++ b/test/test-collection.cpp
@@ -47,6 +47,8 @@ BOOST_AUTO_TEST_CASE(empty)
 	BOOST_REQUIRE(!apply(&Base::add));
 	const auto i = applyOne(&Base::add);
 	BOOST_CHECK_EQUAL(i, end());
+	BOOST_CHECK(!find<Base>());
+	BOOST_CHECK(!find<Sub>());
 }
 
 BOOST_AUTO_TEST_CASE(a_base)
@@ -58,16 +60,20 @@ BOOST_AUTO_TEST_CASE(a_base)
 	BOOST_CHECK_EQUAL(b->total, 1);
 	const auto i = applyOne(&Base::add);
 	BOOST_CHECK_EQUAL(i, end());
+	BOOST_CHECK_EQUAL(b.get(), find<Base>());
+	BOOST_CHECK(!find<Sub>());
 }
 
 BOOST_AUTO_TEST_CASE(emplace_others)
 {
-	emplace(std::make_shared<Base>());
+	auto b = emplace(std::make_shared<Base>());
 	BOOST_CHECK_EQUAL(objects.size(), 1);
 	BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
-	emplace(std::make_shared<Sub>());
+	auto s = emplace(std::make_shared<Sub>());
 	BOOST_CHECK_EQUAL(objects.size(), 2);
 	BOOST_CHECK_EQUAL(std::get<OtherObjects<Sub>>(otherObjects).size(), 1);
+	BOOST_CHECK_EQUAL(b.get(), find<Base>());
+	BOOST_CHECK_EQUAL(s.get(), find<Sub>());
 }
 
 BOOST_AUTO_TEST_CASE(a_rbase)
@@ -107,6 +113,25 @@ BOOST_AUTO_TEST_CASE(rbegin_rend)
 	BOOST_CHECK_EQUAL(2, std::distance(rbegin(), rend()));
 }
 
+BOOST_AUTO_TEST_CASE(createCreate)
+{
+	auto b = findOrCreate<Base>();
+	BOOST_CHECK(b);
+	auto b2 = findOrCreate<Base>();
+	BOOST_CHECK_EQUAL(b, b2);
+	auto s = findOrCreate<Sub>();
+	BOOST_CHECK_NE(s, b);
+	auto s2 = findOrCreate<Sub>();
+	BOOST_CHECK_EQUAL(s, s2);
+}
+
+BOOST_AUTO_TEST_CASE(createCreateSub)
+{
+	auto s = findOrCreate<Sub>();
+	auto b = findOrCreate<Base>();
+	BOOST_CHECK_EQUAL(s, b);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 using TestUniqueCollection = UniqueCollection<Base, Sub>;
-- 
cgit v1.2.3