Commit dab3c7d0 authored by Marco Trevisan's avatar Marco Trevisan 🎺
Browse files

jsapi-util: add GjsAutoPointer to simply generate c++ smart pointers

A wrapper on std::unique_ptr that adds facility functions to unref and in case
take ownership of pointers handling the memory management in a smart way.

Keep just few specializations for specific objects
parent 112a7742
......@@ -286,7 +286,7 @@ GParamSpec* ObjectPrototype::find_param_spec_from_id(JSContext* cx,
GjsAutoChar gname = gjs_hyphen_from_camel(js_prop_name.get());
GjsAutoTypeClass<GObjectClass> gobj_class(m_gtype);
GParamSpec* pspec = g_object_class_find_property(gobj_class, gname);
GjsAutoParam param_spec(pspec, GjsAutoParam::TakeOwnership());
GjsAutoParam param_spec(pspec, GjsAutoTakeOwnership());
if (!param_spec) {
_gjs_proxy_throw_nonexistent_field(cx, m_gtype, js_prop_name.get());
......@@ -2386,7 +2386,7 @@ static bool find_vfunc_info(JSContext* context, GType implementor_gtype,
is_interface = g_base_info_get_type(ancestor_info) == GI_INFO_TYPE_INTERFACE;
GjsAutoTypeClass<void> implementor_class(implementor_gtype);
GjsAutoTypeClass<GTypeClass> implementor_class(implementor_gtype);
if (is_interface) {
GTypeInstance *implementor_iface_class;
implementor_iface_class = (GTypeInstance*) g_type_interface_peek(implementor_class,
......
......@@ -39,74 +39,66 @@
#define GJS_ALWAYS_INLINE
#endif
class GjsAutoChar : public std::unique_ptr<char, decltype(&g_free)> {
public:
GjsAutoChar(char *str = nullptr) : unique_ptr(str, g_free) {}
operator const char *() const {
return get();
struct GjsAutoTakeOwnership {};
template <typename T, typename F,
void (*free_func)(F*) = nullptr, F* (*ref_func)(F*) = nullptr>
struct GjsAutoPointer : std::unique_ptr<T, decltype(free_func)> {
GjsAutoPointer(T* ptr = nullptr) // NOLINT(runtime/explicit)
: GjsAutoPointer::unique_ptr(ptr, *free_func) {}
GjsAutoPointer(T* ptr, const GjsAutoTakeOwnership&)
: GjsAutoPointer(nullptr) {
auto ref = ref_func; // use if constexpr ... once we're on C++17
this->reset(ptr && ref ? reinterpret_cast<T*>(ref(ptr)) : ptr);
}
void operator= (char *str) {
reset(str);
}
operator T*() const { return this->get(); }
T& operator[](size_t i) const { return static_cast<T*>(*this)[i]; }
void operator= (const char *str) {
reset(g_strdup(str));
T* copy() const { return reinterpret_cast<T*>(ref_func(this->get())); }
template <typename C>
C* as() const {
return const_cast<C*>(reinterpret_cast<const C*>(this->get()));
}
};
template <typename T>
class GjsAutoUnref : public std::unique_ptr<T, decltype(&g_object_unref)> {
public:
GjsAutoUnref(T *ptr = nullptr) : GjsAutoUnref::unique_ptr(ptr, g_object_unref) {}
operator T *() const {
return GjsAutoUnref::unique_ptr::get();
}
struct GjsAutoCharFuncs {
static char* dup(char* str) { return g_strdup(str); }
static void free(char* str) { g_free(str); }
};
using GjsAutoChar =
GjsAutoPointer<char, char, GjsAutoCharFuncs::free, GjsAutoCharFuncs::dup>;
template <typename T>
using GjsAutoUnref = GjsAutoPointer<T, void, g_object_unref, g_object_ref>;
template<typename T = GTypeClass>
class GjsAutoTypeClass : public std::unique_ptr<T, decltype(&g_type_class_unref)> {
public:
GjsAutoTypeClass(gpointer ptr = nullptr)
: GjsAutoTypeClass::unique_ptr(static_cast<T*>(ptr), g_type_class_unref) {}
template <typename T = GTypeClass>
struct GjsAutoTypeClass : GjsAutoPointer<T, void, &g_type_class_unref> {
GjsAutoTypeClass(gpointer ptr = nullptr) // NOLINT(runtime/explicit)
: GjsAutoPointer<T, void, g_type_class_unref>(static_cast<T*>(ptr)) {}
explicit GjsAutoTypeClass(GType gtype)
: GjsAutoTypeClass(g_type_class_ref(gtype)) {}
operator T *() const { return GjsAutoTypeClass::unique_ptr::get(); }
template<typename C>
C *as() const { return reinterpret_cast<C*>(operator T *()); }
};
// Use this class for owning a GIBaseInfo* of indeterminate type. Any type (e.g.
// GIFunctionInfo*, GIObjectInfo*) will fit. If you know that the info is of a
// certain type (e.g. you are storing the return value of a function that
// returns GIFunctionInfo*,) use one of the derived classes below.
class GjsAutoBaseInfo
: public std::unique_ptr<GIBaseInfo, decltype(&g_base_info_unref)> {
public:
GjsAutoBaseInfo(GIBaseInfo* ptr = nullptr)
: GjsAutoBaseInfo::unique_ptr(ptr, g_base_info_unref) {}
operator GIBaseInfo*() const { return get(); }
const char* name(void) const { return g_base_info_get_name(get()); }
const char* ns(void) const { return g_base_info_get_namespace(get()); }
GIInfoType type(void) const { return g_base_info_get_type(get()); }
struct GjsAutoBaseInfo : GjsAutoPointer<GIBaseInfo, GIBaseInfo,
g_base_info_unref, g_base_info_ref> {
GjsAutoBaseInfo(GIBaseInfo* ptr = nullptr) // NOLINT(runtime/explicit)
: GjsAutoPointer(ptr) {}
const char* name() const { return g_base_info_get_name(*this); }
const char* ns() const { return g_base_info_get_namespace(*this); }
GIInfoType type() const { return g_base_info_get_type(*this); }
};
// Use GjsAutoInfo, preferably its typedefs below, when you know for sure that
// the info is either of a certain type or null.
template <GIInfoType TAG>
class GjsAutoInfo : public GjsAutoBaseInfo {
void validate(void) const {
if (*this)
g_assert(g_base_info_get_type(get()) == TAG);
}
public:
struct GjsAutoInfo : GjsAutoBaseInfo {
// Normally one-argument constructors should be explicit, but we are trying
// to conform to the interface of std::unique_ptr here.
GjsAutoInfo(GIBaseInfo* ptr = nullptr) // NOLINT(runtime/explicit)
......@@ -115,12 +107,18 @@ class GjsAutoInfo : public GjsAutoBaseInfo {
}
void reset(GIBaseInfo* other = nullptr) {
GjsAutoInfo::unique_ptr::reset(other);
GjsAutoBaseInfo::reset(other);
validate();
}
// You should not need this method, because you already know the answer.
GIInfoType type(void) = delete;
GIInfoType type() = delete;
private:
void validate() const {
if (GIBaseInfo* base = *this)
g_assert(g_base_info_get_type(base) == TAG);
}
};
using GjsAutoEnumInfo = GjsAutoInfo<GI_INFO_TYPE_ENUM>;
......@@ -135,56 +133,39 @@ using GjsAutoVFuncInfo = GjsAutoInfo<GI_INFO_TYPE_VFUNC>;
// GICallableInfo can be one of several tags, so we have to have a separate
// class, and use GI_IS_CALLABLE_INFO() to validate.
class GjsAutoCallableInfo : public GjsAutoBaseInfo {
void validate(void) const {
if (*this)
g_assert(GI_IS_CALLABLE_INFO(get()));
}
public:
struct GjsAutoCallableInfo : GjsAutoBaseInfo {
GjsAutoCallableInfo(GIBaseInfo* ptr = nullptr) // NOLINT(runtime/explicit)
: GjsAutoBaseInfo(ptr) {
validate();
}
void reset(GIBaseInfo* other = nullptr) {
GjsAutoCallableInfo::unique_ptr::reset(other);
GjsAutoBaseInfo::reset(other);
validate();
}
private:
void validate() const {
if (GIBaseInfo* base = *this)
g_assert(GI_IS_CALLABLE_INFO(base));
}
};
/* For use of GjsAutoInfo<TAG> in GC hash maps */
namespace JS {
template <GIInfoType TAG>
struct GCPolicy<GjsAutoInfo<TAG>> : public IgnoreGCPolicy<GjsAutoInfo<TAG>> {};
}
class GjsAutoParam
: public std::unique_ptr<GParamSpec, decltype(&g_param_spec_unref)> {
public:
struct TakeOwnership {};
GjsAutoParam(GParamSpec* ptr = nullptr)
: unique_ptr(ptr, g_param_spec_unref) {}
GjsAutoParam(GParamSpec* ptr, const TakeOwnership&)
: GjsAutoParam(ptr ? g_param_spec_ref(ptr) : nullptr) {}
} // namespace JS
operator GParamSpec*() const { return get(); }
};
using GjsAutoParam = GjsAutoPointer<GParamSpec, GParamSpec, g_param_spec_unref,
g_param_spec_ref>;
/* For use of GjsAutoParam in GC hash maps */
namespace JS {
template<>
template <>
struct GCPolicy<GjsAutoParam> : public IgnoreGCPolicy<GjsAutoParam> {};
} // namespace JS
struct GjsJSFreeArgs {
void operator() (char *str) {
JS_free(nullptr, str);
}
};
G_BEGIN_DECLS
#define GJS_UTIL_ERROR gjs_util_error_quark ()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment