2015-12-30 00:12:49 -08:00
|
|
|
/*
|
2016-01-01 23:38:51 -08:00
|
|
|
* moocpp/grefptr.h
|
2015-12-30 00:12:49 -08:00
|
|
|
*
|
2016-01-01 23:38:51 -08:00
|
|
|
* Copyright (C) 2004-2016 by Yevgen Muntyan <emuntyan@users.sourceforge.net>
|
2015-12-30 00:12:49 -08:00
|
|
|
*
|
|
|
|
* This file is part of medit. medit is free software; you can
|
|
|
|
* redistribute it and/or modify it under the terms of the
|
|
|
|
* GNU Lesser General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2.1 of the License,
|
|
|
|
* or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2015-12-31 16:41:12 -08:00
|
|
|
#include "moocpp/utils.h"
|
|
|
|
#include <glib-object.h>
|
2015-12-30 00:12:49 -08:00
|
|
|
|
|
|
|
namespace moo {
|
|
|
|
|
|
|
|
template<typename ObjClass>
|
2016-01-02 04:31:23 -08:00
|
|
|
class mg_obj_handle
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
mg_obj_handle() : m_p(nullptr) {}
|
|
|
|
|
|
|
|
mg_obj_handle(const mg_obj_handle&) = delete;
|
|
|
|
mg_obj_handle& operator=(const mg_obj_handle&) = delete;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
ObjClass* _get_pointer() const { return m_p; }
|
|
|
|
void _set_pointer(ObjClass* p) { m_p = p; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
ObjClass* m_p;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename ObjClass>
|
|
|
|
class mg_obj_ref_unref;
|
2015-12-30 00:12:49 -08:00
|
|
|
|
2016-01-01 22:25:53 -08:00
|
|
|
enum class ref_transfer
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
2016-01-01 22:25:53 -08:00
|
|
|
take_ownership,
|
|
|
|
make_copy,
|
|
|
|
};
|
2015-12-31 16:41:12 -08:00
|
|
|
|
2016-01-02 04:31:23 -08:00
|
|
|
template<typename ObjClass,
|
|
|
|
typename ObjRefUnref = mg_obj_ref_unref<ObjClass>,
|
|
|
|
typename ObjHandle = mg_obj_handle<ObjClass>>
|
|
|
|
class grefptr : private ObjHandle
|
2016-01-01 22:25:53 -08:00
|
|
|
{
|
|
|
|
public:
|
2016-01-02 04:31:23 -08:00
|
|
|
grefptr() {}
|
|
|
|
grefptr(const nullptr_t) {}
|
2015-12-31 16:41:12 -08:00
|
|
|
|
2016-01-01 22:25:53 -08:00
|
|
|
grefptr(ObjClass* obj, ref_transfer policy)
|
2015-12-31 16:41:12 -08:00
|
|
|
{
|
|
|
|
assign(obj, policy);
|
2015-12-30 00:12:49 -08:00
|
|
|
}
|
|
|
|
|
2016-01-02 04:31:23 -08:00
|
|
|
static grefptr wrap_new(ObjClass* obj)
|
|
|
|
{
|
|
|
|
return grefptr(obj, ref_transfer::take_ownership);
|
|
|
|
}
|
|
|
|
|
2016-01-01 22:25:53 -08:00
|
|
|
~grefptr()
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
2015-12-31 16:41:12 -08:00
|
|
|
reset();
|
2015-12-30 00:12:49 -08:00
|
|
|
}
|
|
|
|
|
2015-12-31 16:41:12 -08:00
|
|
|
void ref(ObjClass* obj)
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
2016-01-01 22:25:53 -08:00
|
|
|
assign(obj, ref_transfer::make_copy);
|
2015-12-30 00:12:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void take(ObjClass* obj)
|
|
|
|
{
|
2016-01-01 22:25:53 -08:00
|
|
|
assign(obj, ref_transfer::take_ownership);
|
2015-12-30 00:12:49 -08:00
|
|
|
}
|
|
|
|
|
2016-01-02 04:31:23 -08:00
|
|
|
ObjClass* release()
|
|
|
|
{
|
|
|
|
auto* tmp = ObjHandle::_get_pointer();
|
|
|
|
ObjHandle::_set_pointer(nullptr);
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
2015-12-31 16:41:12 -08:00
|
|
|
void reset()
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
2016-01-02 04:31:23 -08:00
|
|
|
auto* tmp = ObjHandle::_get_pointer();
|
|
|
|
ObjHandle::_set_pointer(nullptr);
|
2015-12-30 00:12:49 -08:00
|
|
|
if (tmp)
|
2016-01-02 04:31:23 -08:00
|
|
|
ObjRefUnref::unref(tmp);
|
2015-12-30 00:12:49 -08:00
|
|
|
}
|
|
|
|
|
2015-12-31 16:41:12 -08:00
|
|
|
// Implicit conversion to ObjClass* is dangerous because there is a lot
|
|
|
|
// of code still which frees/steals objects directly. For example:
|
|
|
|
// FooObject* tmp = x->s;
|
|
|
|
// x->s = NULL;
|
|
|
|
// g_object_unref (tmp);
|
2016-01-02 04:31:23 -08:00
|
|
|
operator const ObjClass* () const { return get(); }
|
|
|
|
ObjClass* get() const { return ObjHandle::_get_pointer(); }
|
|
|
|
ObjClass& operator*() const { return *get(); }
|
2016-01-01 22:25:53 -08:00
|
|
|
|
|
|
|
// Explicitly forbid other pointer conversions. This way it's still possible to implement
|
|
|
|
// implicit conversions in subclasses, like that to GTypeInstance in gobjptr.
|
|
|
|
template<typename T>
|
|
|
|
operator T*() const = delete;
|
2015-12-30 00:12:49 -08:00
|
|
|
|
2016-01-02 04:31:23 -08:00
|
|
|
operator bool() const { return get() != nullptr; }
|
|
|
|
bool operator!() const { return get() == nullptr; }
|
2015-12-30 00:12:49 -08:00
|
|
|
|
|
|
|
template<typename X>
|
2015-12-31 16:41:12 -08:00
|
|
|
bool operator==(X* other) const
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
|
|
|
return get() == other;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename X, typename Y>
|
2016-01-01 22:25:53 -08:00
|
|
|
bool operator==(const grefptr<X, Y>& other) const
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
|
|
|
return get() == other.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename X>
|
|
|
|
bool operator!=(const X& anything) const
|
|
|
|
{
|
|
|
|
return !(*this == anything);
|
|
|
|
}
|
|
|
|
|
2016-01-01 22:25:53 -08:00
|
|
|
grefptr(const grefptr& other)
|
|
|
|
: grefptr(other.get())
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-01-01 22:25:53 -08:00
|
|
|
grefptr(grefptr&& other)
|
2016-01-02 04:31:23 -08:00
|
|
|
: grefptr()
|
2015-12-30 02:05:05 -08:00
|
|
|
{
|
2016-01-02 04:31:23 -08:00
|
|
|
this->ObjHandle::_set_pointer(other.get());
|
|
|
|
(&other)->ObjHandle::_set_pointer(nullptr);
|
2015-12-30 02:05:05 -08:00
|
|
|
}
|
|
|
|
|
2016-01-01 22:25:53 -08:00
|
|
|
grefptr& operator=(const grefptr& other)
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
2016-01-02 04:31:23 -08:00
|
|
|
assign(other.get(), ref_transfer::make_copy);
|
2015-12-31 16:41:12 -08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note that when T is const Foo, then assign(p) inside will be called with
|
|
|
|
// a const Foo, which can't be converted to non-const ObjClass*, so one can't
|
|
|
|
// steal a reference to a const object with this method.
|
|
|
|
template<typename T>
|
2016-01-01 22:25:53 -08:00
|
|
|
grefptr& operator=(T* p)
|
2015-12-31 16:41:12 -08:00
|
|
|
{
|
2016-01-01 22:25:53 -08:00
|
|
|
assign(p, ref_transfer::take_ownership);
|
2016-01-02 04:31:23 -08:00
|
|
|
return *this;
|
2015-12-31 16:41:12 -08:00
|
|
|
}
|
|
|
|
|
2016-01-01 22:25:53 -08:00
|
|
|
grefptr& operator=(const nullptr_t&)
|
2015-12-31 16:41:12 -08:00
|
|
|
{
|
|
|
|
reset();
|
2015-12-30 00:12:49 -08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-01-01 22:25:53 -08:00
|
|
|
grefptr& operator=(grefptr&& other)
|
2015-12-30 02:05:05 -08:00
|
|
|
{
|
2016-01-02 04:31:23 -08:00
|
|
|
if (get() != other.get())
|
2015-12-30 02:05:05 -08:00
|
|
|
{
|
2016-01-02 04:31:23 -08:00
|
|
|
assign(other.get(), ref_transfer::take_ownership);
|
|
|
|
(&other)->ObjHandle::_set_pointer(nullptr);
|
2015-12-30 02:05:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2015-12-30 00:12:49 -08:00
|
|
|
private:
|
2016-01-01 22:25:53 -08:00
|
|
|
void assign(ObjClass* obj, ref_transfer policy)
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
2016-01-02 04:31:23 -08:00
|
|
|
if (get() != obj)
|
2015-12-30 00:12:49 -08:00
|
|
|
{
|
2016-01-02 04:31:23 -08:00
|
|
|
ObjClass* tmp = get();
|
|
|
|
ObjHandle::_set_pointer(obj);
|
|
|
|
if (obj && (policy == ref_transfer::make_copy))
|
|
|
|
ObjRefUnref::ref(obj);
|
2015-12-30 00:12:49 -08:00
|
|
|
if (tmp)
|
2016-01-02 04:31:23 -08:00
|
|
|
ObjRefUnref::unref(tmp);
|
2015-12-30 00:12:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-01-02 04:31:23 -08:00
|
|
|
//template<typename ObjClass, typename ObjRefUnrefHelper = mg_ref_unref<ObjClass>>
|
|
|
|
//class grefptr
|
|
|
|
//{
|
|
|
|
//public:
|
|
|
|
// grefptr() : m_obj(nullptr) {}
|
|
|
|
// grefptr(const nullptr_t) : grefptr() {}
|
|
|
|
//
|
|
|
|
// grefptr(ObjClass* obj, ref_transfer policy)
|
|
|
|
// : grefptr()
|
|
|
|
// {
|
|
|
|
// assign(obj, policy);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// ~grefptr()
|
|
|
|
// {
|
|
|
|
// reset();
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// void ref(ObjClass* obj)
|
|
|
|
// {
|
|
|
|
// assign(obj, ref_transfer::make_copy);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// void take(ObjClass* obj)
|
|
|
|
// {
|
|
|
|
// assign(obj, ref_transfer::take_ownership);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// void reset()
|
|
|
|
// {
|
|
|
|
// auto* tmp = m_obj;
|
|
|
|
// m_obj = nullptr;
|
|
|
|
// if (tmp)
|
|
|
|
// ObjRefUnrefHelper::unref(tmp);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Implicit conversion to ObjClass* is dangerous because there is a lot
|
|
|
|
// // of code still which frees/steals objects directly. For example:
|
|
|
|
// // FooObject* tmp = x->s;
|
|
|
|
// // x->s = NULL;
|
|
|
|
// // g_object_unref (tmp);
|
|
|
|
// operator const ObjClass* () const { return m_obj; }
|
|
|
|
// ObjClass* get() const { return m_obj; }
|
|
|
|
// ObjClass& operator*() const { return *m_obj; }
|
|
|
|
//
|
|
|
|
// // Explicitly forbid other pointer conversions. This way it's still possible to implement
|
|
|
|
// // implicit conversions in subclasses, like that to GTypeInstance in gobjptr.
|
|
|
|
// template<typename T>
|
|
|
|
// operator T*() const = delete;
|
|
|
|
//
|
|
|
|
// operator bool() const { return m_obj != nullptr; }
|
|
|
|
// bool operator!() const { return m_obj == nullptr; }
|
|
|
|
//
|
|
|
|
// template<typename X>
|
|
|
|
// bool operator==(X* other) const
|
|
|
|
// {
|
|
|
|
// return get() == other;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// template<typename X, typename Y>
|
|
|
|
// bool operator==(const grefptr<X, Y>& other) const
|
|
|
|
// {
|
|
|
|
// return get() == other.get();
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// template<typename X>
|
|
|
|
// bool operator!=(const X& anything) const
|
|
|
|
// {
|
|
|
|
// return !(*this == anything);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// grefptr(const grefptr& other)
|
|
|
|
// : grefptr(other.get())
|
|
|
|
// {
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// grefptr(grefptr&& other)
|
|
|
|
// : m_obj(other.m_obj)
|
|
|
|
// {
|
|
|
|
// other.m_obj = nullptr;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// grefptr& operator=(const grefptr& other)
|
|
|
|
// {
|
|
|
|
// assign(other.m_obj, ref_transfer::make_copy);
|
|
|
|
// return *this;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Note that when T is const Foo, then assign(p) inside will be called with
|
|
|
|
// // a const Foo, which can't be converted to non-const ObjClass*, so one can't
|
|
|
|
// // steal a reference to a const object with this method.
|
|
|
|
// template<typename T>
|
|
|
|
// grefptr& operator=(T* p)
|
|
|
|
// {
|
|
|
|
// assign(p, ref_transfer::take_ownership);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// grefptr& operator=(const nullptr_t&)
|
|
|
|
// {
|
|
|
|
// reset();
|
|
|
|
// return *this;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// grefptr& operator=(grefptr&& other)
|
|
|
|
// {
|
|
|
|
// if (m_obj != other.m_obj)
|
|
|
|
// {
|
|
|
|
// assign(other.m_obj, ref_transfer::take_ownership);
|
|
|
|
// other.m_obj = nullptr;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// return *this;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
//private:
|
|
|
|
// void assign(ObjClass* obj, ref_transfer policy)
|
|
|
|
// {
|
|
|
|
// if (m_obj != obj)
|
|
|
|
// {
|
|
|
|
// ObjClass* tmp = m_obj;
|
|
|
|
// m_obj = obj;
|
|
|
|
// if (m_obj && (policy == ref_transfer::make_copy))
|
|
|
|
// ObjRefUnrefHelper::ref(m_obj);
|
|
|
|
// if (tmp)
|
|
|
|
// ObjRefUnrefHelper::unref(tmp);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
//private:
|
|
|
|
// ObjClass* m_obj;
|
|
|
|
//};
|
|
|
|
|
2015-12-30 00:12:49 -08:00
|
|
|
} // namespace moo
|