| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- #ifndef GI_BOXED_HPP
- #define GI_BOXED_HPP
- #include <memory>
- #include <glib-object.h>
- #include <glib.h>
- 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
- {};
- // should be used within proper namespace
- #define GI_ENABLE_BOXED_COPY(CType) \
- template<> \
- struct enable_boxed_copy<CType> : public std::true_type \
- {};
- } // 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
|