summaryrefslogtreecommitdiffstats
path: root/contrib/python/kiwisolver/py3/py/expression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/python/kiwisolver/py3/py/expression.cpp')
-rw-r--r--contrib/python/kiwisolver/py3/py/expression.cpp251
1 files changed, 251 insertions, 0 deletions
diff --git a/contrib/python/kiwisolver/py3/py/expression.cpp b/contrib/python/kiwisolver/py3/py/expression.cpp
new file mode 100644
index 00000000000..38400483f67
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/expression.cpp
@@ -0,0 +1,251 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2019, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file LICENSE, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <sstream>
+#include <cppy/cppy.h>
+#include "symbolics.h"
+#include "types.h"
+#include "util.h"
+
+
+namespace kiwisolver
+{
+
+namespace
+{
+
+PyObject*
+Expression_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "terms", "constant", 0 };
+ PyObject* pyterms;
+ PyObject* pyconstant = 0;
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "O|O:__new__", const_cast<char**>( kwlist ),
+ &pyterms, &pyconstant ) )
+ return 0;
+ cppy::ptr terms( PySequence_Tuple( pyterms ) );
+ if( !terms )
+ return 0;
+ Py_ssize_t end = PyTuple_GET_SIZE( terms.get() );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( terms.get(), i );
+ if( !Term::TypeCheck( item ) )
+ return cppy::type_error( item, "Term" );
+ }
+ double constant = 0.0;
+ if( pyconstant && !convert_to_double( pyconstant, constant ) )
+ return 0;
+ PyObject* pyexpr = PyType_GenericNew( type, args, kwargs );
+ if( !pyexpr )
+ return 0;
+ Expression* self = reinterpret_cast<Expression*>( pyexpr );
+ self->terms = terms.release();
+ self->constant = constant;
+ return pyexpr;
+}
+
+
+void
+Expression_clear( Expression* self )
+{
+ Py_CLEAR( self->terms );
+}
+
+
+int
+Expression_traverse( Expression* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->terms );
+#if PY_VERSION_HEX >= 0x03090000
+ // This was not needed before Python 3.9 (Python issue 35810 and 40217)
+ Py_VISIT(Py_TYPE(self));
+#endif
+ return 0;
+}
+
+
+void
+Expression_dealloc( Expression* self )
+{
+ PyObject_GC_UnTrack( self );
+ Expression_clear( self );
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+PyObject*
+Expression_repr( Expression* self )
+{
+ std::stringstream stream;
+ Py_ssize_t end = PyTuple_GET_SIZE( self->terms );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( self->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ stream << term->coefficient << " * ";
+ stream << reinterpret_cast<Variable*>( term->variable )->variable.name();
+ stream << " + ";
+ }
+ stream << self->constant;
+ return PyUnicode_FromString( stream.str().c_str() );
+}
+
+
+PyObject*
+Expression_terms( Expression* self )
+{
+ return cppy::incref( self->terms );
+}
+
+
+PyObject*
+Expression_constant( Expression* self )
+{
+ return PyFloat_FromDouble( self->constant );
+}
+
+
+PyObject*
+Expression_value( Expression* self )
+{
+ double result = self->constant;
+ Py_ssize_t size = PyTuple_GET_SIZE( self->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( self->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ Variable* pyvar = reinterpret_cast<Variable*>( term->variable );
+ result += term->coefficient * pyvar->variable.value();
+ }
+ return PyFloat_FromDouble( result );
+}
+
+
+PyObject*
+Expression_add( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryAdd, Expression>()( first, second );
+}
+
+
+PyObject*
+Expression_sub( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinarySub, Expression>()( first, second );
+}
+
+
+PyObject*
+Expression_mul( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryMul, Expression>()( first, second );
+}
+
+
+PyObject*
+Expression_div( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryDiv, Expression>()( first, second );
+}
+
+
+PyObject*
+Expression_neg( PyObject* value )
+{
+ return UnaryInvoke<UnaryNeg, Expression>()( value );
+}
+
+
+PyObject*
+Expression_richcmp( PyObject* first, PyObject* second, int op )
+{
+ switch( op )
+ {
+ case Py_EQ:
+ return BinaryInvoke<CmpEQ, Expression>()( first, second );
+ case Py_LE:
+ return BinaryInvoke<CmpLE, Expression>()( first, second );
+ case Py_GE:
+ return BinaryInvoke<CmpGE, Expression>()( first, second );
+ default:
+ break;
+ }
+ PyErr_Format(
+ PyExc_TypeError,
+ "unsupported operand type(s) for %s: "
+ "'%.100s' and '%.100s'",
+ pyop_str( op ),
+ Py_TYPE( first )->tp_name,
+ Py_TYPE( second )->tp_name
+ );
+ return 0;
+}
+
+
+static PyMethodDef
+Expression_methods[] = {
+ { "terms", ( PyCFunction )Expression_terms, METH_NOARGS,
+ "Get the tuple of terms for the expression." },
+ { "constant", ( PyCFunction )Expression_constant, METH_NOARGS,
+ "Get the constant for the expression." },
+ { "value", ( PyCFunction )Expression_value, METH_NOARGS,
+ "Get the value for the expression." },
+ { 0 } // sentinel
+};
+
+
+static PyType_Slot Expression_Type_slots[] = {
+ { Py_tp_dealloc, void_cast( Expression_dealloc ) }, /* tp_dealloc */
+ { Py_tp_traverse, void_cast( Expression_traverse ) }, /* tp_traverse */
+ { Py_tp_clear, void_cast( Expression_clear ) }, /* tp_clear */
+ { Py_tp_repr, void_cast( Expression_repr ) }, /* tp_repr */
+ { Py_tp_richcompare, void_cast( Expression_richcmp ) }, /* tp_richcompare */
+ { Py_tp_methods, void_cast( Expression_methods ) }, /* tp_methods */
+ { Py_tp_new, void_cast( Expression_new ) }, /* tp_new */
+ { Py_tp_alloc, void_cast( PyType_GenericAlloc ) }, /* tp_alloc */
+ { Py_tp_free, void_cast( PyObject_GC_Del ) }, /* tp_free */
+ { Py_nb_add, void_cast( Expression_add ) }, /* nb_add */
+ { Py_nb_subtract, void_cast( Expression_sub ) }, /* nb_sub */
+ { Py_nb_multiply, void_cast( Expression_mul ) }, /* nb_mul */
+ { Py_nb_negative, void_cast( Expression_neg ) }, /* nb_neg */
+ { Py_nb_true_divide, void_cast( Expression_div ) }, /* nb_div */
+ { 0, 0 },
+};
+
+
+} // namespace
+
+
+// Initialize static variables (otherwise the compiler eliminates them)
+PyTypeObject* Expression::TypeObject = NULL;
+
+
+PyType_Spec Expression::TypeObject_Spec = {
+ "kiwisolver.Expression", /* tp_name */
+ sizeof( Expression ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ Py_TPFLAGS_DEFAULT|
+ Py_TPFLAGS_HAVE_GC|
+ Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Expression_Type_slots /* slots */
+};
+
+
+bool Expression::Ready()
+{
+ // The reference will be handled by the module to which we will add the type
+ TypeObject = pytype_cast( PyType_FromSpec( &TypeObject_Spec ) );
+ if( !TypeObject )
+ {
+ return false;
+ }
+ return true;
+}
+
+} // namesapce kiwisolver