medit/moo/moocpp/gobjptr.h
Yevgen Muntyan b69764f55e More C++
2016-01-04 03:56:42 -08:00

298 lines
8.3 KiB
C++

/*
* moocpp/gobjptr.h
*
* Copyright (C) 2004-2016 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
#include "moocpp/gobjrawptr.h"
#include "moocpp/grefptr.h"
namespace moo {
///////////////////////////////////////////////////////////////////////////////////////////
//
// gobjptr
//
template<typename Object>
class gobjptr_impl
{
using ptr_type = gobjptr<Object>;
using ref_type = gobjref<Object>;
public:
gobjptr_impl() {}
gobjptr_impl(Object* obj, ref_transfer policy)
{
assign(obj, policy);
}
static ptr_type wrap_new(Object* obj)
{
return ptr_type(obj, ref_transfer::take_ownership);
}
static ptr_type wrap(Object* obj)
{
return ptr_type(obj, ref_transfer::make_copy);
}
~gobjptr_impl()
{
reset();
}
void ref(Object* obj)
{
assign(obj, ref_transfer::make_copy);
}
void take(Object* obj)
{
assign(obj, ref_transfer::take_ownership);
}
Object* release()
{
auto* tmp = get();
m_ref._set_gobj(nullptr);
return tmp;
}
void reset()
{
auto* tmp = get();
if (tmp)
{
m_ref._set_gobj(nullptr);
g_object_unref(tmp);
}
}
// Implicit conversion to non-const Object* 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 Object* () const { return get(); }
operator ref_type*() const { return m_ref.self(); }
ref_type* operator->() const { return m_ref.self(); }
ref_type& operator*() const { return m_ref; }
Object* get() const { return m_ref.gobj(); }
template<typename Super>
Super* get() const
{
return gobj_is_subclass<Object, Super>::down_cast(m_ref.gobj());
}
template<typename Super>
operator const Super* () const { return get<Super>(); }
operator bool() const { return get() != nullptr; }
bool operator!() const { return get() == nullptr; }
gobjptr_impl(const gobjptr_impl& other) = delete;
gobjptr_impl& operator=(const gobjptr_impl& other) = delete;
gobjptr_impl(gobjptr_impl&& other)
: gobjptr_impl()
{
m_ref._set_gobj(other.get());
other.m_ref._set_gobj(nullptr);
}
// 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 Object*, so one can't
// steal a reference to a const object with this method.
template<typename T>
gobjptr_impl& operator=(T* p)
{
assign(p, ref_transfer::take_ownership);
return *this;
}
gobjptr_impl& operator=(const nullptr_t&)
{
reset();
return *this;
}
gobjptr_impl& operator=(gobjptr_impl&& other)
{
if (get() != other.get())
{
assign(other.get(), ref_transfer::take_ownership);
other.m_ref._set_gobj(nullptr);
}
return *this;
}
private:
void assign(Object* obj, ref_transfer policy)
{
if (get() != obj)
{
Object* tmp = get();
m_ref._set_gobj(obj);
if (obj)
{
if (policy == ref_transfer::make_copy)
g_object_ref(obj);
else if (g_object_is_floating(obj))
g_object_ref_sink(obj);
}
if (tmp)
g_object_unref(tmp);
}
}
private:
mutable gobjref<Object> m_ref;
};
template<typename Object>
inline gobjptr<Object> wrap_new(Object *obj)
{
return gobjptr<Object>::wrap_new(obj);
}
template<typename Object>
inline gobjptr<Object> wrap(Object* obj)
{
return gobjptr<Object>::wrap(obj);
}
template<typename Object>
inline gobjptr<Object> wrap(gobjref<Object>& obj)
{
return gobjptr<Object>::wrap(obj.gobj());
}
#define MOO_DEFINE_GOBJPTR_METHODS(Object) \
using ref_type = gobjref<Object>; \
using impl_type = gobjptr_impl<Object>; \
\
gobjptr() {} \
gobjptr(const nullptr_t) {} \
\
gobjptr(Object* obj, ref_transfer policy) \
: impl_type(obj, policy) \
{ \
} \
\
gobjptr(const gobjptr& other) = delete; \
gobjptr& operator=(const gobjptr& other) = delete; \
\
gobjptr(gobjptr&& other) \
: impl_type(std::move(static_cast<impl_type&&>(other))) \
{ \
} \
\
gobjptr& operator=(gobjptr&& other) \
{ \
impl_type::operator=(std::move(static_cast<impl_type&&>(other))); \
return *this; \
} \
\
gobjptr& operator=(const nullptr_t&) \
{ \
reset(); \
return *this; \
}
// Generic implementation.
template<typename Object>
class gobjptr : public gobjptr_impl<Object>
{
public:
MOO_DEFINE_GOBJPTR_METHODS(Object)
};
template<> class gobjref<GObject>;
template<typename X>
void g_object_unref(const moo::gobjptr<X>&);
template<typename X>
void g_free(const moo::gobjptr<X>&);
} // namespace moo
template<typename X>
inline bool operator==(const moo::gobjptr<X>& p, const nullptr_t&)
{
return p.get() == nullptr;
}
template<typename X>
inline bool operator==(const nullptr_t&, const moo::gobjptr<X>& p)
{
return p.get() == nullptr;
}
template<typename X, typename Y>
inline bool operator==(const moo::gobjptr<X>& p1, const moo::gobjptr<Y>& p2)
{
return p1.get() == p2.get();
}
template<typename X, typename Y>
inline bool operator==(const moo::gobjptr<X>& p1, const Y* p2)
{
return p1.get() == p2;
}
template<typename X, typename Y>
inline bool operator==(const X* p1, const moo::gobjptr<Y>& p2)
{
return p1 == p2.get();
}
template<typename X, typename Y>
inline bool operator==(const moo::gobjptr<X>& p1, const moo::gobj_raw_ptr<Y>& p2)
{
return p1.get() == p2.get();
}
template<typename X, typename Y>
inline bool operator==(const moo::gobj_raw_ptr<Y>& p1, const moo::gobjptr<X>& p2)
{
return p1.get() == p2.get();
}
template<typename X, typename Y>
bool operator!=(const moo::gobjptr<X>& p1, const moo::gobjptr<Y>& p2)
{
return !(p1 == p2);
}
template<typename X, typename Y>
bool operator!=(const moo::gobjptr<X>& p1, const Y& p2)
{
return !(p1 == p2);
}
template<typename X, typename Y>
bool operator!=(const X& p1, const moo::gobjptr<Y>& p2)
{
return !(p1 == p2);
}