| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- #ifndef GI_ENUMFLAG_HPP
- #define GI_ENUMFLAG_HPP
- #include "base.hpp"
- #include "exception.hpp"
- #include "value.hpp"
- #include <type_traits>
- 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)
- #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); \
- }
- /* 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
|