mirror of https://github.com/KLayout/klayout.git
WIP: refactoring
This commit is contained in:
parent
d3a36e66f2
commit
2c18bc6c46
|
|
@ -49,6 +49,7 @@ static int t_double () { return T_double; }
|
|||
static int t_float () { return T_float; }
|
||||
static int t_var () { return T_var; }
|
||||
static int t_string () { return T_string; }
|
||||
static int t_byte_array () { return T_byte_array; }
|
||||
static int t_void_ptr () { return T_void_ptr; }
|
||||
static int t_object () { return T_object; }
|
||||
static int t_vector () { return T_vector; }
|
||||
|
|
@ -77,30 +78,31 @@ static tl::Variant default_value (const ArgType *t)
|
|||
}
|
||||
|
||||
Class<ArgType> decl_ArgType ("tl", "ArgType",
|
||||
gsi::method ("TypeVoid|#t_void", &t_void) +
|
||||
gsi::method ("TypeBool|#t_bool", &t_bool) +
|
||||
gsi::method ("TypeChar|#t_char", &t_char) +
|
||||
gsi::method ("TypeSChar|#t_schar", &t_schar) +
|
||||
gsi::method ("TypeUChar|#t_uchar", &t_uchar) +
|
||||
gsi::method ("TypeShort|#t_short", &t_short) +
|
||||
gsi::method ("TypeUShort|#t_ushort", &t_ushort) +
|
||||
gsi::method ("TypeInt|#t_int", &t_int) +
|
||||
gsi::method ("TypeUInt|#t_uint", &t_uint) +
|
||||
gsi::method ("TypeLong|#t_long", &t_long) +
|
||||
gsi::method ("TypeULong|#t_ulong", &t_ulong) +
|
||||
gsi::method ("TypeLongLong|#t_longlong", &t_longlong) +
|
||||
gsi::method ("TypeULongLong|#t_ulonglong", &t_ulonglong) +
|
||||
gsi::method ("TypeVoid", &t_void) +
|
||||
gsi::method ("TypeBool", &t_bool) +
|
||||
gsi::method ("TypeChar", &t_char) +
|
||||
gsi::method ("TypeSChar", &t_schar) +
|
||||
gsi::method ("TypeUChar", &t_uchar) +
|
||||
gsi::method ("TypeShort", &t_short) +
|
||||
gsi::method ("TypeUShort", &t_ushort) +
|
||||
gsi::method ("TypeInt", &t_int) +
|
||||
gsi::method ("TypeUInt", &t_uint) +
|
||||
gsi::method ("TypeLong", &t_long) +
|
||||
gsi::method ("TypeULong", &t_ulong) +
|
||||
gsi::method ("TypeLongLong", &t_longlong) +
|
||||
gsi::method ("TypeULongLong", &t_ulonglong) +
|
||||
#if defined(HAVE_64BIT_COORD)
|
||||
gsi::method ("TypeInt128|#t_int128", &t_int128) +
|
||||
#endif
|
||||
gsi::method ("TypeDouble|#t_double", &t_double) +
|
||||
gsi::method ("TypeFloat|#t_float", &t_float) +
|
||||
gsi::method ("TypeVar|#t_var", &t_var) +
|
||||
gsi::method ("TypeString|#t_string", &t_string) +
|
||||
gsi::method ("TypeVoidPtr|#t_void_ptr", &t_void_ptr) +
|
||||
gsi::method ("TypeObject|#t_object", &t_object) +
|
||||
gsi::method ("TypeVector|#t_vector", &t_vector) +
|
||||
gsi::method ("TypeMap|#t_map", &t_map) +
|
||||
gsi::method ("TypeDouble", &t_double) +
|
||||
gsi::method ("TypeFloat", &t_float) +
|
||||
gsi::method ("TypeVar", &t_var) +
|
||||
gsi::method ("TypeByteArray", &t_byte_array) +
|
||||
gsi::method ("TypeString", &t_string) +
|
||||
gsi::method ("TypeVoidPtr", &t_void_ptr) +
|
||||
gsi::method ("TypeObject", &t_object) +
|
||||
gsi::method ("TypeVector", &t_vector) +
|
||||
gsi::method ("TypeMap", &t_map) +
|
||||
gsi::method_ext ("type", &type,
|
||||
"@brief Return the basic type (see t_.. constants)\n"
|
||||
) +
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HDR_pyaCallables
|
||||
#define _HDR_pyaCallables
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "pyaCommon.h"
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
void pya_object_deallocate (PyObject *self);
|
||||
int pya_object_init (PyObject * /*self*/, PyObject *args, PyObject *kwds);
|
||||
PyObject *pya_object_new (PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/);
|
||||
|
||||
PyObject *object_default_ne_impl (PyObject *self, PyObject *args);
|
||||
PyObject *object_default_ge_impl (PyObject *self, PyObject *args);
|
||||
PyObject *object_default_le_impl (PyObject *self, PyObject *args);
|
||||
PyObject *object_default_gt_impl (PyObject *self, PyObject *args);
|
||||
|
||||
typedef PyObject *(*py_func_ptr_t) (PyObject *, PyObject *);
|
||||
|
||||
py_func_ptr_t get_method_adaptor (int n);
|
||||
py_func_ptr_t get_property_getter_adaptor (int n);
|
||||
py_func_ptr_t get_property_setter_adaptor (int n);
|
||||
py_func_ptr_t get_method_init_adaptor (int n);
|
||||
|
||||
inline void *make_closure (int mid_getter, int mid_setter)
|
||||
{
|
||||
size_t g = mid_getter < 0 ? (size_t) 0 : (size_t) mid_getter;
|
||||
size_t s = mid_setter < 0 ? (size_t) 0 : (size_t) mid_setter;
|
||||
return (void *) ((s << 16) | g);
|
||||
}
|
||||
|
||||
inline unsigned int getter_from_closure (void *closure)
|
||||
{
|
||||
return (unsigned int) (size_t (closure) & 0xffff);
|
||||
}
|
||||
|
||||
inline unsigned int setter_from_closure (void *closure)
|
||||
{
|
||||
return (unsigned int) (size_t (closure) >> 16);
|
||||
}
|
||||
|
||||
PyObject *property_getter_func (PyObject *self, void *closure);
|
||||
int property_setter_func (PyObject *self, PyObject *value, void *closure);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,793 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "pya.h"
|
||||
#include "pyaInternal.h"
|
||||
#include "pyaModule.h"
|
||||
#include "pyaObject.h"
|
||||
|
||||
#include "tlLog.h"
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// MethodTableEntry implementation
|
||||
|
||||
MethodTableEntry::MethodTableEntry (const std::string &name, bool st, bool prot)
|
||||
: m_name (name), m_is_static (st), m_is_protected (prot), m_is_enabled (true)
|
||||
{ }
|
||||
|
||||
const std::string &
|
||||
MethodTableEntry::name () const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void
|
||||
MethodTableEntry::set_name (const std::string &n)
|
||||
{
|
||||
m_name = n;
|
||||
}
|
||||
|
||||
void
|
||||
MethodTableEntry::set_enabled (bool en)
|
||||
{
|
||||
m_is_enabled = en;
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTableEntry::is_enabled () const
|
||||
{
|
||||
return m_is_enabled;
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTableEntry::is_static () const
|
||||
{
|
||||
return m_is_static;
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTableEntry::is_protected () const
|
||||
{
|
||||
return m_is_protected;
|
||||
}
|
||||
|
||||
void
|
||||
MethodTableEntry::add (const gsi::MethodBase *m)
|
||||
{
|
||||
m_methods.push_back (m);
|
||||
}
|
||||
|
||||
void
|
||||
MethodTableEntry::finish ()
|
||||
{
|
||||
// remove duplicate entries in the method list
|
||||
std::vector<const gsi::MethodBase *> m = m_methods;
|
||||
std::sort(m.begin (), m.end ());
|
||||
m_methods.assign (m.begin (), std::unique (m.begin (), m.end ()));
|
||||
}
|
||||
|
||||
MethodTableEntry::method_iterator
|
||||
MethodTableEntry::begin () const
|
||||
{
|
||||
return m_methods.begin ();
|
||||
}
|
||||
|
||||
MethodTableEntry::method_iterator
|
||||
MethodTableEntry::end () const
|
||||
{
|
||||
return m_methods.end ();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// MethodTable implementation
|
||||
|
||||
MethodTable::MethodTable (const gsi::ClassBase *cls_decl, PythonModule *module)
|
||||
: m_method_offset (0), m_property_offset (0), mp_cls_decl (cls_decl), mp_module (module)
|
||||
{
|
||||
if (cls_decl->base ()) {
|
||||
const MethodTable *base_mt = method_table_by_class (cls_decl->base ());
|
||||
tl_assert (base_mt);
|
||||
m_method_offset = base_mt->top_mid ();
|
||||
m_property_offset = base_mt->top_property_mid ();
|
||||
}
|
||||
|
||||
// signals are translated into the setters and getters
|
||||
for (gsi::ClassBase::method_iterator m = cls_decl->begin_methods (); m != cls_decl->end_methods (); ++m) {
|
||||
if ((*m)->is_signal ()) {
|
||||
for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||
add_getter (syn->name, *m);
|
||||
add_setter (syn->name, *m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// first add getters and setters
|
||||
for (gsi::ClassBase::method_iterator m = cls_decl->begin_methods (); m != cls_decl->end_methods (); ++m) {
|
||||
if (! (*m)->is_callback ()) {
|
||||
for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||
if (syn->is_getter) {
|
||||
add_getter (syn->name, *m);
|
||||
} else if (syn->is_setter) {
|
||||
add_setter (syn->name, *m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then add normal methods - on name clash with properties make them a getter
|
||||
for (gsi::ClassBase::method_iterator m = cls_decl->begin_methods (); m != cls_decl->end_methods (); ++m) {
|
||||
if (! (*m)->is_callback () && ! (*m)->is_signal ()) {
|
||||
for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||
if (! syn->is_getter && ! syn->is_setter) {
|
||||
if ((*m)->end_arguments () - (*m)->begin_arguments () == 0 && find_property ((*m)->is_static (), syn->name).first) {
|
||||
add_getter (syn->name, *m);
|
||||
} else {
|
||||
add_method (syn->name, *m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
MethodTable::bottom_mid () const
|
||||
{
|
||||
return m_method_offset;
|
||||
}
|
||||
|
||||
size_t
|
||||
MethodTable::top_mid () const
|
||||
{
|
||||
return m_method_offset + m_table.size ();
|
||||
}
|
||||
|
||||
size_t
|
||||
MethodTable::bottom_property_mid () const
|
||||
{
|
||||
return m_property_offset;
|
||||
}
|
||||
|
||||
size_t
|
||||
MethodTable::top_property_mid () const
|
||||
{
|
||||
return m_property_offset + m_property_table.size ();
|
||||
}
|
||||
|
||||
std::pair<bool, size_t>
|
||||
MethodTable::find_method (bool st, const std::string &name) const
|
||||
{
|
||||
std::map <std::pair<bool, std::string>, size_t>::const_iterator t = m_name_map.find (std::make_pair (st, name));
|
||||
if (t != m_name_map.end ()) {
|
||||
return std::make_pair (true, t->second + m_method_offset);
|
||||
} else {
|
||||
return std::make_pair (false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, size_t>
|
||||
MethodTable::find_property (bool st, const std::string &name) const
|
||||
{
|
||||
std::map <std::pair<bool, std::string>, size_t>::const_iterator t = m_property_name_map.find (std::make_pair (st, name));
|
||||
if (t != m_property_name_map.end ()) {
|
||||
return std::make_pair (true, t->second + m_property_offset);
|
||||
} else {
|
||||
return std::make_pair (false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts the Python name from a generic name
|
||||
*
|
||||
* Returns an empty string if no Python name could be generated.
|
||||
*/
|
||||
static std::string extract_python_name (const std::string &name)
|
||||
{
|
||||
// some operator replacements
|
||||
if (name == "++") {
|
||||
return "inc";
|
||||
} else if (name == "--") {
|
||||
return "dec";
|
||||
} else if (name == "()") {
|
||||
return "call";
|
||||
} else if (name == "!") {
|
||||
return "not";
|
||||
} else if (name == "==") {
|
||||
return "__eq__";
|
||||
} else if (name == "!=") {
|
||||
return "__ne__";
|
||||
} else if (name == "<") {
|
||||
return "__lt__";
|
||||
} else if (name == "<=") {
|
||||
return "__le__";
|
||||
} else if (name == ">") {
|
||||
return "__gt__";
|
||||
} else if (name == ">=") {
|
||||
return "__ge__";
|
||||
} else if (name == "<=>") {
|
||||
return "__cmp__";
|
||||
} else if (name == "+") {
|
||||
return "__add__";
|
||||
} else if (name == "+@") {
|
||||
return "__pos__";
|
||||
} else if (name == "-") {
|
||||
return "__sub__";
|
||||
} else if (name == "-@") {
|
||||
return "__neg__";
|
||||
} else if (name == "/") {
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
return "__div__";
|
||||
#else
|
||||
return "__truediv__";
|
||||
#endif
|
||||
} else if (name == "*" || name == "*!") {
|
||||
return "__mul__";
|
||||
} else if (name == "%") {
|
||||
return "__mod__";
|
||||
} else if (name == "<<") {
|
||||
return "__lshift__";
|
||||
} else if (name == ">>") {
|
||||
return "__rshift__";
|
||||
} else if (name == "~") {
|
||||
return "__invert__";
|
||||
} else if (name == "&") {
|
||||
return "__and__";
|
||||
} else if (name == "|") {
|
||||
return "__or__";
|
||||
} else if (name == "^") {
|
||||
return "__xor__";
|
||||
} else if (name == "+=") {
|
||||
return "__iadd__";
|
||||
} else if (name == "-=") {
|
||||
return "__isub__";
|
||||
} else if (name == "/=") {
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
return "__idiv__";
|
||||
#else
|
||||
return "__itruediv__";
|
||||
#endif
|
||||
} else if (name == "*=") {
|
||||
return "__imul__";
|
||||
} else if (name == "%=") {
|
||||
return "__imod__";
|
||||
} else if (name == "<<=") {
|
||||
return "__ilshift__";
|
||||
} else if (name == ">>=") {
|
||||
return "__irshift__";
|
||||
} else if (name == "&=") {
|
||||
return "__iand__";
|
||||
} else if (name == "|=") {
|
||||
return "__ior__";
|
||||
} else if (name == "^=") {
|
||||
return "__ixor__";
|
||||
} else if (name == "[]") {
|
||||
return "__getitem__";
|
||||
} else if (name == "[]=") {
|
||||
return "__setitem__";
|
||||
} else {
|
||||
|
||||
const char *c = name.c_str ();
|
||||
if (! isalnum (*c) && *c != '_') {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
// question-mark symbol and trailing = are removed.
|
||||
size_t n = 0;
|
||||
for ( ; *c; ++c) {
|
||||
if (*c == '=' || *c == '?') {
|
||||
if (! c[1]) {
|
||||
if (*c == '=') {
|
||||
// Normally, this method is replaced by an attribute.
|
||||
// If that fails, we prepend a "set_" to make the name unique.
|
||||
return "set_" + std::string (name, 0, n);
|
||||
} else {
|
||||
return std::string (name, 0, n);
|
||||
}
|
||||
} else {
|
||||
return std::string ();
|
||||
}
|
||||
} else if (! isalnum (*c) && *c != '_') {
|
||||
return std::string ();
|
||||
} else {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MethodTable::add_method (const std::string &name, const gsi::MethodBase *mb)
|
||||
{
|
||||
if (name == "to_s" && mb->compatible_with_num_args (0)) {
|
||||
|
||||
add_method_basic (name, mb);
|
||||
|
||||
// The str method is also routed via the tp_str implementation
|
||||
add_method_basic ("__str__", mb);
|
||||
|
||||
#if defined(GSI_ALIAS_INSPECT)
|
||||
// also alias to "__repr__" unless there is an explicit "inspect" method
|
||||
bool alias_inspect = true;
|
||||
for (gsi::ClassBase::method_iterator m = mp_cls_decl->begin_methods (); m != mp_cls_decl->end_methods () && alias_inspect; ++m) {
|
||||
if (! (*m)->is_callback () && ! (*m)->is_signal ()) {
|
||||
for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms () && alias_inspect; ++syn) {
|
||||
if (! syn->is_getter && ! syn->is_setter && syn->name == "inspect") {
|
||||
alias_inspect = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
bool alias_inspect = false;
|
||||
#endif
|
||||
if (alias_inspect) {
|
||||
add_method_basic ("__repr__", mb);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method is also available as 'str(object)' and 'repr(object)'")));
|
||||
} else {
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method is also available as 'str(object)'")));
|
||||
}
|
||||
|
||||
} else if (name == "hash" && mb->compatible_with_num_args (0)) {
|
||||
|
||||
// The hash method is also routed via the tp_hash implementation
|
||||
add_method_basic ("__hash__", mb);
|
||||
|
||||
add_method_basic (name, mb);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method is also available as 'hash(object)'")));
|
||||
|
||||
} else if (name == "inspect" && mb->compatible_with_num_args (0)) {
|
||||
|
||||
// The str method is also routed via the tp_str implementation
|
||||
add_method_basic ("__repr__", mb);
|
||||
|
||||
add_method_basic (name, mb);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method is also available as 'repr(object)'")));
|
||||
|
||||
} else if (name == "size" && mb->compatible_with_num_args (0)) {
|
||||
|
||||
// The size method is also routed via the sequence methods protocol if there
|
||||
// is a [] function
|
||||
add_method_basic ("__len__", mb);
|
||||
|
||||
add_method_basic (name, mb);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method is also available as 'len(object)'")));
|
||||
|
||||
} else if (name == "each" && mb->compatible_with_num_args (0) && mb->ret_type ().is_iter ()) {
|
||||
|
||||
// each makes the object iterable
|
||||
add_method_basic ("__iter__", mb);
|
||||
|
||||
add_method_basic (name, mb);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method enables iteration of the object")));
|
||||
|
||||
} else if (name == "dup" && mb->compatible_with_num_args (0)) {
|
||||
|
||||
// If the object supports the dup method, then it is a good
|
||||
// idea to define the __copy__ method.
|
||||
add_method_basic ("__copy__", mb);
|
||||
|
||||
add_method_basic (name, mb);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method also implements '__copy__'")));
|
||||
|
||||
} else {
|
||||
|
||||
std::string py_name = extract_python_name (name);
|
||||
if (py_name.empty ()) {
|
||||
|
||||
// drop non-standard names
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::warn << tl::to_string (tr ("Class ")) << mp_cls_decl->name () << ": " << tl::to_string (tr ("no Python mapping for method ")) << name;
|
||||
}
|
||||
|
||||
add_method_basic (name, mb, false);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method is not available for Python")));
|
||||
|
||||
} else {
|
||||
|
||||
add_method_basic (py_name, mb);
|
||||
|
||||
if (name == "*") {
|
||||
// Supply a commutative multiplication version unless the operator is "*!"
|
||||
add_method_basic ("__rmul__", mb);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method also implements '__rmul__'")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MethodTable::add_setter (const std::string &name, const gsi::MethodBase *setter)
|
||||
{
|
||||
bool st = setter->is_static ();
|
||||
|
||||
std::map<std::pair<bool, std::string>, size_t>::iterator n = m_property_name_map.find (std::make_pair (st, name));
|
||||
if (n == m_property_name_map.end ()) {
|
||||
|
||||
m_property_name_map.insert (std::make_pair (std::make_pair(st, name), m_property_table.size ()));
|
||||
m_property_table.push_back (std::make_pair (MethodTableEntry (name, st, false), MethodTableEntry (name, st, false)));
|
||||
m_property_table.back ().first.add (setter);
|
||||
|
||||
} else {
|
||||
|
||||
m_property_table [n->second].first.add (setter);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MethodTable::add_getter (const std::string &name, const gsi::MethodBase *getter)
|
||||
{
|
||||
bool st = getter->is_static ();
|
||||
|
||||
std::map<std::pair<bool, std::string>, size_t>::iterator n = m_property_name_map.find (std::make_pair (st, name));
|
||||
if (n == m_property_name_map.end ()) {
|
||||
|
||||
m_property_name_map.insert (std::make_pair (std::make_pair(st, name), m_property_table.size ()));
|
||||
m_property_table.push_back (std::make_pair (MethodTableEntry (name, st, false), MethodTableEntry (name, st, false)));
|
||||
m_property_table.back ().second.add (getter);
|
||||
|
||||
} else {
|
||||
|
||||
m_property_table [n->second].second.add (getter);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTable::is_enabled (size_t mid) const
|
||||
{
|
||||
return m_table [mid - m_method_offset].is_enabled ();
|
||||
}
|
||||
|
||||
void
|
||||
MethodTable::set_enabled (size_t mid, bool en)
|
||||
{
|
||||
m_table [mid - m_method_offset].set_enabled (en);
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTable::is_static (size_t mid) const
|
||||
{
|
||||
return m_table [mid - m_method_offset].is_static ();
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTable::is_protected (size_t mid) const
|
||||
{
|
||||
return m_table [mid - m_method_offset].is_protected ();
|
||||
}
|
||||
|
||||
void
|
||||
MethodTable::rename (size_t mid, const std::string &new_name)
|
||||
{
|
||||
std::string old_name = name (mid);
|
||||
bool st = is_static (mid);
|
||||
|
||||
m_table [mid - m_method_offset].set_name (new_name);
|
||||
|
||||
auto nm = m_name_map.find (std::make_pair (st, old_name));
|
||||
if (nm != m_name_map.end ()) {
|
||||
m_name_map.erase (nm);
|
||||
m_name_map.insert (std::make_pair (std::make_pair (st, new_name), mid));
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
MethodTable::name (size_t mid) const
|
||||
{
|
||||
return m_table [mid - m_method_offset].name ();
|
||||
}
|
||||
|
||||
const std::string &
|
||||
MethodTable::property_name (size_t mid) const
|
||||
{
|
||||
return m_property_table [mid - m_property_offset].first.name ();
|
||||
}
|
||||
|
||||
MethodTableEntry::method_iterator
|
||||
MethodTable::begin_setters (size_t mid) const
|
||||
{
|
||||
return m_property_table[mid - m_property_offset].first.begin ();
|
||||
}
|
||||
|
||||
MethodTableEntry::method_iterator
|
||||
MethodTable::end_setters (size_t mid) const
|
||||
{
|
||||
return m_property_table[mid - m_property_offset].first.end ();
|
||||
}
|
||||
|
||||
MethodTableEntry::method_iterator
|
||||
MethodTable::begin_getters (size_t mid) const
|
||||
{
|
||||
return m_property_table[mid - m_property_offset].second.begin ();
|
||||
}
|
||||
|
||||
MethodTableEntry::method_iterator
|
||||
MethodTable::end_getters (size_t mid) const
|
||||
{
|
||||
return m_property_table[mid - m_property_offset].second.end ();
|
||||
}
|
||||
|
||||
MethodTableEntry::method_iterator
|
||||
MethodTable::begin (size_t mid) const
|
||||
{
|
||||
return m_table[mid - m_method_offset].begin ();
|
||||
}
|
||||
|
||||
MethodTableEntry::method_iterator
|
||||
MethodTable::end (size_t mid) const
|
||||
{
|
||||
return m_table[mid - m_method_offset].end ();
|
||||
}
|
||||
|
||||
void
|
||||
MethodTable::finish ()
|
||||
{
|
||||
for (std::vector<MethodTableEntry>::iterator m = m_table.begin (); m != m_table.end (); ++m) {
|
||||
m->finish ();
|
||||
}
|
||||
for (std::vector<std::pair<MethodTableEntry, MethodTableEntry> >::iterator m = m_property_table.begin (); m != m_property_table.end (); ++m) {
|
||||
m->first.finish ();
|
||||
m->second.finish ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MethodTable::add_method_basic (const std::string &name, const gsi::MethodBase *mb, bool enabled)
|
||||
{
|
||||
bool st = mb->is_static ();
|
||||
|
||||
std::map<std::pair<bool, std::string>, size_t>::iterator n = m_name_map.find (std::make_pair (st, name));
|
||||
if (n == m_name_map.end ()) {
|
||||
|
||||
m_name_map.insert (std::make_pair (std::make_pair (st, name), m_table.size ()));
|
||||
m_table.push_back (MethodTableEntry (name, st, mb->is_protected ()));
|
||||
if (! enabled) {
|
||||
m_table.back ().set_enabled (false);
|
||||
}
|
||||
m_table.back ().add (mb);
|
||||
|
||||
} else {
|
||||
|
||||
if (m_table [n->second].is_protected () != mb->is_protected ()) {
|
||||
tl::warn << "Class " << mp_cls_decl->name () << ": method '" << name << " is both a protected and non-protected";
|
||||
}
|
||||
|
||||
m_table [n->second].add (mb);
|
||||
if (! enabled) {
|
||||
m_table [n->second].set_enabled (false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
MethodTable *
|
||||
MethodTable::method_table_by_class (const gsi::ClassBase *cls_decl)
|
||||
{
|
||||
PythonClassClientData *cd = dynamic_cast<PythonClassClientData *>(cls_decl->data (gsi::ClientIndex::Python));
|
||||
return cd ? &cd->method_table : 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// PythonClassClientData implementation
|
||||
|
||||
PythonClassClientData::PythonClassClientData (const gsi::ClassBase *_cls, PyTypeObject *_py_type, PyTypeObject *_py_type_static, PythonModule *module)
|
||||
: py_type_object (_py_type), py_type_object_static (_py_type_static), method_table (_cls, module)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PyTypeObject *
|
||||
PythonClassClientData::py_type (const gsi::ClassBase &cls_decl, bool as_static)
|
||||
{
|
||||
PythonClassClientData *cd = dynamic_cast<PythonClassClientData *>(cls_decl.data (gsi::ClientIndex::Python));
|
||||
return cd ? (as_static ? cd->py_type_object_static : cd->py_type_object) : 0;
|
||||
}
|
||||
|
||||
void
|
||||
PythonClassClientData::initialize (const gsi::ClassBase &cls_decl, PyTypeObject *py_type, bool as_static, PythonModule *module)
|
||||
{
|
||||
PythonClassClientData *cd = dynamic_cast<PythonClassClientData *>(cls_decl.data (gsi::ClientIndex::Python));
|
||||
if (cd) {
|
||||
if (as_static) {
|
||||
cd->py_type_object_static = py_type;
|
||||
} else {
|
||||
cd->py_type_object = py_type;
|
||||
}
|
||||
} else {
|
||||
cls_decl.set_data (gsi::ClientIndex::Python, new PythonClassClientData (&cls_decl, as_static ? NULL : py_type, as_static ? py_type : NULL, module));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// The PythonModule implementation
|
||||
|
||||
std::map<const gsi::MethodBase *, std::string> PythonModule::m_python_doc;
|
||||
std::vector<const gsi::ClassBase *> PythonModule::m_classes;
|
||||
|
||||
const std::string pymod_name ("klayout");
|
||||
|
||||
PythonModule::PythonModule ()
|
||||
: mp_mod_def (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PythonModule::~PythonModule ()
|
||||
{
|
||||
PYAObjectBase::clear_callbacks_cache ();
|
||||
|
||||
// the Python objects were probably deleted by Python itself as it exited -
|
||||
// don't try to delete them again.
|
||||
mp_module.release ();
|
||||
|
||||
while (!m_methods_heap.empty ()) {
|
||||
delete m_methods_heap.back ();
|
||||
m_methods_heap.pop_back ();
|
||||
}
|
||||
|
||||
while (!m_getseters_heap.empty ()) {
|
||||
delete m_getseters_heap.back ();
|
||||
m_getseters_heap.pop_back ();
|
||||
}
|
||||
|
||||
if (mp_mod_def) {
|
||||
delete[] mp_mod_def;
|
||||
mp_mod_def = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PythonModule::module ()
|
||||
{
|
||||
return mp_module.get ();
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PythonModule::take_module ()
|
||||
{
|
||||
return mp_module.release ();
|
||||
}
|
||||
|
||||
void
|
||||
PythonModule::init (const char *mod_name, const char *description)
|
||||
{
|
||||
// create a (standalone) Python interpreter if we don't have one yet
|
||||
// NOTE: Python itself will take care to remove this instance in this case.
|
||||
if (! pya::PythonInterpreter::instance ()) {
|
||||
new pya::PythonInterpreter (false);
|
||||
}
|
||||
|
||||
// do some checks before we create the module
|
||||
tl_assert (mod_name != 0);
|
||||
tl_assert (mp_module.get () == 0);
|
||||
|
||||
m_mod_name = pymod_name + "." + mod_name;
|
||||
m_mod_description = description;
|
||||
|
||||
PyObject *module = 0;
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{NULL} // Sentinel
|
||||
};
|
||||
|
||||
module = Py_InitModule3 (m_mod_name.c_str (), module_methods, m_mod_description.c_str ());
|
||||
|
||||
#else
|
||||
|
||||
struct PyModuleDef mod_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
m_mod_name.c_str (),
|
||||
NULL, // module documentation
|
||||
-1, // size of per-interpreter state of the module,
|
||||
// if the module keeps state in global variables.
|
||||
NULL
|
||||
};
|
||||
|
||||
tl_assert (! mp_mod_def);
|
||||
|
||||
// prepare a persistent structure with the module definition
|
||||
// and pass this one to PyModule_Create
|
||||
mp_mod_def = new char[sizeof (PyModuleDef)];
|
||||
memcpy ((void *) mp_mod_def, (const void *) &mod_def, sizeof (PyModuleDef));
|
||||
|
||||
module = PyModule_Create ((PyModuleDef *) mp_mod_def);
|
||||
|
||||
#endif
|
||||
|
||||
mp_module = PythonRef (module);
|
||||
}
|
||||
|
||||
void
|
||||
PythonModule::init (const char *mod_name, PyObject *module)
|
||||
{
|
||||
// do some checks before we create the module
|
||||
tl_assert (mp_module.get () == 0);
|
||||
|
||||
m_mod_name = mod_name;
|
||||
mp_module = PythonRef (module);
|
||||
}
|
||||
|
||||
PyMethodDef *
|
||||
PythonModule::make_method_def ()
|
||||
{
|
||||
static PyMethodDef md = { };
|
||||
m_methods_heap.push_back (new PyMethodDef (md));
|
||||
return m_methods_heap.back ();
|
||||
}
|
||||
|
||||
PyGetSetDef *
|
||||
PythonModule::make_getset_def ()
|
||||
{
|
||||
static PyGetSetDef gsd = { };
|
||||
m_getseters_heap.push_back (new PyGetSetDef (gsd));
|
||||
return m_getseters_heap.back ();
|
||||
}
|
||||
|
||||
char *
|
||||
PythonModule::make_string (const std::string &s)
|
||||
{
|
||||
m_string_heap.push_back (s);
|
||||
return const_cast<char *> (m_string_heap.back ().c_str ());
|
||||
}
|
||||
|
||||
void
|
||||
PythonModule::add_python_doc (const gsi::ClassBase & /*cls*/, const MethodTable *mt, int mid, const std::string &doc)
|
||||
{
|
||||
for (MethodTableEntry::method_iterator m = mt->begin (mid); m != mt->end (mid); ++m) {
|
||||
std::string &doc_string = m_python_doc [*m];
|
||||
doc_string += doc;
|
||||
doc_string += "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PythonModule::add_python_doc (const gsi::MethodBase *m, const std::string &doc)
|
||||
{
|
||||
m_python_doc [m] += doc;
|
||||
}
|
||||
|
||||
std::string
|
||||
PythonModule::python_doc (const gsi::MethodBase *method)
|
||||
{
|
||||
std::map<const gsi::MethodBase *, std::string>::const_iterator d = m_python_doc.find (method);
|
||||
if (d != m_python_doc.end ()) {
|
||||
return d->second;
|
||||
} else {
|
||||
return std::string ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _HDR_pyaInternal
|
||||
#define _HDR_pyaInternal
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "pyaCommon.h"
|
||||
#include "pyaRefs.h"
|
||||
|
||||
#include "gsiClassBase.h"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
class MethodBase;
|
||||
}
|
||||
|
||||
namespace pya
|
||||
{
|
||||
|
||||
class PythonModule;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// The lookup table for the method overload resolution
|
||||
|
||||
/**
|
||||
* @brief A single entry in the method table
|
||||
* This class provides an entry for one name. It provides flags
|
||||
* (ctor, static, protected) for the method and a list of implementations
|
||||
* (gsi::MethodBase objects)
|
||||
*/
|
||||
class MethodTableEntry
|
||||
{
|
||||
public:
|
||||
typedef std::vector<const gsi::MethodBase *>::const_iterator method_iterator;
|
||||
|
||||
MethodTableEntry (const std::string &name, bool st, bool prot);
|
||||
|
||||
const std::string &name () const;
|
||||
void set_name (const std::string &n);
|
||||
|
||||
void set_enabled (bool en);
|
||||
bool is_enabled () const;
|
||||
|
||||
bool is_static () const;
|
||||
|
||||
bool is_protected () const;
|
||||
|
||||
void add (const gsi::MethodBase *m);
|
||||
|
||||
void finish ();
|
||||
|
||||
method_iterator begin () const;
|
||||
method_iterator end () const;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
bool m_is_static : 1;
|
||||
bool m_is_protected : 1;
|
||||
bool m_is_enabled : 1;
|
||||
std::vector<const gsi::MethodBase *> m_methods;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The method table for a class
|
||||
* The method table will provide the methods associated with a native method, i.e.
|
||||
* a certain name. It only provides the methods, not a overload resolution strategy.
|
||||
*/
|
||||
class MethodTable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* This constructor will create a method table for the given class and register
|
||||
* this table under this class.
|
||||
*/
|
||||
MethodTable (const gsi::ClassBase *cls_decl, PythonModule *module);
|
||||
/**
|
||||
* @brief Returns the lowest method ID within the space of this table
|
||||
* Method IDs below this one are reserved for base class methods
|
||||
*/
|
||||
size_t bottom_mid () const;
|
||||
|
||||
/**
|
||||
* @brief Returns the topmost + 1 method ID.
|
||||
*/
|
||||
size_t top_mid () const;
|
||||
|
||||
/**
|
||||
* @brief Returns the lowest property method ID within the space of this table
|
||||
* Method IDs below this one are reserved for base class methods
|
||||
*/
|
||||
size_t bottom_property_mid () const;
|
||||
|
||||
/**
|
||||
* @brief Returns the topmost + 1 property method ID.
|
||||
*/
|
||||
size_t top_property_mid () const;
|
||||
|
||||
/**
|
||||
* @brief Find a method with the given name and static flag
|
||||
* Returns true or false in the first part (true, if found) and
|
||||
* the MID in the second part.
|
||||
*/
|
||||
std::pair<bool, size_t> find_method (bool st, const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Find a property with the given name and static flag
|
||||
* Returns true or false in the first part (true, if found) and
|
||||
* the MID in the second part.
|
||||
*/
|
||||
std::pair<bool, size_t> find_property (bool st, const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Adds a method to the table
|
||||
*/
|
||||
void add_method (const std::string &name, const gsi::MethodBase *mb);
|
||||
|
||||
/**
|
||||
* @brief Adds a setter with the given name
|
||||
*/
|
||||
void add_setter (const std::string &name, const gsi::MethodBase *setter);
|
||||
|
||||
/**
|
||||
* @brief Adds a getter with the given name
|
||||
*/
|
||||
void add_getter (const std::string &name, const gsi::MethodBase *getter);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the method is enabled
|
||||
*/
|
||||
bool is_enabled (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Enables or disables a method
|
||||
*/
|
||||
void set_enabled (size_t mid, bool en);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the method with the given ID is static
|
||||
*/
|
||||
bool is_static (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the method with the given ID is protected
|
||||
*/
|
||||
bool is_protected (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Renames a method
|
||||
*/
|
||||
void rename (size_t mid, const std::string &new_name);
|
||||
|
||||
/**
|
||||
* @brief Returns the name of the method with the given ID
|
||||
*/
|
||||
const std::string &name (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the name of the property with the given ID
|
||||
*/
|
||||
const std::string &property_name (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Begins iteration of the overload variants for setter of property ID mid
|
||||
*/
|
||||
MethodTableEntry::method_iterator begin_setters (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Ends iteration of the overload variants for setter of property ID mid
|
||||
*/
|
||||
MethodTableEntry::method_iterator end_setters (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Begins iteration of the overload variants for getter of property ID mid
|
||||
*/
|
||||
MethodTableEntry::method_iterator begin_getters (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Ends iteration of the overload variants for getter of property ID mid
|
||||
*/
|
||||
MethodTableEntry::method_iterator end_getters (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Begins iteration of the overload variants for method ID mid
|
||||
*/
|
||||
MethodTableEntry::method_iterator begin (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Ends iteration of the overload variants for method ID mid
|
||||
*/
|
||||
MethodTableEntry::method_iterator end (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Finishes construction of the table
|
||||
* This method must be called after the add_method calls have been used
|
||||
* to fill the table. It will remove duplicate entries and clean up memory.
|
||||
*/
|
||||
void finish ();
|
||||
|
||||
/**
|
||||
* @brief Obtain a method table for a given class
|
||||
*/
|
||||
static MethodTable *method_table_by_class (const gsi::ClassBase *cls_decl);
|
||||
|
||||
private:
|
||||
size_t m_method_offset;
|
||||
size_t m_property_offset;
|
||||
const gsi::ClassBase *mp_cls_decl;
|
||||
std::map<std::pair<bool, std::string>, size_t> m_name_map;
|
||||
std::map<std::pair<bool, std::string>, size_t> m_property_name_map;
|
||||
std::vector<MethodTableEntry> m_table;
|
||||
std::vector<std::pair<MethodTableEntry, MethodTableEntry> > m_property_table;
|
||||
PythonModule *mp_module;
|
||||
|
||||
void add_method_basic (const std::string &name, const gsi::MethodBase *mb, bool enabled = true);
|
||||
};
|
||||
|
||||
struct PythonClassClientData
|
||||
: public gsi::PerClassClientSpecificData
|
||||
{
|
||||
PythonClassClientData (const gsi::ClassBase *_cls, PyTypeObject *_py_type, PyTypeObject *_py_type_static, PythonModule *module);
|
||||
|
||||
PyTypeObject *py_type_object;
|
||||
PyTypeObject *py_type_object_static;
|
||||
MethodTable method_table;
|
||||
|
||||
static PyTypeObject *py_type (const gsi::ClassBase &cls_decl, bool as_static);
|
||||
static void initialize (const gsi::ClassBase &cls_decl, PyTypeObject *py_type, bool as_static, PythonModule *module);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -45,7 +45,6 @@ namespace gsi
|
|||
namespace pya
|
||||
{
|
||||
|
||||
class PYAObjectBase;
|
||||
class Callee;
|
||||
class StatusChangedListener;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue