diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-03-23 13:00:03 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-03-23 13:00:03 +0000 |
commit | a53a6672b8fc89834b1ec3aa7afae150a617473f (patch) | |
tree | efd2ab5e32cd75e2e36ad53042725c91346b7cfa | |
parent | Make Collections::objects protected, extend interface (diff) | |
download | ilt-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.h | 79 | ||||
-rw-r--r-- | test/test-collection.cpp | 16 |
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); |