summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/collection.h263
-rw-r--r--lib/manyPtr.h86
-rw-r--r--lib/persistence.h3
3 files changed, 317 insertions, 35 deletions
diff --git a/lib/collection.h b/lib/collection.h
index 6802bcb..1c77e1c 100644
--- a/lib/collection.h
+++ b/lib/collection.h
@@ -3,29 +3,62 @@
#include <algorithm>
#include <functional>
#include <memory>
+#include <special_members.h>
#include <type_traits>
#include <vector>
-template<typename Object, bool shared = true> class Collection {
+template<typename Ptr, typename... Others> class Collection {
public:
+ Collection() = default;
virtual ~Collection() = default;
- using Ptr = std::conditional_t<shared, std::shared_ptr<Object>, std::unique_ptr<Object>>;
+ DEFAULT_MOVE_NO_COPY(Collection);
+
+ using Object = Ptr::element_type;
using Objects = std::vector<Ptr>;
- Objects objects;
+ template<typename T> using OtherObjects = std::vector<T *>;
+
+ Collection &
+ operator=(Objects && other)
+ {
+ objects = std::move(other);
+ ((std::get<OtherObjects<Others>>(otherObjects).clear()), ...);
+ for (const auto & other : objects) {
+ addOthersPtr(other.get());
+ }
+ return *this;
+ }
+
+ const Ptr &
+ operator[](size_t idx) const
+ {
+ return objects[idx];
+ }
+
+ template<typename T = Object>
+ requires(std::is_same_v<T, Object> || (std::is_base_of_v<Others, T> || ...))
+ [[nodiscard]] auto
+ size() const noexcept
+ {
+ return containerFor<T>().size();
+ }
template<typename T = Object, typename... Params>
auto
create(Params &&... params)
requires std::is_base_of_v<Object, T>
{
- if constexpr (shared) {
+ 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;
}
}
@@ -33,12 +66,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;
}
@@ -58,74 +98,229 @@ public:
auto
apply(const auto & m, Params &&... params) const
{
- return apply_internal<T>(objects.begin(), objects.end(), m, std::forward<Params>(params)...);
+ const auto & srcObjects = containerFor<T>();
+ return apply_internal<T>(srcObjects.begin(), srcObjects.end(), m, std::forward<Params>(params)...);
}
template<typename T = Object, typename... Params>
auto
rapply(const auto & m, Params &&... params) const
{
- return apply_internal<T>(objects.rbegin(), objects.rend(), m, std::forward<Params>(params)...);
+ const auto & srcObjects = containerFor<T>();
+ return apply_internal<T>(srcObjects.rbegin(), srcObjects.rend(), m, std::forward<Params>(params)...);
}
template<typename T = Object, typename... Params>
auto
applyOne(const auto & m, Params &&... params) const
{
- return applyOne_internal<T>(objects.begin(), objects.end(), m, std::forward<Params>(params)...);
+ const auto & srcObjects = containerFor<T>();
+ return applyOne_internal<T>(srcObjects.begin(), srcObjects.end(), m, std::forward<Params>(params)...);
}
template<typename T = Object, typename... Params>
auto
rapplyOne(const auto & m, Params &&... params) const
{
- return applyOne_internal<T>(objects.rbegin(), objects.rend(), m, std::forward<Params>(params)...);
+ const auto & srcObjects = containerFor<T>();
+ return applyOne_internal<T>(srcObjects.rbegin(), srcObjects.rend(), m, std::forward<Params>(params)...);
}
- template<typename T = Object>
+ template<typename T>
+ requires std::is_base_of_v<Object, T>
auto
removeAll()
{
- return std::erase_if(objects, [](auto && op) {
- return dynamic_cast<T *>(op.get());
- });
+ auto removeAllFrom = [](auto & container) {
+ if constexpr (std::is_base_of_v<T, std::decay_t<decltype(*container.front())>>) {
+ const auto size = container.size();
+ container.clear();
+ return size;
+ }
+ else {
+ return std::erase_if(container, [](auto && objPtr) -> bool {
+ return dynamic_cast<const T *>(std::to_address(objPtr));
+ });
+ }
+ };
+ (removeAllFrom(std::get<OtherObjects<Others>>(otherObjects)), ...);
+ return removeAllFrom(objects);
+ }
+
+ void
+ clear()
+ {
+ ((std::get<OtherObjects<Others>>(otherObjects).clear()), ...);
+ objects.clear();
}
- auto
+ [[nodiscard]] auto
+ begin() const
+ {
+ return objects.begin();
+ }
+
+ [[nodiscard]] auto
end() const
{
return objects.end();
}
- auto
+ [[nodiscard]] auto
+ rbegin() const
+ {
+ return objects.rbegin();
+ }
+
+ [[nodiscard]] auto
rend() const
{
return objects.rend();
}
+ [[nodiscard]] bool
+ empty() const
+ {
+ return objects.empty();
+ }
+
+ decltype(auto)
+ emplace(Ptr && ptr)
+ {
+ const 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, typename... Params>
+ requires(sizeof...(Others) == 0)
+ void
+ applyToOthersType(const auto &, Params...)
+ {
+ }
+
+ void
+ applyToOthersPtr(const auto &, Object *)
+ requires(sizeof...(Others) == 0)
+ {
+ }
+
+ template<typename T, typename... Params>
+ requires(sizeof...(Others) > 0)
+ void
+ applyToOthersType(const auto & func, Params &&... params)
+ {
+ (
+ [&]() {
+ if constexpr (std::is_convertible_v<T *, Others *>) {
+ std::invoke(
+ func, std::get<OtherObjects<Others>>(otherObjects), std::forward<Params>(params)...);
+ }
+ }(),
+ ...);
+ }
+
+ 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>
+ requires((std::is_base_of_v<Others, T> || ...))
+ [[nodiscard]] consteval static size_t
+ idx()
+ {
+ size_t typeIdx = 0;
+ auto found = ((++typeIdx && std::is_base_of_v<Others, T>) || ...);
+ return typeIdx - found;
+ }
+
+ template<typename T>
+ [[nodiscard]]
+ constexpr const auto &
+ containerFor() const
+ {
+ if constexpr ((std::is_base_of_v<Others, T> || ...)) {
+ return std::get<idx<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
{
- return std::count_if(begin, end, [&m, &params...](auto && op) {
- if (auto o = dynamic_cast<T *>(op.get())) {
- std::invoke(m, o, std::forward<Params>(params)...);
- return true;
- }
- return false;
- });
+ if constexpr (std::is_convertible_v<decltype(std::to_address(*begin)), T *>) {
+ std::for_each(begin, end, [&m, &params...](auto && op) {
+ std::invoke(m, op, std::forward<Params>(params)...);
+ });
+ return std::distance(begin, end);
+ }
+ else {
+ return std::count_if(begin, end, [&m, &params...](auto && op) {
+ if (auto o = dynamic_cast<T *>(std::to_address(op))) {
+ std::invoke(m, o, std::forward<Params>(params)...);
+ return true;
+ }
+ return false;
+ });
+ }
}
template<typename T = Object, typename... Params>
auto
applyOne_internal(const auto begin, const auto end, const auto & m, Params &&... params) const
{
- return std::find_if(begin, end, [&m, &params...](auto && op) {
- if (auto o = dynamic_cast<T *>(op.get())) {
- return std::invoke(m, o, std::forward<Params>(params)...);
- }
- return false;
- });
+ if constexpr (std::is_convertible_v<decltype(std::to_address(*begin)), T *>) {
+ return std::find_if(begin, end, [&m, &params...](auto && op) {
+ return std::invoke(m, op, std::forward<Params>(params)...);
+ });
+ }
+ else {
+ return std::find_if(begin, end, [&m, &params...](auto && op) {
+ if (auto o = dynamic_cast<T *>(std::to_address(op))) {
+ return std::invoke(m, o, std::forward<Params>(params)...);
+ }
+ return false;
+ });
+ }
}
};
+
+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/lib/manyPtr.h b/lib/manyPtr.h
new file mode 100644
index 0000000..9e08452
--- /dev/null
+++ b/lib/manyPtr.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <memory>
+#include <tuple>
+
+template<typename Primary, typename... Others> class ManyPtr : Primary {
+public:
+ using element_type = typename Primary::element_type;
+
+ template<typename... Params> ManyPtr(Params &&... params) : Primary {std::forward<Params>(params)...}
+ {
+ updatePtrs();
+ }
+
+ using Primary::operator->;
+ using Primary::operator*;
+ using Primary::operator bool;
+ using Primary::get;
+
+ template<typename... Params>
+ void
+ reset(Params &&... params)
+ {
+ Primary::reset(std::forward<Params>(params)...);
+ updatePtrs();
+ }
+
+ template<typename Other>
+ [[nodiscard]] consteval static bool
+ couldBe()
+ {
+ return (std::is_convertible_v<Others *, Other *> || ...);
+ }
+
+ template<typename Other>
+ requires(couldBe<Other>())
+ [[nodiscard]] auto
+ getAs() const
+ {
+ return std::get<idx<Other>()>(others);
+ }
+
+ template<typename Other>
+ requires(!couldBe<Other>() && requires { std::dynamic_pointer_cast<Other>(std::declval<Primary>()); })
+ [[nodiscard]] auto
+ dynamicCast() const
+ {
+ return std::dynamic_pointer_cast<Other>(*this);
+ }
+
+ template<typename Other>
+ requires(!couldBe<Other>() && !requires { std::dynamic_pointer_cast<Other>(std::declval<Primary>()); })
+ [[nodiscard]] auto
+ dynamicCast() const
+ {
+ return dynamic_cast<Other *>(get());
+ }
+
+private:
+ using OtherPtrs = std::tuple<Others *...>;
+
+ template<typename Other>
+ requires(couldBe<Other>())
+ [[nodiscard]] consteval static bool
+ idx()
+ {
+ size_t typeIdx = 0;
+ return ((typeIdx++ && std::is_convertible_v<Others *, Other *>) || ...);
+ }
+
+ void
+ updatePtrs()
+ {
+ if (*this) {
+ others = {dynamic_cast<Others *>(get())...};
+ }
+ else {
+ others = {};
+ }
+ }
+
+ OtherPtrs others;
+};
+
+template<typename Primary, typename... Others> using ManySharedPtr = ManyPtr<std::shared_ptr<Primary>, Others...>;
+template<typename Primary, typename... Others> using ManyUniquePtr = ManyPtr<std::unique_ptr<Primary>, Others...>;
diff --git a/lib/persistence.h b/lib/persistence.h
index e385b20..75bcea6 100644
--- a/lib/persistence.h
+++ b/lib/persistence.h
@@ -1,5 +1,6 @@
#pragma once
+#include "manyPtr.h"
#include <charconv>
#include <format>
#include <functional>
@@ -200,7 +201,7 @@ namespace Persistence {
}
[[nodiscard]] virtual NameActionSelection setName(const std::string_view key, SelectionFactory &&) = 0;
- virtual void selHandler() {};
+ virtual void selHandler() { };
virtual void setType(const std::string_view, const Persistable *) = 0;
SelectionPtr sel {};