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 {
  125        template<typename T, typename Deleter = std::default_delete<T>>
  126        static _unique<T, Deleter> make_unique_with_deleter(T* ptr, Deleter deleter = Deleter{}) {
  127            return { ptr, std::move(deleter) };
  128        }
  129
  136        template<typename T>
  137        static _<T> manage(T* raw);
  138
  147        template<typename T, typename Deleter>
  148        static _<T> manage(T* raw, Deleter deleter);
  149
  156        template<typename T>
  157        static _unique<T> unique(T* raw);
  158
  166        template<typename T>
  167        static _<T> fake(T* raw);
  168    };
  169}
  170
  171
  177template<typename T>
  178class _ : public std::shared_ptr<T>
  179{
  180    friend struct aui::ptr;
  181private:
  182    using super = std::shared_ptr<T>;
  183
  184    _(T* raw, std::nullopt_t): std::shared_ptr<T>(raw) {
  185
  186    }
  187
  188#ifdef AUI_SHARED_PTR_FIND_INSTANCES
  189    friend API_AUI_CORE void aui::impl::shared_ptr::printAllInstancesOf(void* ptrToSharedPtr) noexcept;
  190    struct InstanceDescriber;
  191
  192    static AStacktrace makeStacktrace();
  193
  194    struct InstanceDescriber {
  195        aui::fast_pimpl<AStacktrace, sizeof(std::vector<int>) + 8, alignof(std::vector<int>)> stacktrace;
  196        _<T>* self;
  197        T* pointingTo;
  198
  199        InstanceDescriber(_<T>* self): stacktrace(_<T>::makeStacktrace()), self(self), pointingTo(self->get()) {
  200            if (pointingTo == nullptr) return;
  201            std::unique_lock lock(aui::impl::shared_ptr::instances().sync);
  202            aui::impl::shared_ptr::instances().map[pointingTo].insert(self);
  203            //std::printf("[AUI_SHARED_PTR_FIND_INSTANCES] %s << %p\n", AClass<T>::name().toStdString().c_str(), pointingTo);
  204        }
  205
  206        InstanceDescriber(const InstanceDescriber&) = delete;
  207        InstanceDescriber(InstanceDescriber&&) = delete;
  208
  209        ~InstanceDescriber() {
  210            if (pointingTo == nullptr) return;
  211            auto& inst = aui::impl::shared_ptr::instances();
  212            std::unique_lock lock(inst.sync);
  213            if (auto mapIt = inst.map.find(pointingTo); mapIt != inst.map.end()) {
  214                auto setIt = mapIt->second.find(self);
  215                AUI_ASSERT(setIt != mapIt->second.end());
  216                mapIt->second.erase(setIt);
  217                if (mapIt->second.empty()) {
  218                    //inst.map.erase(it);
  219                }
  220            }
  221            //std::printf("[AUI_SHARED_PTR_FIND_INSTANCES] %s >> %p\n", AClass<T>::name().toStdString().c_str(), pointingTo);
  222        }
  223    } mInstanceDescriber = this;
  224
  225#endif
  226
  227public:
  228    using stored_t = T;
  229
  230
  231#ifdef AUI_SHARED_PTR_FIND_INSTANCES
  232    void printAllInstances() {
  233        aui::impl::shared_ptr::printAllInstancesOf(this);
  234    }
  235    void printAllInstances() const {
  236        const_cast<_<T>&>(*this).printAllInstances();
  237    }
  238#endif
  239
  240    using std::shared_ptr<T>::shared_ptr;
  241
  242    _(const std::shared_ptr<T>& v): std::shared_ptr<T>(v) {}
  243    _(std::shared_ptr<T>&& v) noexcept: std::shared_ptr<T>(std::move(v)) {}
  244    _(const _& v): std::shared_ptr<T>(v) {}
  245    _(_&& v) noexcept: std::shared_ptr<T>(std::move(v)) {}
  246    _(const std::weak_ptr<T>& v): std::shared_ptr<T>(v) {}
  247    _(const _weak<T>& v): std::shared_ptr<T>(v) {}
  248
  249    _& operator=(const _& rhs) noexcept {
  250        std::shared_ptr<T>::operator=(rhs);
  251        return *this;
  252    }
  253
  254    _& operator=(_&& rhs) noexcept {
  255        std::shared_ptr<T>::operator=(std::forward<_>(rhs));
  256        return *this;
  257    }
  258
  264    _(T* v) = delete;
  265
  269    [[nodiscard]]
  270    _weak<T> weak() const {
  271        return _weak<T>(*this);
  272    }
  273
  274    template<typename SignalField, typename Object, typename Function>
  275    inline _<T>& connect(SignalField signalField, Object object, Function&& function);
  276
  277    template<typename SignalField, typename Function>
  278    inline _<T>& connect(SignalField signalField, Function&& function);
  279
  280
  281    template <typename Functor>
  282    const _<T>& operator^(Functor&& functor) const {
  283        functor(*this);
  284        return *this;
  285    }
  286
  293    [[nodiscard]]
  294    std::add_lvalue_reference_t<T> value() const noexcept {
  295#if AUI_DEBUG
  296        AUI_ASSERTX(super::get() != nullptr, "an attempt to dereference a null pointer");
  297#endif
  298        return *super::get();
  299    }
  300
  307    [[nodiscard]]
  308    std::add_lvalue_reference_t<T> operator*() const noexcept {
  309        return value();
  310    }
  311
  318    [[nodiscard]]
  319    std::add_pointer_t<T> operator->() const noexcept {
  320        return &value();
  321    }
  322
  323    // forward ranged-for loops
  324    auto begin() const requires requires(T& t) { t.begin(); } {
  325        return super::operator->()->begin();
  326    }
  327    auto end() const requires requires(T& t) { t.end(); } {
  328        return super::operator->()->end();
  329    }
  330    auto begin() requires requires(T& t) { t.begin(); } {
  331        return super::operator->()->begin();
  332    }
  333    auto end() requires requires(T& t) { t.end(); } {
  334        return super::operator->()->end();
  335    }
  336
  337    // operators
  338
  339    template<typename Arg>
  340    requires requires (T&& l, Arg&& r) { std::forward<T>(l) << std::forward<Arg>(r); }
  341    const _<T>& operator<<(Arg&& value) const {
  342        (*super::get()) << std::forward<Arg>(value);
  343        return *this;
  344    }
  345
  346    template<typename Arg>
  347    _<T>& operator<<(Arg&& value) {
  348        (*super::get()) << std::forward<Arg>(value);
  349        return *this;
  350    }
  351
  352    template<typename... Arg>
  353    auto operator()(Arg&&... value) const requires std::is_invocable_v<T, Arg...> {
  354        return (*super::get())(std::forward<Arg>(value)...);
  355    }
  356
  357    template<typename Arg>
  358    requires requires (T&& l, Arg&& r) { std::forward<T>(l) + std::forward<Arg>(r); }
  359    const _<T>& operator+(Arg&& value) const {
  360        (*super::get()) + std::forward<Arg>(value);
  361        return *this;
  362    }
  363
  364    template<typename Arg>
  365    requires requires (T&& l, Arg&& r) { std::forward<T>(l) & std::forward<Arg>(r); }
  366    const _<T>& operator&(Arg&& value) const {
  367        (*super::get()) & std::forward<Arg>(value);
  368        return *this;
  369    }
  370
  371    template<typename Arg>
  372    requires requires (T&& l, Arg&& r) { std::forward<T>(l) | std::forward<Arg>(r); }
  373    const _<T>& operator|(Arg&& value) const {
  374        (*super::get()) | std::forward<Arg>(value);
  375        return *this;
  376    }
  377
  378    template<typename Arg>
  379    _<T>& operator+(Arg&& value) {
  380        (*super::get()) + std::forward<Arg>(value);
  381        return *this;
  382    }
  383
  384    template<typename Arg>
  385    const _<T>& operator*(Arg&& value) {
  386        (*super::get()) * std::forward<Arg>(value);
  387        return *this;
  388    }
  389
  390    template<typename Arg>
  391    requires requires (T&& l, Arg&& r) { std::forward<T>(l) - std::forward<Arg>(r); }
  392    const _<T>& operator-(Arg&& value) const {
  393        (*super::get()) - std::forward<Arg>(value);
  394        return *this;
  395    }
  396
  397    template<typename Arg>
  398    _<T>& operator-(Arg&& value) {
  399        (*super::get()) - std::forward<Arg>(value);
  400        return *this;
  401    }
  402
  403    template<typename Arg>
  404    requires requires (T&& l, Arg&& r) { std::forward<T>(l) >> std::forward<Arg>(r); }
  405    const _<T>& operator>>(Arg&& value) const {
  406        (*super::get()) >> std::forward<Arg>(value);
  407        return *this;
  408    }
  409
  410    template<typename...Args>
  411    _<T>& operator()(const Args&... value) {
  412        (*super::get())(value...);
  413        return *this;
  414    }
  415    template<typename...Args>
  416    auto operator()(Args&&... value) {
  417        return (*super::get())(std::forward<Args>(value)...);
  418    }
  419};
  420
  421
  422namespace aui {
  423    template<typename T>
  424    _<T> ptr::manage(T* raw) {
  425        return _<T>(raw, std::nullopt);
  426    }
  427
  428    template<typename T>
  429    _<T> ptr::fake(T* raw) {
  430        return _<T>(std::shared_ptr<void>{}, raw);
  431    }
  432
  433    template<typename T, typename Deleter>
  434    _<T> ptr::manage(T* raw, Deleter deleter) {
  435        return _<T>(raw, deleter);
  436    }
  437    template<typename T>
  438    _unique<T> ptr::unique(T* raw) {
  439        return _unique<T>(raw);
  440    }
  441}
  442
  443template<typename TO, typename FROM>
  444inline TO* _cast(const _unique<FROM>& object)
  445{
  446    return dynamic_cast<TO*>(object.get());
  447}
  448
  449template<typename TO, typename FROM>
  450inline _<TO> _cast(const _<FROM>& object)
  451{
  452    return std::dynamic_pointer_cast<TO, FROM>(object);
  453}
  454
  455template<typename TO, typename FROM>
  456inline _<TO> _cast(_<FROM>&& object)
  457{
  458    return std::dynamic_pointer_cast<TO, FROM>(std::move(object));
  459}
  460
  461template<typename TO, typename FROM>
  462inline _<TO> _cast(const std::shared_ptr<FROM>& object)
  463{
  464    return std::dynamic_pointer_cast<TO, FROM>(object);
  465}
  466
  467
  468template<typename TO, typename FROM>
  469inline _<TO> _cast(std::shared_ptr<FROM>&& object)
  470{
  471    return std::dynamic_pointer_cast<TO, FROM>(std::move(object));
  472}
  473
  474
  475
  517#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:179
_(T *v)=delete
std::add_pointer_t< T > operator->() const noexcept
Dereferences the stored pointer.
Definition SharedPtrTypes.h:319
_weak< T > weak() const
Definition SharedPtrTypes.h:270
std::add_lvalue_reference_t< T > operator*() const noexcept
Dereferences the stored pointer.
Definition SharedPtrTypes.h:308
std::add_lvalue_reference_t< T > value() const noexcept
Dereferences the stored pointer.
Definition SharedPtrTypes.h:294
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 _unique< T > unique(T *raw)
Delegates memory management of the raw pointer T* raw to the unique pointer, which is returned.
Definition SharedPtrTypes.h:438
static _unique< T, Deleter > make_unique_with_deleter(T *ptr, Deleter deleter=Deleter{})
Creates unique_ptr from raw pointer and a deleter.
Definition SharedPtrTypes.h:126
static _< T > manage(T *raw)
Delegates memory management of the raw pointer T* raw to the shared pointer, which is returned.
Definition SharedPtrTypes.h:424
static _< T > fake(T *raw)
Creates fake shared pointer to T* raw with empty destructor, which does nothing. It's useful when som...
Definition SharedPtrTypes.h:429