Merge pull request #1055 from KLayout/enums-vs-int

Enums vs int
This commit is contained in:
Matthias Köfferlein 2022-04-09 18:07:57 +02:00 committed by GitHub
commit 19aac2abd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 346 additions and 8 deletions

View File

@ -30,6 +30,7 @@
#include "tlTypeTraits.h"
#include "tlHeap.h"
#include "tlUtils.h"
#include "tlVariant.h"
#include <memory>
@ -76,7 +77,7 @@ struct _var_user_less_impl<T, false>
};
/**
* @brief A helper function to implement equal as efficiently as possible
* @brief A helper function to implement to_string as efficiently as possible
*/
template<class T, bool> struct _var_user_to_string_impl;
@ -92,6 +93,57 @@ struct _var_user_to_string_impl<T, false>
static std::string call (const T *a, const VariantUserClassImpl *delegate) { return delegate->to_string_impl ((void *) a); }
};
/**
* @brief A helper function to implement to_variant as efficiently as possible
*/
template<class T, bool> struct _var_user_to_variant_impl;
template<class T>
struct _var_user_to_variant_impl<T, true>
{
static tl::Variant call (const T *a, const VariantUserClassImpl * /*delegate*/) { return a->to_variant (); }
};
template<class T>
struct _var_user_to_variant_impl<T, false>
{
static tl::Variant call (const T *a, const VariantUserClassImpl *delegate) { return delegate->to_variant_impl ((void *) a); }
};
/**
* @brief A helper function to implement to_int as efficiently as possible
*/
template<class T, bool> struct _var_user_to_int_impl;
template<class T>
struct _var_user_to_int_impl<T, true>
{
static int call (const T *a, const VariantUserClassImpl * /*delegate*/) { return a->to_int (); }
};
template<class T>
struct _var_user_to_int_impl<T, false>
{
static int call (const T *a, const VariantUserClassImpl *delegate) { return delegate->to_int_impl ((void *) a); }
};
/**
* @brief A helper function to implement to_double as efficiently as possible
*/
template<class T, bool> struct _var_user_to_double_impl;
template<class T>
struct _var_user_to_double_impl<T, true>
{
static double call (const T *a, const VariantUserClassImpl * /*delegate*/) { return a->to_double (); }
};
template<class T>
struct _var_user_to_double_impl<T, false>
{
static double call (const T *a, const VariantUserClassImpl *delegate) { return delegate->to_double_impl ((void *) a); }
};
/**
* @brief A VariantUserClassBase specialization that links GSI classes and Variant classes
*/
@ -152,11 +204,26 @@ public:
return gsi::_var_user_less_impl<T, tl::has_less_operator<T>::value>::call ((const T *) a, (const T *) b, this);
}
virtual void to_variant (const void *a, tl::Variant &var) const
{
var = gsi::_var_user_to_variant_impl<T, tl::has_to_variant<T>::value>::call ((const T *) a, this);
}
virtual std::string to_string (const void *a) const
{
return gsi::_var_user_to_string_impl<T, tl::has_to_string<T>::value>::call ((const T *) a, this);
}
virtual int to_int (const void *a) const
{
return gsi::_var_user_to_int_impl<T, tl::has_to_int<T>::value>::call ((const T *) a, this);
}
virtual double to_double (const void *a) const
{
return gsi::_var_user_to_double_impl<T, tl::has_to_double<T>::value>::call ((const T *) a, this);
}
void *clone (const void *obj) const
{
void *new_obj = mp_cls->create ();

View File

@ -26,6 +26,7 @@
#include "gsiDecl.h"
#include "tlString.h"
#include "tlVariant.h"
#if defined(HAVE_QT)
# include <QFlags>
@ -60,6 +61,16 @@ public:
E &value () { return m_e; }
const E &value () const { return m_e; }
int to_int () const { return int (m_e); }
tl::Variant to_variant () const { return tl::Variant (int (m_e)); }
std::string to_string () const
{
const Enum<E> *ecls = dynamic_cast<const Enum<E> *> (cls_decl<E> ());
tl_assert (ecls != 0);
return ecls->enum_to_string (m_e);
}
private:
E m_e;
};
@ -209,7 +220,7 @@ public:
return ecls->enum_to_string_inspect (*e);
}
static int enum_to_i (const E *e)
static int enum_to_int (const E *e)
{
return int (*e);
}
@ -219,16 +230,31 @@ public:
return *e == other;
}
static bool enum_ne (const E *e, const E &other)
static bool enum_eq_with_int (const E *e, int other)
{
return int (*e) == other;
}
static bool enum_ne (const E *e, const E &other)
{
return *e != other;
}
static bool enum_lt (const E *e, const E &other)
static bool enum_ne_with_int (const E *e, int other)
{
return int (*e) != other;
}
static bool enum_lt (const E *e, const E &other)
{
return *e < other;
}
static bool enum_lt_with_int (const E *e, int other)
{
return int (*e) < other;
}
static E *new_enum_from_int (int i)
{
return new E (E (i));
@ -248,10 +274,13 @@ public:
gsi::constructor ("new", &new_enum_from_string, gsi::arg("s"), "@brief Creates an enum from a string value") +
gsi::method_ext ("to_s", &enum_to_string_ext, "@brief Gets the symbolic string from an enum") +
gsi::method_ext ("inspect", &enum_to_string_inspect_ext, "@brief Converts an enum to a visual string") +
gsi::method_ext ("to_i", &enum_to_i, "@brief Gets the integer value from the enum") +
gsi::method_ext ("to_i", &enum_to_int, "@brief Gets the integer value from the enum") +
gsi::method_ext ("==", &enum_eq, gsi::arg("other"), "@brief Compares two enums") +
gsi::method_ext ("==", &enum_eq_with_int, gsi::arg("other"), "@brief Compares an enum with an integer value") +
gsi::method_ext ("!=", &enum_ne, gsi::arg("other"), "@brief Compares two enums for inequality") +
gsi::method_ext ("<", &enum_lt, gsi::arg("other"), "@brief Returns true if the first enum is less (in the enum symbol order) than the second");
gsi::method_ext ("!=", &enum_ne_with_int, gsi::arg("other"), "@brief Compares an enum with an integer for inequality") +
gsi::method_ext ("<", &enum_lt, gsi::arg("other"), "@brief Returns true if the first enum is less (in the enum symbol order) than the second") +
gsi::method_ext ("<", &enum_lt_with_int, gsi::arg("other"), "@brief Returns true if the enum is less (in the enum symbol order) than the integer value");
return m + defs ();
}

View File

@ -1241,6 +1241,96 @@ VariantUserClassImpl::to_string_impl (void *obj) const
}
}
tl::Variant
VariantUserClassImpl::to_variant_impl (void *obj) const
{
if (obj) {
if (! has_method ("to_v")) {
// no method to convert the object to a string
return tl::Variant ();
} else {
tl::ExpressionParserContext context;
tl::Variant out;
tl::Variant object (obj, mp_object_cls, false);
std::vector<tl::Variant> vv;
execute_gsi (context, out, object, "to_v", vv);
return out;
}
} else {
return tl::Variant ();
}
}
int
VariantUserClassImpl::to_int_impl (void *obj) const
{
if (obj) {
if (! has_method ("to_i")) {
// no method to convert the object to an integer
return 0;
} else {
tl::ExpressionParserContext context;
tl::Variant out;
tl::Variant object (obj, mp_object_cls, false);
std::vector<tl::Variant> vv;
execute_gsi (context, out, object, "to_i", vv);
return out.to_int ();
}
} else {
return 0;
}
}
double
VariantUserClassImpl::to_double_impl (void *obj) const
{
if (obj) {
if (! has_method ("to_f")) {
// no method to convert the object to a double value
return 0.0;
} else {
tl::ExpressionParserContext context;
tl::Variant out;
tl::Variant object (obj, mp_object_cls, false);
std::vector<tl::Variant> vv;
execute_gsi (context, out, object, "to_f", vv);
return out.to_double ();
}
} else {
return 0.0;
}
}
void
VariantUserClassImpl::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const
{

View File

@ -50,7 +50,10 @@ public:
bool equal_impl (void *, void *) const;
bool less_impl (void *, void *) const;
tl::Variant to_variant_impl (void *) const;
std::string to_string_impl (void *) const;
int to_int_impl (void *) const;
double to_double_impl (void *) const;
virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const;

View File

@ -1984,6 +1984,9 @@ static std::string get_technology (const lay::CellViewRef *cv)
static tl::Event &get_technology_changed_event (lay::CellViewRef *cv)
{
if (! cv->is_valid ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Not a valid cellview")));
}
return (*cv)->technology_changed_event;
}

View File

@ -632,6 +632,14 @@ static std::string extract_python_name (const std::string &name)
static void
pya_object_deallocate (PyObject *self)
{
// This avoids an assertion in debug builds (Python, gcmodule.c - update_refs).
// In short, the GC expects not to see objects with refcount 0 and asserts.
// However, due to triggering of signals or similar, the destructor call below
// may trigger a GC (https://github.com/KLayout/klayout/issues/1054).
// According to the comments this may be turned into a release mode assertion, so
// we better work around it.
++self->ob_refcnt;
PYAObjectBase *p = PYAObjectBase::from_pyobject (self);
p->~PYAObjectBase ();
Py_TYPE (self)->tp_free (self);

View File

@ -71,6 +71,18 @@ inline bool value_of (false_tag) { return false; }
typedef char __yes_type [1];
typedef char __no_type [2];
/**
* @brief Detects whether a class has a "to_variant" method with a matching signature
*/
template <typename T> static __yes_type &__test_to_variant_func (decltype (&T::to_variant));
template <typename> static __no_type &__test_to_variant_func (...);
template <typename T>
struct has_to_variant
{
static constexpr bool value = sizeof (__test_to_variant_func<T> (nullptr)) == sizeof (__yes_type);
};
/**
* @brief Detects whether a class has a "to_string" method with a matching signature
*/
@ -83,6 +95,30 @@ struct has_to_string
static constexpr bool value = sizeof (__test_to_string_func<T> (nullptr)) == sizeof (__yes_type);
};
/**
* @brief Detects whether a class has a "to_int" method with a matching signature
*/
template <typename T> static __yes_type &__test_to_int_func (decltype (&T::to_int));
template <typename> static __no_type &__test_to_int_func (...);
template <typename T>
struct has_to_int
{
static constexpr bool value = sizeof (__test_to_int_func<T> (nullptr)) == sizeof (__yes_type);
};
/**
* @brief Detects whether a class has a "to_double" method with a matching signature
*/
template <typename T> static __yes_type &__test_to_double_func (decltype (&T::to_double));
template <typename> static __no_type &__test_to_double_func (...);
template <typename T>
struct has_to_double
{
static constexpr bool value = sizeof (__test_to_double_func<T> (nullptr)) == sizeof (__yes_type);
};
/**
* @brief Detects whether a class has an equal operator
*/

View File

@ -1820,6 +1820,10 @@ Variant::to_int128 () const
__int128 l = 0;
ex.read (l);
return l;
} else if (m_type == t_user) {
return m_var.mp_user.cls->to_int (m_var.mp_user.object);
} else if (m_type == t_user_ref) {
return m_var.mp_user_ref.cls->to_int (m_var.mp_user_ref.cls->deref_proxy_const (reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ()));
} else {
return 0;
}
@ -1875,6 +1879,10 @@ Variant::to_ulonglong () const
unsigned long long l = 0;
tl::from_string (to_string (), l);
return l;
} else if (m_type == t_user) {
return (unsigned long long) m_var.mp_user.cls->to_int (m_var.mp_user.object);
} else if (m_type == t_user_ref) {
return (unsigned long long) m_var.mp_user_ref.cls->to_int (m_var.mp_user_ref.cls->deref_proxy_const (reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ()));
} else {
return 0;
}
@ -1929,6 +1937,10 @@ Variant::to_longlong () const
long long l = 0;
tl::from_string (to_string (), l);
return l;
} else if (m_type == t_user) {
return (long long) m_var.mp_user.cls->to_int (m_var.mp_user.object);
} else if (m_type == t_user_ref) {
return (long long) m_var.mp_user_ref.cls->to_int (m_var.mp_user_ref.cls->deref_proxy_const (reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ()));
} else {
return 0;
}
@ -1983,6 +1995,10 @@ Variant::to_ulong () const
unsigned long l = 0;
tl::from_string (to_string (), l);
return l;
} else if (m_type == t_user) {
return (unsigned long) m_var.mp_user.cls->to_int (m_var.mp_user.object);
} else if (m_type == t_user_ref) {
return (unsigned long) m_var.mp_user_ref.cls->to_int (m_var.mp_user_ref.cls->deref_proxy_const (reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ()));
} else {
return 0;
}
@ -2037,6 +2053,10 @@ Variant::to_long () const
long l = 0;
tl::from_string (to_string (), l);
return l;
} else if (m_type == t_user) {
return (long) m_var.mp_user.cls->to_int (m_var.mp_user.object);
} else if (m_type == t_user_ref) {
return (long) m_var.mp_user_ref.cls->to_int (m_var.mp_user_ref.cls->deref_proxy_const (reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ()));
} else {
return 0;
}
@ -2143,6 +2163,10 @@ Variant::to_double () const
double d = 0;
tl::from_string (to_string (), d);
return d;
} else if (m_type == t_user) {
return m_var.mp_user.cls->to_double (m_var.mp_user.object);
} else if (m_type == t_user_ref) {
return m_var.mp_user_ref.cls->to_double (m_var.mp_user_ref.cls->deref_proxy_const (reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ()));
} else {
return 0;
}
@ -2513,7 +2537,9 @@ QVariant Variant::to_qvariant () const
} else if (dynamic_cast<const tl::VariantUserClass<QVector4D> *> (cls)) {
return QVariant (to_user<QVector4D> ());
} else {
return QVariant ();
tl::Variant var;
cls->to_variant (to_user (), var);
return var.to_qvariant ();
}
}
default:

View File

@ -53,6 +53,7 @@ namespace gsi
namespace tl
{
class Variant;
class Extractor;
class EvalClass;
template <class T> void extractor_impl (tl::Extractor &, T &);
@ -76,6 +77,9 @@ public:
virtual bool less (const void *, const void *) const = 0;
virtual void *clone (const void *) const = 0;
virtual std::string to_string (const void *) const = 0;
virtual int to_int (const void *) const = 0;
virtual double to_double (const void *) const = 0;
virtual void to_variant (const void *, tl::Variant &var) const = 0;
virtual void read (void *, tl::Extractor &ex) const = 0;
virtual const char *name () const = 0;
virtual bool is_const () const = 0;

View File

@ -119,6 +119,57 @@ struct _var_user_to_string_impl<T, false>
static std::string call (const T *) { tl_assert (false); }
};
/**
* @brief A helper function to implement equal as efficiently as possible
*/
template<class T, bool> struct _var_user_to_int_impl;
template<class T>
struct _var_user_to_int_impl<T, true>
{
static int call (const T *a) { return a->to_int (); }
};
template<class T>
struct _var_user_to_int_impl<T, false>
{
static int call (const T *) { tl_assert (false); }
};
/**
* @brief A helper function to implement equal as efficiently as possible
*/
template<class T, bool> struct _var_user_to_double_impl;
template<class T>
struct _var_user_to_double_impl<T, true>
{
static double call (const T *a) { return a->to_double (); }
};
template<class T>
struct _var_user_to_double_impl<T, false>
{
static double call (const T *) { tl_assert (false); }
};
/**
* @brief A helper function to implement equal as efficiently as possible
*/
template<class T, bool> struct _var_user_to_variant_impl;
template<class T>
struct _var_user_to_variant_impl<T, true>
{
static tl::Variant call (const T *a) { return a->to_variant (); }
};
template<class T>
struct _var_user_to_variant_impl<T, false>
{
static tl::Variant call (const T *) { tl_assert (false); }
};
/**
* @brief A utility implementation of tl::VariantUserClass using type traits for the implementation
*/
@ -162,7 +213,22 @@ public:
return _var_user_to_string_impl<T, tl::has_to_string<T>::value>::call ((const T *) a);
}
virtual void read (void *a, tl::Extractor &ex) const
virtual int to_int (const void *a) const
{
return _var_user_to_int_impl<T, tl::has_to_int<T>::value>::call ((const T *) a);
}
virtual double to_double (const void *a) const
{
return _var_user_to_double_impl<T, tl::has_to_double<T>::value>::call ((const T *) a);
}
virtual void to_variant (const void *a, tl::Variant &v) const
{
v = _var_user_to_variant_impl<T, tl::has_to_variant<T>::value>::call ((const T *) a);
}
virtual void read (void *a, tl::Extractor &ex) const
{
ex.read (*(T *)a);
}

View File

@ -454,6 +454,9 @@ public:
virtual void *clone (const void *) const { tl_assert (false); }
virtual void assign (void *, const void *) const { tl_assert (false); }
virtual std::string to_string (const void *) const { tl_assert (false); }
virtual int to_int (const void *) const { tl_assert (false); }
virtual double to_double (const void *) const { tl_assert (false); }
virtual void to_variant (const void *, tl::Variant &) const { tl_assert (false); }
virtual void read (void *, tl::Extractor &) const { }
virtual const char *name () const { return "Box"; }
virtual unsigned int type_code () const { return 0; }
@ -519,6 +522,9 @@ public:
virtual void *clone (const void *) const { tl_assert (false); }
virtual void assign (void *, const void *) const { tl_assert (false); }
virtual std::string to_string (const void *) const { tl_assert (false); }
virtual int to_int (const void *) const { tl_assert (false); }
virtual double to_double (const void *) const { tl_assert (false); }
virtual void to_variant (const void *, tl::Variant &) const { tl_assert (false); }
virtual void read (void *, tl::Extractor &) const { }
virtual const char *name () const { return "Edge"; }
virtual unsigned int type_code () const { return 0; }