AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
SharedPtrTypes.h
    1/*
    2 * AUI Framework - Declarative UI toolkit for modern C++20
    3 * Copyright (C) 2020-2025 Alex2772 and Contributors
    4 *
    5 * SPDX-License-Identifier: MPL-2.0
    6 *
    7 * This Source Code Form is subject to the terms of the Mozilla Public
    8 * License, v. 2.0. If a copy of the MPL was not distributed with this
    9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
   10 */
   11
   12#pragma once
   13
   14#include <memory>
   15#include <functional>
   16#include <optional>
   17#include <type_traits>
   18#include <AUI/Util/Assert.h>
   19
   20class AObject;
   21
   22#ifdef AUI_SHARED_PTR_FIND_INSTANCES
   23#include <AUI/api.h>
   24#include <AUI/Util/APimpl.h>
   25#include <map>
   26#include <set>
   27#include <mutex>
   28#include <AUI/Reflect/AClass.h>
   29
   30class API_AUI_CORE AStacktrace;
   31
   32namespace aui::impl::shared_ptr {
   33    struct InstancesDict {
   34        std::recursive_mutex sync;
   35        std::map<void*, std::set<void*>> map;
   36    };
   37
   38    API_AUI_CORE InstancesDict& instances() noexcept;
   39    API_AUI_CORE void printAllInstancesOf(void* ptrToSharedPtr) noexcept;
   40}
   41
   42#endif
   43
   44template<typename T>
   45class _;
   46
   51template<typename T>
   52struct _weak: public std::weak_ptr<T> {
   53private:
   54    using super = std::weak_ptr<T>;
   55
   56public:
   57    using super::weak_ptr;
   58
   59    _weak(const _weak<T>& v) noexcept: std::weak_ptr<T>(v) {}
   60    _weak(_weak<T>&& v) noexcept: std::weak_ptr<T>(std::move(v)) {}
   61    _weak(const std::weak_ptr<T>& v): std::weak_ptr<T>(v) {}
   62    _weak(std::weak_ptr<T>&& v) noexcept: std::weak_ptr<T>(std::move(v)) {}
   63
   64    _<T> lock() const noexcept {
   65        return static_cast<_<T>>(super::lock());
   66    }
   67
   68    _weak& operator=(const std::weak_ptr<T>& v) noexcept {
   69        super::weak_ptr::operator=(v);
   70        return *this;
   71    }
   72
   73    _weak& operator=(std::weak_ptr<T>&& v) noexcept {
   74        super::weak_ptr::operator=(std::move(v));
   75        return *this;
   76    }
   77
   78    _weak& operator=(const _weak<T>& v) noexcept {
   79        super::weak_ptr::operator=(v);
   80        return *this;
   81    }
   82
   83    _weak& operator=(_weak<T>&& v) noexcept {
   84        super::weak_ptr::operator=(std::move(v));
   85        return *this;
   86    }
   87
   88    _weak& operator=(const std::shared_ptr<T>& v) noexcept {
   89        super::weak_ptr::operator=(v);
   90        return *this;
   91    }
   92
   93    _weak& operator=(std::shared_ptr<T>&& v) noexcept {
   94        super::weak_ptr::operator=(std::move(v));
   95        return *this;
   96    }
   97
   98    _weak& operator=(const _<T>& v) noexcept {
   99        super::weak_ptr::operator=(v);
  100        return *this;
  101    }
  102
  103    _weak& operator=(_<T>&& v) noexcept {
  104        super::weak_ptr::operator=(std::move(v));
  105        return *this;
  106    }
  107};
  108
  109template<typename T, typename Deleter = std::default_delete<T>>
  110using _unique = std::unique_ptr<T, Deleter>;
  111
  112
  113namespace aui {
  114
  115    struct ptr {
  132        template<typename T, typename Deleter = std::default_delete<T>>
  133        static _unique<T, Deleter> manage_unique(T* ptr, Deleter deleter = Deleter{}) {
  134            return { ptr, std::move(deleter) };
  135        }
  136
  144        template<typename T>
  145        static _<T> manage_shared(T* raw);
  146
  156        template<typename T, typename Deleter>
  157        static _<T> manage_shared(T* raw, Deleter deleter);
  158
  166        template<typename T>
  167        static _<T> fake_shared(T* raw);
  168
  181        template <typename T>
  182        static _<T> shared_from_this(T* raw) {
  183            return _<T>(raw->shared_from_this(), raw);
  184        }
  185
  198        template <typename T>
  199        static _weak<T> weak_from_this(T* raw) {
  200            // std::weak_ptr not having an aliasing constructor is clearly intentional rather than oversight --
  201            // although i dont understand reasons behind it
  202            return _weak<T>(shared_from_this(raw));
  203        }
  204    };
  205}
  206
  207
  213template<typename T>
  214class _ : public std::shared_ptr<T>
  215{
  216    friend struct aui::ptr;
  217private:
  218    using super = std::shared_ptr<T>;
  219
  220    _(T* raw, std::nullopt_t): std::shared_ptr<T>(raw) {
  221
  222    }
  223
  224#ifdef AUI_SHARED_PTR_FIND_INSTANCES
  225    friend API_AUI_CORE void aui::impl::shared_ptr::printAllInstancesOf(void* ptrToSharedPtr) noexcept;
  226    struct InstanceDescriber;
  227
  228    static AStacktrace makeStacktrace();
  229
  230    struct InstanceDescriber {
  231        aui::fast_pimpl<AStacktrace, sizeof(std::vector<int>) + 8, alignof(std::vector<int>)> stacktrace;
  232        _<T>* self;
  233        T* pointingTo;
  234
  235        InstanceDescriber(_<T>* self): stacktrace(_<T>::makeStacktrace()), self(self), pointingTo(self->get()) {
  236            if (pointingTo == nullptr) return;
  237            std::unique_lock lock(aui::impl::shared_ptr::instances().sync);
  238            aui::impl::shared_ptr::instances().map[pointingTo].insert(self);
  239            //std::printf("[AUI_SHARED_PTR_FIND_INSTANCES] %s << %p\n", AClass<T>::name().toStdString().c_str(), pointingTo);
  240        }
  241
  242        InstanceDescriber(const InstanceDescriber&) = delete;
  243        InstanceDescriber(InstanceDescriber&&) = delete;
  244
  245        ~InstanceDescriber() {
  246            if (pointingTo == nullptr) return;
  247            auto& inst = aui::impl::shared_ptr::instances();
  248            std::unique_lock lock(inst.sync);
  249            if (auto mapIt = inst.map.find(pointingTo); mapIt != inst.map.end()) {
  250                auto setIt = mapIt->second.find(self);
  251                AUI_ASSERT(setIt != mapIt->second.end());
  252                mapIt->second.erase(setIt);
  253                if (mapIt->second.empty()) {
  254                    //inst.map.erase(it);
  255                }
  256            }
  257            //std::printf("[AUI_SHARED_PTR_FIND_INSTANCES] %s >> %p\n", AClass<T>::name().toStdString().c_str(), pointingTo);
  258        }
  259    } mInstanceDescriber = this;
  260
  261#endif
  262
  263public:
  264    using stored_t = T;
  265
  266
  267#ifdef AUI_SHARED_PTR_FIND_INSTANCES
  268    void printAllInstances() {
  269        aui::impl::shared_ptr::printAllInstancesOf(this);
  270    }
  271    void printAllInstances() const {
  272        const_cast<_<T>&>(*this).printAllInstances();
  273    }
  274#endif
  275
  276    using std::shared_ptr<T>::shared_ptr;
  277
  278    _(const std::shared_ptr<T>& v): std::shared_ptr<T>(v) {}
  279    _(std::shared_ptr<T>&& v) noexcept: std::shared_ptr<T>(std::move(v)) {}
  280    _(const _& v): std::shared_ptr<T>(v) {}
  281    _(_&& v) noexcept: std::shared_ptr<T>(std::move(v)) {}
  282    _(const std::weak_ptr<T>& v): std::shared_ptr<T>(v) {}
  283    _(const _weak<T>& v): std::shared_ptr<T>(v) {}
  284
  285    _& operator=(const _& rhs) noexcept {
  286        std::shared_ptr<T>::operator=(rhs);
  287        return *this;
  288    }
  289
  290    _& operator=(_&& rhs) noexcept {
  291        std::shared_ptr<T>::operator=(std::forward<_>(rhs));
  292        return *this;
  293    }
  294
  300    _(T* v) = delete;
  301
  305    [[nodiscard]]
  306    _weak<T> weak() const {
  307        return _weak<T>(*this);
  308    }
  309
  310    template<typename SignalField, typename Object, typename Function>
  311    inline _<T>& connect(SignalField signalField, Object object, Function&& function);
  312
  313    template<typename SignalField, typename Function>
  314    inline _<T>& connect(SignalField signalField, Function&& function);
  315
  316
  317    template <typename Functor>
  318    const _<T>& operator^(Functor&& functor) const {
  319        functor(*this);
  320        return *this;
  321    }
  322
  329    [[nodiscard]]
  330    std::add_lvalue_reference_t<T> value() const noexcept {
  331#if AUI_DEBUG
  332        AUI_ASSERTX(super::get() != nullptr, "an attempt to dereference a null pointer");
  333#endif
  334        return *super::get();
  335    }
  336
  343    [[nodiscard]]
  344    std::add_lvalue_reference_t<T> operator*() const noexcept {
  345        return value();
  346    }
  347
  354    [[nodiscard]]
  355    std::add_pointer_t<T> operator->() const noexcept {
  356        return &value();
  357    }
  358
  359    // forward ranged-for loops
  360    auto begin() const requires requires(T& t) { t.begin(); } {
  361        return super::operator->()->begin();
  362    }
  363    auto end() const requires requires(T& t) { t.end(); } {
  364        return super::operator->()->end();
  365    }
  366    auto begin() requires requires(T& t) { t.begin(); } {
  367        return super::operator->()->begin();
  368    }
  369    auto end() requires requires(T& t) { t.end(); } {
  370        return super::operator->()->end();
  371    }
  372
  373    // operators
  374
  375    template<typename Arg>
  376    requires requires (T&& l, Arg&& r) { std::forward<T>(l) << std::forward<Arg>(r); }
  377    const _<T>& operator<<(Arg&& value) const {
  378        (*super::get()) << std::forward<Arg>(value);
  379        return *this;
  380    }
  381
  382    template<typename Arg>
  383    _<T>& operator<<(Arg&& value) {
  384        (*super::get()) << std::forward<Arg>(value);
  385        return *this;
  386    }
  387
  388    template<typename... Arg>
  389    auto operator()(Arg&&... value) const requires std::is_invocable_v<T, Arg...> {
  390        return (*super::get())(std::forward<Arg>(value)...);
  391    }
  392
  393    template<typename Arg>
  394    requires requires (T&& l, Arg&& r) { std::forward<T>(l) + std::forward<Arg>(r); }
  395    const _<T>& operator+(Arg&& value) const {
  396        (*super::get()) + std::forward<Arg>(value);
  397        return *this;
  398    }
  399
  400    template<typename Arg>
  401    requires requires (T&& l, Arg&& r) { std::forward<T>(l) & std::forward<Arg>(r); }
  402    const _<T>& operator&(Arg&& value) const {
  403        (*super::get()) & std::forward<Arg>(value);
  404        return *this;
  405    }
  406
  407    template<typename Arg>
  408    requires requires (T&& l, Arg&& r) { std::forward<T>(l) | std::forward<Arg>(r); }
  409    const _<T>& operator|(Arg&& value) const {
  410        (*super::get()) | std::forward<Arg>(value);
  411        return *this;
  412    }
  413
  414    template<typename Arg>
  415    _<T>& operator+(Arg&& value) {
  416        (*super::get()) + std::forward<Arg>(value);
  417        return *this;
  418    }
  419
  420    template<typename Arg>
  421    const _<T>& operator*(Arg&& value) {
  422        (*super::get()) * std::forward<Arg>(value);
  423        return *this;
  424    }
  425
  426    template<typename Arg>
  427    requires requires (T&& l, Arg&& r) { std::forward<T>(l) - std::forward<Arg>(r); }
  428    const _<T>& operator-(Arg&& value) const {
  429        (*super::get()) - std::forward<Arg>(value);
  430        return *this;
  431    }
  432
  433    template<typename Arg>
  434    _<T>& operator-(Arg&& value) {
  435        (*super::get()) - std::forward<Arg>(value);
  436        return *this;
  437    }
  438
  439    template<typename Arg>
  440    requires requires (T&& l, Arg&& r) { std::forward<T>(l) >> std::forward<Arg>(r); }
  441    const _<T>& operator>>(Arg&& value) const {
  442        (*super::get()) >> std::forward<Arg>(value);
  443        return *this;
  444    }
  445
  446    template<typename...Args>
  447    _<T>& operator()(const Args&... value) {
  448        (*super::get())(value...);
  449        return *this;
  450    }
  451    template<typename...Args>
  452    auto operator()(Args&&... value) {
  453        return (*super::get())(std::forward<Args>(value)...);
  454    }
  455};
  456
  457
  458namespace aui {
  459    template<typename T>
  461        return _<T>(raw, std::nullopt);
  462    }
  463
  464    template<typename T>
  465    _<T> ptr::fake_shared(T* raw) {
  466        return _<T>(std::shared_ptr<void>{}, raw);
  467    }
  468
  469    template<typename T, typename Deleter>
  470    _<T> ptr::manage_shared(T* raw, Deleter deleter) {
  471        return _<T>(raw, deleter);
  472    }
  473}
  474
  475template<typename TO, typename FROM>
  476inline TO* _cast(const _unique<FROM>& object)
  477{
  478    return dynamic_cast<TO*>(object.get());
  479}
  480
  481template<typename TO, typename FROM>
  482inline _<TO> _cast(const _<FROM>& object)
  483{
  484    return std::dynamic_pointer_cast<TO, FROM>(object);
  485}
  486
  487template<typename TO, typename FROM>
  488inline _<TO> _cast(_<FROM>&& object)
  489{
  490    return std::dynamic_pointer_cast<TO, FROM>(std::move(object));
  491}
  492
  493template<typename TO, typename FROM>
  494inline _<TO> _cast(const std::shared_ptr<FROM>& object)
  495{
  496    return std::dynamic_pointer_cast<TO, FROM>(object);
  497}
  498
  499
  500template<typename TO, typename FROM>
  501inline _<TO> _cast(std::shared_ptr<FROM>&& object)
  502{
  503    return std::dynamic_pointer_cast<TO, FROM>(std::move(object));
  504}
  505
  506
  507
  549#define AUI_NULLSAFE(s) if(decltype(auto) _tmp = (s))_tmp
A base object class.
Definition AObject.h:39
Stacktrace consisting of a collection of stack function frames.
Definition AStacktrace.h:28
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:215
_(T *v)=delete
std::add_pointer_t< T > operator->() const noexcept
Dereferences the stored pointer.
Definition SharedPtrTypes.h:355
_weak< T > weak() const
Definition SharedPtrTypes.h:306
std::add_lvalue_reference_t< T > operator*() const noexcept
Dereferences the stored pointer.
Definition SharedPtrTypes.h:344
std::add_lvalue_reference_t< T > value() const noexcept
Dereferences the stored pointer.
Definition SharedPtrTypes.h:330
ParentSubSelector< L, R > operator>>(L l, R r)
Makes indirect parent subselector.
Definition ParentSelector.h:89
type_of< T > t
Selects views that are of the specified C++ types.
Definition type_of.h:71
#define AUI_ASSERT(condition)
Asserts that the passed condition evaluates to true.
Definition Assert.h:55
#define AUI_ASSERTX(condition, what)
Asserts that the passed condition evaluates to true. Adds extra message string.
Definition Assert.h:74
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:52
Utility wrapper implementing the stack-allocated (fast) pimpl idiom.
Definition APimpl.h:31
Definition SharedPtrTypes.h:115
static _< T > fake_shared(T *raw)
Creates fake shared pointer to T* raw with empty destructor, which does nothing. It's useful when som...
Definition SharedPtrTypes.h:465
static _< T > manage_shared(T *raw)
Delegates memory management of the raw pointer T* raw to the shared pointer, which is returned.
Definition SharedPtrTypes.h:460
static _weak< T > weak_from_this(T *raw)
Downcasts std::enable_shared_from_this<base class> to the derived class T.
Definition SharedPtrTypes.h:199
static _< T > shared_from_this(T *raw)
Downcasts std::enable_shared_from_this<base class> to the derived class T.
Definition SharedPtrTypes.h:182
static _unique< T, Deleter > manage_unique(T *ptr, Deleter deleter=Deleter{})
Creates unique_ptr from raw pointer and a deleter.
Definition SharedPtrTypes.h:133