medit/moo/moocpp/gobjectptr.h

229 lines
5.3 KiB
C
Raw Normal View History

2015-12-30 00:12:49 -08:00
/*
2015-12-30 22:23:51 -08:00
* moocpp/gobjectptr.h
2015-12-30 00:12:49 -08:00
*
* Copyright (C) 2004-2015 by Yevgen Muntyan <emuntyan@users.sourceforge.net>
*
* 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-01 22:25:53 -08:00
class mg_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-01 22:25:53 -08:00
template<typename ObjClass, typename ObjRefUnrefHelper = mg_ref_unref<ObjClass>>
class grefptr
{
public:
grefptr() : m_obj(nullptr) {}
grefptr(const nullptr_t) : grefptr() {}
2015-12-31 16:41:12 -08:00
2016-01-01 22:25:53 -08:00
grefptr(ObjClass* obj, ref_transfer policy)
: grefptr()
2015-12-31 16:41:12 -08:00
{
assign(obj, policy);
2015-12-30 00:12:49 -08:00
}
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
}
2015-12-31 16:41:12 -08:00
void reset()
2015-12-30 00:12:49 -08:00
{
auto* tmp = m_obj;
m_obj = nullptr;
if (tmp)
2015-12-31 04:49:08 -08:00
ObjRefUnrefHelper::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);
operator const ObjClass* () const { return m_obj; }
2015-12-30 00:12:49 -08:00
ObjClass* get() const { return m_obj; }
2016-01-01 22:25:53 -08:00
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;
2015-12-30 00:12:49 -08:00
operator bool() const { return m_obj != nullptr; }
bool operator!() const { return m_obj == nullptr; }
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)
2015-12-31 16:41:12 -08:00
: m_obj(other.m_obj)
{
other.m_obj = nullptr;
}
2016-01-01 22:25:53 -08:00
grefptr& operator=(const grefptr& other)
2015-12-30 00:12:49 -08:00
{
2016-01-01 22:25:53 -08:00
assign(other.m_obj, 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);
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)
{
if (m_obj != other.m_obj)
{
2016-01-01 22:25:53 -08:00
assign(other.m_obj, ref_transfer::take_ownership);
other.m_obj = nullptr;
}
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
{
if (m_obj != obj)
{
ObjClass* tmp = m_obj;
m_obj = obj;
2016-01-01 22:25:53 -08:00
if (m_obj && (policy == ref_transfer::make_copy))
2015-12-30 00:12:49 -08:00
ObjRefUnrefHelper::ref(m_obj);
if (tmp)
ObjRefUnrefHelper::unref(tmp);
}
}
private:
ObjClass* m_obj;
};
2016-01-01 22:25:53 -08:00
class mg_gobj_ref_unref
2015-12-30 00:12:49 -08:00
{
public:
static void ref(gpointer obj) { g_object_ref(obj); }
static void unref(gpointer obj) { g_object_unref(obj); }
};
template<typename GObjClass>
2016-01-01 22:25:53 -08:00
class gobjptr : public grefptr<GObjClass, mg_gobj_ref_unref>
2015-12-30 00:12:49 -08:00
{
2016-01-01 22:25:53 -08:00
using base = grefptr<GObjClass, mg_gobj_ref_unref>;
2015-12-30 01:37:01 -08:00
2015-12-30 00:12:49 -08:00
public:
2016-01-01 22:25:53 -08:00
gobjptr() {}
gobjptr(nullptr_t) {}
2015-12-31 16:41:12 -08:00
2016-01-01 22:25:53 -08:00
gobjptr(GObjClass* obj, ref_transfer policy)
2015-12-31 16:41:12 -08:00
: base(obj, policy)
{
}
2016-01-01 22:25:53 -08:00
gobjptr(const gobjptr& other)
2015-12-31 16:41:12 -08:00
: base(other)
2015-12-30 00:12:49 -08:00
{
}
2016-01-01 22:25:53 -08:00
gobjptr(gobjptr&& other)
2015-12-31 16:41:12 -08:00
: base(std::move(other))
{
}
2016-01-01 22:25:53 -08:00
gobjptr& operator=(const gobjptr& other)
2015-12-31 16:41:12 -08:00
{
(static_cast<base&>(*this)) = other;
return *this;
}
template<typename T>
2016-01-01 22:25:53 -08:00
gobjptr& operator=(T* p)
2015-12-31 16:41:12 -08:00
{
(static_cast<base&>(*this)) = p;
return *this;
}
2016-01-01 22:25:53 -08:00
gobjptr& operator=(const nullptr_t&)
2015-12-31 16:41:12 -08:00
{
(static_cast<base&>(*this)) = nullptr;
return *this;
}
2016-01-01 22:25:53 -08:00
gobjptr& operator=(gobjptr&& other)
2015-12-31 16:41:12 -08:00
{
(static_cast<base&>(*this)) = std::move(other);
return *this;
}
// Returning the GTypeInstance pointer is just as unsafe in general
// as returning the pointer to the object, but it's unlikely that there
// is code which gets a GTypeInstance and then calls g_object_unref()
// on it. Normally GTypeInstance* is used inside FOO_WIDGET() macros,
// where this conversion is safe.
operator GTypeInstance* () const { return get() ? &G_OBJECT(get())->g_type_instance : nullptr; }
2015-12-30 00:12:49 -08:00
};
} // namespace moo