summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2025-03-23 13:00:03 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2025-03-23 13:00:03 +0000
commita53a6672b8fc89834b1ec3aa7afae150a617473f (patch)
treeefd2ab5e32cd75e2e36ad53042725c91346b7cfa
parentMake Collections::objects protected, extend interface (diff)
downloadilt-a53a6672b8fc89834b1ec3aa7afae150a617473f.tar.bz2
ilt-a53a6672b8fc89834b1ec3aa7afae150a617473f.tar.xz
ilt-a53a6672b8fc89834b1ec3aa7afae150a617473f.zip
Populate typed collection of pointers
create and emplace only, so far
-rw-r--r--lib/collection.h79
-rw-r--r--test/test-collection.cpp16
2 files changed, 89 insertions, 6 deletions
diff --git a/lib/collection.h b/lib/collection.h
index c843bad..e68a8db 100644
--- a/lib/collection.h
+++ b/lib/collection.h
@@ -6,12 +6,13 @@
#include <type_traits>
#include <vector>
-template<typename Ptr> class Collection {
+template<typename Ptr, typename... Others> class Collection {
public:
virtual ~Collection() = default;
using Object = Ptr::element_type;
using Objects = std::vector<Ptr>;
+ template<typename T> using OtherObjects = std::vector<T *>;
Collection &
operator=(Objects && other)
@@ -34,10 +35,14 @@ public:
if constexpr (requires(Ptr ptr) { ptr = std::make_shared<T>(std::forward<Params>(params)...); }) {
auto obj = std::make_shared<T>(std::forward<Params>(params)...);
objects.emplace_back(obj);
+ addOthersType<T>(obj.get());
return obj;
}
else {
- return static_cast<T *>(objects.emplace_back(std::make_unique<T>(std::forward<Params>(params)...)).get());
+ auto obj = static_cast<T *>(
+ objects.emplace_back(std::make_unique<T>(std::forward<Params>(params)...)).get());
+ addOthersType<T>(obj);
+ return obj;
}
}
@@ -136,11 +141,75 @@ public:
auto
emplace(Ptr && ptr)
{
- return objects.emplace_back(std::move(ptr));
+ auto object = objects.emplace_back(std::move(ptr));
+ addOthersPtr(object.get());
+ return object;
}
protected:
Objects objects;
+ std::tuple<OtherObjects<Others>...> otherObjects;
+
+ template<typename T>
+ void
+ addOthersType(T * obj)
+ {
+ applyToOthersType<T>(
+ [](auto & others, auto ptr) {
+ others.emplace_back(ptr);
+ },
+ obj);
+ }
+
+ void
+ addOthersPtr(Object * obj)
+ {
+ applyToOthersPtr(
+ [](auto & others, auto ptr) {
+ others.emplace_back(ptr);
+ },
+ obj);
+ }
+
+ template<typename T>
+ requires(sizeof...(Others) == 0)
+ void
+ applyToOthersType(const auto &, T *)
+ {
+ }
+
+ void
+ applyToOthersPtr(const auto &, Object *)
+ requires(sizeof...(Others) == 0)
+ {
+ }
+
+ template<typename T>
+ requires(sizeof...(Others) > 0)
+ void
+ applyToOthersType(const auto & func, T * obj)
+ {
+ (
+ [&]() {
+ if constexpr (std::is_convertible_v<T *, Others *>) {
+ std::invoke(func, std::get<OtherObjects<Others>>(otherObjects), obj);
+ }
+ }(),
+ ...);
+ }
+
+ void
+ applyToOthersPtr(const auto & func, Object * obj)
+ requires(sizeof...(Others) > 0)
+ {
+ (
+ [&]() {
+ if (auto ptr = dynamic_cast<Others *>(obj)) {
+ std::invoke(func, std::get<OtherObjects<Others>>(otherObjects), ptr);
+ }
+ }(),
+ ...);
+ }
template<typename T = Object, typename... Params>
auto
@@ -168,5 +237,5 @@ protected:
}
};
-template<typename T> using SharedCollection = Collection<std::shared_ptr<T>>;
-template<typename T> using UniqueCollection = Collection<std::unique_ptr<T>>;
+template<typename T, typename... Others> using SharedCollection = Collection<std::shared_ptr<T>, Others...>;
+template<typename T, typename... Others> using UniqueCollection = Collection<std::unique_ptr<T>, Others...>;
diff --git a/test/test-collection.cpp b/test/test-collection.cpp
index 00298bb..5c67a8c 100644
--- a/test/test-collection.cpp
+++ b/test/test-collection.cpp
@@ -34,7 +34,7 @@ public:
}
};
-using TestCollection = SharedCollection<Base>;
+using TestCollection = SharedCollection<Base, Sub>;
BOOST_TEST_DONT_PRINT_LOG_VALUE(TestCollection::Objects::const_iterator)
BOOST_TEST_DONT_PRINT_LOG_VALUE(TestCollection::Objects::const_reverse_iterator)
@@ -51,12 +51,24 @@ BOOST_AUTO_TEST_CASE(empty)
BOOST_AUTO_TEST_CASE(a_base)
{
auto b = create<Base>();
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
BOOST_REQUIRE(apply(&Base::add));
BOOST_CHECK_EQUAL(b->total, 1);
const auto i = applyOne(&Base::add);
BOOST_CHECK_EQUAL(i, end());
}
+BOOST_AUTO_TEST_CASE(emplace_others)
+{
+ emplace(std::make_shared<Base>());
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
+ emplace(std::make_shared<Sub>());
+ BOOST_CHECK_EQUAL(objects.size(), 2);
+ BOOST_CHECK_EQUAL(std::get<OtherObjects<Sub>>(otherObjects).size(), 1);
+}
+
BOOST_AUTO_TEST_CASE(a_rbase)
{
auto b = create<Base>();
@@ -69,6 +81,8 @@ BOOST_AUTO_TEST_CASE(a_rbase)
BOOST_AUTO_TEST_CASE(a_sub)
{
auto s = create<Sub>();
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK_EQUAL(std::get<OtherObjects<Sub>>(otherObjects).size(), 1);
BOOST_REQUIRE(apply(&Base::add));
BOOST_CHECK_EQUAL(s->total, 2);
const auto i = applyOne(&Base::add);