klayout/src/pya/pyaObject.h

347 lines
8.3 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 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_pyaObject
#define _HDR_pyaObject
#include "Python.h"
#include "gsiDecl.h"
#include "gsiDeclBasic.h"
#include "gsiSignals.h"
#include "tlObject.h"
#include "pyaRefs.h"
namespace pya
{
class PYAObjectBase;
/**
* @brief A storage object for a function to callback
*/
struct CallbackFunction
{
CallbackFunction (PythonRef pym, const gsi::MethodBase *m);
PythonRef callable () const;
const gsi::MethodBase *method () const;
bool operator== (const CallbackFunction &other) const;
private:
PythonRef m_callable;
PythonRef m_weak_self;
PythonRef m_class;
const gsi::MethodBase *mp_method;
PyObject *self_ref () const;
PyObject *callable_ref () const;
bool is_instance_method () const;
};
/**
* @brief An adaptor class for the callback mechanism
*/
class Callee
: public gsi::Callee
{
public:
/**
* @brief Constructor for a Callee object pointing the to given Python object
*/
Callee (PYAObjectBase *obj);
/**
* @brief Destructor
*/
~Callee ();
/**
* @brief Adds a callback (given by the CallbackFunction)
* This method returns a callback ID which can be used to register the callback
* at an GSI object.
*/
int add_callback (const CallbackFunction &vf);
/**
* @brief Clears all callbacks registered
*/
void clear_callbacks ();
/**
* @brief Implementation of the Callee interface
*/
virtual void call (int id, gsi::SerialArgs &args, gsi::SerialArgs &ret) const;
private:
PYAObjectBase *mp_obj;
std::vector<CallbackFunction> m_cbfuncs;
};
/**
* @brief The signal handler abstraction
*
* This class implements the signal handler that interfaces to GSI's signal system
*/
class SignalHandler
: public gsi::SignalHandler
{
public:
/**
* @brief Constructor
*/
SignalHandler ();
/**
* @brief Destructor
*/
~SignalHandler ();
/**
* @brief Implementation of the callback interface
*/
virtual void call (const gsi::MethodBase *method, gsi::SerialArgs &args, gsi::SerialArgs &ret) const;
/**
* @brief Adds a callable to the list of targets
*/
void add (PyObject *callable);
/**
* @brief Removes a callable from the list of targets
*/
void remove (PyObject *callable);
/**
* @brief Clears the list of callables
*/
void clear ();
/**
* @brief Assign another handler to this
*/
void assign (const SignalHandler *other);
private:
std::vector<CallbackFunction> m_cbfuncs;
};
/**
* @brief A helper object to forward status changed events to a Python object
* This object is used to connect the events to the Python object. Unfortunately,
* PYAObjectBase cannot be derived from tl::Object directly since in that case,
* tl::Object will be placed before PyObject in the memory layout.
*/
class StatusChangedListener
: public tl::Object
{
public:
StatusChangedListener (PYAObjectBase *pya_object);
void object_status_changed (gsi::ObjectBase::StatusEventType type);
PYAObjectBase *pya_object () const
{
return mp_pya_object;
}
private:
PYAObjectBase *mp_pya_object;
};
/**
* @brief The Python object representing a GSI object
*
* Note: the PYAObjectBase must be directly derived from PyObject so that
* a PyObject pointer can be cast to a PYAObjectBase pointer.
*/
class PYAObjectBase
: public PyObject
{
public:
/**
* @brief Constructor - creates a new object for the given GSI class
*/
PYAObjectBase (const gsi::ClassBase *_cls_decl);
/**
* @brief Destructor
*/
~PYAObjectBase ();
/**
* @brief Indicates that a C++ object is present
*/
bool is_attached () const
{
return m_obj != 0;
}
/**
* @brief Explicitly destroy the C++ object
* If the C++ object is owned by the Python object, this method will delete the C++
* object and the \destroyed attribute will become true.
* The reference is no longer valid.
*/
void destroy ();
/**
* @brief Links the Python object with a C++ object
* The "owned" attribute indicates that the reference will be owned by the Python object.
* That means that the C++ object is being destroyed when the Python object expires.
* If "const_ref" is true, the Python object is said to be a const object which means
* only const methods can be called on it. That is a somewhat weak emulation for the
* constness concept in C++ since there is only one Python object representing multiple
* references. If one of these references goes to non-const, the Python object will accept
* non-const method calls.
* "can_destroy" indicates that the C++ object can be destroyed (has a destructor).
*/
void set (void *obj, bool owned, bool const_ref, bool can_destroy);
/**
* @brief Unlinks the C++ object from the Python object
* This method can be called to make the Python object cut the link to the C++ object.
* After that operation, the \destroyed attribute will be come true, even though the
* C++ object may not actually be destroyed.
* The reference will become invalid.
*/
void detach ();
/**
* @brief Gets the GSI class object
*/
const gsi::ClassBase *cls_decl () const
{
return m_cls_decl;
}
/**
* @brief Gets a flag indicating that the corresponding C++ object expired
* If the Python object acts as a weak reference to a foreign object (owned = false),
* the foreign object may expire before the Python object is deleted.
* In that case, destroyed becomes true.
*/
bool destroyed () const
{
return m_destroyed;
}
/**
* @brief Returns a flag indicating that this Python object is a const reference to a C++ object
* See \set for a description of that flag
*/
bool const_ref () const
{
return m_const_ref;
}
/**
* @brief Sets a flag indicating that this Python object is a const reference to the C++ object
* See \set for a description of that flag.
*/
void set_const_ref (bool c)
{
m_const_ref = c;
}
/**
* @brief Returns the C++ object reference
*/
void *obj ();
/**
* @brief Puts this object under C++ management (release from script management)
*/
void keep ();
/**
* @brief Puts this object under script management again
*/
void release ();
/**
* @brief Returns true, if the C++ object is owned by the Python object
* See \set for details about this flag
*/
bool owned () const
{
return m_owned;
}
/**
* @brief The callee interface
*/
Callee &callee ()
{
return m_callee;
}
/**
* @brief The callee interface (const pointer)
*/
const Callee &callee () const
{
return m_callee;
}
/**
* @brief Returns the signal handler for the signal given by "meth"
* If a signal handler was already present, the existing object is returned.
*/
pya::SignalHandler *signal_handler (const gsi::MethodBase *meth);
/**
* @brief Clears the callbacks cache
*/
static void clear_callbacks_cache ();
private:
friend class StatusChangedListener;
typedef std::vector<const gsi::MethodBase *> callback_methods_type;
typedef std::map<PythonRef, callback_methods_type> callbacks_cache;
static callbacks_cache s_callbacks_cache;
void detach_callbacks ();
void initialize_callbacks ();
StatusChangedListener m_listener;
Callee m_callee;
const gsi::ClassBase *m_cls_decl;
void *m_obj;
bool m_owned : 1;
bool m_const_ref : 1;
bool m_destroyed : 1;
bool m_can_destroy : 1;
std::map <const gsi::MethodBase *, pya::SignalHandler> m_signal_table;
void object_status_changed (gsi::ObjectBase::StatusEventType type);
void keep_internal ();
};
}
#endif