medit/moo/moocpp/grefptr.h

200 lines
4.6 KiB
C
Raw Normal View History

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
2016-01-17 00:04:49 -08:00
#ifdef __cplusplus
2015-12-31 16:41:12 -08:00
#include "moocpp/utils.h"
2015-12-30 00:12:49 -08:00
namespace moo {
2016-01-03 05:13:00 -08:00
template<typename Object>
2016-01-19 00:33:23 -08:00
struct obj_ref_unref
2016-01-02 07:09:54 -08:00
{
2016-01-03 05:13:00 -08:00
static void ref(Object* obj) { obj->ref(); }
static void unref(Object* obj) { obj->unref(); }
2016-01-02 07:09:54 -08:00
};
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-03 05:13:00 -08:00
template<typename Object,
typename ObjRefUnref = obj_ref_unref<Object>>
2016-01-17 00:04:49 -08:00
class gref_ptr
2016-01-01 22:25:53 -08:00
{
public:
2016-01-17 00:04:49 -08:00
gref_ptr() : m_p(nullptr) {}
gref_ptr(const nullptr_t&) : gref_ptr() {}
2015-12-31 16:41:12 -08:00
2016-01-17 00:04:49 -08:00
gref_ptr(Object* obj, ref_transfer policy)
: gref_ptr()
2015-12-31 16:41:12 -08:00
{
assign(obj, policy);
2015-12-30 00:12:49 -08:00
}
2016-01-02 07:09:54 -08:00
template<typename ...Args>
2016-01-17 00:04:49 -08:00
static gref_ptr create(Args&& ...args)
2016-01-02 07:09:54 -08:00
{
2016-01-03 05:13:00 -08:00
return wrap_new(new Object(std::forward<Args>(args)...));
2016-01-02 07:09:54 -08:00
}
2016-01-17 00:04:49 -08:00
static gref_ptr wrap_new(Object* obj)
2016-01-02 04:31:23 -08:00
{
2016-01-17 00:04:49 -08:00
return gref_ptr(obj, ref_transfer::take_ownership);
2016-01-02 04:31:23 -08:00
}
2016-01-17 00:04:49 -08:00
~gref_ptr()
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
}
2016-01-03 05:13:00 -08:00
void ref(Object* 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
}
2016-01-03 05:13:00 -08:00
void take(Object* obj)
2015-12-30 00:12:49 -08:00
{
2016-01-01 22:25:53 -08:00
assign(obj, ref_transfer::take_ownership);
2015-12-30 00:12:49 -08:00
}
2016-01-03 05:13:00 -08:00
Object* release()
2016-01-02 04:31:23 -08:00
{
2016-01-03 05:13:00 -08:00
auto* tmp = m_p;
m_p = nullptr;
2016-01-02 04:31:23 -08:00
return tmp;
}
2015-12-31 16:41:12 -08:00
void reset()
2015-12-30 00:12:49 -08:00
{
2016-01-03 05:13:00 -08:00
auto* tmp = m_p;
m_p = 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
}
2016-01-03 05:13:00 -08:00
// Implicit conversion to Object* is dangerous because there is a lot
2015-12-31 16:41:12 -08:00
// of code still which frees/steals objects directly. For example:
// FooObject* tmp = x->s;
// x->s = NULL;
// g_object_unref (tmp);
2016-01-04 10:24:03 -08:00
operator const Object* () const { return gobj(); }
Object* gobj() const { return m_p; }
Object& operator*() const { return *gobj(); }
Object* operator->() const { return gobj(); }
2016-01-01 22:25:53 -08:00
// Explicitly forbid other pointer conversions. This way it's still possible to implement
2016-01-04 09:56:33 -08:00
// implicit conversions in subclasses, like that to GTypeInstance in gobj_ptr.
2016-01-01 22:25:53 -08:00
template<typename T>
operator T*() const = delete;
2015-12-30 00:12:49 -08:00
2016-01-04 10:24:03 -08:00
operator bool() const { return gobj() != nullptr; }
bool operator!() const { return gobj() == 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
{
2016-01-04 10:24:03 -08:00
return gobj() == other;
2015-12-30 00:12:49 -08:00
}
template<typename X, typename Y>
2016-01-17 00:04:49 -08:00
bool operator==(const gref_ptr<X, Y>& other) const
2015-12-30 00:12:49 -08:00
{
2016-01-04 10:24:03 -08:00
return gobj() == other.gobj();
2015-12-30 00:12:49 -08:00
}
template<typename X>
bool operator!=(const X& anything) const
{
return !(*this == anything);
}
2016-01-17 00:04:49 -08:00
gref_ptr(const gref_ptr& other)
: gref_ptr(other.gobj(), ref_transfer::make_copy)
2015-12-30 00:12:49 -08:00
{
}
2016-01-17 00:04:49 -08:00
gref_ptr(gref_ptr&& other)
: gref_ptr()
{
2016-01-03 05:13:00 -08:00
this->m_p = other.m_p;
other.m_p = nullptr;
}
2016-01-17 00:04:49 -08:00
gref_ptr& operator=(const gref_ptr& other)
2015-12-30 00:12:49 -08:00
{
2016-01-04 10:24:03 -08:00
assign(other.gobj(), 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
2016-01-03 05:13:00 -08:00
// a const Foo, which can't be converted to non-const Object*, so one can't
2015-12-31 16:41:12 -08:00
// steal a reference to a const object with this method.
template<typename T>
2016-01-17 00:04:49 -08:00
gref_ptr& 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-17 00:04:49 -08:00
gref_ptr& 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-17 00:04:49 -08:00
gref_ptr& operator=(gref_ptr&& other)
{
2016-01-04 10:24:03 -08:00
if (gobj() != other.gobj())
{
2016-01-03 05:13:00 -08:00
assign(other.m_p, ref_transfer::take_ownership);
other.m_p = nullptr;
}
return *this;
}
2015-12-30 00:12:49 -08:00
private:
2016-01-03 05:13:00 -08:00
void assign(Object* obj, ref_transfer policy)
2015-12-30 00:12:49 -08:00
{
2016-01-04 10:24:03 -08:00
if (gobj() != obj)
2015-12-30 00:12:49 -08:00
{
2016-01-04 10:24:03 -08:00
Object* tmp = gobj();
2016-01-03 05:13:00 -08:00
m_p = obj;
2016-01-02 04:31:23 -08:00
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-03 05:13:00 -08:00
private:
Object* m_p;
};
2016-01-02 04:31:23 -08:00
2016-01-04 13:02:56 -08:00
// Make sure these aren't called in code ported from pure glib C
template<typename X>
2016-01-17 00:04:49 -08:00
void g_object_unref(const gref_ptr<X>&) = delete;
2016-01-04 13:02:56 -08:00
template<typename X>
2016-01-17 00:04:49 -08:00
void g_free(const gref_ptr<X>&) = delete;
2016-01-04 13:02:56 -08:00
2015-12-30 00:12:49 -08:00
} // namespace moo
2016-01-17 00:04:49 -08:00
#endif // __cplusplus