/* This file is part of Kepka - The Unofficial Telegram Desktop client, see https://github.com/procxx/kepka Kepka is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library. Full license: https://github.com/procxx/kepka/blob/master/LICENSE Copyright (c) 2018 pro.cxx Community */ #pragma once #include "core/utils.h" // @todo used for base::take #include #include // Smart pointer for QObject*, has move semantics, destroys object if it doesn't have a parent. template class object_ptr { public: object_ptr(std::nullptr_t) {} // No default constructor, but constructors with at least // one argument are simply make functions. template explicit object_ptr(Parent &&parent, Args &&... args) : _object(new Object(std::forward(parent), std::forward(args)...)) {} object_ptr(const object_ptr &other) = delete; object_ptr &operator=(const object_ptr &other) = delete; object_ptr(object_ptr &&other) : _object(base::take(other._object)) {} object_ptr &operator=(object_ptr &&other) { auto temp = std::move(other); destroy(); std::swap(_object, temp._object); return *this; } template ::value>> object_ptr(object_ptr &&other) : _object(base::take(other._object)) {} template ::value>> object_ptr &operator=(object_ptr &&other) { _object = base::take(other._object); return *this; } object_ptr &operator=(std::nullptr_t) { _object = nullptr; return *this; } // So we can pass this pointer to methods like connect(). Object *data() const { return static_cast(_object.data()); } operator Object *() const { return data(); } explicit operator bool() const { return _object != nullptr; } Object *operator->() const { return data(); } Object &operator*() const { return *data(); } // Use that instead "= new Object(parent, ...)" template void create(Parent &&parent, Args &&... args) { destroy(); _object = new Object(std::forward(parent), std::forward(args)...); } void destroy() { delete base::take(_object); } void destroyDelayed() { if (_object) { if (auto widget = base::up_cast(data())) { widget->hide(); } base::take(_object)->deleteLater(); } } ~object_ptr() { if (auto pointer = _object) { if (!pointer->parent()) { destroy(); } } } template friend object_ptr static_object_cast(object_ptr source); private: template friend class object_ptr; QPointer _object; }; template inline object_ptr static_object_cast(object_ptr source) { auto result = object_ptr(nullptr); result._object = static_cast(base::take(source._object).data()); return std::move(result); }