init
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
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
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
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
503
cmake/external/glib/cppgir/gi/base.hpp
vendored
Normal file
503
cmake/external/glib/cppgir/gi/base.hpp
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
#ifndef GI_BASE_HPP
|
||||
#define GI_BASE_HPP
|
||||
|
||||
#include "gi_inc.hpp"
|
||||
|
||||
#include "boxed.hpp"
|
||||
#include "objectbase.hpp"
|
||||
|
||||
// un-inline some glib parts
|
||||
// (otherwise they have internal linkage and not usable in non-TU-local context)
|
||||
#ifdef GI_MODULE_IN_INTERFACE
|
||||
#ifdef g_strdup
|
||||
#undef g_strdup
|
||||
#endif
|
||||
#endif
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline std::string
|
||||
exception_desc(const std::exception &e)
|
||||
{
|
||||
auto desc = e.what();
|
||||
return desc ? desc : typeid(e).name();
|
||||
}
|
||||
|
||||
inline std::string
|
||||
exception_desc(...)
|
||||
{
|
||||
return "[unknown]";
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
[[noreturn]] inline void
|
||||
try_throw(E &&e)
|
||||
{
|
||||
#if GI_CONFIG_EXCEPTIONS
|
||||
throw std::forward<E>(e);
|
||||
#else
|
||||
g_critical("no throw exception; %s", exception_desc(e).c_str());
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
// constructor does not appreciate NULL, so wrap that here
|
||||
// map NULL to empty string; not quite the same, but it will do
|
||||
inline std::string
|
||||
make_string(const char *s)
|
||||
{
|
||||
return std::string(s ? s : "");
|
||||
}
|
||||
|
||||
// helper string subtype
|
||||
// used to overload unwrap of optional string argument
|
||||
// (transfrom empty string to null)
|
||||
// NOTE std::optional requires C++17
|
||||
class optional_string : public std::string
|
||||
{};
|
||||
|
||||
class noncopyable
|
||||
{
|
||||
public:
|
||||
noncopyable() {}
|
||||
noncopyable(const noncopyable &) = delete;
|
||||
noncopyable &operator=(const noncopyable &) = delete;
|
||||
|
||||
noncopyable(noncopyable &&) = default;
|
||||
noncopyable &operator=(noncopyable &&) = default;
|
||||
};
|
||||
|
||||
class scope_guard : public noncopyable
|
||||
{
|
||||
private:
|
||||
std::function<void()> cleanup_;
|
||||
|
||||
public:
|
||||
scope_guard(std::function<void()> &&cleanup) : cleanup_(std::move(cleanup)) {}
|
||||
|
||||
~scope_guard() noexcept(false)
|
||||
{
|
||||
#if GI_CONFIG_EXCEPTIONS
|
||||
#if __cplusplus >= 201703L
|
||||
auto pending = std::uncaught_exceptions();
|
||||
#else
|
||||
auto pending = std::uncaught_exception();
|
||||
#endif
|
||||
try {
|
||||
#endif
|
||||
cleanup_();
|
||||
#if GI_CONFIG_EXCEPTIONS
|
||||
} catch (...) {
|
||||
if (!pending)
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// as in
|
||||
// http://ericniebler.com/2013/08/07/universal-references-and-the-copy-constructo/
|
||||
template<typename A, typename B>
|
||||
using disable_if_same_or_derived = typename std::enable_if<
|
||||
!std::is_base_of<A, typename std::remove_reference<B>::type>::value>::type;
|
||||
} // namespace detail
|
||||
|
||||
namespace repository
|
||||
{
|
||||
// class types declare c type within class
|
||||
// others can do so using this (e.g. enum)
|
||||
template<typename CppType>
|
||||
struct declare_ctype_of
|
||||
{};
|
||||
|
||||
// and for all cases the reverse cpp type
|
||||
template<typename CType>
|
||||
struct declare_cpptype_of
|
||||
{};
|
||||
|
||||
// generate code must specialize appropriately
|
||||
template<typename T>
|
||||
struct is_enumeration : public std::false_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_bitfield : public std::false_type
|
||||
{};
|
||||
|
||||
} // namespace repository
|
||||
|
||||
struct transfer_full_t;
|
||||
struct transfer_none_t;
|
||||
|
||||
namespace traits
|
||||
{
|
||||
template<typename T, typename U = void>
|
||||
struct if_valid_type
|
||||
{
|
||||
typedef U type;
|
||||
};
|
||||
|
||||
template<typename, typename = void>
|
||||
struct is_type_complete : public std::false_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_type_complete<T, typename if_valid_type<decltype(sizeof(
|
||||
typename std::decay<T>::type))>::type>
|
||||
: public std::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
using is_decayed = std::is_same<typename std::decay<T>::type, T>;
|
||||
|
||||
template<typename T>
|
||||
using is_cboxed =
|
||||
typename std::conditional<std::is_base_of<detail::CBoxed, T>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
template<typename T>
|
||||
using is_gboxed =
|
||||
typename std::conditional<std::is_base_of<detail::GBoxed, T>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
template<typename T>
|
||||
using is_boxed =
|
||||
typename std::conditional<std::is_base_of<detail::Boxed, T>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
// avoid derived cases
|
||||
template<typename T>
|
||||
using is_object =
|
||||
typename std::conditional<std::is_base_of<detail::ObjectBase, T>::value &&
|
||||
sizeof(T) == sizeof(gpointer),
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
template<typename T>
|
||||
using is_wrapper =
|
||||
typename std::conditional<std::is_base_of<detail::wrapper_tag, T>::value &&
|
||||
sizeof(T) == sizeof(gpointer),
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
// bring in to this namespace
|
||||
using repository::is_bitfield;
|
||||
using repository::is_enumeration;
|
||||
|
||||
// aka passthrough
|
||||
template<typename T>
|
||||
using is_basic =
|
||||
typename std::conditional<std::is_same<T, gpointer>::value ||
|
||||
std::is_same<T, gconstpointer>::value ||
|
||||
std::is_arithmetic<T>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
// almost passthrough (on lower level at least)
|
||||
template<typename T>
|
||||
using is_plain = typename std::conditional<traits::is_basic<T>::value ||
|
||||
std::is_enum<T>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
template<typename T, typename E = void>
|
||||
struct is_reftype : public std::false_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_reftype<T,
|
||||
typename if_valid_type<typename std::decay<T>::type::BoxType>::type>
|
||||
: public std::true_type
|
||||
{};
|
||||
|
||||
template<typename T, typename Enable = void>
|
||||
struct has_ctype_member : public std::false_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct has_ctype_member<T,
|
||||
typename if_valid_type<typename T::BaseObjectType>::type>
|
||||
: public std::true_type
|
||||
{};
|
||||
|
||||
// return corresponding c type (if any)
|
||||
// (string and basic type not considered)
|
||||
// preserve const
|
||||
template<typename T, typename Enable = void>
|
||||
struct ctype
|
||||
{};
|
||||
|
||||
// class case
|
||||
template<typename T>
|
||||
struct ctype<T,
|
||||
typename if_valid_type<typename std::decay<T>::type::BaseObjectType>::type>
|
||||
{
|
||||
typedef typename std::remove_reference<T>::type CppType;
|
||||
// make sure; avoid subclassed cases
|
||||
static_assert(is_wrapper<CppType>::value || is_boxed<CppType>::value,
|
||||
"must be object or boxed wrapper");
|
||||
typedef typename CppType::BaseObjectType CType;
|
||||
typedef typename std::conditional<std::is_const<CppType>::value, const CType,
|
||||
CType>::type *type;
|
||||
};
|
||||
|
||||
// remaining cases
|
||||
template<typename T>
|
||||
struct ctype<T, typename if_valid_type<
|
||||
typename repository::declare_ctype_of<T>::type>::type>
|
||||
{
|
||||
typedef typename repository::declare_ctype_of<T>::type CType;
|
||||
typedef typename std::conditional<std::is_const<T>::value, const CType,
|
||||
CType>::type type;
|
||||
};
|
||||
|
||||
// basic cases passthrough
|
||||
template<typename T>
|
||||
struct ctype<T,
|
||||
typename std::enable_if<(std::is_fundamental<T>::value &&
|
||||
!std::is_same<T, bool>::value) ||
|
||||
std::is_same<T, gpointer>::value ||
|
||||
std::is_same<T, gconstpointer>::value>::type>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
// ... exception though for bool
|
||||
template<>
|
||||
struct ctype<bool, void>
|
||||
{
|
||||
typedef gboolean type;
|
||||
};
|
||||
|
||||
// as used in callback signatures
|
||||
// or in list (un)wrapping
|
||||
template<>
|
||||
struct ctype<const std::string &, void>
|
||||
{
|
||||
typedef const char *type;
|
||||
};
|
||||
template<>
|
||||
struct ctype<std::string, void>
|
||||
{
|
||||
typedef char *type;
|
||||
};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
struct ctype<std::pair<T1, T2>>
|
||||
{
|
||||
typedef std::pair<typename ctype<T1>::type, typename ctype<T2>::type> type;
|
||||
};
|
||||
|
||||
// conversely
|
||||
// return corresponding cpp type (if known)
|
||||
// (string and basic type not considered)
|
||||
// preserve const
|
||||
template<typename T, typename Transfer = transfer_full_t,
|
||||
typename Enable = void>
|
||||
struct cpptype
|
||||
{};
|
||||
|
||||
// generic
|
||||
template<typename T>
|
||||
struct cpptype<T *, transfer_full_t,
|
||||
typename if_valid_type<typename repository::declare_cpptype_of<
|
||||
typename std::remove_const<T>::type>::type>::type>
|
||||
{
|
||||
typedef typename repository::declare_cpptype_of<
|
||||
typename std::remove_const<T>::type>::type CppType;
|
||||
typedef typename std::conditional<std::is_const<T>::value, const CppType,
|
||||
CppType>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct cpptype<T, transfer_full_t,
|
||||
typename if_valid_type<typename repository::declare_cpptype_of<
|
||||
typename std::remove_const<T>::type>::type>::type>
|
||||
{
|
||||
typedef typename repository::declare_cpptype_of<
|
||||
typename std::remove_const<T>::type>::type CppType;
|
||||
typedef typename std::conditional<std::is_const<T>::value, const CppType,
|
||||
CppType>::type type;
|
||||
};
|
||||
|
||||
// basic cases passthrough
|
||||
template<typename T>
|
||||
struct cpptype<T, transfer_full_t,
|
||||
typename std::enable_if<std::is_fundamental<T>::value ||
|
||||
std::is_same<T, gpointer>::value ||
|
||||
std::is_same<T, gconstpointer>::value>::type>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
#if 0
|
||||
template<>
|
||||
struct cpptype<char *, transfer_full_t>
|
||||
{
|
||||
using type = std::string;
|
||||
};
|
||||
#endif
|
||||
|
||||
// handle none transfer case
|
||||
template<typename T>
|
||||
struct cpptype<T, transfer_none_t>
|
||||
{
|
||||
using CppType = typename cpptype<T, transfer_full_t>::type;
|
||||
template<typename TT, typename Enable = void>
|
||||
struct map_type
|
||||
{
|
||||
using type = TT;
|
||||
};
|
||||
template<typename TT>
|
||||
struct map_type<TT, typename if_valid_type<typename TT::ReferenceType>::type>
|
||||
{
|
||||
using type = typename TT::ReferenceType;
|
||||
};
|
||||
using type = typename map_type<CppType>::type;
|
||||
};
|
||||
|
||||
// map owning box type to corresponding reference box type
|
||||
template<typename T>
|
||||
struct reftype
|
||||
{
|
||||
typedef typename T::ReferenceType type;
|
||||
};
|
||||
|
||||
} // namespace traits
|
||||
|
||||
// specify transfer type when (un)wrapping
|
||||
// this approach is safer than some booleans and allows overload combinations
|
||||
struct transfer_t
|
||||
{
|
||||
const int value;
|
||||
constexpr explicit transfer_t(int v = 0) : value(v) {}
|
||||
};
|
||||
struct transfer_none_t : public transfer_t
|
||||
{
|
||||
constexpr transfer_none_t() : transfer_t(0) {}
|
||||
};
|
||||
struct transfer_full_t : public transfer_t
|
||||
{
|
||||
constexpr transfer_full_t() : transfer_t(1) {}
|
||||
};
|
||||
struct transfer_container_t : public transfer_t
|
||||
{
|
||||
constexpr transfer_container_t() : transfer_t(2) {}
|
||||
};
|
||||
|
||||
GI_MODULE_INLINE const constexpr transfer_t transfer_dummy = transfer_t();
|
||||
GI_MODULE_INLINE const constexpr transfer_none_t transfer_none =
|
||||
transfer_none_t();
|
||||
GI_MODULE_INLINE const constexpr transfer_full_t transfer_full =
|
||||
transfer_full_t();
|
||||
GI_MODULE_INLINE const constexpr transfer_container_t transfer_container =
|
||||
transfer_container_t();
|
||||
|
||||
template<typename Transfer>
|
||||
struct element_transfer
|
||||
{};
|
||||
template<>
|
||||
struct element_transfer<transfer_none_t>
|
||||
{
|
||||
typedef transfer_none_t type;
|
||||
};
|
||||
template<>
|
||||
struct element_transfer<transfer_full_t>
|
||||
{
|
||||
typedef transfer_full_t type;
|
||||
};
|
||||
template<>
|
||||
struct element_transfer<transfer_container_t>
|
||||
{
|
||||
typedef transfer_none_t type;
|
||||
};
|
||||
|
||||
// unwrapping a callback
|
||||
// specify call scope type
|
||||
struct scope_t
|
||||
{
|
||||
const int value;
|
||||
constexpr explicit scope_t(int v = 0) : value(v) {}
|
||||
};
|
||||
struct scope_call_t : public scope_t
|
||||
{
|
||||
constexpr scope_call_t() : scope_t(0) {}
|
||||
};
|
||||
struct scope_async_t : public scope_t
|
||||
{
|
||||
constexpr scope_async_t() : scope_t(1) {}
|
||||
};
|
||||
struct scope_notified_t : public scope_t
|
||||
{
|
||||
constexpr scope_notified_t() : scope_t(2) {}
|
||||
};
|
||||
|
||||
GI_MODULE_INLINE const constexpr scope_t scope_dummy = scope_t();
|
||||
GI_MODULE_INLINE const constexpr scope_call_t scope_call = scope_call_t();
|
||||
GI_MODULE_INLINE const constexpr scope_async_t scope_async = scope_async_t();
|
||||
GI_MODULE_INLINE const constexpr scope_notified_t scope_notified =
|
||||
scope_notified_t();
|
||||
|
||||
// (dummy) helper tag to aid in overload resolution
|
||||
template<typename Interface>
|
||||
struct interface_tag
|
||||
{
|
||||
typedef Interface type;
|
||||
};
|
||||
|
||||
// CallArgs minimal helper type
|
||||
// only provide what is needed
|
||||
// not intended for general use, even though not in internal namespace
|
||||
template<typename T>
|
||||
class required
|
||||
{
|
||||
T data_;
|
||||
|
||||
public:
|
||||
constexpr required(T v) : data_(std::move(v)) {}
|
||||
constexpr operator T &() &noexcept { return data_; }
|
||||
constexpr operator T &&() &&noexcept { return std::move(data_); }
|
||||
constexpr T &value() &noexcept { return data_; }
|
||||
constexpr T &&value() &&noexcept { return std::move(data_); }
|
||||
};
|
||||
|
||||
// helper tag type to aid in overload resolution of CallArgs
|
||||
// this is used as the first argument of a (non-plain) signature variant
|
||||
// (since it may otherwise have only 1 struct argument, like the plain variant)
|
||||
template<typename... CA_TAG>
|
||||
using ca = std::tuple<CA_TAG...>;
|
||||
|
||||
struct ca_tag
|
||||
{};
|
||||
struct ca_in_tag : public ca_tag
|
||||
{};
|
||||
struct ca_bc_tag : public ca_tag
|
||||
{};
|
||||
// convenience abbreviation
|
||||
using ca_in = ca<ca_in_tag>;
|
||||
|
||||
#if GI_DL
|
||||
namespace detail
|
||||
{
|
||||
// dynamic load of symbol
|
||||
inline void *
|
||||
load_symbol(const std::vector<const char *> libs, const char *symbol)
|
||||
{
|
||||
void *s = nullptr;
|
||||
for (const auto &l : libs) {
|
||||
auto h = dlopen(l, RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE);
|
||||
if (h) {
|
||||
s = dlsym(h, symbol);
|
||||
dlclose(h);
|
||||
if (s)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
#endif // GI_DL
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // GI_BASE_HPP
|
||||
349
cmake/external/glib/cppgir/gi/boxed.hpp
vendored
Normal file
349
cmake/external/glib/cppgir/gi/boxed.hpp
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
#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
|
||||
960
cmake/external/glib/cppgir/gi/callback.hpp
vendored
Normal file
960
cmake/external/glib/cppgir/gi/callback.hpp
vendored
Normal file
@@ -0,0 +1,960 @@
|
||||
#ifndef GI_CALLBACK_HPP
|
||||
#define GI_CALLBACK_HPP
|
||||
|
||||
#include "base.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "wrap.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
#if GI_CONFIG_EXCEPTIONS
|
||||
|
||||
inline ::GError **
|
||||
find_gerror(bool &has_gerror)
|
||||
{
|
||||
has_gerror = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline ::GError **
|
||||
find_gerror(bool &has_gerror, ::GError **error)
|
||||
{
|
||||
has_gerror = true;
|
||||
return error;
|
||||
}
|
||||
|
||||
template<typename CT, typename... CType>
|
||||
inline ::GError **
|
||||
find_gerror(bool &has_gerror, CT /*arg*/, CType... args)
|
||||
{
|
||||
return find_gerror(has_gerror, args...);
|
||||
}
|
||||
|
||||
inline ::GError *
|
||||
exception_error(const repository::GLib::Error &exc)
|
||||
{
|
||||
return g_error_copy(exc.gobj_());
|
||||
}
|
||||
|
||||
inline ::GError *
|
||||
exception_error(const repository::GLib::Error_Ref &exc)
|
||||
{
|
||||
return g_error_copy(exc.gobj_());
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
inline ::GError *
|
||||
exception_error(const E &exc)
|
||||
{
|
||||
static auto quark = g_quark_from_static_string("gi-error-quark");
|
||||
return g_error_new(quark, 0, "%s", exception_desc(exc).c_str());
|
||||
}
|
||||
|
||||
template<bool SILENT = FALSE, typename E, typename... CType>
|
||||
void
|
||||
report_exception(const E &exc, CType... args)
|
||||
{
|
||||
// see if we can really report error somewhere
|
||||
bool has_gerror = false;
|
||||
GError **error = find_gerror(has_gerror, args...);
|
||||
if (has_gerror) {
|
||||
g_return_if_fail(error == NULL || *error == NULL);
|
||||
if (error)
|
||||
*error = exception_error(exc);
|
||||
// if caller does not need/want error, exception disappears here
|
||||
} else {
|
||||
// simply report the hard and simple way
|
||||
// otherwise catch internally if something else/more is desired
|
||||
if (!SILENT) {
|
||||
auto msg = std::string("handler exception; ") + exception_desc(exc);
|
||||
g_critical("%s", msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// (re)float only applies to GObject
|
||||
template<typename CppType, typename Transfer,
|
||||
typename std::enable_if<!traits::is_object<CppType>::value>::type * =
|
||||
nullptr>
|
||||
auto
|
||||
unwrap_maybe_float(CppType &&v, const Transfer &t)
|
||||
{
|
||||
return unwrap(std::forward<CppType>(v), t);
|
||||
}
|
||||
|
||||
// (re) float only for transfer none/floating
|
||||
template<typename CppType,
|
||||
typename std::enable_if<traits::is_object<CppType>::value>::type * =
|
||||
nullptr>
|
||||
inline typename traits::ctype<CppType>::type
|
||||
unwrap_maybe_float(CppType &&v, const transfer_full_t &t)
|
||||
{
|
||||
return unwrap(std::forward<CppType>(v), t);
|
||||
}
|
||||
|
||||
template<typename CppType,
|
||||
typename std::enable_if<traits::is_object<CppType>::value>::type * =
|
||||
nullptr>
|
||||
inline typename traits::ctype<CppType>::type
|
||||
unwrap_maybe_float(CppType &&v, const transfer_none_t &)
|
||||
{
|
||||
// expected called with r-value
|
||||
static_assert(!std::is_reference<CppType>::value, "");
|
||||
// steal/take from wrapper
|
||||
auto result = (typename traits::ctype<CppType>::type)v.release_();
|
||||
// the following is essentially a bit of a hack as mentioned in
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=693393)
|
||||
// that is, we are about to return an object to C (from binding/callback)
|
||||
// and this should be done with none transfer
|
||||
// this none may actually mean floating (e.g. a factory-like callback)
|
||||
// but no way to know from annotations
|
||||
// so if at runtime the wrapper actually holds the only reference,
|
||||
// then it is about to be destroyed (when wrapper goes away)
|
||||
// *before* the object can make it back to caller
|
||||
// so turn that ref into a floating one (as only that makes sense)
|
||||
// if it is not the only ref, it is kept alive elsewhere
|
||||
// (as typically so for a "getter" callback)
|
||||
// so it is really treated as none
|
||||
auto obj = (GObject *)result;
|
||||
// theoretically not MT safe, but if == 1, only 1 thread should be involved
|
||||
if (obj->ref_count == 1) {
|
||||
g_object_force_floating(obj);
|
||||
} else {
|
||||
// otherwise unref as wrapper would have
|
||||
g_object_unref(obj);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T
|
||||
unconst(T t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
inline char *
|
||||
unconst(const char *t)
|
||||
{
|
||||
return (char *)t;
|
||||
}
|
||||
|
||||
// helper types to provide additional argument info beyond Transfer
|
||||
template<std::size_t... index>
|
||||
struct args_index
|
||||
{
|
||||
static constexpr auto value = std::make_tuple(index...);
|
||||
using value_type = decltype(value);
|
||||
};
|
||||
|
||||
template<typename Transfer, bool _inout, typename CustomTraits = void,
|
||||
typename ArgsIndex = args_index<>>
|
||||
struct arg_info
|
||||
{
|
||||
using transfer_type = Transfer;
|
||||
static constexpr bool inout = _inout;
|
||||
// tuple of index; used to selects the C arguments (to assemble C++ argument)
|
||||
using args_type = ArgsIndex;
|
||||
// additional info as used by corresponding cb_arg_handler
|
||||
using custom_type = CustomTraits;
|
||||
};
|
||||
|
||||
// access above info by forwarding types
|
||||
template<typename T, typename Enable = void>
|
||||
struct arg_traits
|
||||
{
|
||||
using transfer_type = typename T::transfer_type;
|
||||
static constexpr bool inout = T::inout;
|
||||
using args_type = typename T::args_type;
|
||||
using custom_type = typename T::custom_type;
|
||||
};
|
||||
|
||||
// legacy case; only transfer type
|
||||
template<typename T>
|
||||
struct arg_traits<T,
|
||||
typename std::enable_if<std::is_base_of<transfer_t, T>::value>::type>
|
||||
{
|
||||
using transfer_type = T;
|
||||
static constexpr bool inout = false;
|
||||
using args_type = args_index<>;
|
||||
using custom_type = void;
|
||||
};
|
||||
|
||||
// IndexTuple is essentially an args_index<...>
|
||||
template<typename IndexTuple, std::size_t... Index, typename F,
|
||||
typename ArgTuple>
|
||||
decltype(auto)
|
||||
apply_with_args(std::index_sequence<Index...>, F &&f, ArgTuple &&args)
|
||||
{
|
||||
return f(std::get<std::get<Index>(IndexTuple::value)>(args)...);
|
||||
}
|
||||
|
||||
template<typename IndexTuple, typename F, typename... Args>
|
||||
decltype(auto)
|
||||
apply_with_args(F &&f, Args &&...args)
|
||||
{
|
||||
return apply_with_args<IndexTuple>(
|
||||
std::make_index_sequence<
|
||||
std::tuple_size<typename IndexTuple::value_type>::value>(),
|
||||
std::forward<F>(f), std::forward_as_tuple(args...));
|
||||
}
|
||||
|
||||
// a simple callback has no (need for) args_index
|
||||
template<typename T>
|
||||
struct is_simple_cb : public std::true_type
|
||||
{};
|
||||
|
||||
template<typename Transfer, typename... Transfers>
|
||||
struct is_simple_cb<std::tuple<Transfer, Transfers...>>
|
||||
{
|
||||
static constexpr bool value =
|
||||
std::tuple_size<
|
||||
typename arg_traits<Transfer>::args_type::value_type>::value == 0 ||
|
||||
(sizeof...(Transfers) > 0 &&
|
||||
is_simple_cb<std::tuple<Transfers...>>::value);
|
||||
};
|
||||
|
||||
template<typename T, typename CT = void>
|
||||
struct map_cpp_function;
|
||||
|
||||
// handles all calls C -> C++ (callbacks, virtual method calls)
|
||||
// restrictions though on types supported (enforced by code generation)
|
||||
template<typename T, typename RetTransfer, typename ArgTransfers,
|
||||
typename CT = typename map_cpp_function<T>::type,
|
||||
bool SIMPLE = is_simple_cb<ArgTransfers>::value>
|
||||
struct transform_caller;
|
||||
|
||||
// helper used below that provides pre-call and post-call steps
|
||||
// to handle each argument's conversion to and from C++
|
||||
// in so-called (most) simple cases, there is one-to-one mapping between
|
||||
// C and C++ arguments and C++ argument type that allows to deduce context
|
||||
// (in particular, no callbacks or sized array)
|
||||
// as such, proper steps can be obtained by specialization on Cpp argument type
|
||||
template<typename CppArg, typename Enable = void>
|
||||
struct cb_arg_handler;
|
||||
|
||||
// in simple cases, C signature can be derived from C++ signature
|
||||
template<typename T, typename CT>
|
||||
struct map_cpp_function
|
||||
{
|
||||
using type = CT;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct map_cpp_function<R(Args...), void>
|
||||
{
|
||||
using type = typename traits::ctype<R>::type(
|
||||
typename cb_arg_handler<Args>::c_type...);
|
||||
};
|
||||
|
||||
// signature used in virtual method handling
|
||||
template<typename R, typename... Args>
|
||||
struct map_cpp_function<R (*)(Args...), void>
|
||||
{
|
||||
using type = typename traits::ctype<R>::type(
|
||||
typename cb_arg_handler<Args>::c_type...);
|
||||
};
|
||||
|
||||
// NOTE function type R(const A) is identical to R(A)
|
||||
// so no deduced Args below will retain const (if such)
|
||||
// in simple cases, *Transfer* is simply a transfer type
|
||||
// but it may also be a more elaborate argument trait
|
||||
|
||||
template<typename R, typename... Args, typename RetTransfer,
|
||||
typename... Transfers, typename CR, typename... CArgs, bool SIMPLE>
|
||||
struct transform_caller<R(Args...), RetTransfer, std::tuple<Transfers...>,
|
||||
CR(CArgs...), SIMPLE>
|
||||
{
|
||||
static_assert(sizeof...(Args) == sizeof...(Transfers), "");
|
||||
static_assert(!SIMPLE || sizeof...(Args) == sizeof...(CArgs), "");
|
||||
|
||||
typedef transform_caller self_type;
|
||||
typedef R (*caller_type)(Args &&..., void *d);
|
||||
|
||||
private:
|
||||
static R do_call(Args &&...args, caller_type func, void *d)
|
||||
{
|
||||
return func(std::forward<Args>(args)..., d);
|
||||
}
|
||||
|
||||
// helper that provides context for pack expansion below
|
||||
static void dummy_call(...){};
|
||||
|
||||
template<typename T>
|
||||
static auto _tt(const T &)
|
||||
{
|
||||
return typename arg_traits<T>::transfer_type();
|
||||
}
|
||||
|
||||
// non-void return
|
||||
template<typename T, std::size_t... Index,
|
||||
typename std::enable_if<SIMPLE && !std::is_void<T>::value>::type * =
|
||||
nullptr>
|
||||
static CR _wrapper(
|
||||
CArgs... args, caller_type func, void *d, std::index_sequence<Index...>)
|
||||
{
|
||||
std::tuple<cb_arg_handler<Args>...> handlers;
|
||||
auto ret = do_call(
|
||||
std::get<Index>(handlers).arg(args, _tt(Transfers()), Transfers())...,
|
||||
func, d);
|
||||
dummy_call((std::get<Index>(handlers).post(args, _tt(Transfers())), 0)...);
|
||||
return unconst(unwrap_maybe_float(std::move(ret), RetTransfer()));
|
||||
}
|
||||
|
||||
// void return
|
||||
template<typename T, std::size_t... Index,
|
||||
typename std::enable_if<SIMPLE && std::is_void<T>::value>::type * =
|
||||
nullptr>
|
||||
static CR _wrapper(
|
||||
CArgs... args, caller_type func, void *d, std::index_sequence<Index...>)
|
||||
{
|
||||
std::tuple<cb_arg_handler<Args>...> handlers;
|
||||
do_call(
|
||||
std::get<Index>(handlers).arg(args, _tt(Transfers()), Transfers())...,
|
||||
func, d);
|
||||
dummy_call((std::get<Index>(handlers).post(args, _tt(Transfers())), 0)...);
|
||||
}
|
||||
|
||||
// complex; non-void return
|
||||
template<typename T, std::size_t... Index,
|
||||
typename std::enable_if<!SIMPLE && !std::is_void<T>::value>::type * =
|
||||
nullptr>
|
||||
static CR _wrapper(
|
||||
CArgs... args, caller_type func, void *d, std::index_sequence<Index...>)
|
||||
{
|
||||
std::tuple<cb_arg_handler<Args>...> handlers;
|
||||
auto ret = do_call(
|
||||
apply_with_args<typename arg_traits<Transfers>::args_type>(
|
||||
[&handlers](auto... selargs) mutable -> decltype(auto) {
|
||||
return std::get<Index>(handlers).arg(selargs...,
|
||||
typename arg_traits<Transfers>::transfer_type(), Transfers());
|
||||
},
|
||||
args...)...,
|
||||
func, d);
|
||||
dummy_call((apply_with_args<typename arg_traits<Transfers>::args_type>(
|
||||
[&handlers](auto... selargs) mutable -> decltype(auto) {
|
||||
return std::get<Index>(handlers).post(selargs...,
|
||||
typename arg_traits<Transfers>::transfer_type());
|
||||
},
|
||||
args...),
|
||||
0)...);
|
||||
return unconst(unwrap_maybe_float(std::move(ret), RetTransfer()));
|
||||
}
|
||||
|
||||
// complex; void return
|
||||
template<typename T, std::size_t... Index,
|
||||
typename std::enable_if<!SIMPLE && std::is_void<T>::value>::type * =
|
||||
nullptr>
|
||||
static CR _wrapper(
|
||||
CArgs... args, caller_type func, void *d, std::index_sequence<Index...>)
|
||||
{
|
||||
std::tuple<cb_arg_handler<Args>...> handlers;
|
||||
do_call(apply_with_args<typename arg_traits<Transfers>::args_type>(
|
||||
[&handlers](auto... selargs) mutable -> decltype(auto) {
|
||||
return std::get<Index>(handlers).arg(selargs...,
|
||||
typename arg_traits<Transfers>::transfer_type(),
|
||||
Transfers());
|
||||
},
|
||||
args...)...,
|
||||
func, d);
|
||||
dummy_call((apply_with_args<typename arg_traits<Transfers>::args_type>(
|
||||
[&handlers](auto... selargs) mutable -> decltype(auto) {
|
||||
return std::get<Index>(handlers).post(selargs...,
|
||||
typename arg_traits<Transfers>::transfer_type());
|
||||
},
|
||||
args...),
|
||||
0)...);
|
||||
}
|
||||
|
||||
public:
|
||||
static CR wrapper(CArgs... args, caller_type func, void *d)
|
||||
{
|
||||
// exceptions should not escape into plain C
|
||||
#if GI_CONFIG_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
return self_type::template _wrapper<R>(
|
||||
args..., func, d, std::make_index_sequence<sizeof...(Args)>());
|
||||
#if GI_CONFIG_EXCEPTIONS
|
||||
} catch (const repository::GLib::Error &exc) {
|
||||
report_exception(exc, args...);
|
||||
} catch (const repository::GLib::Error_Ref &exc) {
|
||||
report_exception(exc, args...);
|
||||
} catch (const std::exception &exc) {
|
||||
report_exception(exc, args...);
|
||||
} catch (...) {
|
||||
report_exception(nullptr, args...);
|
||||
}
|
||||
return typename traits::ctype<R>::type();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// minor helper traits used below
|
||||
namespace _traits
|
||||
{
|
||||
template<typename T>
|
||||
struct remove_all_pointers
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_all_pointers<T *>
|
||||
{
|
||||
using type = typename remove_all_pointers<T>::type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_all_pointers<T *const>
|
||||
{
|
||||
using type = typename remove_all_pointers<T>::type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using is_basic_or_void = typename std::conditional<traits::is_basic<T>::value ||
|
||||
std::is_void<T>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
template<typename T>
|
||||
using is_basic_argument = typename std::conditional<
|
||||
is_basic_or_void<typename std::remove_cv<
|
||||
typename remove_all_pointers<T>::type>::type>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
template<typename T>
|
||||
using is_const_lvalue = typename std::conditional<
|
||||
std::is_lvalue_reference<T>::value &&
|
||||
std::is_const<typename std::remove_reference<T>::type>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
} // namespace _traits
|
||||
|
||||
// generic fallback case; assume input parameter
|
||||
// (also covers boxed callerallocates, which pretty much is/becomes input)
|
||||
template<typename CppArg, typename Enable>
|
||||
struct cb_arg_handler
|
||||
{
|
||||
using c_type = typename traits::ctype<CppArg>::type;
|
||||
|
||||
// use generic CType to handle const differences wrt c_type
|
||||
template<typename CType, typename Transfer, typename ArgTrait>
|
||||
typename std::decay<CppArg>::type arg(
|
||||
CType arg, const Transfer &t, const ArgTrait &) noexcept
|
||||
{
|
||||
// wrap to normalized destination target (no const &)
|
||||
// the destination type here is really only relevant for collection cases
|
||||
// (since that depends on the contained element)
|
||||
// otherwise all the info is pretty much in c_type type
|
||||
return wrap_to<typename std::decay<CppArg>::type>(arg, t);
|
||||
}
|
||||
|
||||
// minor variation; dynamic sized array input
|
||||
// also accepts length input
|
||||
template<typename CType, typename Transfer, typename ArgTrait>
|
||||
typename std::decay<CppArg>::type arg(
|
||||
CType arg, int length, const Transfer &t, const ArgTrait &) noexcept
|
||||
{
|
||||
// destination also really needed here
|
||||
return wrap_to<typename std::decay<CppArg>::type>(arg, length, t);
|
||||
}
|
||||
|
||||
void post(...){};
|
||||
};
|
||||
|
||||
// passthrough on (pointers to) basic values;
|
||||
// handles input/output of basic values, as well as arrays of such
|
||||
template<typename CppArg>
|
||||
struct cb_arg_handler<CppArg,
|
||||
typename std::enable_if<_traits::is_basic_argument<CppArg>::value>::type>
|
||||
{
|
||||
using c_type = CppArg;
|
||||
|
||||
template<typename CType, typename Transfer, typename ArgTrait>
|
||||
CType arg(CType arg, const Transfer &, const ArgTrait &) noexcept
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
void post(...){};
|
||||
|
||||
// array size case; inout C int* to in Cpp int
|
||||
// (only enable if so tagged by non-default custom trait type)
|
||||
template<typename CType, typename Transfer, typename ArgTrait>
|
||||
typename std::enable_if<
|
||||
!std::is_void<typename arg_traits<ArgTrait>::custom_type>::value,
|
||||
CType>::type
|
||||
arg(CType *arg, const Transfer &, const ArgTrait &) noexcept
|
||||
{
|
||||
return *arg;
|
||||
}
|
||||
};
|
||||
|
||||
// handle "complex" (in)out argument
|
||||
// (though also handles e.g. int& case, which might be optimized, but anyways)
|
||||
// these are recognized/assumed to be a pointer or reference to non-basic type
|
||||
template<typename CppArg>
|
||||
struct cb_arg_handler<CppArg,
|
||||
typename std::enable_if<
|
||||
!_traits::is_basic_argument<CppArg>::value &&
|
||||
(std::is_pointer<CppArg>::value ||
|
||||
(std::is_lvalue_reference<CppArg>::value &&
|
||||
!_traits::is_const_lvalue<CppArg>::value))>::type>
|
||||
{
|
||||
using BaseCppType =
|
||||
typename std::decay<typename std::remove_pointer<CppArg>::type>::type;
|
||||
// no more pointer expected here
|
||||
// (other than for void* cases, which do not introspect well, but anyways)
|
||||
static_assert(!std::is_pointer<BaseCppType>::value ||
|
||||
std::is_same<BaseCppType, gpointer>::value ||
|
||||
std::is_same<BaseCppType, gconstpointer>::value,
|
||||
"");
|
||||
using c_type = typename traits::ctype<BaseCppType>::type *;
|
||||
|
||||
// intermediate helper storage
|
||||
BaseCppType var_{};
|
||||
|
||||
// pointer case
|
||||
CppArg rv(std::true_type) { return &var_; }
|
||||
// ref case
|
||||
CppArg rv(std::false_type) { return var_; }
|
||||
|
||||
// handle const variations (e.g. const char**)
|
||||
template<typename T, typename X>
|
||||
static void assign(T *&t, X val)
|
||||
{
|
||||
t = const_cast<T *>(val);
|
||||
}
|
||||
|
||||
template<typename T, typename X>
|
||||
static void assign(T &t, X val)
|
||||
{
|
||||
t = unconst(val);
|
||||
}
|
||||
|
||||
template<typename Transfer, typename ArgTrait>
|
||||
CppArg arg(c_type arg, const Transfer &t, const ArgTrait &)
|
||||
{
|
||||
bool inout = arg_traits<ArgTrait>::inout;
|
||||
// a plain type has no special needs
|
||||
// so we can always take any bogus value as-is
|
||||
// (which is then less sensitive to incorrect annotation)
|
||||
if (arg && (inout || traits::is_plain<BaseCppType>::value))
|
||||
var_ = wrap_to<BaseCppType>(*arg, t);
|
||||
return rv(std::is_pointer<CppArg>());
|
||||
}
|
||||
|
||||
// overall function call happens following arg call above
|
||||
// post invoked after function call
|
||||
template<typename Transfer>
|
||||
void post(c_type arg, const Transfer &t)
|
||||
{
|
||||
if (arg)
|
||||
assign(*arg, unwrap_maybe_float(std::move(var_), t));
|
||||
}
|
||||
|
||||
// sized array variants; arguments (data, size)
|
||||
// latter could be input (int) or (in)out (int*)
|
||||
template<typename Transfer, typename Int, typename ArgTrait>
|
||||
CppArg arg(c_type arg, Int size, const Transfer &t, const ArgTrait &)
|
||||
{
|
||||
bool inout = arg_traits<ArgTrait>::inout;
|
||||
if (arg && inout)
|
||||
var_ = wrap_to<BaseCppType>(*arg, size, t);
|
||||
return rv(std::is_pointer<CppArg>());
|
||||
}
|
||||
|
||||
template<typename Transfer, typename Int, typename ArgTrait>
|
||||
CppArg arg(c_type arg, Int *size, const Transfer &t, const ArgTrait &)
|
||||
{
|
||||
bool inout = arg_traits<ArgTrait>::inout;
|
||||
if (arg && size && inout)
|
||||
var_ = wrap_to<BaseCppType>(*arg, *size, t);
|
||||
return rv(std::is_pointer<CppArg>());
|
||||
}
|
||||
|
||||
template<typename Transfer, typename Int>
|
||||
void post(c_type arg, Int, const Transfer &t)
|
||||
{
|
||||
post(arg, nullptr, t);
|
||||
}
|
||||
|
||||
template<typename Transfer, typename Int>
|
||||
void post(c_type arg, Int *size, const Transfer &t)
|
||||
{
|
||||
if (arg)
|
||||
assign(*arg, unwrap_maybe_float(std::move(var_), t));
|
||||
if (size)
|
||||
*size = var_.size();
|
||||
}
|
||||
};
|
||||
|
||||
// handles callback argument
|
||||
// (as argument in anther callback, most likely a virtual method)
|
||||
template<typename CppArg>
|
||||
struct cb_arg_handler<CppArg,
|
||||
typename std::enable_if<
|
||||
std::is_pointer<typename CppArg::cfunction_type>::value>::type>
|
||||
{
|
||||
template<typename CType, typename Transfer, typename ArgTrait>
|
||||
CppArg arg(CType cb, gpointer userdata, ::GDestroyNotify destroy,
|
||||
const Transfer &, const ArgTrait &) noexcept
|
||||
{
|
||||
using ct = typename arg_traits<ArgTrait>::custom_type;
|
||||
// setup shared pointer to userdata with destroy as Deleter
|
||||
auto sp = destroy ? std::shared_ptr<void>(userdata, destroy) : nullptr;
|
||||
// keep userdata/destroy alive as long as lambda handler
|
||||
auto h = [cb, userdata, sp = std::move(sp)](
|
||||
auto &&...args) -> decltype(auto) {
|
||||
// original callback type CType should match deduced handler_cb_tpe
|
||||
// but let's make sure as usual
|
||||
return ct::handler(std::forward<decltype(args)>(args)...,
|
||||
typename ct::handler_cb_type(cb), userdata);
|
||||
};
|
||||
return h;
|
||||
}
|
||||
|
||||
template<typename CType, typename Transfer, typename ArgTrait>
|
||||
CppArg arg(CType cb, gpointer userdata, const Transfer &t,
|
||||
const ArgTrait &tt) noexcept
|
||||
{
|
||||
return arg(cb, userdata, nullptr, t, tt);
|
||||
}
|
||||
|
||||
void post(...){};
|
||||
};
|
||||
|
||||
class connection_status
|
||||
{
|
||||
public:
|
||||
struct data
|
||||
{
|
||||
bool connected{false};
|
||||
};
|
||||
|
||||
bool connected() const
|
||||
{
|
||||
auto sp = data_.lock();
|
||||
return sp && sp->connected;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::weak_ptr<data> data_;
|
||||
};
|
||||
|
||||
// callback handling
|
||||
template<typename G>
|
||||
class connectable;
|
||||
|
||||
template<typename G, bool AUTODESTROY = false>
|
||||
class callback_wrapper;
|
||||
|
||||
template<typename R, typename... Args>
|
||||
class connectable<R(Args...)>
|
||||
{
|
||||
friend class callback_wrapper<R(Args...)>;
|
||||
struct data : public connection_status::data
|
||||
{
|
||||
template<typename T,
|
||||
typename Enable = typename detail::disable_if_same_or_derived<data, T>>
|
||||
data(T &&t) : callable(std::forward<T>(t))
|
||||
{}
|
||||
|
||||
std::function<R(Args... args)> callable;
|
||||
};
|
||||
|
||||
struct connection_status_factory : public connection_status
|
||||
{
|
||||
connection_status_factory(std::shared_ptr<data> p)
|
||||
{
|
||||
data_ = std::weak_ptr<connection_status::data>(p);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
// avoid copy constructor mishaps
|
||||
template<typename T,
|
||||
typename Enable =
|
||||
typename detail::disable_if_same_or_derived<connectable, T>>
|
||||
connectable(T &&t) : data_(std::make_shared<data>(std::forward<T>(t)))
|
||||
{}
|
||||
|
||||
connection_status connection() const
|
||||
{
|
||||
return connection_status_factory(data_);
|
||||
}
|
||||
|
||||
R operator()(Args... args) const
|
||||
{
|
||||
return data_->callable(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
explicit operator bool() const { return data_ && data_->callable; }
|
||||
|
||||
private:
|
||||
// state management by wrapper
|
||||
void connected(bool conn) { data_->connected = conn; }
|
||||
void disconnect() { data_->connected = false; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<data> data_;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args, bool AUTODESTROY>
|
||||
class callback_wrapper<R(Args...), AUTODESTROY>
|
||||
{
|
||||
typedef callback_wrapper self_type;
|
||||
|
||||
public:
|
||||
template<typename T,
|
||||
typename Enable =
|
||||
typename detail::disable_if_same_or_derived<callback_wrapper, T>>
|
||||
callback_wrapper(T &&t) : _callback(std::forward<T>(t))
|
||||
{
|
||||
// mark connected now that it is wrapped
|
||||
_callback.connected(true);
|
||||
}
|
||||
|
||||
// (only) used by manual callback workaround
|
||||
static R wrapper(Args... args, gpointer user_data)
|
||||
{
|
||||
auto t = reinterpret_cast<callback_wrapper *>(user_data);
|
||||
std::unique_ptr<self_type> wt(AUTODESTROY ? t : nullptr);
|
||||
return t->_callback(args...);
|
||||
}
|
||||
|
||||
static void destroy(gpointer user_data)
|
||||
{
|
||||
auto t = reinterpret_cast<callback_wrapper *>(user_data);
|
||||
delete t;
|
||||
}
|
||||
|
||||
// (async scope) wrapper may have to take ownership of additional data
|
||||
// (other callback wrapper)
|
||||
template<typename T>
|
||||
void take_data(std::shared_ptr<T> d)
|
||||
{
|
||||
auto cb = std::move(_callback.data_->callable);
|
||||
auto newcb = [d, cb](Args &&...args) {
|
||||
return cb(std::forward<Args>(args)...);
|
||||
};
|
||||
_callback.data_->callable = std::move(newcb);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void take_data(T *d)
|
||||
{
|
||||
take_data(std::shared_ptr<T>(d));
|
||||
}
|
||||
|
||||
~callback_wrapper()
|
||||
{
|
||||
// other shared ptr to data might be around (unlikely though)
|
||||
// but regardless disconnect now as requested (as wrapper is going away)
|
||||
_callback.disconnect();
|
||||
}
|
||||
|
||||
connectable<R(Args... args)> _callback;
|
||||
};
|
||||
|
||||
template<typename G, typename CG = typename map_cpp_function<G>::type>
|
||||
struct transform_callback_wrapper;
|
||||
|
||||
template<typename R, typename... Args, typename CR, typename... CArgs>
|
||||
struct transform_callback_wrapper<R(Args...), CR(CArgs...)>
|
||||
{
|
||||
// transfers of arguments
|
||||
template<bool AUTODESTROY, typename RetTransfer, typename... Transfers>
|
||||
class with_transfer : public callback_wrapper<R(Args...)>
|
||||
{
|
||||
typedef callback_wrapper<R(Args...)> super_type;
|
||||
typedef with_transfer self_type;
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
explicit with_transfer(T &&t) : super_type(std::forward<T>(t))
|
||||
{}
|
||||
|
||||
private:
|
||||
static R caller(Args &&...args, void *d)
|
||||
{
|
||||
auto this_ = (self_type *)d;
|
||||
return this_->_callback(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
public:
|
||||
static CR wrapper(CArgs... args, gpointer user_data)
|
||||
{
|
||||
auto t = reinterpret_cast<self_type *>(user_data);
|
||||
std::unique_ptr<self_type> wt(AUTODESTROY ? t : nullptr);
|
||||
return transform_caller<R(Args...), RetTransfer, std::tuple<Transfers...>,
|
||||
CR(CArgs...)>::wrapper(args..., caller, t);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// used early in declarations, so avoid using unknown types in CSigOrVoid
|
||||
template<typename CppSig, typename RetTransfer,
|
||||
typename ArgTransfers = std::tuple<>, typename CSigOrVoid = void>
|
||||
class callback;
|
||||
|
||||
template<typename CppSig, typename RetTransfer, typename... Transfers,
|
||||
typename CSigOrVoid>
|
||||
class callback<CppSig, RetTransfer, std::tuple<Transfers...>, CSigOrVoid>
|
||||
: public connectable<CppSig>
|
||||
{
|
||||
typedef connectable<CppSig> super_type;
|
||||
|
||||
public:
|
||||
typedef CppSig function_type;
|
||||
typedef typename map_cpp_function<CppSig, CSigOrVoid>::type CSig;
|
||||
|
||||
template<bool ASYNC = false>
|
||||
using wrapper_type = typename transform_callback_wrapper<function_type,
|
||||
CSig>::template with_transfer<ASYNC, RetTransfer, Transfers...>;
|
||||
|
||||
typedef typename std::add_pointer<decltype(wrapper_type<>::wrapper)>::type
|
||||
cfunction_type;
|
||||
|
||||
using super_type::super_type;
|
||||
};
|
||||
|
||||
// signal handling;
|
||||
// transfer none for arguments
|
||||
// transfer full for return
|
||||
template<typename G>
|
||||
struct transform_signal_wrapper;
|
||||
|
||||
template<typename T>
|
||||
struct signal_arg_transfer
|
||||
{
|
||||
typedef transfer_none_t type;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct transform_signal_wrapper<R(Args...)>
|
||||
: public transform_callback_wrapper<R(
|
||||
Args...)>::template with_transfer<false, transfer_full_t,
|
||||
typename detail::signal_arg_transfer<Args>::type...>
|
||||
{
|
||||
private:
|
||||
typedef typename transform_callback_wrapper<R(
|
||||
Args...)>::template with_transfer<false, transfer_full_t,
|
||||
typename detail::signal_arg_transfer<Args>::type...>
|
||||
super_;
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
transform_signal_wrapper(T &&t) : super_(std::forward<T>(t))
|
||||
{}
|
||||
};
|
||||
|
||||
// connection helpers
|
||||
class connection_impl
|
||||
{
|
||||
public:
|
||||
connection_impl(gulong id, connection_status s) : id_(id), status_(s) {}
|
||||
|
||||
bool connected() const { return status_.connected(); }
|
||||
|
||||
gulong id() const { return id_; }
|
||||
|
||||
protected:
|
||||
gulong id_;
|
||||
connection_status status_;
|
||||
};
|
||||
|
||||
template<typename Connection>
|
||||
class connection
|
||||
{
|
||||
typedef Connection impl;
|
||||
|
||||
public:
|
||||
connection() = default;
|
||||
|
||||
template<typename... Args>
|
||||
explicit connection(Args... arg)
|
||||
: conn_(std::make_shared<impl>(std::forward<Args>(arg)...))
|
||||
{
|
||||
// this is to be expected at this time
|
||||
if (!connected()) {
|
||||
g_warning("creating non-connected connection");
|
||||
}
|
||||
}
|
||||
|
||||
// implicit copy/move
|
||||
|
||||
bool connected() const { return conn_ && conn_->connected(); }
|
||||
void disconnect()
|
||||
{
|
||||
if (connected())
|
||||
conn_->disconnect();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<impl> conn_;
|
||||
};
|
||||
|
||||
template<typename ConnectionBase>
|
||||
class scoped_connection : public ConnectionBase
|
||||
{
|
||||
typedef ConnectionBase connection;
|
||||
|
||||
public:
|
||||
scoped_connection() : connection() {}
|
||||
~scoped_connection() { this->disconnect(); }
|
||||
|
||||
void release() { this->conn_.reset(); }
|
||||
|
||||
// ensure default movable
|
||||
scoped_connection(scoped_connection &&other) = default;
|
||||
scoped_connection &operator=(scoped_connection &&other) = default;
|
||||
|
||||
// not copyable; to avoid inadvertent disconnect
|
||||
scoped_connection(const scoped_connection &other) = delete;
|
||||
scoped_connection &operator=(const scoped_connection &other) = delete;
|
||||
|
||||
// but convert/assign from base class
|
||||
scoped_connection(const connection &other) : connection(other) {}
|
||||
scoped_connection &operator=(const connection &other)
|
||||
{
|
||||
(*(connection *)(this)) = other;
|
||||
return *this;
|
||||
}
|
||||
scoped_connection &operator=(const connection &&other)
|
||||
{
|
||||
(*(connection *)(this)) = std::move(other);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// function bind helpers
|
||||
template<typename R, typename T, typename Tp, typename... Args>
|
||||
inline std::function<R(Args...)>
|
||||
mem_fun(R (T::*pm)(Args...), Tp object)
|
||||
{
|
||||
return [object, pm](Args... args) {
|
||||
return (object->*pm)(std::forward<Args>(args)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename R, typename T, typename Tp, typename... Args>
|
||||
inline std::function<R(Args...)>
|
||||
mem_fun(R (T::*pm)(Args...) const, Tp object)
|
||||
{
|
||||
return [object, pm](Args... args) {
|
||||
return (object->*pm)(std::forward<Args>(args)...);
|
||||
};
|
||||
}
|
||||
|
||||
// expose for use in fallback scenarios
|
||||
using detail::callback_wrapper;
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // CALLBACK_HPP
|
||||
1970
cmake/external/glib/cppgir/gi/container.hpp
vendored
Normal file
1970
cmake/external/glib/cppgir/gi/container.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
268
cmake/external/glib/cppgir/gi/enumflag.hpp
vendored
Normal file
268
cmake/external/glib/cppgir/gi/enumflag.hpp
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
#ifndef GI_ENUMFLAG_HPP
|
||||
#define GI_ENUMFLAG_HPP
|
||||
|
||||
#include "base.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "value.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct EnumValueTraits
|
||||
{
|
||||
typedef GEnumClass class_type;
|
||||
typedef GEnumValue value_type;
|
||||
|
||||
static class_type *get_class(GType gtype)
|
||||
{
|
||||
auto c = g_type_class_peek(gtype);
|
||||
return (class_type *)(c ? G_ENUM_CLASS(c) : c);
|
||||
}
|
||||
static value_type *get_value(class_type *klass, int v)
|
||||
{
|
||||
return g_enum_get_value(klass, v);
|
||||
}
|
||||
static value_type *get_by_name(class_type *klass, const char *name)
|
||||
{
|
||||
return g_enum_get_value_by_name(klass, name);
|
||||
}
|
||||
static value_type *get_by_nick(class_type *klass, const char *name)
|
||||
{
|
||||
return g_enum_get_value_by_nick(klass, name);
|
||||
}
|
||||
};
|
||||
|
||||
struct FlagsValueTraits
|
||||
{
|
||||
typedef GFlagsClass class_type;
|
||||
typedef GFlagsValue value_type;
|
||||
|
||||
static class_type *get_class(GType gtype)
|
||||
{
|
||||
auto c = g_type_class_peek(gtype);
|
||||
return (class_type *)(c ? G_FLAGS_CLASS(c) : c);
|
||||
}
|
||||
static value_type *get_value(class_type *klass, int v)
|
||||
{
|
||||
return g_flags_get_first_value(klass, v);
|
||||
}
|
||||
static value_type *get_by_name(class_type *klass, const char *name)
|
||||
{
|
||||
return g_flags_get_value_by_name(klass, name);
|
||||
}
|
||||
static value_type *get_by_nick(class_type *klass, const char *name)
|
||||
{
|
||||
return g_flags_get_value_by_nick(klass, name);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename EnumType, typename Traits>
|
||||
class EnumValue
|
||||
{
|
||||
typedef EnumValue self;
|
||||
|
||||
typedef typename Traits::value_type value_type;
|
||||
typedef typename Traits::class_type class_type;
|
||||
|
||||
value_type *value_;
|
||||
|
||||
static class_type *get_class()
|
||||
{
|
||||
auto c = Traits::get_class(get_type_());
|
||||
if (!c) {
|
||||
detail::try_throw(std::invalid_argument("unknown class"));
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
EnumValue(gint v) : EnumValue(static_cast<EnumType>(v)) {}
|
||||
EnumValue(value_type *_value) : value_(_value) {}
|
||||
|
||||
public:
|
||||
typedef EnumType enum_type;
|
||||
|
||||
static GType get_type_() { return traits::gtype<EnumType>::get_type(); }
|
||||
|
||||
EnumValue(EnumType v) : value_(Traits::get_value(get_class(), (int)v))
|
||||
{
|
||||
if (!value_)
|
||||
detail::try_throw(std::invalid_argument(
|
||||
"invalid value " + std::to_string((unsigned)v)));
|
||||
}
|
||||
|
||||
static self get_by_name(const gi::cstring_v name)
|
||||
{
|
||||
auto v = Traits::get_by_name(get_class(), name.c_str());
|
||||
if (!v)
|
||||
detail::try_throw(std::invalid_argument("unknown name"));
|
||||
else
|
||||
return self(v);
|
||||
}
|
||||
static self get_by_nick(const gi::cstring_v nick)
|
||||
{
|
||||
auto v = Traits::get_by_nick(get_class(), nick.c_str());
|
||||
if (!v)
|
||||
detail::try_throw(std::invalid_argument("unknown nick"));
|
||||
else
|
||||
return self(v);
|
||||
}
|
||||
|
||||
operator EnumType() const noexcept
|
||||
{
|
||||
return static_cast<EnumType>(value_->value);
|
||||
}
|
||||
|
||||
gi::cstring_v value_name() const noexcept { return value_->value_name; }
|
||||
|
||||
gi::cstring_v value_nick() const noexcept { return value_->value_nick; }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// enumeration nick/name helpers
|
||||
template<typename EnumType>
|
||||
using EnumValue = detail::EnumValue<EnumType, detail::EnumValueTraits>;
|
||||
|
||||
template<typename EnumType,
|
||||
typename std::enable_if<traits::is_enumeration<EnumType>::value &&
|
||||
traits::gtype<EnumType>::value>::type * = nullptr>
|
||||
inline EnumValue<EnumType>
|
||||
value_info(EnumType v)
|
||||
{
|
||||
return EnumValue<EnumType>(v);
|
||||
}
|
||||
|
||||
// bitfield nick/name helpers
|
||||
template<typename EnumType>
|
||||
using FlagsValue = detail::EnumValue<EnumType, detail::FlagsValueTraits>;
|
||||
|
||||
template<typename EnumType,
|
||||
typename std::enable_if<traits::is_bitfield<EnumType>::value &&
|
||||
traits::gtype<EnumType>::value>::type * = nullptr>
|
||||
inline FlagsValue<EnumType>
|
||||
value_info(EnumType v)
|
||||
{
|
||||
return FlagsValue<EnumType>(v);
|
||||
}
|
||||
|
||||
// bitfield operation helpers
|
||||
template<typename FlagType,
|
||||
typename std::enable_if<traits::is_bitfield<FlagType>::value>::type * =
|
||||
nullptr>
|
||||
inline FlagType
|
||||
operator|(FlagType lhs, FlagType rhs)
|
||||
{
|
||||
return static_cast<FlagType>(
|
||||
static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
|
||||
}
|
||||
|
||||
template<typename FlagType,
|
||||
typename std::enable_if<traits::is_bitfield<FlagType>::value>::type * =
|
||||
nullptr>
|
||||
inline FlagType
|
||||
operator&(FlagType lhs, FlagType rhs)
|
||||
{
|
||||
return static_cast<FlagType>(
|
||||
static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
|
||||
}
|
||||
|
||||
template<typename FlagType,
|
||||
typename std::enable_if<traits::is_bitfield<FlagType>::value>::type * =
|
||||
nullptr>
|
||||
inline FlagType
|
||||
operator^(FlagType lhs, FlagType rhs)
|
||||
{
|
||||
return static_cast<FlagType>(
|
||||
static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs));
|
||||
}
|
||||
|
||||
template<typename FlagType,
|
||||
typename std::enable_if<traits::is_bitfield<FlagType>::value>::type * =
|
||||
nullptr>
|
||||
inline FlagType
|
||||
operator~(FlagType flags)
|
||||
{
|
||||
return static_cast<FlagType>(~static_cast<unsigned>(flags));
|
||||
}
|
||||
|
||||
template<typename FlagType,
|
||||
typename std::enable_if<traits::is_bitfield<FlagType>::value>::type * =
|
||||
nullptr>
|
||||
inline FlagType &
|
||||
operator|=(FlagType &lhs, FlagType rhs)
|
||||
{
|
||||
return (lhs = static_cast<FlagType>(
|
||||
static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs)));
|
||||
}
|
||||
|
||||
template<typename FlagType,
|
||||
typename std::enable_if<traits::is_bitfield<FlagType>::value>::type * =
|
||||
nullptr>
|
||||
inline FlagType &
|
||||
operator&=(FlagType &lhs, FlagType rhs)
|
||||
{
|
||||
return (lhs = static_cast<FlagType>(
|
||||
static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs)));
|
||||
}
|
||||
|
||||
template<typename FlagType,
|
||||
typename std::enable_if<traits::is_bitfield<FlagType>::value>::type * =
|
||||
nullptr>
|
||||
inline FlagType &
|
||||
operator^=(FlagType &lhs, FlagType rhs)
|
||||
{
|
||||
return (lhs = static_cast<FlagType>(
|
||||
static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs)));
|
||||
}
|
||||
|
||||
} // namespace gi
|
||||
|
||||
// sadly, the above templates are not picked up by ADL
|
||||
// and might therefore only end up used in case of a `using namespace gi`
|
||||
|
||||
// so also explicitly add operators in generated namespace
|
||||
// (by means of macro to simplify generation)
|
||||
|
||||
// see macro interface
|
||||
|
||||
/* NOTE:
|
||||
*
|
||||
* enumeration/bitfield TypeX is currently represented by an enum class TypeX
|
||||
* along with a namespace TypeXNS_ that holds the member functions.
|
||||
*
|
||||
* This could be merged into single class TypeX
|
||||
* (possibly using templated helpers);
|
||||
*
|
||||
* class TypeX
|
||||
* {
|
||||
* enum Enum {
|
||||
* VALUE_A,
|
||||
* VALUE_B
|
||||
* }
|
||||
* Enum value;
|
||||
*
|
||||
* (or C++17):
|
||||
* inline static const TypeX VALUE_A;
|
||||
* (note; constexpr not possible with incomplete type)
|
||||
*
|
||||
* constructor (Enum)
|
||||
* operator Enum()
|
||||
* ... etc ...
|
||||
* std::string value_name(); [opt]
|
||||
* std::string value_nick(); [opt]
|
||||
* }
|
||||
*
|
||||
* Disadvantage is that TypeX::VALUE_A would not have type TypeX,
|
||||
* although easily converted from/to TypeX, and so it would mostly work.
|
||||
* However, the operators above would have to be (even more) complicated and
|
||||
* accept various combinations of TypeX and TypeX::Enum (in case of a bitfield).
|
||||
*
|
||||
* All in all, the type mismatch (and moderately rare member function
|
||||
* occurrence) does not warrant going this way at this time. Also avoid C++17
|
||||
* for now, so as it stands ...
|
||||
*/
|
||||
|
||||
#endif // GI_ENUMFLAG_HPP
|
||||
170
cmake/external/glib/cppgir/gi/exception.hpp
vendored
Normal file
170
cmake/external/glib/cppgir/gi/exception.hpp
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
#ifndef GI_EXCEPTION_HPP
|
||||
#define GI_EXCEPTION_HPP
|
||||
|
||||
#include "base.hpp"
|
||||
#include "wrap.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline std::logic_error
|
||||
transform_error(GType tp, const char *name = nullptr)
|
||||
{
|
||||
auto n = g_type_name(tp);
|
||||
auto msg = std::string("could not transform value to type ") +
|
||||
detail::make_string(n);
|
||||
if (name)
|
||||
msg += std::string(" of property \'") + name + "\'";
|
||||
return std::invalid_argument(msg);
|
||||
}
|
||||
|
||||
inline std::logic_error
|
||||
unknown_property_error(GType tp, const gchar *property)
|
||||
{
|
||||
auto n = g_type_name(tp);
|
||||
auto msg = std::string("object of type ") + detail::make_string(n) +
|
||||
" does not have property \'" + detail::make_string(property) +
|
||||
"\'";
|
||||
return std::invalid_argument(msg);
|
||||
}
|
||||
|
||||
inline std::logic_error
|
||||
unknown_signal_error(GType tp, const std::string &name)
|
||||
{
|
||||
auto n = g_type_name(tp);
|
||||
auto msg = std::string("object of type ") + detail::make_string(n) +
|
||||
" does not have signal \'" + name + "\'";
|
||||
return std::invalid_argument(msg);
|
||||
}
|
||||
|
||||
inline std::logic_error
|
||||
invalid_signal_callback_error(
|
||||
GType tp, const std::string &name, const std::string &_msg)
|
||||
{
|
||||
auto n = g_type_name(tp);
|
||||
auto msg = std::string("invalid callback for signal ") + n + "::" + name +
|
||||
"; " + _msg;
|
||||
return std::invalid_argument(msg);
|
||||
}
|
||||
|
||||
// partially generated GError wrapper
|
||||
class Error : public gi::detail::GBoxedWrapperBase<Error, GError>
|
||||
{
|
||||
typedef gi::detail::GBoxedWrapperBase<Error, GError> super_type;
|
||||
|
||||
public:
|
||||
Error(GError *obj = nullptr) : super_type(obj) {}
|
||||
|
||||
static GType get_type_() G_GNUC_CONST { return g_error_get_type(); }
|
||||
|
||||
// use with care; dangling reference caution applies here
|
||||
gint &code_() { return gobj_()->code; }
|
||||
const gint &code_() const { return gobj_()->code; }
|
||||
|
||||
// use with care; dangling reference caution applies here
|
||||
gi::cstring_v message_() const { return gobj_()->message; }
|
||||
|
||||
// gboolean g_error_matches (const GError* error, GQuark domain, gint code);
|
||||
inline bool matches(GQuark domain, gint code) const
|
||||
{
|
||||
return g_error_matches(gobj_(), domain, code);
|
||||
}
|
||||
|
||||
}; // class
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace repository
|
||||
{
|
||||
namespace GLib
|
||||
{
|
||||
class Error_Ref;
|
||||
|
||||
class Error
|
||||
: public std::runtime_error,
|
||||
public detail::GBoxedWrapper<Error, ::GError, detail::Error, Error_Ref>
|
||||
{
|
||||
typedef std::runtime_error super;
|
||||
|
||||
static inline std::string make_message(GError *error)
|
||||
{
|
||||
return error ? detail::make_string(g_quark_to_string(error->domain)) +
|
||||
": " + detail::make_string(error->message) + "(" +
|
||||
std::to_string(error->code) + ")"
|
||||
: "";
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Error(GError *obj = nullptr) : super(make_message(obj))
|
||||
{
|
||||
data_ = obj;
|
||||
}
|
||||
|
||||
// GError* g_error_new_literal (GQuark domain, gint code, const gchar*
|
||||
// message);
|
||||
static inline Error new_literal(
|
||||
GQuark domain, gint code, const std::string &message)
|
||||
{
|
||||
return Error(g_error_new_literal(
|
||||
domain, code, gi::unwrap(message, gi::transfer_none)));
|
||||
}
|
||||
|
||||
// GError* g_error_copy (const GError* error);
|
||||
inline Error copy() const { return Error(g_error_copy(gobj_())); }
|
||||
|
||||
// override wrap since we are no longer in a simple single-base case
|
||||
template<typename Cpp, typename Enable = typename std::enable_if<
|
||||
std::is_base_of<Error, Cpp>::value>::type>
|
||||
static Cpp wrap(const typename Cpp::BaseObjectType *obj)
|
||||
{
|
||||
static_assert(sizeof(Cpp) == sizeof(Error), "type wrap not supported");
|
||||
Error w(const_cast<GError *>(obj));
|
||||
return std::move(*static_cast<Cpp *>(&w));
|
||||
}
|
||||
};
|
||||
|
||||
class Error_Ref
|
||||
: public gi::detail::GBoxedRefWrapper<GLib::Error, ::GError, detail::Error>
|
||||
{
|
||||
typedef gi::detail::GBoxedRefWrapper<GLib::Error, ::GError, detail::Error>
|
||||
super_type;
|
||||
using super_type::super_type;
|
||||
|
||||
// GError* g_error_copy (const GError* error);
|
||||
inline Error copy() const { return Error(g_error_copy(gobj_())); }
|
||||
};
|
||||
|
||||
} // namespace GLib
|
||||
|
||||
template<>
|
||||
struct declare_cpptype_of<GError>
|
||||
{
|
||||
typedef GLib::Error type;
|
||||
};
|
||||
|
||||
} // namespace repository
|
||||
|
||||
inline void
|
||||
check_error(GError *error)
|
||||
{
|
||||
if (error)
|
||||
detail::try_throw(repository::GLib::Error(error));
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline repository::GLib::Error
|
||||
missing_symbol_error(const std::string &symbol)
|
||||
{
|
||||
::GQuark domain = g_quark_from_static_string("gi-error-quark");
|
||||
auto error =
|
||||
g_error_new(domain, 0, "could not find symbol %s", symbol.c_str());
|
||||
return repository::GLib::Error(error);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // GI_EXCEPTION_HPP
|
||||
112
cmake/external/glib/cppgir/gi/expected.hpp
vendored
Normal file
112
cmake/external/glib/cppgir/gi/expected.hpp
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
#ifndef GI_EXPECTED_HPP
|
||||
#define GI_EXPECTED_HPP
|
||||
|
||||
#include "base.hpp"
|
||||
#include "exception.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
// alias so we might route to a std type some day ...
|
||||
template<typename T, typename E>
|
||||
#ifdef expected_lite_VERSION
|
||||
using expected = nonstd::expected<T, E>;
|
||||
#else
|
||||
using expected = std::expected<T, E>;
|
||||
#endif
|
||||
|
||||
template<typename E>
|
||||
#ifdef expected_lite_VERSION
|
||||
using unexpected = nonstd::unexpected_type<E>;
|
||||
#else
|
||||
using unexpected = std::unexpected<E>;
|
||||
#endif
|
||||
|
||||
// standardize on glib error
|
||||
template<typename T>
|
||||
using result = expected<T, repository::GLib::Error>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// only use nonstd if it does not delegate to std (in incomplete way)
|
||||
#if defined(expected_lite_VERSION) && !nsel_USES_STD_EXPECTED
|
||||
inline unexpected<repository::GLib::Error>
|
||||
make_unexpected(repository::GLib::Error error)
|
||||
{
|
||||
assert(error);
|
||||
return nonstd::make_unexpected(std::move(error));
|
||||
}
|
||||
#else
|
||||
inline unexpected<repository::GLib::Error>
|
||||
make_unexpected(repository::GLib::Error error)
|
||||
{
|
||||
assert(error);
|
||||
return std::unexpected<repository::GLib::Error>(std::move(error));
|
||||
}
|
||||
#endif
|
||||
|
||||
inline unexpected<repository::GLib::Error>
|
||||
make_unexpected(GError *error)
|
||||
{
|
||||
assert(error);
|
||||
return make_unexpected(repository::GLib::Error(error));
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
// no forwarding reference; T must be non-reference type
|
||||
template<typename T>
|
||||
result<T>
|
||||
make_result(T t, GError *error)
|
||||
{
|
||||
if (error)
|
||||
return detail::make_unexpected(error);
|
||||
return t;
|
||||
}
|
||||
|
||||
// rough helpers to unwrap result/expected
|
||||
// unwrap by move
|
||||
template<typename T>
|
||||
T
|
||||
expect(gi::result<T> &&t)
|
||||
{
|
||||
if (!t) {
|
||||
g_critical("error result %s", t.error().what());
|
||||
detail::try_throw(std::move(t.error()));
|
||||
}
|
||||
return std::move(*t);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
void test_result(const gi::result<T> &);
|
||||
template<typename T>
|
||||
int test_result(const T &);
|
||||
template<typename T>
|
||||
using is_result = std::is_same<void,
|
||||
decltype(test_result(std::forward<T>(std::declval<T>())))>;
|
||||
} // namespace detail
|
||||
|
||||
// should only be used for a non-result
|
||||
// (e.g. avoid l-value result ending up here)
|
||||
template<typename T, typename Enable = typename std::enable_if<
|
||||
!detail::is_result<T>::value>::type>
|
||||
T
|
||||
expect(T &&t)
|
||||
{
|
||||
return std::forward<T>(t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct rv
|
||||
{
|
||||
#if GI_DL && GI_EXPECTED
|
||||
using type = gi::result<T>;
|
||||
#else
|
||||
using type = T;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // GI_EXPECTED_HPP
|
||||
20
cmake/external/glib/cppgir/gi/gi.hpp
vendored
Normal file
20
cmake/external/glib/cppgir/gi/gi.hpp
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef GI_HPP
|
||||
#define GI_HPP
|
||||
|
||||
#include "base.hpp"
|
||||
#include "container.hpp"
|
||||
#include "enumflag.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "expected.hpp"
|
||||
#include "object.hpp"
|
||||
#include "objectclass.hpp"
|
||||
#include "string.hpp"
|
||||
|
||||
// check that include path has been setup properly to include override
|
||||
#if defined(__has_include)
|
||||
#if !__has_include(<glib/glib_extra_def.hpp>)
|
||||
#warning "overrides not found in include path"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // GI_HPP
|
||||
283
cmake/external/glib/cppgir/gi/gi_inc.hpp
vendored
Normal file
283
cmake/external/glib/cppgir/gi/gi_inc.hpp
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
#ifndef GI_INC_HPP
|
||||
#define GI_INC_HPP
|
||||
|
||||
// gi preprocessor/macro interface
|
||||
// aka global module fragment part
|
||||
|
||||
#define GI_VERSION_MAJAOR (2)
|
||||
#define GI_VERSION_MINOR (0)
|
||||
#define GI_VERSION_MICRO (0)
|
||||
|
||||
#ifdef GI_INLINE
|
||||
#define GI_INLINE_DECL inline
|
||||
#else
|
||||
#define GI_INLINE_DECL
|
||||
#endif
|
||||
|
||||
// == we could be included in some module setting
|
||||
#ifdef GI_MODULE_IN_INTERFACE
|
||||
#if __cplusplus < 201703L
|
||||
#error "need at least C++17 for modules"
|
||||
#endif
|
||||
#define GI_MODULE_EXPORT export
|
||||
#define GI_MODULE_INLINE inline
|
||||
#define GI_MODULE_STATIC_OR_INLINE inline
|
||||
#else // GI_MODULE_IN_INTERFACE
|
||||
#define GI_MODULE_EXPORT
|
||||
#define GI_MODULE_INLINE
|
||||
#define GI_MODULE_STATIC_OR_INLINE static
|
||||
#endif
|
||||
|
||||
// only used in module context
|
||||
#ifdef GI_MODULE_EXTERN
|
||||
#define GI_MODULE_EXTERN_BEGIN extern "C++" {
|
||||
#define GI_MODULE_EXTERN_END }
|
||||
#else
|
||||
#define GI_MODULE_EXTERN_BEGIN
|
||||
#define GI_MODULE_EXTERN_END
|
||||
#endif
|
||||
// related; another clang warning
|
||||
// https://github.com/llvm/llvm-project/issues/68615
|
||||
// `#include <filename>' attaches the declarations to the named module`
|
||||
#ifdef __clang__
|
||||
#define GI_MODULE_DISABLE_WARN_BEGIN \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Winclude-angled-in-module-purview\"")
|
||||
#define GI_MODULE_DISABLE_WARN_END _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define GI_MODULE_DISABLE_WARN_BEGIN
|
||||
#define GI_MODULE_DISABLE_WARN_END
|
||||
#endif
|
||||
|
||||
#define GI_MODULE_BEGIN \
|
||||
GI_MODULE_DISABLE_WARN_BEGIN \
|
||||
GI_MODULE_EXTERN_BEGIN
|
||||
|
||||
#define GI_MODULE_END \
|
||||
GI_MODULE_EXTERN_END \
|
||||
GI_MODULE_DISABLE_WARN_BEGIN
|
||||
// ==
|
||||
|
||||
// lots of declarations might be attributed as deprecated,
|
||||
// but not so annotated, so let's avoid warning floods
|
||||
// also handle complaints about const qualified casts
|
||||
// (due to silly const qualified scalar parameters)
|
||||
#define GI_DISABLE_DEPRECATED_WARN_BEGIN \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wignored-qualifiers\"")
|
||||
|
||||
#define GI_DISABLE_DEPRECATED_WARN_END \
|
||||
_Pragma("GCC diagnostic pop") _Pragma("GCC diagnostic pop")
|
||||
|
||||
// typically clang might warn but gcc might complain about pragma clang ...
|
||||
#ifdef GI_CLASS_IMPL_PRAGMA
|
||||
#ifndef GI_CLASS_IMPL_BEGIN
|
||||
#define GI_CLASS_IMPL_BEGIN \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"")
|
||||
#endif
|
||||
|
||||
#ifndef GI_CLASS_IMPL_END
|
||||
#define GI_CLASS_IMPL_END _Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
#else
|
||||
#define GI_CLASS_IMPL_BEGIN
|
||||
#define GI_CLASS_IMPL_END
|
||||
#endif
|
||||
|
||||
// attempt to auto-discover exception support:
|
||||
#ifndef GI_CONFIG_EXCEPTIONS
|
||||
#if defined(_MSC_VER)
|
||||
#include <cstddef> // for _HAS_EXCEPTIONS
|
||||
#endif
|
||||
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
|
||||
#define GI_CONFIG_EXCEPTIONS 1
|
||||
#else
|
||||
#define GI_CONFIG_EXCEPTIONS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#if __has_include("nonstd/expected.hpp")
|
||||
#if __cpp_concepts >= 202002L
|
||||
// this is also required in gcc's libstdc++ expected
|
||||
#else
|
||||
// so if that is missing, then prevent delegation to <expected>
|
||||
#define nsel_CONFIG_SELECT_EXPECTED nsel_EXPECTED_NONSTD
|
||||
#endif
|
||||
#include "nonstd/expected.hpp"
|
||||
#else
|
||||
#include <expected>
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
// define << operator if not unwanted
|
||||
#ifndef GI_NO_STRING_IOS
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#if GI_DL
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib.h>
|
||||
#include <gobject/gvaluecollector.h>
|
||||
|
||||
// various macros from all over the place
|
||||
// sadly, module refactor means breaking things apart
|
||||
|
||||
// exception
|
||||
// exception specification is generated according to settings and situation
|
||||
// some derived code (e.g. overrides) may need to follow suit accordingly
|
||||
#if GI_EXPECTED
|
||||
// no exception if reported through expected
|
||||
#define GI_NOEXCEPT_DECL(nonthrowing) noexcept
|
||||
#elif GI_DL
|
||||
// otherwise, everything can start failing if resolved at runtime
|
||||
#define GI_NOEXCEPT_DECL(nonthrowing)
|
||||
#else
|
||||
// otherwise, depends on whether (wrapped) function is (GError) throwing
|
||||
#define GI_NOEXCEPT_DECL(nonthrowing) noexcept(nonthrowing)
|
||||
#endif
|
||||
|
||||
// callback
|
||||
#define GI_CB_ARG_CALLBACK_CUSTOM(Type, CF_CType, CF_handler) \
|
||||
struct Type \
|
||||
{ \
|
||||
using handler_cb_type = CF_CType; \
|
||||
static constexpr auto handler = CF_handler; \
|
||||
}
|
||||
|
||||
// boxed
|
||||
// should be used within gi.repository namespace
|
||||
#define GI_ENABLE_BOXED_COPY(CType) \
|
||||
template<> \
|
||||
struct enable_boxed_copy<CType> : public std::true_type \
|
||||
{};
|
||||
|
||||
// enumflag
|
||||
#define GI_FLAG_OPERATORS(FlagType) \
|
||||
inline FlagType operator|(FlagType lhs, FlagType rhs) \
|
||||
{ \
|
||||
return static_cast<FlagType>( \
|
||||
static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs)); \
|
||||
} \
|
||||
\
|
||||
inline FlagType operator&(FlagType lhs, FlagType rhs) \
|
||||
{ \
|
||||
return static_cast<FlagType>( \
|
||||
static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs)); \
|
||||
} \
|
||||
\
|
||||
inline FlagType operator^(FlagType lhs, FlagType rhs) \
|
||||
{ \
|
||||
return static_cast<FlagType>( \
|
||||
static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs)); \
|
||||
} \
|
||||
\
|
||||
inline FlagType operator~(FlagType flags) \
|
||||
{ \
|
||||
return static_cast<FlagType>(~static_cast<unsigned>(flags)); \
|
||||
} \
|
||||
\
|
||||
inline FlagType &operator|=(FlagType &lhs, FlagType rhs) \
|
||||
{ \
|
||||
return (lhs = static_cast<FlagType>( \
|
||||
static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs))); \
|
||||
} \
|
||||
\
|
||||
inline FlagType &operator&=(FlagType &lhs, FlagType rhs) \
|
||||
{ \
|
||||
return (lhs = static_cast<FlagType>( \
|
||||
static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs))); \
|
||||
} \
|
||||
\
|
||||
inline FlagType &operator^=(FlagType &lhs, FlagType rhs) \
|
||||
{ \
|
||||
return (lhs = static_cast<FlagType>( \
|
||||
static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs))); \
|
||||
}
|
||||
|
||||
#define GI_ENUM_NUMERIC(EnumType) \
|
||||
inline std::underlying_type<EnumType>::type operator+(EnumType e) \
|
||||
{ \
|
||||
return static_cast<std::underlying_type<EnumType>::type>(e); \
|
||||
}
|
||||
|
||||
// objectclass
|
||||
// helper macro to obtain data from factory (if provided)
|
||||
#define GI_MEMBER_INIT_DATA(ClassType, factory) \
|
||||
(factory ? ((ClassType(*)())(factory))() : ClassType());
|
||||
|
||||
// conflicts might arise between interfaces and/or class
|
||||
// generate some dummy check types to force failure
|
||||
#define GI_MEMBER_CHECK_CONFLICT(member) _check_member_conflict_##member
|
||||
|
||||
// generated code tries to detect a defined member in SubClass as follows
|
||||
#define GI_MEMBER_DEFAULT_HAS_DEFINITION(BaseDef, member) \
|
||||
template<typename SubClass> \
|
||||
constexpr static bool has_definition(const member##_t *, const SubClass *) \
|
||||
{ \
|
||||
/* the use of conflict type check is only to trigger a compiler error \
|
||||
* if there is such a conflict \
|
||||
* in that case, manual specification of definitions are needed \
|
||||
* (which will then avoid this code path instantiation) \
|
||||
* (type should never be void, so merely serves as dummy check) \
|
||||
*/ \
|
||||
return std::is_void<typename SubClass::GI_MEMBER_CHECK_CONFLICT( \
|
||||
member)>::value || \
|
||||
!std::is_same<decltype(&BaseDef::member##_), \
|
||||
decltype(&SubClass::member##_)>::value; \
|
||||
}
|
||||
|
||||
// helper macro used in generated code
|
||||
#define GI_MEMBER_DEFINE(BaseDef, member) \
|
||||
struct member##_tag; \
|
||||
using member##_t = detail::member_type<member##_tag>; \
|
||||
member##_t member; \
|
||||
GI_MEMBER_DEFAULT_HAS_DEFINITION(BaseDef, member)
|
||||
|
||||
// the automated way might/will fail in case of overload resolution failure
|
||||
// (due to member conflicts with interfaces)
|
||||
// so the following can be used to specify definition situation
|
||||
// should be used in an inner struct DefinitionData in the SubClass
|
||||
#define GI_DEFINES_MEMBER(BaseDef, member, _defines) \
|
||||
template<typename SubClass> \
|
||||
constexpr static bool defines( \
|
||||
const BaseDef::TypeInitData::member##_t *, const SubClass *) \
|
||||
{ \
|
||||
return _defines; \
|
||||
}
|
||||
|
||||
// uses function overload on all of the above to determine
|
||||
// if member of DefData is defined/overridden in SubClass
|
||||
// (and should then be registered in the class/interface struct)
|
||||
#define GI_MEMBER_HAS_DEFINITION(SubClass, DefData, member) \
|
||||
DefData::defines((member##_t *)(nullptr), (SubClass *)(nullptr))
|
||||
|
||||
#endif // GI_INC_HPP
|
||||
694
cmake/external/glib/cppgir/gi/object.hpp
vendored
Normal file
694
cmake/external/glib/cppgir/gi/object.hpp
vendored
Normal file
@@ -0,0 +1,694 @@
|
||||
#ifndef GI_OBJECT_HPP
|
||||
#define GI_OBJECT_HPP
|
||||
|
||||
#include "callback.hpp"
|
||||
#include "container.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "objectbase.hpp"
|
||||
#include "paramspec.hpp"
|
||||
#include "value.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// helper
|
||||
|
||||
// signal argument connect/emit helper;
|
||||
// turn (C++) argument into a GType or GValue
|
||||
// most arguments are inputs (with specific GType),
|
||||
// but some arguments are used as output with G_TYPE_POINTER (e.g. int*)
|
||||
// which are mapped to (e.g.) int* or int& in C++ signature
|
||||
template<typename Arg, bool DECAY>
|
||||
struct signal_arg
|
||||
{
|
||||
static GType get_type() { return traits::gtype<Arg>::get_type(); }
|
||||
static detail::Value make(Arg arg)
|
||||
{
|
||||
return detail::Value(std::forward<Arg>(arg));
|
||||
}
|
||||
};
|
||||
|
||||
// re-route e.g. const std::string& cases
|
||||
template<typename Arg>
|
||||
struct signal_arg<const Arg &, false> : public signal_arg<const Arg &, true>
|
||||
{};
|
||||
|
||||
template<typename Arg>
|
||||
struct signal_arg<Arg &, false>
|
||||
{
|
||||
static GType get_type() { return G_TYPE_POINTER; }
|
||||
static detail::Value make(Arg &arg)
|
||||
{
|
||||
return signal_arg<Arg *, false>::make(&arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Arg>
|
||||
struct signal_arg<Arg *, false>
|
||||
{
|
||||
static GType get_type() { return G_TYPE_POINTER; }
|
||||
static detail::Value make(Arg *arg)
|
||||
{
|
||||
// (size of) wrapper argument should match wrappee
|
||||
static_assert(sizeof(typename traits::ctype<Arg>::type) == sizeof(Arg), "");
|
||||
// the above should suffice for proper handling
|
||||
// however, in these output cases, transfer should also be considered,
|
||||
// which is not (yet) available here
|
||||
// (but could be passed along similar to callback argument info)
|
||||
// so, restrict to plain cases for now
|
||||
static_assert(traits::is_plain<Arg>::value, "");
|
||||
return detail::Value(gpointer(arg));
|
||||
}
|
||||
};
|
||||
|
||||
// returns -size if signed numeric, +size if unsigned numeric, otherwise 0
|
||||
inline int
|
||||
get_number_size_signed(GType type)
|
||||
{
|
||||
// note; these are generally lower (absolute) bounds
|
||||
// at least it works in the context where it is used below
|
||||
#define GI_HANDLE_TYPE_SWITCH(cpptype, g_type, factor) \
|
||||
case g_type: \
|
||||
return factor * int(sizeof(cpptype));
|
||||
switch (type) {
|
||||
GI_HANDLE_TYPE_SWITCH(gchar, G_TYPE_CHAR, -1)
|
||||
GI_HANDLE_TYPE_SWITCH(guchar, G_TYPE_UCHAR, 1)
|
||||
GI_HANDLE_TYPE_SWITCH(gint, G_TYPE_INT, -1)
|
||||
GI_HANDLE_TYPE_SWITCH(guint, G_TYPE_UINT, 1)
|
||||
GI_HANDLE_TYPE_SWITCH(glong, G_TYPE_LONG, -1)
|
||||
GI_HANDLE_TYPE_SWITCH(gulong, G_TYPE_ULONG, 1)
|
||||
GI_HANDLE_TYPE_SWITCH(gint64, G_TYPE_INT64, -1)
|
||||
GI_HANDLE_TYPE_SWITCH(guint64, G_TYPE_UINT64, 1)
|
||||
}
|
||||
#undef GI_HANDLE_TYPE_SWITCH
|
||||
return 0;
|
||||
}
|
||||
|
||||
// glib type systems treats G_TYPE_INT64 as distinct from the other types
|
||||
// in practice, however, quite likely C gint64 == long
|
||||
inline bool
|
||||
compatible_type(GType expected, GType actual)
|
||||
{
|
||||
if (expected == G_TYPE_BOOLEAN)
|
||||
return std::abs(get_number_size_signed(actual)) == sizeof(gboolean);
|
||||
auto ssa_e = get_number_size_signed(expected);
|
||||
auto ssa_a = get_number_size_signed(actual);
|
||||
return ssa_e == ssa_a;
|
||||
}
|
||||
|
||||
inline void
|
||||
check_signal_type(GType tp, const gi::cstring_v name, GType return_type,
|
||||
GType *param_types, guint n_params)
|
||||
{
|
||||
const char *errmsg("expected ");
|
||||
auto check_types = [tp, &name, &errmsg](const std::string &desc,
|
||||
GType expected, GType actual) {
|
||||
// normalize
|
||||
expected &= ~G_SIGNAL_TYPE_STATIC_SCOPE;
|
||||
actual &= ~G_SIGNAL_TYPE_STATIC_SCOPE;
|
||||
if (expected == actual || compatible_type(expected, actual) ||
|
||||
g_type_is_a(expected, actual))
|
||||
return;
|
||||
std::string msg = errmsg;
|
||||
msg += desc + " type ";
|
||||
msg += detail::make_string(g_type_name(expected)) + " != ";
|
||||
msg += detail::make_string(g_type_name(actual));
|
||||
detail::try_throw(invalid_signal_callback_error(tp, name, msg));
|
||||
};
|
||||
|
||||
// determine signal (detail)
|
||||
guint id;
|
||||
GQuark detail;
|
||||
if (!g_signal_parse_name(name.c_str(), tp, &id, &detail, false) || (id == 0))
|
||||
detail::try_throw(unknown_signal_error(tp, name));
|
||||
// get signal info
|
||||
GSignalQuery query;
|
||||
g_signal_query(id, &query);
|
||||
// check
|
||||
if (n_params != query.n_params + 1) {
|
||||
auto msg = std::string(errmsg) + "argument count ";
|
||||
msg += std::to_string(query.n_params);
|
||||
msg += " != " + std::to_string(n_params);
|
||||
detail::try_throw(invalid_signal_callback_error(tp, name, msg));
|
||||
}
|
||||
check_types("return", query.return_type, return_type);
|
||||
check_types("instance", query.itype, param_types[0]);
|
||||
const std::string arg("argument ");
|
||||
for (guint i = 0; i < query.n_params; ++i)
|
||||
check_types(
|
||||
arg + std::to_string(i + 1), query.param_types[i], param_types[i + 1]);
|
||||
}
|
||||
|
||||
template<typename G>
|
||||
struct signal_type;
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct signal_type<R(Args...)>
|
||||
{
|
||||
static void check(GType tp, const gi::cstring_v name)
|
||||
{
|
||||
// capture type info and delegate
|
||||
const int argcount = sizeof...(Args);
|
||||
GType ti[] = {signal_arg<Args, false>::get_type()...};
|
||||
check_signal_type(tp, name, traits::gtype<R>::get_type(), ti, argcount);
|
||||
}
|
||||
};
|
||||
|
||||
// like GParameter, but with extra Value trimming
|
||||
struct Parameter
|
||||
{
|
||||
const char *name;
|
||||
detail::Value value;
|
||||
};
|
||||
|
||||
#ifdef GI_OBJECT_NEWV
|
||||
GI_DISABLE_DEPRECATED_WARN_BEGIN
|
||||
static_assert(sizeof(Parameter) == sizeof(GParameter), "");
|
||||
GI_DISABLE_DEPRECATED_WARN_END
|
||||
#endif
|
||||
|
||||
inline void
|
||||
fill_parameters(Parameter *)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
template<typename Arg, typename... Args>
|
||||
inline void
|
||||
fill_parameters(Parameter *param, const char *name, Arg &&arg, Args &&...args)
|
||||
{
|
||||
param->name = name;
|
||||
param->value.init<typename std::remove_reference<Arg>::type>();
|
||||
set_value(¶m->value, std::forward<Arg>(arg));
|
||||
fill_parameters(param + 1, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#if GLIB_CHECK_VERSION(2, 54, 0)
|
||||
#define GI_GOBJECT_PROPERTY_VALUE 1
|
||||
#endif
|
||||
|
||||
namespace repository
|
||||
{
|
||||
/* if you have arrived here due to an ambiguous GObject reference
|
||||
* (both the C typedef GObject and this namespace)
|
||||
* then that can be worked-around by:
|
||||
* + using _GObject (struct name instead)
|
||||
* + adjust 'using namespace' style imports e.g. alias
|
||||
* namespace GObject_ = gi::GObject;
|
||||
* or simply do not mention GObject at all and simply use the wrappers ;-)
|
||||
*/
|
||||
namespace GObject
|
||||
{
|
||||
typedef std::vector<detail::Parameter> construct_params;
|
||||
|
||||
template<typename... Args>
|
||||
construct_params
|
||||
make_construct_params(Args &&...args)
|
||||
{
|
||||
const int nparams = sizeof...(Args) / 2;
|
||||
construct_params parameters;
|
||||
parameters.resize(nparams);
|
||||
detail::fill_parameters(parameters.data(), std::forward<Args>(args)...);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
class Object : public detail::ObjectBase
|
||||
{
|
||||
typedef Object self;
|
||||
typedef detail::ObjectBase super_type;
|
||||
|
||||
public:
|
||||
typedef ::GObject BaseObjectType;
|
||||
|
||||
Object(std::nullptr_t = nullptr) : super_type() {}
|
||||
|
||||
BaseObjectType *gobj_() { return (BaseObjectType *)super_type::gobj_(); }
|
||||
const BaseObjectType *gobj_() const
|
||||
{
|
||||
return (const BaseObjectType *)super_type::gobj_();
|
||||
}
|
||||
BaseObjectType *gobj_copy_() const
|
||||
{
|
||||
return (BaseObjectType *)super_type::gobj_copy_();
|
||||
}
|
||||
|
||||
// class type
|
||||
static GType get_type_() { return G_TYPE_OBJECT; }
|
||||
// instance type
|
||||
GType gobj_type_() const { return G_OBJECT_TYPE(gobj_()); }
|
||||
|
||||
// type-erased generic object creation
|
||||
// transfer full return
|
||||
static gpointer new_(GType gtype, const construct_params ¶ms)
|
||||
{
|
||||
#ifdef GI_OBJECT_NEWV
|
||||
GI_DISABLE_DEPRECATED_WARN_BEGIN
|
||||
auto result =
|
||||
g_object_newv(gtype, params.size(), (GParameter *)params.data());
|
||||
GI_DISABLE_DEPRECATED_WARN_END
|
||||
#else
|
||||
std::vector<const char *> names;
|
||||
std::vector<GValue> values;
|
||||
names.reserve(params.size());
|
||||
values.reserve(params.size());
|
||||
// ownership remains in params
|
||||
for (auto &&p : params) {
|
||||
names.push_back(p.name);
|
||||
values.emplace_back(p.value);
|
||||
}
|
||||
auto result = g_object_new_with_properties(
|
||||
gtype, params.size(), names.data(), values.data());
|
||||
#endif
|
||||
// GIR says transfer full, but let's be careful and really make it so
|
||||
// if likely still floating, then we assume ownership
|
||||
// but if it is no longer, then it has already been stolen (e.g.
|
||||
// GtkWindow), and we need to add one here
|
||||
if (g_type_is_a(gtype, G_TYPE_INITIALLY_UNOWNED))
|
||||
g_object_ref_sink(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// type-based generic object creation
|
||||
template<typename CTYPE, typename... Args>
|
||||
static auto new_(GType gtype, Args &&...args)
|
||||
{
|
||||
auto parameters = make_construct_params(std::forward<Args>(args)...);
|
||||
auto *result = CTYPE(new_(gtype, parameters));
|
||||
return gi::wrap(result, transfer_full);
|
||||
}
|
||||
|
||||
// type-based generic object creation
|
||||
// Args are a sequence of name, value
|
||||
template<typename TYPE, typename... Args>
|
||||
static TYPE new_(Args &&...args)
|
||||
{
|
||||
return new_<typename TYPE::BaseObjectType *>(
|
||||
TYPE::get_type_(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// property stuff
|
||||
// generic type unsafe
|
||||
template<typename V>
|
||||
self &set_property(ParamSpec _pspec, V &&val)
|
||||
{
|
||||
// additional checks
|
||||
// allows for basic conversion between arithmetic types
|
||||
// without worrying about those details
|
||||
auto pspec = _pspec.gobj_();
|
||||
detail::Value v(std::forward<V>(val));
|
||||
detail::Value dest;
|
||||
GValue *p = &v;
|
||||
if (G_VALUE_TYPE(&v) != pspec->value_type) {
|
||||
g_value_init(&dest, pspec->value_type);
|
||||
if (!g_value_transform(&v, &dest))
|
||||
detail::try_throw(
|
||||
detail::transform_error(pspec->value_type, pspec->name));
|
||||
p = &dest;
|
||||
}
|
||||
g_object_set_property(gobj_(), pspec->name, p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
self &set_property(const gi::cstring_v propname, V &&val)
|
||||
{
|
||||
return set_property<V>(find_property(propname, true), std::forward<V>(val));
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
self &set_properties(const gi::cstring_v propname, V &&val)
|
||||
{
|
||||
return set_property<V>(propname, std::forward<V>(val));
|
||||
}
|
||||
|
||||
// set a number of props
|
||||
template<typename V, typename... Args>
|
||||
self &set_properties(const gi::cstring_v propname, V &&val, Args... args)
|
||||
{
|
||||
g_object_freeze_notify(gobj_());
|
||||
#if GI_CONFIG_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
set_property(propname, std::forward<V>(val));
|
||||
set_properties(std::forward<Args>(args)...);
|
||||
#if GI_CONFIG_EXCEPTIONS
|
||||
} catch (...) {
|
||||
g_object_thaw_notify(gobj_());
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
g_object_thaw_notify(gobj_());
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef GI_GOBJECT_PROPERTY_VALUE
|
||||
self &set_property(const gi::cstring_v propname, Value val)
|
||||
{
|
||||
g_object_set_property(gobj_(), propname.c_str(), val.gobj_());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename V>
|
||||
V get_property(const char *propname) const
|
||||
{
|
||||
// this would return a ref to what is owned by stack-local v below
|
||||
static_assert(!traits::is_reftype<V>::value, "dangling ref");
|
||||
detail::Value v;
|
||||
v.init<V>();
|
||||
// the _get_ already tries to transform
|
||||
// also close enough to const
|
||||
g_object_get_property(const_cast<::GObject *>(gobj_()), propname, &v);
|
||||
return detail::get_value<V>(&v);
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
V get_property(const gi::cstring_v propname) const
|
||||
{
|
||||
return get_property<V>(propname.c_str());
|
||||
}
|
||||
|
||||
#ifdef GI_GOBJECT_PROPERTY_VALUE
|
||||
Value get_property(const gi::cstring_v propname) const
|
||||
{
|
||||
Value result;
|
||||
const gchar *name = propname.c_str();
|
||||
GValue *val = result.gobj_();
|
||||
g_object_getv(const_cast<::GObject *>(gobj_()), 1, &name, val);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ParamSpec find_property(
|
||||
GType gtype, const gi::cstring_v propname, bool _throw = false)
|
||||
{
|
||||
GParamSpec *spec;
|
||||
if (g_type_is_a(gtype, G_TYPE_INTERFACE)) {
|
||||
// interface should be loaded if we have an instance here
|
||||
auto vtable = g_type_default_interface_peek(gtype);
|
||||
spec = g_object_interface_find_property(vtable, propname.c_str());
|
||||
} else {
|
||||
spec = g_object_class_find_property(
|
||||
(GObjectClass *)g_type_class_peek(gtype), propname.c_str());
|
||||
}
|
||||
if (_throw && !spec)
|
||||
detail::try_throw(
|
||||
detail::unknown_property_error(gtype, propname.c_str()));
|
||||
return gi::wrap(spec, transfer_none);
|
||||
}
|
||||
|
||||
ParamSpec find_property(
|
||||
const gi::cstring_v propname, bool _throw = false) const
|
||||
{
|
||||
return find_property(gobj_type_(), propname, _throw);
|
||||
}
|
||||
|
||||
gi::Collection<gi::DSpan, GParamSpec *, gi::transfer_container_t>
|
||||
list_properties() const
|
||||
{
|
||||
GParamSpec **specs;
|
||||
guint nspecs = 0;
|
||||
if (g_type_is_a(gobj_type_(), G_TYPE_INTERFACE)) {
|
||||
// interface should be loaded if we have an instance here
|
||||
auto vtable = g_type_default_interface_peek(gobj_type_());
|
||||
specs = g_object_interface_list_properties(vtable, &nspecs);
|
||||
} else {
|
||||
specs =
|
||||
g_object_class_list_properties(G_OBJECT_GET_CLASS(gobj_()), &nspecs);
|
||||
}
|
||||
return wrap_to<
|
||||
gi::Collection<gi::DSpan, GParamSpec *, gi::transfer_container_t>>(
|
||||
specs, nspecs, transfer_container);
|
||||
}
|
||||
|
||||
// signal stuff
|
||||
private:
|
||||
template<typename F, typename Functor>
|
||||
gulong connect_data(
|
||||
const gi::cstring_v signal, Functor &&f, GConnectFlags flags)
|
||||
{
|
||||
// runtime signature check
|
||||
detail::signal_type<F>::check(gobj_type_(), signal);
|
||||
auto w = new detail::transform_signal_wrapper<F>(std::forward<Functor>(f));
|
||||
// mind gcc's -Wcast-function-type
|
||||
return g_signal_connect_data(gobj_(), signal.c_str(),
|
||||
(GCallback)&w->wrapper, w, (GClosureNotify)(GCallback)&w->destroy,
|
||||
flags);
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename F, typename Functor>
|
||||
gulong connect(const gi::cstring_v signal, Functor &&f)
|
||||
{
|
||||
return connect_data<F, Functor>(
|
||||
signal, std::forward<Functor>(f), (GConnectFlags)0);
|
||||
}
|
||||
|
||||
template<typename F, typename Functor>
|
||||
gulong connect_after(const gi::cstring_v signal, Functor &&f)
|
||||
{
|
||||
return connect_data<F, Functor>(
|
||||
signal, std::forward<Functor>(f), G_CONNECT_AFTER);
|
||||
}
|
||||
|
||||
// TODO the object variants ??
|
||||
|
||||
// in case of unsupported signal signature
|
||||
// connect using a plain C signature without check/transform (wrap/unwrap)
|
||||
template<typename F, typename Functor>
|
||||
gulong connect_unchecked(
|
||||
const gi::cstring_v signal, Functor &&f, GConnectFlags flags = {})
|
||||
{
|
||||
auto w = new detail::callback_wrapper<F>(std::forward<Functor>(f));
|
||||
// mind gcc's -Wcast-function-type
|
||||
return g_signal_connect_data(gobj_(), signal.c_str(),
|
||||
(GCallback)&w->wrapper, w, (GClosureNotify)(GCallback)&w->destroy,
|
||||
flags);
|
||||
}
|
||||
|
||||
void disconnect(gulong id) { g_signal_handler_disconnect(gobj_(), id); }
|
||||
|
||||
// Args... may be explicitly specified or deduced
|
||||
// if deduced; arrange to decay/strip reference below
|
||||
// if not deduced; may need to considere specified type as-is
|
||||
template<typename R, bool DECAY = true, typename... Args>
|
||||
R emit(const gi::cstring_v signal, Args &&...args)
|
||||
{
|
||||
// static constexpr bool DECAY = true;
|
||||
guint id;
|
||||
GQuark detail;
|
||||
if (!g_signal_parse_name(signal.c_str(), gobj_type_(), &id, &detail, true))
|
||||
detail::try_throw(std::out_of_range(std::string("unknown signal name: ") +
|
||||
detail::make_string(signal.c_str())));
|
||||
|
||||
detail::Value values[] = {detail::Value(*this),
|
||||
detail::signal_arg<Args, DECAY>::make(std::forward<Args>(args))...};
|
||||
detail::Value retv;
|
||||
retv.init<R>();
|
||||
g_signal_emitv(values, id, detail, &retv);
|
||||
return detail::get_value<R>(&retv);
|
||||
}
|
||||
|
||||
void handler_block(gulong handler_id)
|
||||
{
|
||||
g_signal_handler_block(gobj_(), handler_id);
|
||||
}
|
||||
|
||||
void handler_unblock(gulong handler_id)
|
||||
{
|
||||
g_signal_handler_unblock(gobj_(), handler_id);
|
||||
}
|
||||
|
||||
bool handler_is_connected(gulong handler_id)
|
||||
{
|
||||
return g_signal_handler_is_connected(gobj_(), handler_id);
|
||||
}
|
||||
|
||||
void stop_emission(guint id, GQuark detail)
|
||||
{
|
||||
g_signal_stop_emission(gobj_(), id, detail);
|
||||
}
|
||||
|
||||
void stop_emission_by_name(const gi::cstring_v signal)
|
||||
{
|
||||
g_signal_stop_emission_by_name(gobj_(), signal.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace GObject
|
||||
|
||||
template<>
|
||||
struct declare_cpptype_of<::GObject>
|
||||
{
|
||||
typedef repository::GObject::Object type;
|
||||
};
|
||||
|
||||
namespace GLib
|
||||
{
|
||||
// predefined
|
||||
typedef detail::callback<void(), gi::transfer_none_t> DestroyNotify;
|
||||
} // namespace GLib
|
||||
|
||||
} // namespace repository
|
||||
|
||||
// type safe signal connection
|
||||
template<typename T, typename Base = repository::GObject::Object>
|
||||
class signal_proxy;
|
||||
|
||||
template<typename R, typename Instance, typename... Args, typename Base>
|
||||
class signal_proxy<R(Instance, Args...), Base>
|
||||
{
|
||||
protected:
|
||||
typedef R(CppSig)(Instance, Args...);
|
||||
Base object_;
|
||||
gi::cstring name_;
|
||||
|
||||
public:
|
||||
typedef CppSig function_type;
|
||||
typedef detail::connectable<function_type> slot_type;
|
||||
|
||||
signal_proxy(Base owner, gi::cstring name)
|
||||
: object_(owner), name_(std::move(name))
|
||||
{}
|
||||
|
||||
template<typename Functor>
|
||||
gulong connect(Functor &&f)
|
||||
{
|
||||
return object_.template connect<CppSig>(name_, std::forward<Functor>(f));
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
gulong connect_after(Functor &&f)
|
||||
{
|
||||
return object_.template connect_after<CppSig>(
|
||||
name_, std::forward<Functor>(f));
|
||||
}
|
||||
|
||||
R emit(Args... args)
|
||||
{
|
||||
return object_.template emit<R, false, Args...>(
|
||||
name_, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
slot_type slot(Functor &&f)
|
||||
{
|
||||
return slot_type(std::forward<Functor>(f));
|
||||
}
|
||||
};
|
||||
|
||||
// type safe property setting
|
||||
template<typename T, typename Base = repository::GObject::Object>
|
||||
class property_proxy
|
||||
{
|
||||
typedef property_proxy self;
|
||||
typedef repository::GObject::ParamSpec ParamSpec;
|
||||
|
||||
protected:
|
||||
Base object_;
|
||||
ParamSpec pspec_;
|
||||
|
||||
public:
|
||||
property_proxy(Base owner, ParamSpec pspec) : object_(owner), pspec_(pspec) {}
|
||||
|
||||
property_proxy(Base owner, const gi::cstring_v name)
|
||||
: property_proxy(owner, owner.find_property(name, true))
|
||||
{}
|
||||
|
||||
void set(T v) { object_.set_property(pspec_, std::move(v)); }
|
||||
|
||||
self &operator=(T v)
|
||||
{
|
||||
set(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T get() const
|
||||
{
|
||||
return object_.template get_property<T>(pspec_.gobj_()->name);
|
||||
}
|
||||
|
||||
ParamSpec param_spec() const { return pspec_; }
|
||||
|
||||
signal_proxy<void(Base, ParamSpec)> signal_notify() const
|
||||
{
|
||||
return signal_proxy<void(Base, ParamSpec)>(
|
||||
object_, gi::cstring_v("notify::") + gi::cstring_v(pspec_.name_()));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Base = repository::GObject::Object>
|
||||
class property_proxy_read : private property_proxy<T, Base>
|
||||
{
|
||||
typedef property_proxy<T, Base> super;
|
||||
|
||||
public:
|
||||
using super::get;
|
||||
using super::property_proxy;
|
||||
};
|
||||
|
||||
template<typename T, typename Base = repository::GObject::Object>
|
||||
class property_proxy_write : private property_proxy<T, Base>
|
||||
{
|
||||
typedef property_proxy<T, Base> super;
|
||||
|
||||
public:
|
||||
using super::property_proxy;
|
||||
using super::set;
|
||||
using super::operator=;
|
||||
};
|
||||
|
||||
// interface (ptr) is wrapped the same way,
|
||||
// as it is essentially a ptr to implementing object
|
||||
// TODO use other intermediate base ??
|
||||
using InterfaceBase = repository::GObject::Object;
|
||||
|
||||
namespace repository
|
||||
{
|
||||
namespace GObject
|
||||
{
|
||||
// connection helpers
|
||||
namespace internal
|
||||
{
|
||||
class SignalConnection : public detail::connection_impl
|
||||
{
|
||||
public:
|
||||
SignalConnection(gulong id, detail::connection_status s, Object object)
|
||||
: connection_impl(id, s), object_(object)
|
||||
{}
|
||||
|
||||
void disconnect() { object_.disconnect(id_); }
|
||||
|
||||
private:
|
||||
Object object_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
using SignalConnection = detail::connection<internal::SignalConnection>;
|
||||
using SignalScopedConnection = detail::scoped_connection<SignalConnection>;
|
||||
|
||||
} // namespace GObject
|
||||
|
||||
} // namespace repository
|
||||
|
||||
// connection callback type
|
||||
template<typename G>
|
||||
using slot = detail::connectable<G>;
|
||||
|
||||
template<typename G>
|
||||
inline repository::GObject::SignalConnection
|
||||
make_connection(
|
||||
gulong id, const gi::slot<G> &s, repository::GObject::Object object)
|
||||
{
|
||||
using repository::GObject::SignalConnection;
|
||||
return SignalConnection(id, s.connection(), object);
|
||||
}
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // GI_OBJECT_HPP
|
||||
172
cmake/external/glib/cppgir/gi/objectbase.hpp
vendored
Normal file
172
cmake/external/glib/cppgir/gi/objectbase.hpp
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
#ifndef GI_OBJECTBASE_HPP
|
||||
#define GI_OBJECTBASE_HPP
|
||||
|
||||
#include "gi_inc.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct GObjectFuncs
|
||||
{
|
||||
static void *ref(void *data) { return g_object_ref(data); }
|
||||
static void *sink(void *data) { return g_object_ref_sink(data); }
|
||||
static void free(void *data) { g_object_unref(data); }
|
||||
static void *float_(void *data)
|
||||
{
|
||||
g_object_force_floating((GObject *)data);
|
||||
return g_object_ref(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Funcs, typename CType = void>
|
||||
class Wrapper
|
||||
{
|
||||
protected:
|
||||
CType *data_ = nullptr;
|
||||
|
||||
static CType *_ref(CType *data) { return data ? Funcs::ref(data) : data; }
|
||||
static CType *_sink(CType *data) { return data ? Funcs::sink(data) : data; }
|
||||
static CType *_float(CType *data)
|
||||
{
|
||||
return data ? Funcs::float_(data) : data;
|
||||
}
|
||||
static void _deleter(CType *&data)
|
||||
{
|
||||
if (data)
|
||||
Funcs::free(data);
|
||||
}
|
||||
|
||||
public:
|
||||
Wrapper(decltype(data_) d = nullptr, bool own = true, bool sink = true)
|
||||
: data_(own ? d : (sink ? _sink(d) : _ref(d)))
|
||||
{}
|
||||
|
||||
~Wrapper() { _deleter(data_); }
|
||||
|
||||
Wrapper(const Wrapper &other)
|
||||
{
|
||||
_deleter(data_);
|
||||
data_ = _ref(other.data_);
|
||||
}
|
||||
|
||||
Wrapper(Wrapper &&other) noexcept
|
||||
{
|
||||
_deleter(data_);
|
||||
data_ = other.data_;
|
||||
other.data_ = nullptr;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return (bool)data_; }
|
||||
|
||||
Wrapper &operator=(const Wrapper &other)
|
||||
{
|
||||
if (&other != this) {
|
||||
_deleter(data_);
|
||||
data_ = _ref(other.data_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Wrapper &operator=(Wrapper &&other) noexcept
|
||||
{
|
||||
if (&other != this) {
|
||||
_deleter(data_);
|
||||
data_ = other.data_;
|
||||
other.data_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Wrapper &other) const { return data_ == other.data_; }
|
||||
|
||||
bool operator==(std::nullptr_t o) const
|
||||
{
|
||||
(void)o;
|
||||
return data_ == o;
|
||||
}
|
||||
|
||||
bool operator!=(const Wrapper &other) const { return data_ != other.data_; }
|
||||
|
||||
bool operator!=(std::nullptr_t o) const { return data_ != o; }
|
||||
|
||||
CType *gobj_() { return this->data_; }
|
||||
const CType *gobj_() const { return this->data_; }
|
||||
};
|
||||
|
||||
class wrapper_tag
|
||||
{};
|
||||
|
||||
template<typename CType, typename Funcs, GType GTYPE_>
|
||||
class WrapperBase : public Wrapper<Funcs>, public wrapper_tag
|
||||
{
|
||||
typedef WrapperBase self;
|
||||
typedef Wrapper<Funcs> super_type;
|
||||
|
||||
public:
|
||||
typedef CType BaseObjectType;
|
||||
|
||||
BaseObjectType *gobj_() { return (BaseObjectType *)this->data_; }
|
||||
const BaseObjectType *gobj_() const
|
||||
{
|
||||
return (const BaseObjectType *)this->data_;
|
||||
}
|
||||
BaseObjectType *gobj_copy_() const
|
||||
{
|
||||
return (BaseObjectType *)self::_ref(this->data_);
|
||||
}
|
||||
BaseObjectType *gobj_float_() const
|
||||
{
|
||||
return (BaseObjectType *)self::_float(this->data_);
|
||||
}
|
||||
BaseObjectType *release_()
|
||||
{
|
||||
void *r = nullptr;
|
||||
std::swap(this->data_, r);
|
||||
return (BaseObjectType *)r;
|
||||
}
|
||||
|
||||
static GType get_type_() { return GTYPE_; }
|
||||
GType gobj_type_() { return GTYPE_; }
|
||||
|
||||
WrapperBase(BaseObjectType *p = nullptr, bool own = true, bool argout = true)
|
||||
: super_type(p, own, argout)
|
||||
{}
|
||||
|
||||
WrapperBase(const self &other) = default;
|
||||
WrapperBase(self &&other) = default;
|
||||
|
||||
self &operator=(const self &other) = default;
|
||||
self &operator=(self &&other) = default;
|
||||
|
||||
// always arrange to sink by default nowadays
|
||||
template<typename Cpp>
|
||||
static Cpp wrap(
|
||||
const typename Cpp::BaseObjectType *obj, bool own, bool argout = true)
|
||||
{
|
||||
static_assert(sizeof(Cpp) == sizeof(self), "type wrap not supported");
|
||||
static_assert(std::is_base_of<self, Cpp>::value, "type wrap not supported");
|
||||
WrapperBase w((self::BaseObjectType *)(obj), own, argout);
|
||||
return std::move(*static_cast<Cpp *>(&w));
|
||||
}
|
||||
};
|
||||
|
||||
typedef WrapperBase<void, GObjectFuncs, G_TYPE_NONE> ObjectBase;
|
||||
|
||||
// foundation for Variant that will be generated
|
||||
struct GVariantFuncs
|
||||
{
|
||||
static void *ref(void *data) { return g_variant_ref((GVariant *)data); }
|
||||
static void *sink(void *data) { return g_variant_ref_sink((GVariant *)data); }
|
||||
static void free(void *data) { g_variant_unref((GVariant *)data); }
|
||||
static void *float_(void *data) { return data; }
|
||||
};
|
||||
|
||||
typedef WrapperBase<GVariant, GVariantFuncs, G_TYPE_VARIANT> VariantWrapper;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // GI_OBJECTBASE_HPP
|
||||
1562
cmake/external/glib/cppgir/gi/objectclass.hpp
vendored
Normal file
1562
cmake/external/glib/cppgir/gi/objectclass.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
242
cmake/external/glib/cppgir/gi/paramspec.hpp
vendored
Normal file
242
cmake/external/glib/cppgir/gi/paramspec.hpp
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
#ifndef GI_PARAMSPEC_HPP
|
||||
#define GI_PARAMSPEC_HPP
|
||||
|
||||
#include "objectbase.hpp"
|
||||
#include "value.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
// slightly nasty; will be generated
|
||||
namespace repository
|
||||
{
|
||||
namespace GObject
|
||||
{
|
||||
enum class ParamFlags : std::underlying_type<::GParamFlags>::type;
|
||||
}
|
||||
} // namespace repository
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct GParamSpecFuncs
|
||||
{
|
||||
static void *ref(void *data) { return g_param_spec_ref((GParamSpec *)data); }
|
||||
static void *sink(void *data)
|
||||
{
|
||||
return g_param_spec_ref_sink((GParamSpec *)data);
|
||||
}
|
||||
static void free(void *data) { g_param_spec_unref((GParamSpec *)data); }
|
||||
static void *float_(void *data) { return data; }
|
||||
};
|
||||
|
||||
using ParamFlags = repository::GObject::ParamFlags;
|
||||
|
||||
// helper paramspec type
|
||||
template<typename T>
|
||||
struct param_spec_constructor;
|
||||
|
||||
#define GI_DECLARE_PARAM_SPEC(cpptype, suffix) \
|
||||
template<> \
|
||||
struct param_spec_constructor<cpptype> \
|
||||
{ \
|
||||
typedef std::true_type range_type; \
|
||||
static const constexpr decltype(&g_param_spec_##suffix) new_ = \
|
||||
g_param_spec_##suffix; \
|
||||
};
|
||||
|
||||
GI_DECLARE_PARAM_SPEC(char, char)
|
||||
GI_DECLARE_PARAM_SPEC(unsigned char, uchar)
|
||||
GI_DECLARE_PARAM_SPEC(int, int)
|
||||
GI_DECLARE_PARAM_SPEC(unsigned int, uint)
|
||||
GI_DECLARE_PARAM_SPEC(long, long)
|
||||
GI_DECLARE_PARAM_SPEC(unsigned long, ulong)
|
||||
GI_DECLARE_PARAM_SPEC(long long, int64)
|
||||
GI_DECLARE_PARAM_SPEC(unsigned long long, uint64)
|
||||
GI_DECLARE_PARAM_SPEC(float, float)
|
||||
GI_DECLARE_PARAM_SPEC(double, double)
|
||||
|
||||
#undef GI_DECLARE_PARAM_SPEC
|
||||
|
||||
// specialize appropriately with static new_ member
|
||||
template<typename T, typename Enable = void>
|
||||
struct ParamSpecFactory;
|
||||
|
||||
template<typename T>
|
||||
struct ParamSpecFactory<T,
|
||||
typename std::enable_if<param_spec_constructor<T>::range_type::value>::type>
|
||||
{
|
||||
static GParamSpec *new_(const gi::cstring_v name, const gi::cstring_v nick,
|
||||
const gi::cstring_v blurb, T min, T max, T _default,
|
||||
ParamFlags flags = (ParamFlags)G_PARAM_READWRITE)
|
||||
{
|
||||
return param_spec_constructor<T>::new_(name.c_str(), nick.c_str(),
|
||||
blurb.c_str(), min, max, _default, (GParamFlags)flags);
|
||||
}
|
||||
|
||||
static GParamSpec *new_(const gi::cstring_v name, const gi::cstring_v nick,
|
||||
const gi::cstring_v blurb, T min, T max,
|
||||
ParamFlags flags = (ParamFlags)G_PARAM_READWRITE)
|
||||
{
|
||||
return new_(name, nick, blurb, min, max, T{}, flags);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamSpecFactory<bool>
|
||||
{
|
||||
static GParamSpec *new_(const gi::cstring_v name, const gi::cstring_v nick,
|
||||
const gi::cstring_v blurb, bool _default,
|
||||
ParamFlags flags = (ParamFlags)G_PARAM_READWRITE)
|
||||
{
|
||||
return g_param_spec_boolean(name.c_str(), nick.c_str(), blurb.c_str(),
|
||||
_default, (GParamFlags)flags);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamSpecFactory<gpointer>
|
||||
{
|
||||
static GParamSpec *new_(const gi::cstring_v name, const gi::cstring_v nick,
|
||||
const gi::cstring_v blurb,
|
||||
ParamFlags flags = (ParamFlags)G_PARAM_READWRITE)
|
||||
{
|
||||
return g_param_spec_pointer(
|
||||
name.c_str(), nick.c_str(), blurb.c_str(), (GParamFlags)flags);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamSpecFactory<std::string>
|
||||
{
|
||||
static GParamSpec *new_(const gi::cstring_v name, const gi::cstring_v nick,
|
||||
const gi::cstring_v blurb, const gi::cstring_v _default,
|
||||
ParamFlags flags = (ParamFlags)G_PARAM_READWRITE)
|
||||
{
|
||||
return g_param_spec_string(name.c_str(), nick.c_str(), blurb.c_str(),
|
||||
_default.c_str(), (GParamFlags)flags);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamSpecFactory<gi::cstring> : public ParamSpecFactory<std::string>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct ParamSpecFactory<T,
|
||||
typename std::enable_if<traits::is_object<T>::value>::type>
|
||||
{
|
||||
static GParamSpec *new_(const gi::cstring_v name, const gi::cstring_v nick,
|
||||
const gi::cstring_v blurb,
|
||||
ParamFlags flags = (ParamFlags)G_PARAM_READWRITE)
|
||||
{
|
||||
return g_param_spec_object(name.c_str(), nick.c_str(), blurb.c_str(),
|
||||
traits::gtype<T>::get_type(), (GParamFlags)flags);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ParamSpecFactory<T,
|
||||
typename std::enable_if<traits::is_boxed<T>::value>::type>
|
||||
{
|
||||
static GParamSpec *new_(const gi::cstring_v name, const gi::cstring_v nick,
|
||||
const gi::cstring_v blurb,
|
||||
ParamFlags flags = (ParamFlags)G_PARAM_READWRITE)
|
||||
{
|
||||
return g_param_spec_boxed(name.c_str(), nick.c_str(), blurb.c_str(),
|
||||
traits::gtype<T>::get_type(), (GParamFlags)flags);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ParamSpecFactory<T,
|
||||
typename std::enable_if<traits::is_enum_or_bitfield<T>::value>::type>
|
||||
{
|
||||
static GParamSpec *new_(const gi::cstring_v name, const gi::cstring_v nick,
|
||||
const gi::cstring_v blurb, guint _default = 0,
|
||||
ParamFlags flags = (ParamFlags)G_PARAM_READWRITE)
|
||||
{
|
||||
GType t = traits::gtype<T>::get_type();
|
||||
// FIXME compile-time determination rather than dynamic ??
|
||||
return G_TYPE_IS_FLAGS(t)
|
||||
? g_param_spec_flags(name.c_str(), nick.c_str(), blurb.c_str(),
|
||||
t, _default, (GParamFlags)flags)
|
||||
: g_param_spec_enum(name.c_str(), nick.c_str(), blurb.c_str(), t,
|
||||
_default, (GParamFlags)flags);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace repository
|
||||
{
|
||||
// slightly nasty
|
||||
namespace GObject
|
||||
{
|
||||
class ParamSpec;
|
||||
}
|
||||
|
||||
template<>
|
||||
struct declare_cpptype_of<GParamSpec>
|
||||
{
|
||||
typedef GObject::ParamSpec type;
|
||||
};
|
||||
|
||||
namespace GObject
|
||||
{
|
||||
class ParamSpec : public detail::WrapperBase<GParamSpec,
|
||||
detail::GParamSpecFuncs, G_TYPE_PARAM>
|
||||
{
|
||||
typedef WrapperBase<GParamSpec, detail::GParamSpecFuncs, G_TYPE_PARAM> super;
|
||||
|
||||
public:
|
||||
ParamSpec(std::nullptr_t = nullptr) {}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
static ParamSpec new_(Args &&...args)
|
||||
{
|
||||
return static_cast<ParamSpec &&>(
|
||||
super(detail::ParamSpecFactory<T>::new_(std::forward<Args>(args)...)));
|
||||
}
|
||||
|
||||
// special override case
|
||||
static ParamSpec new_(const gi::cstring_v name, ParamSpec overridden)
|
||||
{
|
||||
return static_cast<ParamSpec &&>(
|
||||
super(g_param_spec_override(name.c_str(), overridden.gobj_())));
|
||||
}
|
||||
|
||||
gi::cstring_v get_blurb() { return g_param_spec_get_blurb(gobj_()); }
|
||||
|
||||
gi::cstring_v get_nick() { return g_param_spec_get_nick(gobj_()); }
|
||||
|
||||
gi::cstring_v get_name() { return g_param_spec_get_name(gobj_()); }
|
||||
|
||||
GQuark get_name_quark() { return g_param_spec_get_name_quark(gobj_()); }
|
||||
|
||||
repository::GObject::Value get_default_value()
|
||||
{
|
||||
return gi::wrap(g_param_spec_get_default_value(gobj_()), transfer_none);
|
||||
}
|
||||
|
||||
ParamSpec get_redirect_target()
|
||||
{
|
||||
return gi::wrap(g_param_spec_get_redirect_target(gobj_()), transfer_none);
|
||||
}
|
||||
|
||||
// struct fields
|
||||
const gchar *name_() const { return gobj_()->name; }
|
||||
|
||||
ParamFlags value_type() const { return (ParamFlags)gobj_()->flags; }
|
||||
|
||||
GType value_type_() const { return gobj_()->value_type; }
|
||||
|
||||
GType owner_type_() const { return gobj_()->owner_type; }
|
||||
};
|
||||
|
||||
} // namespace GObject
|
||||
|
||||
} // namespace repository
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // GI_PARAMSPEC_HPP
|
||||
874
cmake/external/glib/cppgir/gi/string.hpp
vendored
Normal file
874
cmake/external/glib/cppgir/gi/string.hpp
vendored
Normal file
@@ -0,0 +1,874 @@
|
||||
#ifndef GI_STRING_HPP
|
||||
#define GI_STRING_HPP
|
||||
|
||||
#include "base.hpp"
|
||||
|
||||
#ifdef __has_builtin
|
||||
#define GI_HAS_BUILTIN(x) __has_builtin(x)
|
||||
#else
|
||||
#define GI_HAS_BUILTIN(x) 0
|
||||
#endif
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
namespace convert
|
||||
{
|
||||
// generic template; specialize as needed where appropriate
|
||||
template<typename From, typename To, class Enable = void>
|
||||
struct converter
|
||||
{
|
||||
// fail in explanatory way if we end up here
|
||||
static To convert(const From &)
|
||||
{
|
||||
static_assert(!std::is_void<Enable>::value, "unknown type conversion");
|
||||
return To();
|
||||
}
|
||||
};
|
||||
|
||||
// implementation should provide some types
|
||||
template<typename From, typename To, class Enable = void>
|
||||
struct converter_base : public std::true_type
|
||||
{
|
||||
typedef From from_type;
|
||||
typedef To to_type;
|
||||
};
|
||||
|
||||
// conversion check for complete type
|
||||
template<typename From, typename To, typename Enable = void>
|
||||
struct is_convertible_impl : public std::false_type
|
||||
{};
|
||||
|
||||
template<typename From, typename To>
|
||||
struct is_convertible_impl<From, To,
|
||||
typename std::enable_if<std::is_base_of<To, From>::value>::type>
|
||||
: public std::false_type
|
||||
{};
|
||||
|
||||
template<typename From, typename To>
|
||||
struct is_convertible_impl<From, To,
|
||||
typename std::enable_if<!std::is_base_of<To, From>::value &&
|
||||
std::is_pointer<typename converter<From,
|
||||
To>::from_type *>::value>::type>
|
||||
: public std::true_type
|
||||
{};
|
||||
|
||||
template<typename From, typename To, bool complete>
|
||||
struct is_convertible_pre
|
||||
{
|
||||
using type = std::false_type;
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
struct is_convertible_pre<From, To, true>
|
||||
{
|
||||
using type = is_convertible_impl<From, To>;
|
||||
};
|
||||
|
||||
// check whether conversion possible
|
||||
// reject incomplete forward declared types
|
||||
template<typename From, typename To, typename Enable = void>
|
||||
struct is_convertible : public is_convertible_pre<From, To,
|
||||
gi::traits::is_type_complete<To>::value>::type
|
||||
{};
|
||||
} // namespace convert
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// tag
|
||||
|
||||
struct String
|
||||
{};
|
||||
|
||||
template<typename Transfer>
|
||||
struct StringFuncs
|
||||
{
|
||||
static void _deleter(char *&p)
|
||||
{
|
||||
if (Transfer().value)
|
||||
g_free(p);
|
||||
p = nullptr;
|
||||
}
|
||||
static void _copy(const char *p)
|
||||
{
|
||||
return Transfer().value ? g_strdup(p) : p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Transfer>
|
||||
class cstr : public String
|
||||
{
|
||||
using self_type = cstr;
|
||||
|
||||
protected:
|
||||
using _member_type =
|
||||
typename std::conditional<std::is_same<Transfer, transfer_full_t>::value,
|
||||
char, const char>::type;
|
||||
|
||||
_member_type *data_ = nullptr;
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (Transfer().value && data_)
|
||||
g_free((char *)data_);
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
using traits_type = std::char_traits<char>;
|
||||
using value_type = char;
|
||||
using pointer = char *;
|
||||
using const_pointer = const char *;
|
||||
using reference = char &;
|
||||
using const_reference = const char &;
|
||||
using const_iterator = const char *;
|
||||
using iterator = const_iterator;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using reverse_iterator = const_reverse_iterator;
|
||||
using size_type = size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using view_type = cstr<transfer_none_t>;
|
||||
static constexpr bool is_view_type =
|
||||
!std::is_same<Transfer, transfer_full_t>::value;
|
||||
|
||||
static constexpr size_type npos = static_cast<size_type>(-1);
|
||||
|
||||
constexpr cstr() noexcept : data_(nullptr) {}
|
||||
|
||||
constexpr cstr(std::nullptr_t) noexcept : data_(nullptr) {}
|
||||
|
||||
// const usually means none, so only on view type
|
||||
// also, no arbitrary size is accepted here
|
||||
template<typename Enable = void,
|
||||
typename std::enable_if<std::is_same<Enable, void>::value &&
|
||||
is_view_type>::type * = nullptr>
|
||||
constexpr cstr(const char *data) : data_(data)
|
||||
{}
|
||||
|
||||
// a single pointer, optionally specify ownership
|
||||
// behave like string by default, assume no ownership of incoming pointer
|
||||
template<typename LTransfer = transfer_none_t,
|
||||
typename std::enable_if<
|
||||
(std::is_same<LTransfer, transfer_full_t>::value ||
|
||||
std::is_same<LTransfer, transfer_none_t>::value) &&
|
||||
!is_view_type>::type * = nullptr>
|
||||
cstr(char *data, const LTransfer &t)
|
||||
: data_((t.value == transfer_full.value) || !data ? data : g_strdup(data))
|
||||
{}
|
||||
|
||||
// pointer along with size
|
||||
// always behave like string and make a copy
|
||||
template<typename Enable = void,
|
||||
typename std::enable_if<std::is_same<Enable, void>::value &&
|
||||
!is_view_type>::type * = nullptr>
|
||||
cstr(const char *data, size_t len = npos)
|
||||
: data_(!data ? nullptr
|
||||
: (len == npos ? g_strdup(data) : g_strndup(data, len)))
|
||||
{}
|
||||
|
||||
// construct from any transfer variant
|
||||
template<typename OTransfer>
|
||||
cstr(const cstr<OTransfer> &s) : cstr(s.data())
|
||||
{}
|
||||
|
||||
// accept from string, but NOT string_view as that may not be null-terminated
|
||||
template<typename Allocator>
|
||||
cstr(const std::basic_string<char, std::char_traits<char>, Allocator>
|
||||
&s) noexcept
|
||||
: cstr(s.data())
|
||||
{}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
// some optional variants of above
|
||||
constexpr cstr(std::nullopt_t) noexcept : data_(nullptr) {}
|
||||
|
||||
template<typename Allocator>
|
||||
cstr(const std::optional<
|
||||
std::basic_string<char, std::char_traits<char>, Allocator>> &s) noexcept
|
||||
: cstr(s ? s.value().data() : nullptr)
|
||||
{}
|
||||
#endif
|
||||
|
||||
// hook extensible conversion
|
||||
// (avoid instantiation and confusion with self and base types)
|
||||
template<typename From,
|
||||
typename NoBase = typename std::enable_if<
|
||||
!std::is_base_of<self_type, From>::value>::type,
|
||||
typename Enable = typename std::enable_if<
|
||||
convert::is_convertible<From, self_type>::value>::type>
|
||||
cstr(const From &f) : cstr(convert::converter<From, self_type>::convert(f))
|
||||
{}
|
||||
|
||||
// custom
|
||||
constexpr const_pointer gobj_() const { return data_; }
|
||||
|
||||
explicit constexpr operator bool() const { return data_; }
|
||||
|
||||
_member_type *release_()
|
||||
{
|
||||
auto tmp = this->data_;
|
||||
this->data_ = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// destruct / copy / assign
|
||||
~cstr() { clear(); }
|
||||
|
||||
cstr(const cstr &other) { *this = other; }
|
||||
|
||||
cstr(cstr &&other) { *this = std::move(other); }
|
||||
|
||||
cstr &operator=(const cstr &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
clear();
|
||||
data_ = Transfer().value ? g_strdup(other.data_) : other.data_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
cstr &operator=(cstr &&other)
|
||||
{
|
||||
if (this != &other) {
|
||||
clear();
|
||||
data_ = other.data_;
|
||||
other.data_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// deduced conversion to string(_view)
|
||||
template<typename Destination,
|
||||
typename Check = typename std::enable_if<
|
||||
convert::is_convertible<self_type, Destination>::value>::type>
|
||||
operator Destination() const
|
||||
{
|
||||
return convert::converter<self_type, Destination>::convert(*this);
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
// unfortunately, conversion to std::optional picks Destination = std::string
|
||||
// (which can obviously not be excluded above, or as specialization)
|
||||
std::optional<std::string> opt_()
|
||||
{
|
||||
using To = std::optional<std::string>;
|
||||
return c_str() ? To({c_str(), size()}) : To(std::nullopt);
|
||||
}
|
||||
#endif
|
||||
|
||||
// usual string(view) stuff
|
||||
|
||||
// iterators
|
||||
|
||||
constexpr const_iterator begin() const noexcept { return data_; }
|
||||
|
||||
constexpr const_iterator end() const noexcept
|
||||
{
|
||||
return data_ ? data_ + size() : nullptr;
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept { return begin(); }
|
||||
|
||||
constexpr const_iterator cend() const noexcept { return end(); }
|
||||
|
||||
const_reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
const_reverse_iterator crbegin() const noexcept { return rbegin(); }
|
||||
|
||||
const_reverse_iterator crend() const noexcept { return rend(); }
|
||||
|
||||
// capacity
|
||||
|
||||
constexpr size_type size() const noexcept
|
||||
{
|
||||
#if GI_HAS_BUILTIN(__builtin_strlen) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))
|
||||
return __builtin_strlen(data_);
|
||||
#else
|
||||
return data_ ? strlen(data_) : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr size_type length() const noexcept { return size(); }
|
||||
|
||||
constexpr size_type max_size() const noexcept
|
||||
{
|
||||
return std::numeric_limits<size_type>::max();
|
||||
}
|
||||
|
||||
constexpr bool empty() const noexcept { return !data_ || *data_ == 0; }
|
||||
|
||||
// access
|
||||
|
||||
constexpr const_reference operator[](size_type i) const { return data_[i]; }
|
||||
|
||||
constexpr const_reference at(size_type i) const
|
||||
{
|
||||
return i < size() ? data_[i]
|
||||
: (try_throw(std::out_of_range("cstr::at")), data_[i]);
|
||||
}
|
||||
|
||||
constexpr const_reference front() const { return data_[0]; }
|
||||
|
||||
constexpr const_reference back() const { return data_[size() - 1]; }
|
||||
|
||||
constexpr const_pointer data() const noexcept { return data_; }
|
||||
|
||||
constexpr const_pointer c_str() const noexcept { return data_; }
|
||||
|
||||
// modifiers
|
||||
|
||||
// view only
|
||||
template<typename Enable = void,
|
||||
typename std::enable_if<std::is_same<Enable, void>::value &&
|
||||
is_view_type>::type * = nullptr>
|
||||
constexpr void remove_prefix(size_type n)
|
||||
{
|
||||
data_ += n;
|
||||
}
|
||||
|
||||
constexpr void swap(self_type &s) noexcept
|
||||
{
|
||||
std::swap(this->data_, s.data_);
|
||||
}
|
||||
|
||||
// operations
|
||||
|
||||
size_type copy(char *buf, size_type n, size_type pos = 0) const
|
||||
{
|
||||
auto s = size();
|
||||
if (pos > s)
|
||||
try_throw(std::out_of_range("cstr::copy"));
|
||||
size_type rlen = (std::min)(s - pos, n);
|
||||
if (rlen > 0) {
|
||||
const char *start = data_ + pos;
|
||||
traits_type::copy(buf, start, rlen);
|
||||
}
|
||||
return rlen;
|
||||
}
|
||||
|
||||
int compare(view_type x) const noexcept
|
||||
{
|
||||
return g_strcmp0(data_, x.c_str());
|
||||
}
|
||||
|
||||
int compare(const char *s) const { return compare(view_type(s)); }
|
||||
|
||||
// find
|
||||
|
||||
size_type find(view_type n, size_type pos = 0) const noexcept
|
||||
{
|
||||
auto s = size();
|
||||
auto os = n.size();
|
||||
if (os > s || pos > s - os)
|
||||
return npos;
|
||||
if (!os)
|
||||
return pos <= s ? pos : npos;
|
||||
auto loc = strstr(data_ + pos, n.data());
|
||||
return loc ? loc - data_ : npos;
|
||||
}
|
||||
|
||||
size_type find(char c, size_type pos = 0) const noexcept
|
||||
{
|
||||
if (pos >= size())
|
||||
return npos;
|
||||
auto loc = strchr(data_ + pos, c);
|
||||
return loc ? loc - data_ : npos;
|
||||
}
|
||||
|
||||
size_type find(const char *s, size_type pos = 0) const
|
||||
{
|
||||
return find(view_type(s), pos);
|
||||
}
|
||||
|
||||
size_type rfind(view_type n, size_type pos = npos) const noexcept
|
||||
{
|
||||
auto s = size();
|
||||
if (!s)
|
||||
return npos;
|
||||
auto os = n.size();
|
||||
if (!os)
|
||||
return pos == npos ? s : pos;
|
||||
auto loc = g_strrstr_len(c_str(), pos, n.c_str());
|
||||
return loc ? loc - data_ : npos;
|
||||
}
|
||||
|
||||
size_type rfind(char c, size_type pos = npos) const noexcept
|
||||
{
|
||||
// not quite efficient, but anyways
|
||||
char str[] = {c, 0};
|
||||
return rfind(str, pos);
|
||||
}
|
||||
|
||||
size_type rfind(const char *s, size_type pos = npos) const
|
||||
{
|
||||
return rfind(view_type(s), pos);
|
||||
}
|
||||
|
||||
// find_first_of variants
|
||||
// only provide those if std helps us out
|
||||
#if __cplusplus >= 201703L
|
||||
size_type find_first_of(view_type s, size_type pos = 0) const noexcept
|
||||
{
|
||||
return std::string_view(data_).find_first_of(s.data(), pos);
|
||||
}
|
||||
|
||||
size_type find_first_of(char c, size_type pos = 0) const noexcept
|
||||
{
|
||||
return find(c, pos);
|
||||
}
|
||||
|
||||
size_type find_first_of(const char *s, size_type pos = 0) const
|
||||
{
|
||||
return find_first_of(view_type(s), pos);
|
||||
}
|
||||
|
||||
size_type find_last_of(view_type s, size_type pos = npos) const noexcept
|
||||
{
|
||||
return std::string_view(data_).find_last_of(s.data(), pos);
|
||||
}
|
||||
|
||||
size_type find_last_of(char c, size_type pos = npos) const noexcept
|
||||
{
|
||||
return rfind(c, pos);
|
||||
}
|
||||
|
||||
size_type find_last_of(const char *s, size_type pos = npos) const
|
||||
{
|
||||
return find_last_of(view_type(s), pos);
|
||||
}
|
||||
|
||||
size_type find_first_not_of(view_type s, size_type pos = 0) const noexcept
|
||||
{
|
||||
return std::string_view(data_).find_first_not_of(s.data(), pos);
|
||||
}
|
||||
|
||||
size_type find_first_not_of(char c, size_type pos = 0) const noexcept
|
||||
{
|
||||
return std::string_view(data_).find_first_not_of(c, pos);
|
||||
}
|
||||
|
||||
size_type find_first_not_of(const char *s, size_type pos = 0) const
|
||||
{
|
||||
return find_first_not_of(view_type(s), pos);
|
||||
}
|
||||
|
||||
size_type find_last_not_of(view_type s, size_type pos = npos) const noexcept
|
||||
{
|
||||
return std::string_view(data_).find_last_not_of(s.data(), pos);
|
||||
}
|
||||
|
||||
size_type find_last_not_of(char c, size_type pos = npos) const noexcept
|
||||
{
|
||||
return std::string_view(data_).find_last_not_of(c, pos);
|
||||
}
|
||||
|
||||
size_type find_last_not_of(const char *s, size_type pos = npos) const
|
||||
{
|
||||
return find_last_not_of(view_type(s), pos);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
using _string_view = cstr<transfer_none_t>;
|
||||
|
||||
inline bool
|
||||
operator==(_string_view x, _string_view y) noexcept
|
||||
{
|
||||
return x.compare(y) == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator!=(_string_view x, _string_view y) noexcept
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(_string_view x, _string_view y) noexcept
|
||||
{
|
||||
return x.compare(y) < 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator>(_string_view x, _string_view y) noexcept
|
||||
{
|
||||
return y < x;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<=(_string_view x, _string_view y) noexcept
|
||||
{
|
||||
return !(y < x);
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator>=(_string_view x, _string_view y) noexcept
|
||||
{
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
#ifndef GI_NO_STRING_IOS
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream &o, _string_view sv)
|
||||
{
|
||||
// backwards compatibility; behave similar to empty string
|
||||
return o << (sv ? sv.c_str() : "");
|
||||
}
|
||||
#endif
|
||||
|
||||
// purpose of silly Delay is to avoid gcc premature instantiation of converter
|
||||
// (in the hook constructor of base class with cstring as From ??)
|
||||
template<typename Delay = void>
|
||||
class cstring_d : public cstr<transfer_full_t>
|
||||
{
|
||||
using self_type = cstring_d;
|
||||
using super_type = cstr<transfer_full_t>;
|
||||
|
||||
public:
|
||||
using super_type::super_type;
|
||||
|
||||
// if all other construction fails, try to pass through string
|
||||
template<typename... Args,
|
||||
typename NoConvert = typename std::enable_if<
|
||||
!std::is_constructible<super_type, Args...>::value>::type,
|
||||
typename Enable = typename std::enable_if<
|
||||
std::is_constructible<std::string, Args...>::value>::type>
|
||||
cstring_d(Args &&...args)
|
||||
: super_type(std::string(std::forward<Args>(args)...))
|
||||
{}
|
||||
|
||||
constexpr pointer gobj_() { return data_; }
|
||||
|
||||
// re-use string
|
||||
template<typename... Args>
|
||||
self_type &assign(Args &&...t)
|
||||
{
|
||||
return *this = std::string().assign(std::forward<Args>(t)...);
|
||||
}
|
||||
|
||||
// access
|
||||
|
||||
using super_type::at;
|
||||
constexpr reference at(size_type i)
|
||||
{
|
||||
return i < size() ? data_[i]
|
||||
: (try_throw(std::out_of_range("cstr::at")), data_[i]);
|
||||
}
|
||||
|
||||
using super_type::front;
|
||||
constexpr reference front() { return data_[0]; }
|
||||
|
||||
using super_type::back;
|
||||
constexpr reference back() { return data_[size() - 1]; }
|
||||
|
||||
using super_type::data;
|
||||
constexpr pointer data() noexcept { return data_; }
|
||||
|
||||
// iterators
|
||||
|
||||
using super_type::begin;
|
||||
constexpr iterator begin() noexcept { return data_; }
|
||||
|
||||
using super_type::end;
|
||||
constexpr iterator end() noexcept { return data_ ? data_ + size() : nullptr; }
|
||||
|
||||
using super_type::rbegin;
|
||||
reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
|
||||
|
||||
using super_type::rend;
|
||||
reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
|
||||
|
||||
// operations
|
||||
|
||||
using super_type::clear;
|
||||
|
||||
void push_back(char c)
|
||||
{
|
||||
char str[] = {c, 0};
|
||||
self_type n{
|
||||
g_strconcat(c_str() ? c_str() : "", str, (char *)NULL), transfer_full};
|
||||
swap(n);
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
auto s = size();
|
||||
if (s)
|
||||
at(s - 1) = 0;
|
||||
}
|
||||
|
||||
self_type &append(const char *str)
|
||||
{
|
||||
self_type n{
|
||||
g_strconcat(c_str() ? c_str() : "", str, (char *)NULL), transfer_full};
|
||||
swap(n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Transfer>
|
||||
self_type &append(const cstr<Transfer> &str)
|
||||
{
|
||||
return append(str.data());
|
||||
}
|
||||
|
||||
// otherwise delegate
|
||||
template<typename... Args>
|
||||
self_type &append(Args &&...args)
|
||||
{
|
||||
std::string s;
|
||||
s.append(std::forward<Args>(args)...);
|
||||
// make sure to select the desired variant
|
||||
return append((const char *)s.c_str());
|
||||
}
|
||||
|
||||
// likewise for +=
|
||||
self_type &operator+=(char c)
|
||||
{
|
||||
push_back(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
self_type &operator+=(const T &o)
|
||||
{
|
||||
return append(o);
|
||||
}
|
||||
|
||||
self_type substr(size_type pos = 0, size_type n = npos) const
|
||||
{
|
||||
auto l = size();
|
||||
return (pos > l)
|
||||
? (try_throw(std::out_of_range("cstr::substr")), self_type())
|
||||
: self_type(data_ + pos, std::min(n, l - pos));
|
||||
}
|
||||
|
||||
// indeed some are lacking/skipped
|
||||
// only minimal compatibility
|
||||
|
||||
// custom; align with other cases
|
||||
self_type copy_() { return substr(0); }
|
||||
};
|
||||
|
||||
using cstring = cstring_d<>;
|
||||
|
||||
// likewise; (delayed) view type
|
||||
template<typename Delay = void>
|
||||
class cstring_v_d : public cstr<transfer_none_t>
|
||||
{
|
||||
using self_type = cstring_v_d;
|
||||
using super_type = cstr<transfer_none_t>;
|
||||
|
||||
public:
|
||||
using super_type::super_type;
|
||||
|
||||
// primary reason for subtype
|
||||
// provide copy/upgrade to owning variant
|
||||
cstring copy_() { return {g_strdup(this->data()), transfer_full}; }
|
||||
};
|
||||
|
||||
using cstring_v = cstring_v_d<>;
|
||||
|
||||
inline cstring
|
||||
operator+(const _string_view x, const _string_view y) noexcept
|
||||
{
|
||||
if (!x)
|
||||
return {g_strdup(y.c_str()), transfer_full};
|
||||
if (!y)
|
||||
return {g_strdup(x.c_str()), transfer_full};
|
||||
return {g_strconcat(x.c_str(), y.c_str(), (char *)NULL), transfer_full};
|
||||
}
|
||||
|
||||
inline cstring
|
||||
operator+(const _string_view x, char y) noexcept
|
||||
{
|
||||
if (!x)
|
||||
return {1, y};
|
||||
char str[] = {y, 0};
|
||||
return x + str;
|
||||
}
|
||||
|
||||
inline cstring
|
||||
operator+(char x, const _string_view y) noexcept
|
||||
{
|
||||
if (!y)
|
||||
return {1, x};
|
||||
char str[] = {x, 0};
|
||||
return str + y;
|
||||
}
|
||||
|
||||
// add convenient conversions
|
||||
|
||||
// local helper traits used below
|
||||
namespace trait
|
||||
{
|
||||
template<typename T, std::size_t SIZE, typename Enable = void>
|
||||
struct has_data_member : std::false_type
|
||||
{};
|
||||
|
||||
template<typename T, std::size_t SIZE>
|
||||
struct has_data_member<T, SIZE,
|
||||
typename std::enable_if<
|
||||
std::is_pointer<decltype(std::declval<T>().c_str())>::value>::type>
|
||||
: std::integral_constant<bool, sizeof(*std::declval<T>().c_str()) == SIZE>
|
||||
{};
|
||||
|
||||
template<typename T, typename Enable = void>
|
||||
struct has_size_member : std::false_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct has_size_member<T, typename std::enable_if<std::is_integral<
|
||||
decltype(std::declval<T>().size())>::value>::type>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_string_type
|
||||
: public std::integral_constant<bool,
|
||||
has_data_member<T, 1>::value && has_size_member<T>::value>
|
||||
{};
|
||||
|
||||
} // namespace trait
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace convert
|
||||
{
|
||||
template<typename From>
|
||||
struct converter<From, detail::cstr<transfer_full_t>,
|
||||
typename std::enable_if<detail::trait::is_string_type<From>::value>::type>
|
||||
: public converter_base<From, detail::cstr<transfer_full_t>>
|
||||
{
|
||||
static detail::cstring convert(const From &v)
|
||||
{
|
||||
return {(char *)v.c_str(), v.size()};
|
||||
}
|
||||
};
|
||||
|
||||
// to a typical string(_view) case
|
||||
// (avoid conflict with above)
|
||||
// the traits_type (tries to) restricts this to std::string(_view)
|
||||
// not doing so might conveniently allow conversion to other types as well.
|
||||
// however, this would also allow e.g. QByteArray, which comes with an operator+
|
||||
// in global namespace (also selected by non-ADL lookup),
|
||||
// which then results in ambiguous overload
|
||||
// (with the operator+ that is provided above)
|
||||
template<typename Transfer, typename To>
|
||||
struct converter<detail::cstr<Transfer>, To,
|
||||
typename std::enable_if<
|
||||
!std::is_base_of<detail::String, To>::value &&
|
||||
!std::is_same<typename To::traits_type, void>::value &&
|
||||
std::is_constructible<To, const char *, size_t>::value>::type>
|
||||
: public converter_base<detail::cstr<Transfer>, To>
|
||||
{
|
||||
static To convert(const detail::cstr<Transfer> &v)
|
||||
{
|
||||
return v.c_str() ? To{(char *)v.c_str(), v.size()} : To();
|
||||
}
|
||||
};
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
// to an std::optional string(_view) case
|
||||
template<typename Transfer, typename To>
|
||||
struct converter<detail::cstr<Transfer>, To,
|
||||
typename std::enable_if<std::is_constructible<To, std::in_place_t,
|
||||
const char *, size_t>::value>::type>
|
||||
: public converter_base<detail::cstr<Transfer>, To>
|
||||
{
|
||||
static To convert(const detail::cstr<Transfer> &v)
|
||||
{
|
||||
abort();
|
||||
return v.c_str() ? To{std::in_place, (char *)v.c_str(), v.size()} : To();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace convert
|
||||
|
||||
using detail::cstring;
|
||||
using detail::cstring_v;
|
||||
|
||||
// sanity check; match C counterpart
|
||||
static_assert(sizeof(cstring) == sizeof(char *), "");
|
||||
static_assert(sizeof(cstring_v) == sizeof(char *), "");
|
||||
|
||||
namespace traits
|
||||
{
|
||||
template<>
|
||||
struct ctype<const gi::cstring, void>
|
||||
{
|
||||
typedef const char *type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ctype<gi::cstring, void>
|
||||
{
|
||||
typedef char *type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ctype<const gi::cstring_v, void>
|
||||
{
|
||||
typedef const char *type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ctype<gi::cstring_v, void>
|
||||
{
|
||||
typedef char *type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct cpptype<char *, transfer_full_t>
|
||||
{
|
||||
using type = gi::cstring;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct cpptype<char *, transfer_none_t>
|
||||
{
|
||||
using type = gi::cstring_v;
|
||||
};
|
||||
|
||||
} // namespace traits
|
||||
|
||||
} // namespace gi
|
||||
|
||||
// specialize std::hash for suitable use
|
||||
GI_MODULE_EXPORT
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<gi::cstring>
|
||||
{
|
||||
typedef gi::cstring argument_type;
|
||||
typedef std::size_t result_type;
|
||||
result_type operator()(argument_type const &s) const
|
||||
{
|
||||
return s.c_str() ? g_str_hash(s.c_str()) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<gi::cstring_v>
|
||||
{
|
||||
typedef gi::cstring_v argument_type;
|
||||
typedef std::size_t result_type;
|
||||
result_type operator()(argument_type const &s) const
|
||||
{
|
||||
return s.c_str() ? g_str_hash(s.c_str()) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // GI_STRING_HPP
|
||||
545
cmake/external/glib/cppgir/gi/value.hpp
vendored
Normal file
545
cmake/external/glib/cppgir/gi/value.hpp
vendored
Normal file
@@ -0,0 +1,545 @@
|
||||
#ifndef GI_VALUE_HPP
|
||||
#define GI_VALUE_HPP
|
||||
|
||||
#include "exception.hpp"
|
||||
#include "wrap.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
namespace repository
|
||||
{
|
||||
// specialize to declare gtype info
|
||||
// if not within class get_type()
|
||||
// gvalue info can also be included this way
|
||||
// to inject support into Value wrapper
|
||||
template<typename T>
|
||||
struct declare_gtype_of : public std::false_type
|
||||
{};
|
||||
|
||||
} // namespace repository
|
||||
|
||||
namespace traits
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T, class Enable = void>
|
||||
struct gtype : public std::false_type
|
||||
{
|
||||
static GType get_type()
|
||||
{
|
||||
// dummy test to trigger (almost) always
|
||||
static_assert(std::is_void<T>::value, "type is not a registered GType");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// gboxed/gobject (or otherwise class) cases
|
||||
template<typename T>
|
||||
struct gtype<T, typename if_valid_type<decltype(T::get_type_())>::type>
|
||||
: public std::true_type
|
||||
{
|
||||
typedef typename std::remove_reference<T>::type CppType;
|
||||
static GType get_type() { return CppType::get_type_(); }
|
||||
};
|
||||
|
||||
// otherwise externally declared
|
||||
template<typename T>
|
||||
struct gtype<T, typename if_valid_type<decltype(repository::declare_gtype_of<
|
||||
T>::get_type())>::type> : public std::true_type
|
||||
{
|
||||
static constexpr GType (
|
||||
*get_type)() = repository::declare_gtype_of<T>::get_type;
|
||||
};
|
||||
|
||||
// gvalue helper info
|
||||
template<typename T, class Enable = void>
|
||||
struct gvalue : public std::false_type
|
||||
{};
|
||||
|
||||
// as declared (both of set_value and get_value or neither)
|
||||
template<typename T>
|
||||
struct gvalue<T,
|
||||
typename if_valid_type<decltype(repository::declare_gtype_of<T>::get_value(
|
||||
nullptr))>::type> : public std::true_type
|
||||
{
|
||||
static T get(const GValue *val)
|
||||
{
|
||||
return repository::declare_gtype_of<T>::get_value(val);
|
||||
}
|
||||
static void set(GValue *val, T t)
|
||||
{
|
||||
repository::declare_gtype_of<T>::set_value(val, t);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using is_enum_or_bitfield =
|
||||
typename std::conditional<std::is_enum<T>::value && gtype<T>::value,
|
||||
std::true_type, std::false_type>::type;
|
||||
|
||||
// handle enum/flags cases, rather than many declares
|
||||
template<typename T>
|
||||
struct gvalue<T, typename std::enable_if<is_enum_or_bitfield<T>::value>::type>
|
||||
: public std::true_type
|
||||
{
|
||||
static T get(const GValue *val)
|
||||
{
|
||||
GType t = gtype<T>::get_type();
|
||||
if (G_TYPE_IS_FLAGS(t))
|
||||
return static_cast<T>(g_value_get_flags(val));
|
||||
// assume enum, let glib complain otherwise
|
||||
return static_cast<T>(g_value_get_enum(val));
|
||||
}
|
||||
|
||||
static void set(GValue *val, T v)
|
||||
{
|
||||
GType t = gtype<T>::get_type();
|
||||
if (G_TYPE_IS_FLAGS(t)) {
|
||||
g_value_set_flags(val, (guint)v);
|
||||
} else {
|
||||
// assume enum, let glib complain otherwise
|
||||
g_value_set_enum(val, (gint)v);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
using gtype = detail::gtype<
|
||||
typename std::decay<typename std::remove_reference<T>::type>::type>;
|
||||
|
||||
template<typename T>
|
||||
using gvalue = detail::gvalue<
|
||||
typename std::decay<typename std::remove_reference<T>::type>::type>;
|
||||
|
||||
template<typename T>
|
||||
using is_enum_or_bitfield = detail::is_enum_or_bitfield<
|
||||
typename std::decay<typename std::remove_reference<T>::type>::type>;
|
||||
|
||||
#if 0
|
||||
template<typename T, typename Enable = void>
|
||||
struct is_flag : public std::false_type {};
|
||||
|
||||
// TODO extend fundamental type stuff ??
|
||||
template<typename T>
|
||||
struct is_flag<T,
|
||||
typename std::enable_if<std::is_enum<T>::value &&
|
||||
repository::declare_gtype_of<T>::get_fundamental_type() == G_TYPE_FLAGS>::type> :
|
||||
public std::true_type {};
|
||||
#endif
|
||||
|
||||
} // namespace traits
|
||||
|
||||
// C++ types are used below (e.g. int) instead of e.g. gint
|
||||
// since gint64 might map to same as glong (or not)
|
||||
// so some of the int types are "best approximation" from C++ type to GType
|
||||
// instead; use the following types to guide to the right overload
|
||||
typedef char vchar;
|
||||
typedef long vlong;
|
||||
typedef int vint;
|
||||
typedef long long vint64;
|
||||
typedef bool vboolean;
|
||||
|
||||
typedef unsigned char vuchar;
|
||||
typedef unsigned long vulong;
|
||||
typedef unsigned int vuint;
|
||||
typedef unsigned long long vuint64;
|
||||
|
||||
typedef float vfloat;
|
||||
typedef double vdouble;
|
||||
|
||||
// NOTE: (plain) char might be signed or unsigned depending on platform
|
||||
// but gchar == char always anyway
|
||||
static_assert(std::is_same<gchar, char>::value, "now what");
|
||||
|
||||
namespace repository
|
||||
{
|
||||
template<>
|
||||
struct declare_gtype_of<void>
|
||||
{
|
||||
static GType get_type() { return G_TYPE_NONE; }
|
||||
};
|
||||
|
||||
#define GI_DECLARE_GTYPE(cpptype, g_type) \
|
||||
template<> \
|
||||
struct declare_gtype_of<cpptype> \
|
||||
{ \
|
||||
static constexpr GType get_type() { return g_type; } \
|
||||
};
|
||||
|
||||
#define GI_DECLARE_GTYPE_VALUE(cpptype, g_type, value_suffix) \
|
||||
template<> \
|
||||
struct declare_gtype_of<cpptype> \
|
||||
{ \
|
||||
static constexpr GType get_type() { return g_type; } \
|
||||
static void set_value(GValue *val, cpptype v) \
|
||||
{ \
|
||||
g_value_set_##value_suffix(val, v); \
|
||||
} \
|
||||
static cpptype get_value(const GValue *val) \
|
||||
{ \
|
||||
return g_value_get_##value_suffix(val); \
|
||||
} \
|
||||
};
|
||||
|
||||
// declare non-cv qualified type
|
||||
GI_DECLARE_GTYPE_VALUE(gpointer, G_TYPE_POINTER, pointer)
|
||||
GI_DECLARE_GTYPE_VALUE(bool, G_TYPE_BOOLEAN, boolean)
|
||||
GI_DECLARE_GTYPE_VALUE(char, G_TYPE_CHAR, schar)
|
||||
GI_DECLARE_GTYPE_VALUE(unsigned char, G_TYPE_UCHAR, uchar)
|
||||
GI_DECLARE_GTYPE_VALUE(int, G_TYPE_INT, int)
|
||||
GI_DECLARE_GTYPE_VALUE(unsigned int, G_TYPE_UINT, uint)
|
||||
GI_DECLARE_GTYPE_VALUE(long, G_TYPE_LONG, long)
|
||||
GI_DECLARE_GTYPE_VALUE(unsigned long, G_TYPE_ULONG, ulong)
|
||||
GI_DECLARE_GTYPE_VALUE(long long, G_TYPE_INT64, int64)
|
||||
GI_DECLARE_GTYPE_VALUE(unsigned long long, G_TYPE_UINT64, uint64)
|
||||
GI_DECLARE_GTYPE_VALUE(float, G_TYPE_FLOAT, float)
|
||||
GI_DECLARE_GTYPE_VALUE(double, G_TYPE_DOUBLE, double)
|
||||
// some custom set/get for these
|
||||
// remember; the pointer is non-const
|
||||
GI_DECLARE_GTYPE(const char *, G_TYPE_STRING)
|
||||
GI_DECLARE_GTYPE(char *, G_TYPE_STRING)
|
||||
GI_DECLARE_GTYPE(std::string, G_TYPE_STRING)
|
||||
GI_DECLARE_GTYPE(gi::cstring, G_TYPE_STRING)
|
||||
GI_DECLARE_GTYPE(gi::cstring_v, G_TYPE_STRING)
|
||||
|
||||
#undef GI_DECLARE_GTYPE_VALUE
|
||||
#undef GI_DECLARE_GTYPE
|
||||
|
||||
} // namespace repository
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// GValue helpers
|
||||
|
||||
// set_value
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::gvalue<T>::value>::type * = nullptr>
|
||||
inline void
|
||||
set_value(GValue *val, T v)
|
||||
{
|
||||
traits::gvalue<T>::set(val, v);
|
||||
}
|
||||
|
||||
inline void
|
||||
set_value(GValue *val, const std::string &s)
|
||||
{
|
||||
g_value_set_string(val, s.c_str());
|
||||
}
|
||||
|
||||
inline void
|
||||
set_value(GValue *val, gi::cstring_v s)
|
||||
{
|
||||
g_value_set_string(val, s.c_str());
|
||||
}
|
||||
|
||||
inline void
|
||||
set_value(GValue *val, const char *s)
|
||||
{
|
||||
g_value_set_string(val, s);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::is_object<T>::value>::type * = nullptr>
|
||||
inline void
|
||||
set_value(GValue *val, T v)
|
||||
{
|
||||
// set might not handle NULL case
|
||||
g_value_take_object(val, v.gobj_copy_());
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::is_gboxed<T>::value>::type * = nullptr>
|
||||
inline void
|
||||
set_value(GValue *val, T v)
|
||||
{
|
||||
// set might not handle NULL case
|
||||
g_value_take_boxed(val, v.gobj_copy_());
|
||||
}
|
||||
|
||||
// container case
|
||||
template<typename T, typename T::_detail::DataType * = nullptr>
|
||||
inline void
|
||||
set_value(GValue *val, T v)
|
||||
{
|
||||
v._set_value(val);
|
||||
}
|
||||
|
||||
// get_value
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::is_object<T>::value>::type * = nullptr>
|
||||
inline T
|
||||
get_value(const GValue *val)
|
||||
{
|
||||
// ensure sanity
|
||||
static_assert(std::is_class<T>::value && !std::is_const<T>::value,
|
||||
"non cv-qualified class type required");
|
||||
auto cv =
|
||||
static_cast<typename traits::ctype<T>::type>(g_value_dup_object(val));
|
||||
if (cv && !g_type_is_a(G_OBJECT_TYPE(cv), traits::gtype<T>::get_type()))
|
||||
detail::try_throw(transform_error(G_OBJECT_TYPE(cv)));
|
||||
return gi::wrap(cv, transfer_full);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::is_gboxed<T>::value &&
|
||||
!traits::is_reftype<T>::value>::type * = nullptr>
|
||||
inline T
|
||||
get_value(const GValue *val)
|
||||
{
|
||||
// no way to know whether boxed type is correct
|
||||
// ensure sanity
|
||||
static_assert(std::is_class<T>::value && !std::is_const<T>::value,
|
||||
"non cv-qualified class type required");
|
||||
auto cv =
|
||||
static_cast<typename traits::ctype<T>::type>(g_value_dup_boxed(val));
|
||||
return gi::wrap(cv, transfer_full);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::is_gboxed<T>::value &&
|
||||
traits::is_reftype<T>::value>::type * = nullptr>
|
||||
inline T
|
||||
get_value(const GValue *val)
|
||||
{
|
||||
// no way to know whether boxed type is correct
|
||||
// ensure sanity
|
||||
static_assert(std::is_class<T>::value && !std::is_const<T>::value,
|
||||
"non cv-qualified class type required");
|
||||
auto cv =
|
||||
static_cast<typename traits::ctype<T>::type>(g_value_get_boxed(val));
|
||||
return gi::wrap(cv, transfer_none);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::gvalue<T>::value>::type * = nullptr>
|
||||
inline T
|
||||
get_value(const GValue *val)
|
||||
{
|
||||
return traits::gvalue<T>::get(val);
|
||||
}
|
||||
|
||||
// sigh ...
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_same<T, std::string>::value ||
|
||||
std::is_base_of<detail::String, T>::value>::type * =
|
||||
nullptr>
|
||||
inline T
|
||||
get_value(const GValue *val)
|
||||
{
|
||||
return gi::wrap(g_value_get_string(val), transfer_none);
|
||||
}
|
||||
|
||||
// container case
|
||||
template<typename T, typename T::_detail::DataType * = nullptr>
|
||||
inline T
|
||||
get_value(const GValue *val)
|
||||
{
|
||||
static_assert(traits::is_decayed<T>::value, "");
|
||||
return T::template _get_value<T>(val);
|
||||
}
|
||||
|
||||
// convenience helper ...
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_same<T, void>::value>::type * = nullptr>
|
||||
inline T
|
||||
get_value(const GValue * /*val*/)
|
||||
{}
|
||||
|
||||
// simple (RAII) Value wrapper for (internal) use
|
||||
struct Value : public GValue, noncopyable
|
||||
{
|
||||
void clear() { memset((void *)this, 0, sizeof(*this)); }
|
||||
|
||||
Value() { clear(); }
|
||||
|
||||
template<typename T, typename Enable = disable_if_same_or_derived<T, Value>>
|
||||
explicit Value(T &&v)
|
||||
{
|
||||
clear();
|
||||
g_value_init(this, traits::gtype<T>::get_type());
|
||||
set_value(this, std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void init()
|
||||
{
|
||||
// handle no-op void (return value) corner case
|
||||
const GType tp = traits::gtype<T>::get_type();
|
||||
if (tp != G_TYPE_NONE)
|
||||
g_value_init(this, tp);
|
||||
}
|
||||
|
||||
// let's not copy, but ok to move around
|
||||
Value(Value &&other)
|
||||
{
|
||||
memcpy((void *)this, &other, sizeof(*this));
|
||||
other.clear();
|
||||
}
|
||||
|
||||
Value &operator=(Value &&other)
|
||||
{
|
||||
if (this != &other) {
|
||||
memcpy((void *)this, &other, sizeof(*this));
|
||||
other.clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Value()
|
||||
{
|
||||
if (G_VALUE_TYPE(this))
|
||||
g_value_unset(this);
|
||||
}
|
||||
};
|
||||
|
||||
// we really rely upon this as part of the ABI
|
||||
// justifies operations above and some explicit casts above
|
||||
// (to avoid -Wclass-memaccess)
|
||||
static_assert(sizeof(Value) == sizeof(GValue), "unsupported compiler");
|
||||
|
||||
template<typename R>
|
||||
inline R
|
||||
transform_value(const GValue *val)
|
||||
{
|
||||
detail::Value dest;
|
||||
dest.init<R>();
|
||||
if (!g_value_transform(val, &dest))
|
||||
detail::try_throw(detail::transform_error(G_VALUE_TYPE(&dest)));
|
||||
return detail::get_value<R>(&dest);
|
||||
}
|
||||
|
||||
// hand-crafted Value wrapper with an interface as it would be generated
|
||||
// and used by generated code, along with additional convenience
|
||||
class ValueBase : public gi::detail::GBoxedWrapperBase<ValueBase, GValue>
|
||||
{
|
||||
using self_type = ValueBase;
|
||||
|
||||
public:
|
||||
static GType get_type_() G_GNUC_CONST { return G_TYPE_VALUE; }
|
||||
|
||||
void copy(self_type dest) const { g_value_copy(gobj_(), dest.gobj_()); }
|
||||
|
||||
void reset() { g_value_reset(gobj_()); }
|
||||
|
||||
void unset() { g_value_unset(gobj_()); }
|
||||
|
||||
bool transform(self_type dest) const
|
||||
{
|
||||
return g_value_transform(gobj_(), dest.gobj_());
|
||||
}
|
||||
|
||||
static bool type_compatible(GType src_type, GType dest_type)
|
||||
{
|
||||
return g_value_type_compatible(src_type, dest_type);
|
||||
}
|
||||
|
||||
static bool type_transformable(GType src_type, GType dest_type)
|
||||
{
|
||||
return g_value_type_transformable(src_type, dest_type);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
self_type &set_value(T &&v)
|
||||
{
|
||||
detail::set_value(gobj_(), std::forward<T>(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T get_value() const
|
||||
{
|
||||
return detail::get_value<T>(gobj_());
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
R transform_value()
|
||||
{
|
||||
return detail::transform_value<R>(gobj_());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace repository
|
||||
{
|
||||
namespace GObject
|
||||
{
|
||||
// build on above base with additional convenience (in owning case)
|
||||
class Value_Ref;
|
||||
class Value : public gi::detail::GBoxedWrapper<Value, GValue, detail::ValueBase,
|
||||
Value_Ref>
|
||||
{
|
||||
typedef gi::detail::GBoxedWrapper<Value, GValue, detail::ValueBase, Value_Ref>
|
||||
super_type;
|
||||
typedef Value self_type;
|
||||
|
||||
public:
|
||||
using detail::ValueBase::copy;
|
||||
using super_type::copy;
|
||||
|
||||
// hybrid GBoxed/CBoxed
|
||||
void allocate_()
|
||||
{
|
||||
if (this->data_)
|
||||
return;
|
||||
// make sure we match GValue boxed allocation with boxed free
|
||||
// (though last kown implementation uses g_new0/g_free)
|
||||
detail::Value tmp;
|
||||
this->data_ = (::GValue *)g_boxed_copy(G_TYPE_VALUE, &tmp);
|
||||
}
|
||||
|
||||
// convenience
|
||||
Value() { allocate_(); }
|
||||
|
||||
// allow non-explicit use for convenient calling
|
||||
// but avoid copy/move construct use
|
||||
template<typename T,
|
||||
typename std::enable_if<!std::is_base_of<Value,
|
||||
typename std::remove_reference<T>::type>::value>::type * = nullptr>
|
||||
Value(T &&t)
|
||||
{
|
||||
allocate_();
|
||||
init<T>(std::forward<T>(t));
|
||||
}
|
||||
|
||||
Value &init(GType tp)
|
||||
{
|
||||
// no-op void corner case
|
||||
if (tp != G_TYPE_NONE)
|
||||
g_value_init(gobj_(), tp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Value &init(T &&v)
|
||||
{
|
||||
g_value_init(gobj_(), traits::gtype<T>::get_type());
|
||||
set_value(std::forward<T>(v));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class Value_Ref
|
||||
: public gi::detail::GBoxedRefWrapper<Value, ::GValue, detail::ValueBase>
|
||||
{
|
||||
typedef gi::detail::GBoxedRefWrapper<Value, ::GValue, detail::ValueBase>
|
||||
super_type;
|
||||
using super_type::super_type;
|
||||
};
|
||||
|
||||
} // namespace GObject
|
||||
|
||||
template<>
|
||||
struct declare_cpptype_of<GValue>
|
||||
{
|
||||
typedef GObject::Value type;
|
||||
};
|
||||
|
||||
} // namespace repository
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // GI_VALUE_HPP
|
||||
369
cmake/external/glib/cppgir/gi/wrap.hpp
vendored
Normal file
369
cmake/external/glib/cppgir/gi/wrap.hpp
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
#ifndef GI_WRAP_HPP
|
||||
#define GI_WRAP_HPP
|
||||
|
||||
#include "base.hpp"
|
||||
#include "string.hpp"
|
||||
|
||||
GI_MODULE_EXPORT
|
||||
namespace gi
|
||||
{
|
||||
// object/wrapper conversion
|
||||
template<typename CType, typename TransferType,
|
||||
typename CppType = typename traits::cpptype<CType *>::type,
|
||||
typename Enable =
|
||||
typename std::enable_if<traits::is_wrapper<CppType>::value>::type>
|
||||
inline typename std::remove_const<CppType>::type
|
||||
wrap(CType *v, const TransferType &t)
|
||||
{
|
||||
// should be called with a concrete transfer subtype
|
||||
static_assert(!std::is_same<TransferType, transfer_t>::value, "");
|
||||
// the class wrap only has to deal with non-const class type
|
||||
typedef typename std::remove_const<CppType>::type TNC;
|
||||
return CppType::template wrap<TNC>(v, t.value);
|
||||
}
|
||||
|
||||
// special case; wrap an owned box with full transfer
|
||||
template<typename CType,
|
||||
typename CppType = typename traits::cpptype<CType *>::type,
|
||||
typename Enable =
|
||||
typename std::enable_if<traits::is_boxed<CppType>::value>::type,
|
||||
typename TNC = typename std::remove_const<CppType>::type>
|
||||
inline TNC
|
||||
wrap(CType *v, const transfer_full_t &)
|
||||
{
|
||||
return CppType::template wrap<TNC>(v);
|
||||
}
|
||||
|
||||
// special case; wrap a unowned box (that is, transfer none) to the Ref type
|
||||
template<typename CType,
|
||||
typename CppType = typename traits::cpptype<CType *>::type,
|
||||
typename Enable =
|
||||
typename std::enable_if<traits::is_boxed<CppType>::value>::type,
|
||||
typename RefType = typename traits::reftype<
|
||||
typename std::remove_const<CppType>::type>::type>
|
||||
inline RefType
|
||||
wrap(CType *v, const transfer_none_t &)
|
||||
{
|
||||
// unowned and no copy in all cases
|
||||
return RefType::template wrap<RefType>(v);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::remove_reference<T>::type::BaseObjectType * = nullptr>
|
||||
inline typename traits::ctype<T>::type
|
||||
unwrap(T &&v, const transfer_none_t &)
|
||||
{
|
||||
using DT = typename std::decay<T>::type;
|
||||
// test convenience
|
||||
#ifndef GI_TEST
|
||||
static constexpr bool ALLOW_ALL = false;
|
||||
#else
|
||||
static constexpr bool ALLOW_ALL = true;
|
||||
#endif
|
||||
static_assert(ALLOW_ALL || traits::is_wrapper<DT>::value ||
|
||||
traits::is_reftype<DT>::value,
|
||||
"transfer none expects refcnt wrapper or reftype (not owning box)");
|
||||
return v.gobj_();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// lvalue
|
||||
template<typename T,
|
||||
typename std::enable_if<!traits::is_boxed<T>::value>::type * = nullptr>
|
||||
inline typename traits::ctype<T>::type
|
||||
unwrap(const T &v, const transfer_full_t &, std::true_type)
|
||||
{
|
||||
// no implicit copy for boxed; should end up in other case
|
||||
static_assert(!traits::is_boxed<T>::value, "boxed copy");
|
||||
return v.gobj_copy_();
|
||||
}
|
||||
|
||||
// rvalue
|
||||
template<typename T,
|
||||
typename std::enable_if<!traits::is_reftype<T>::value>::type * = nullptr>
|
||||
inline typename traits::ctype<T>::type
|
||||
unwrap(T &&v, const transfer_full_t &, std::false_type)
|
||||
{
|
||||
// in case of wrapper/object;
|
||||
// release only provided on base case with void* return
|
||||
return (typename traits::ctype<T>::type)v.release_();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename std::decay<T>::type::BaseObjectType * = nullptr>
|
||||
inline typename traits::ctype<T>::type
|
||||
unwrap(T &&v, const transfer_full_t &t)
|
||||
{
|
||||
// universal reference dispatch
|
||||
return detail::unwrap(std::forward<T>(v), t, std::is_lvalue_reference<T>());
|
||||
}
|
||||
|
||||
// container types
|
||||
template<typename T, typename Transfer,
|
||||
typename std::decay<T>::type::_detail::DataType * = nullptr>
|
||||
inline typename std::decay<T>::type::_detail::DataType
|
||||
unwrap(T &&v, const Transfer &t)
|
||||
{
|
||||
// universal reference dispatch
|
||||
return std::forward<T>(v)._unwrap(t);
|
||||
}
|
||||
|
||||
// to wrap a container, the target wrapped type needs to be explicitly specified
|
||||
// (in particular the contained element type)
|
||||
// (target type should be decay'ed type)
|
||||
|
||||
// generic case, let wrap take care of it (usually no target type is needed)
|
||||
template<typename TargetType, typename CType, typename Transfer,
|
||||
decltype(wrap(std::declval<typename std::decay<CType>::type>(),
|
||||
Transfer())) * = nullptr>
|
||||
TargetType
|
||||
wrap_to(CType v, const Transfer &t)
|
||||
{
|
||||
static_assert(traits::is_decayed<TargetType>::value, "");
|
||||
return wrap(v, t);
|
||||
}
|
||||
|
||||
// container case
|
||||
template<typename TargetType, typename CType, typename Transfer,
|
||||
typename TargetType::_detail::DataType * = nullptr>
|
||||
TargetType
|
||||
wrap_to(CType v, const Transfer &t)
|
||||
{
|
||||
static_assert(traits::is_decayed<TargetType>::value, "");
|
||||
return TargetType::template _wrap<TargetType>(v, t);
|
||||
}
|
||||
|
||||
// container size case
|
||||
template<typename TargetType, typename CType, typename Transfer,
|
||||
typename TargetType::_detail::DataType * = nullptr>
|
||||
TargetType
|
||||
wrap_to(CType v, int s, const Transfer &t)
|
||||
{
|
||||
static_assert(traits::is_decayed<TargetType>::value, "");
|
||||
return TargetType::template _wrap<TargetType>(v, s, t);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// string conversion
|
||||
inline std::string
|
||||
wrap(const char *v, const transfer_none_t &,
|
||||
const direction_t & = direction_dummy)
|
||||
{
|
||||
return detail::make_string(v);
|
||||
}
|
||||
|
||||
// actually should not accept const input (as it makes no sense for full
|
||||
// transfer) but let's go the runtime way and not mind that too much (code
|
||||
// generation will warn though)
|
||||
inline std::string
|
||||
wrap(const char *v, const transfer_full_t &,
|
||||
const direction_t & = direction_dummy)
|
||||
{
|
||||
// a custom type that would allow direct mem transfer might be nice
|
||||
// but that might be too nifty and create yet-another-string-type
|
||||
std::string s;
|
||||
if (v) {
|
||||
s = v;
|
||||
g_free((char *)v);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
#else
|
||||
// string conversion
|
||||
inline gi::cstring_v
|
||||
wrap(const char *v, const transfer_none_t &)
|
||||
{
|
||||
return cstring_v(v);
|
||||
}
|
||||
|
||||
// actually should not accept const input (as it makes no sense for full
|
||||
// transfer) but let's go the runtime way and not mind that too much (code
|
||||
// generation will warn though)
|
||||
inline gi::cstring
|
||||
wrap(const char *v, const transfer_full_t &)
|
||||
{
|
||||
// as said, never mind const
|
||||
return cstring{(char *)v, transfer_full};
|
||||
}
|
||||
#endif
|
||||
|
||||
// return const here, as somewhat customary, also
|
||||
// wrapped function call is force-casted anyway (to const char* parameter)
|
||||
// FIXME ?? though const is generally rare and it breaks consistency that way
|
||||
inline const gchar *
|
||||
unwrap(const std::string &v, const transfer_none_t &)
|
||||
{
|
||||
return v.c_str();
|
||||
}
|
||||
|
||||
inline const gchar *
|
||||
unwrap(const detail::optional_string &v, const transfer_none_t &)
|
||||
{
|
||||
return v.empty() ? nullptr : v.c_str();
|
||||
}
|
||||
|
||||
template<typename Transfer>
|
||||
inline const gchar *
|
||||
unwrap(const detail::cstr<Transfer> &v, const transfer_none_t &)
|
||||
{
|
||||
return v.c_str();
|
||||
}
|
||||
|
||||
// R-value variants of the above, akin to transfer_none from an owning R-value
|
||||
// bad dangling things would happen
|
||||
inline const gchar *unwrap(std::string &&v, const transfer_none_t &) = delete;
|
||||
|
||||
inline const gchar *unwrap(
|
||||
detail::optional_string &&v, const transfer_none_t &) = delete;
|
||||
|
||||
template<typename Transfer>
|
||||
inline const gchar *
|
||||
unwrap(detail::cstr<Transfer> &&v, const transfer_none_t &)
|
||||
{
|
||||
static_assert(std::is_same<Transfer, transfer_none_t>::value,
|
||||
"transfer none expects non-owning type");
|
||||
return v.c_str();
|
||||
}
|
||||
|
||||
inline gchar *
|
||||
unwrap(const std::string &v, const transfer_full_t &)
|
||||
{
|
||||
return g_strdup(v.c_str());
|
||||
}
|
||||
|
||||
inline gchar *
|
||||
unwrap(const detail::optional_string &v, const transfer_full_t &)
|
||||
{
|
||||
return v.empty() ? nullptr : g_strdup(v.c_str());
|
||||
}
|
||||
|
||||
template<typename Transfer>
|
||||
inline gchar *
|
||||
unwrap(const gi::detail::cstr<Transfer> &v, const transfer_full_t &)
|
||||
{
|
||||
return g_strdup(v.c_str());
|
||||
}
|
||||
|
||||
inline gchar *
|
||||
unwrap(gi::cstring &&v, const transfer_full_t &)
|
||||
{
|
||||
return v.release_();
|
||||
}
|
||||
|
||||
// enum conversion
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
|
||||
inline typename traits::cpptype<T>::type
|
||||
wrap(T v, const transfer_t & = transfer_dummy)
|
||||
{
|
||||
return (typename traits::cpptype<T>::type)v;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
|
||||
inline typename traits::ctype<T>::type
|
||||
unwrap(T v, const transfer_t & = transfer_dummy)
|
||||
{
|
||||
return (typename traits::ctype<T>::type)v;
|
||||
}
|
||||
|
||||
// plain basic pass along
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::is_basic<T>::value>::type * = nullptr>
|
||||
inline T
|
||||
wrap(T v, const transfer_t & = transfer_dummy)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<traits::is_basic<T>::value>::type * = nullptr>
|
||||
inline T
|
||||
unwrap(T v, const transfer_t & = transfer_dummy)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
// callback conversion
|
||||
// async or destroy-notify;
|
||||
// signature forces copy, and std::move is used in unwrap call
|
||||
template<typename T,
|
||||
typename std::remove_reference<T>::type::CallbackWrapperType * = nullptr>
|
||||
inline typename std::remove_reference<T>::type::CallbackWrapperType
|
||||
unwrap(T &&v, const transfer_t & = transfer_dummy)
|
||||
{
|
||||
return typename std::remove_reference<T>::type::CallbackWrapperType(
|
||||
std::forward<T>(v));
|
||||
}
|
||||
|
||||
// call or destroy-notify scope
|
||||
template<typename T>
|
||||
inline typename std::remove_reference<T>::type::template wrapper_type<false> *
|
||||
unwrap(T &&v, const scope_t &)
|
||||
{
|
||||
return new
|
||||
typename std::remove_reference<T>::type::template wrapper_type<false>(
|
||||
std::forward<T>(v));
|
||||
}
|
||||
|
||||
// async scope
|
||||
template<typename T>
|
||||
inline typename std::remove_reference<T>::type::template wrapper_type<true> *
|
||||
unwrap(T &&v, const scope_async_t &)
|
||||
{
|
||||
return new
|
||||
typename std::remove_reference<T>::type::template wrapper_type<true>(
|
||||
std::forward<T>(v));
|
||||
}
|
||||
|
||||
// dynamic GType casting within GObject/interface hierarchy
|
||||
template<typename T, typename I,
|
||||
typename std::enable_if<
|
||||
traits::is_object<T>::value &&
|
||||
traits::is_object<typename std::decay<I>::type>::value>::type * =
|
||||
nullptr>
|
||||
inline T
|
||||
object_cast(I &&t)
|
||||
{
|
||||
if (!t || !g_type_is_a(t.gobj_type_(), T::get_type_())) {
|
||||
return T();
|
||||
} else {
|
||||
return wrap((typename T::BaseObjectType *)t.gobj_copy_(), transfer_full);
|
||||
}
|
||||
}
|
||||
|
||||
// this utility can be used to arrange for pointer-like const-ness
|
||||
// that is, a const shared_ptr<T> is still usable like (non-const) T*
|
||||
// in a way, any wrapper object T acts much like a smart-pointer,
|
||||
// but as the (code generated) methods are non-const, they are not usable
|
||||
// if the wrapper object is const (e.g. captured in a lambda)
|
||||
// this helper object/class can be wrapped around the wrapper (phew)
|
||||
// to absorb/shield the (outer) `const` (as it behaves as other smart pointers)
|
||||
template<typename T>
|
||||
class cs_ptr
|
||||
{
|
||||
T t;
|
||||
|
||||
public:
|
||||
// rough check; T is expected to be a pointer wrapper
|
||||
static_assert(sizeof(T) == sizeof(void *), "");
|
||||
|
||||
// if T not copy-able, argument may need to be move'd
|
||||
cs_ptr(T _t) : t(std::move(_t)) {}
|
||||
|
||||
operator T() const & { return t; }
|
||||
operator T() && { return std::move(t); }
|
||||
|
||||
T *get() const { return &t; }
|
||||
|
||||
// C++ sacrilege,
|
||||
// but the const of pointer in T does not extend to pointee anyway
|
||||
T *operator*() const { return const_cast<T *>(&t); }
|
||||
T *operator->() const { return const_cast<T *>(&t); }
|
||||
};
|
||||
|
||||
} // namespace gi
|
||||
|
||||
#endif // GI_WRAP_HPP
|
||||
Reference in New Issue
Block a user