#pragma once #include #include #include #include #include template class Collection { public: virtual ~Collection() = default; using Ptr = std::conditional_t, std::unique_ptr>; using Objects = std::vector; Objects objects; template auto create(Params &&... params) requires std::is_base_of_v { if constexpr (shared) { auto obj = std::make_shared(std::forward(params)...); objects.emplace_back(obj); return obj; } else { return static_cast(objects.emplace_back(std::make_unique(std::forward(params)...)).get()); } } template T * find() { if (auto i = std::find_if(objects.begin(), objects.end(), [](auto && o) { return (dynamic_cast(o.get())); }); i != objects.end()) { return static_cast(i->get()); } return nullptr; } template auto findOrCreate(Params &&... params) requires std::is_base_of_v { if (auto o = find()) { return o; } return create(std::forward(params)...).get(); } template auto apply(const auto & m, Params &&... params) const { return apply_internal(objects.begin(), objects.end(), m, std::forward(params)...); } template auto rapply(const auto & m, Params &&... params) const { return apply_internal(objects.rbegin(), objects.rend(), m, std::forward(params)...); } template auto applyOne(const auto & m, Params &&... params) const { return applyOne_internal(objects.begin(), objects.end(), m, std::forward(params)...); } template auto rapplyOne(const auto & m, Params &&... params) const { return applyOne_internal(objects.rbegin(), objects.rend(), m, std::forward(params)...); } template auto removeAll() { return std::erase_if(objects, [](auto && op) { return dynamic_cast(op.get()); }); } auto end() const { return objects.end(); } auto rend() const { return objects.rend(); } protected: template auto apply_internal(const auto begin, const auto end, const auto & m, Params &&... params) const { return std::count_if(begin, end, [&m, ¶ms...](auto && op) { if (auto o = dynamic_cast(op.get())) { std::invoke(m, o, std::forward(params)...); return true; } return false; }); } template auto applyOne_internal(const auto begin, const auto end, const auto & m, Params &&... params) const { return std::find_if(begin, end, [&m, ¶ms...](auto && op) { if (auto o = dynamic_cast(op.get())) { return std::invoke(m, o, std::forward(params)...); } return false; }); } };