Files
tdesktop/cmake/external/glib/cppgir/gi/boxed.hpp
allhaileris afb81b8278
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
init
2026-02-16 15:50:16 +03:00

350 lines
8.0 KiB
C++

#ifndef GI_BOXED_HPP
#define GI_BOXED_HPP
#include "gi_inc.hpp"
GI_MODULE_EXPORT
namespace gi
{
namespace repository
{
// specialize to enable copyable boxed wrapper
// ideally only used in case where the copy is (equivalently);
// * cheap
// * does not change the underlying pointer
// * refcount based
// * has no semantics effects
// (e.g. GstMiniObject refcount affects writable)
template<typename CType>
struct enable_boxed_copy :
#if GI_ENABLE_BOXED_COPY_ALL
public std::true_type
#else
public std::false_type
#endif
{};
} // namespace repository
namespace detail
{
// class tags
class Boxed
{};
class CBoxed : public Boxed
{};
class GBoxed : public Boxed
{};
template<typename CType>
class SharedWrapper
{
public:
typedef SharedWrapper self;
protected:
CType *data_ = nullptr;
public:
CType *gobj_() { return data_; }
const CType *gobj_() const { return data_; }
explicit operator bool() const { return (bool)data_; }
bool operator==(const SharedWrapper &other) const
{
return data_ == other.data_;
}
bool operator==(std::nullptr_t o) const { return data_ == o; }
bool operator!=(const SharedWrapper &other) const
{
return data_ != other.data_;
}
bool operator!=(std::nullptr_t o) const { return data_ != o; }
CType *release_()
{
auto tmp = this->data_;
this->data_ = nullptr;
return tmp;
}
};
template<typename CppType, typename CType>
struct GBoxedFuncs
{
static CType *copy(const void *data)
{
return (CType *)g_boxed_copy(CppType::get_type_(), data);
}
static void free(void *data) { g_boxed_free(CppType::get_type_(), data); }
};
struct CBoxedFuncsBase
{
static void free(void *data) { g_free(data); }
};
template<typename CppType, typename CType>
struct CBoxedFuncs : CBoxedFuncsBase
{
static CType *copy(const void *data)
{
#if GLIB_CHECK_VERSION(2, 68, 0)
return (CType *)g_memdup2(data, sizeof(CType));
#else
return (CType *)g_memdup(data, sizeof(CType));
#endif
}
};
template<typename CType, typename Funcs, typename TagType>
class BoxedWrapper : public SharedWrapper<CType>, public TagType
{
typedef BoxedWrapper self;
protected:
static void _deleter(CType *obj, ...)
{
if (obj)
Funcs::free(obj);
}
static CType *_copy(const CType *obj)
{
return obj ? Funcs::copy(obj) : nullptr;
}
public:
typedef CType BaseObjectType;
BoxedWrapper(CType *obj = nullptr) noexcept { this->data_ = obj; }
CType *gobj_copy_() const { return _copy(this->gobj_()); }
// resulting casted type determines ownership
template<typename Cpp>
static Cpp wrap(const typename Cpp::BaseObjectType *obj)
{
static_assert(sizeof(Cpp) == sizeof(self), "type wrap not supported");
static_assert(std::is_base_of<self, Cpp>::value, "type wrap not supported");
BoxedWrapper w(const_cast<typename Cpp::BaseObjectType *>(obj));
return std::move(*static_cast<Cpp *>(&w));
}
};
// in templates below, Base should be a subclass of BoxedWrapper
// so we re-use the members it provides, as well as the wrap template
// to avoid ambiguous reference to the latter
// (if BoxedWrapper were inherited from again)
// the nullptr_t constructor (indirectly) supports `= nullptr` (assignment)
template<typename CppType, typename CType>
using GBoxedWrapperBase =
BoxedWrapper<CType, GBoxedFuncs<CppType, CType>, GBoxed>;
// assuming Base has suitable members such as above BoxedWrapper
template<typename Base>
class MoveWrapper : public Base
{
typedef Base super;
public:
using super::super;
~MoveWrapper() { this->_deleter(this->data_, static_cast<Base *>(this)); }
MoveWrapper(const MoveWrapper &) = delete;
MoveWrapper &operator=(const MoveWrapper &) = delete;
MoveWrapper(MoveWrapper &&o) noexcept { *this = std::move(o); }
MoveWrapper &operator=(MoveWrapper &&o) noexcept
{
if (this != &o) {
this->_deleter(this->data_, static_cast<Base *>(this));
(Base &)(*this) = std::move(o);
o.data_ = nullptr;
}
return *this;
}
};
template<typename Base>
class CopyWrapper : public MoveWrapper<Base>
{
typedef MoveWrapper<Base> super;
public:
using super::super;
CopyWrapper(const CopyWrapper &o) noexcept : super()
{
this->data_ = this->_copy(o.data_);
}
CopyWrapper &operator=(const CopyWrapper &o) noexcept
{
if (this != &o) {
this->_deleter(this->data_, static_cast<Base *>(this));
if (sizeof(Base) > sizeof(this->data_))
(Base &)(*this) = std::move(o);
this->data_ = this->_copy(o.data_);
}
return *this;
}
CopyWrapper(CopyWrapper &&o) noexcept = default;
CopyWrapper &operator=(CopyWrapper &&o) noexcept = default;
// also accept from corresponding Reference (also based on Base)
CopyWrapper(const Base &o) noexcept : super()
{
this->data_ = this->_copy(((CopyWrapper &)o).data_);
}
CopyWrapper(Base &&o) noexcept : super()
{
(super &)(*this) = std::move((super &)o);
}
};
template<typename CType, typename Base>
using SelectWrapper =
typename std::conditional<repository::enable_boxed_copy<CType>::value,
CopyWrapper<Base>, MoveWrapper<Base>>::type;
// basis for registered boxed types
template<typename CppType, typename CType,
typename Base = GBoxedWrapperBase<CppType, CType>, typename RefType = void>
class GBoxedWrapper : public SelectWrapper<CType, Base>
{
typedef SelectWrapper<CType, Base> super;
public:
typedef RefType ReferenceType;
using super::super;
GBoxedWrapper(std::nullptr_t = nullptr) {}
void allocate_()
{
if (this->data_)
return;
// make sure we match boxed allocation with boxed free
// still guessing here that all-0 makes for a decent init :-(
CType tmp;
memset(&tmp, 0, sizeof(tmp));
this->data_ = (CType *)g_boxed_copy(this->get_type_(), &tmp);
}
// essentially g_boxed_copy
CppType copy_() const
{
return super::template wrap<CppType>(this->gobj_copy_());
}
};
template<typename CppType, typename CType>
using CBoxedWrapperBase =
BoxedWrapper<CType, CBoxedFuncs<CppType, CType>, CBoxed>;
// basis for non-registered plain C boxed type
template<typename CppType, typename CType,
typename Base = CBoxedWrapperBase<CppType, CType>, typename RefType = void>
class CBoxedWrapper : public MoveWrapper<Base>
{
typedef Base super;
public:
typedef RefType ReferenceType;
CBoxedWrapper(std::nullptr_t = nullptr) {}
void allocate_()
{
if (this->data_)
return;
this->data_ = g_new0(CType, 1);
}
static CppType new_()
{
return super::template wrap<CppType>(g_new0(CType, 1));
}
};
// allocate helper;
// dispatch to method if available
template<typename T, typename Enable = void>
struct allocator : public std::false_type
{
static void allocate(T &) {}
};
template<typename T>
struct allocator<T, decltype(T().allocate_())> : public std::true_type
{
static void allocate(T &v) { v.allocate_(); }
};
template<typename T>
void
allocate(T &v)
{
allocator<T>::allocate(v);
}
// basis for ref-holding to registered box type
template<typename CppType, typename CType, typename Base>
class GBoxedRefWrapper : public Base
{
typedef Base super;
public:
typedef CppType BoxType;
GBoxedRefWrapper(std::nullptr_t = nullptr) {}
// construct from owning version, but not the other way around
// (which requires an explicit copy)
GBoxedRefWrapper(const CppType &other)
{
(super &)(*this) = super::template wrap<super>(other.gobj_());
}
// support way to convert to owning box
// (by means of copy as opposed to a simple ref)
CppType copy_() const
{
return super::template wrap<CppType>(this->gobj_copy_());
}
};
// basis for ref-holding to non-registered plain C boxed type
template<typename CppType, typename CType, typename Base>
class CBoxedRefWrapper : public Base
{
typedef Base super;
public:
typedef CppType BoxType;
CBoxedRefWrapper(std::nullptr_t = nullptr) {}
// construct from owning version, but not the other way around
// (which requires an explicit copy)
CBoxedRefWrapper(const CppType &other)
{
(super &)(*this) = super::template wrap<super>(other.gobj_());
}
};
} // namespace detail
} // namespace gi
#endif // GI_BOXED_HPP