1 /*-----------------------------------------------------------------------------
2 | Copyright (c) 2013-2017, Nucleic Development Team.
3 |
4 | Distributed under the terms of the Modified BSD License.
5 |
6 | The full license is in the file COPYING.txt, distributed with this software.
7 |----------------------------------------------------------------------------*/
8 #include <Python.h>
9 #include <kiwi/kiwi.h>
10 #include "pythonhelpers.h"
11 #include "symbolics.h"
12 #include "types.h"
13 #include "util.h"
14 
15 
16 using namespace PythonHelpers;
17 
18 
19 static PyObject*
Variable_new(PyTypeObject * type,PyObject * args,PyObject * kwargs)20 Variable_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
21 {
22 	static const char *kwlist[] = { "name", "context", 0 };
23 	PyObject* context = 0;
24 	PyObject* name = 0;
25 
26 	if( !PyArg_ParseTupleAndKeywords(
27 		args, kwargs, "|OO:__new__", const_cast<char**>( kwlist ),
28 		&name, &context ) )
29 		return 0;
30 
31 	PyObjectPtr pyvar( PyType_GenericNew( type, args, kwargs ) );
32 	if( !pyvar )
33 		return 0;
34 
35 	Variable* self = reinterpret_cast<Variable*>( pyvar.get() );
36 	self->context = xnewref( context );
37 
38 	if( name != 0 )
39 	{
40 #if PY_MAJOR_VERSION >= 3
41 		if( !PyUnicode_Check( name ) )
42 			return py_expected_type_fail( name, "unicode" );
43 #else
44 		if( !( PyString_Check( name ) | PyUnicode_Check( name ) ) )
45 		{
46 			return py_expected_type_fail( name, "str or unicode" );
47 		}
48 #endif
49 		std::string c_name;
50 		if( !convert_pystr_to_str(name, c_name) )
51 			return 0;  // LCOV_EXCL_LINE
52 		new( &self->variable ) kiwi::Variable( c_name );
53 	}
54 	else
55 	{
56 		new( &self->variable ) kiwi::Variable();
57 	}
58 
59 	return pyvar.release();
60 }
61 
62 
63 static void
Variable_clear(Variable * self)64 Variable_clear( Variable* self )
65 {
66 	Py_CLEAR( self->context );
67 }
68 
69 
70 static int
Variable_traverse(Variable * self,visitproc visit,void * arg)71 Variable_traverse( Variable* self, visitproc visit, void* arg )
72 {
73 	Py_VISIT( self->context );
74 	return 0;
75 }
76 
77 
78 static void
Variable_dealloc(Variable * self)79 Variable_dealloc( Variable* self )
80 {
81 	PyObject_GC_UnTrack( self );
82 	Variable_clear( self );
83 	self->variable.~Variable();
84 	Py_TYPE( self )->tp_free( pyobject_cast( self ) );
85 }
86 
87 
88 static PyObject*
Variable_repr(Variable * self)89 Variable_repr( Variable* self )
90 {
91 	return FROM_STRING( self->variable.name().c_str() );
92 }
93 
94 
95 static PyObject*
Variable_name(Variable * self)96 Variable_name( Variable* self )
97 {
98 	return FROM_STRING( self->variable.name().c_str() );
99 }
100 
101 
102 static PyObject*
Variable_setName(Variable * self,PyObject * pystr)103 Variable_setName( Variable* self, PyObject* pystr )
104 {
105 #if PY_MAJOR_VERSION >= 3
106 	if( !PyUnicode_Check( pystr ) )
107 		return py_expected_type_fail( pystr, "unicode" );
108 #else
109    if( !(PyString_Check( pystr ) | PyUnicode_Check( pystr ) ) )
110     {
111         return py_expected_type_fail( pystr, "str or unicode" );
112     }
113 #endif
114    std::string str;
115    if( !convert_pystr_to_str( pystr, str ) )
116        return 0;
117    self->variable.setName( str );
118 	Py_RETURN_NONE;
119 }
120 
121 
122 static PyObject*
Variable_context(Variable * self)123 Variable_context( Variable* self )
124 {
125 	if( self->context )
126 		return newref( self->context );
127 	Py_RETURN_NONE;
128 }
129 
130 
131 static PyObject*
Variable_setContext(Variable * self,PyObject * value)132 Variable_setContext( Variable* self, PyObject* value )
133 {
134 	if( value != self->context )
135 	{
136 		PyObject* temp = self->context;
137 		self->context = newref( value );
138 		Py_XDECREF( temp );
139 	}
140 	Py_RETURN_NONE;
141 }
142 
143 
144 static PyObject*
Variable_value(Variable * self)145 Variable_value( Variable* self )
146 {
147 	return PyFloat_FromDouble( self->variable.value() );
148 }
149 
150 
151 static PyObject*
Variable_add(PyObject * first,PyObject * second)152 Variable_add( PyObject* first, PyObject* second )
153 {
154 	return BinaryInvoke<BinaryAdd, Variable>()( first, second );
155 }
156 
157 
158 static PyObject*
Variable_sub(PyObject * first,PyObject * second)159 Variable_sub( PyObject* first, PyObject* second )
160 {
161 	return BinaryInvoke<BinarySub, Variable>()( first, second );
162 }
163 
164 
165 static PyObject*
Variable_mul(PyObject * first,PyObject * second)166 Variable_mul( PyObject* first, PyObject* second )
167 {
168 	return BinaryInvoke<BinaryMul, Variable>()( first, second );
169 }
170 
171 
172 static PyObject*
Variable_div(PyObject * first,PyObject * second)173 Variable_div( PyObject* first, PyObject* second )
174 {
175 	return BinaryInvoke<BinaryDiv, Variable>()( first, second );
176 }
177 
178 
179 static PyObject*
Variable_neg(PyObject * value)180 Variable_neg( PyObject* value )
181 {
182 	return UnaryInvoke<UnaryNeg, Variable>()( value );
183 }
184 
185 
186 static PyObject*
Variable_richcmp(PyObject * first,PyObject * second,int op)187 Variable_richcmp( PyObject* first, PyObject* second, int op )
188 {
189 	switch( op )
190 	{
191 		case Py_EQ:
192 			return BinaryInvoke<CmpEQ, Variable>()( first, second );
193 		case Py_LE:
194 			return BinaryInvoke<CmpLE, Variable>()( first, second );
195 		case Py_GE:
196 			return BinaryInvoke<CmpGE, Variable>()( first, second );
197 		default:
198 			break;
199 	}
200 	PyErr_Format(
201 		PyExc_TypeError,
202 		"unsupported operand type(s) for %s: "
203 		"'%.100s' and '%.100s'",
204 		pyop_str( op ),
205 		first->ob_type->tp_name,
206 		second->ob_type->tp_name
207 	);
208 	return 0;
209 }
210 
211 
212 static PyMethodDef
213 Variable_methods[] = {
214 	{ "name", ( PyCFunction )Variable_name, METH_NOARGS,
215 	  "Get the name of the variable." },
216 	{ "setName", ( PyCFunction )Variable_setName, METH_O,
217 	  "Set the name of the variable." },
218 	{ "context", ( PyCFunction )Variable_context, METH_NOARGS,
219 	  "Get the context object associated with the variable." },
220 	{ "setContext", ( PyCFunction )Variable_setContext, METH_O,
221 	  "Set the context object associated with the variable." },
222 	{ "value", ( PyCFunction )Variable_value, METH_NOARGS,
223 	  "Get the current value of the variable." },
224 	{ 0 } // sentinel
225 };
226 
227 
228 static PyNumberMethods
229 Variable_as_number = {
230 	(binaryfunc)Variable_add,   /* nb_add */
231 	(binaryfunc)Variable_sub,   /* nb_subtract */
232 	(binaryfunc)Variable_mul,   /* nb_multiply */
233 #if PY_MAJOR_VERSION < 3
234 	(binaryfunc)Variable_div,   /* nb_divide */
235 #endif
236 	0,                          /* nb_remainder */
237 	0,                          /* nb_divmod */
238 	0,                          /* nb_power */
239 	(unaryfunc)Variable_neg,    /* nb_negative */
240 	0,                          /* nb_positive */
241 	0,                          /* nb_absolute */
242 #if PY_MAJOR_VERSION >= 3
243 	0,                          /* nb_bool */
244 #else
245 	0,                          /* nb_nonzero */
246 #endif
247 	0,                          /* nb_invert */
248 	0,                          /* nb_lshift */
249 	0,                          /* nb_rshift */
250 	0,                          /* nb_and */
251 	0,                          /* nb_xor */
252 	(binaryfunc)0,              /* nb_or */
253 #if PY_MAJOR_VERSION < 3
254 	0,                          /* nb_coerce */
255 #endif
256 	0,                          /* nb_int */
257 	0,                          /* nb_long */
258 	0,                          /* nb_float */
259 #if PY_MAJOR_VERSION < 3
260 	0,                          /* nb_oct */
261 	0,                          /* nb_hex */
262 #endif
263 	0,                          /* nb_inplace_add */
264 	0,                          /* nb_inplace_subtract */
265 	0,                          /* nb_inplace_multiply */
266 #if PY_MAJOR_VERSION < 3
267 	0,                          /* nb_inplace_divide */
268 #endif
269 	0,                          /* nb_inplace_remainder */
270 	0,                          /* nb_inplace_power */
271 	0,                          /* nb_inplace_lshift */
272 	0,                          /* nb_inplace_rshift */
273 	0,                          /* nb_inplace_and */
274 	0,                          /* nb_inplace_xor */
275 	0,                          /* nb_inplace_or */
276 	(binaryfunc)0,              /* nb_floor_divide */
277 	(binaryfunc)Variable_div,   /* nb_true_divide */
278 	0,                          /* nb_inplace_floor_divide */
279 	0,                          /* nb_inplace_true_divide */
280 #if PY_VERSION_HEX >= 0x02050000
281 	(unaryfunc)0,               /* nb_index */
282 #endif
283 #if PY_VERSION_HEX >= 0x03050000
284 	(binaryfunc)0,              /* nb_matrix_multiply */
285 	(binaryfunc)0,              /* nb_inplace_matrix_multiply */
286 #endif
287 };
288 
289 
290 PyTypeObject Variable_Type = {
291 	PyVarObject_HEAD_INIT( &PyType_Type, 0 )
292 	"kiwisolver.Variable",                  /* tp_name */
293 	sizeof( Variable ),                     /* tp_basicsize */
294 	0,                                      /* tp_itemsize */
295 	(destructor)Variable_dealloc,           /* tp_dealloc */
296 	(printfunc)0,                           /* tp_print */
297 	(getattrfunc)0,                         /* tp_getattr */
298 	(setattrfunc)0,                         /* tp_setattr */
299 #if PY_VERSION_HEX >= 0x03050000
300 	( PyAsyncMethods* )0,                   /* tp_as_async */
301 #elif PY_VERSION_HEX >= 0x03000000
302 	( void* ) 0,                            /* tp_reserved */
303 #else
304 	( cmpfunc )0,                           /* tp_compare */
305 #endif
306 	(reprfunc)Variable_repr,                /* tp_repr */
307 	(PyNumberMethods*)&Variable_as_number,  /* tp_as_number */
308 	(PySequenceMethods*)0,                  /* tp_as_sequence */
309 	(PyMappingMethods*)0,                   /* tp_as_mapping */
310 	(hashfunc)0,                            /* tp_hash */
311 	(ternaryfunc)0,                         /* tp_call */
312 	(reprfunc)0,                            /* tp_str */
313 	(getattrofunc)0,                        /* tp_getattro */
314 	(setattrofunc)0,                        /* tp_setattro */
315 	(PyBufferProcs*)0,                      /* tp_as_buffer */
316 #if PY_MAJOR_VERSION >= 3
317 	Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */
318 #else
319 	Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
320 #endif
321 	0,                                      /* Documentation string */
322 	(traverseproc)Variable_traverse,        /* tp_traverse */
323 	(inquiry)Variable_clear,                /* tp_clear */
324 	(richcmpfunc)Variable_richcmp,          /* tp_richcompare */
325 	0,                                      /* tp_weaklistoffset */
326 	(getiterfunc)0,                         /* tp_iter */
327 	(iternextfunc)0,                        /* tp_iternext */
328 	(struct PyMethodDef*)Variable_methods,  /* tp_methods */
329 	(struct PyMemberDef*)0,                 /* tp_members */
330 	0,                                      /* tp_getset */
331 	0,                                      /* tp_base */
332 	0,                                      /* tp_dict */
333 	(descrgetfunc)0,                        /* tp_descr_get */
334 	(descrsetfunc)0,                        /* tp_descr_set */
335 	0,                                      /* tp_dictoffset */
336 	(initproc)0,                            /* tp_init */
337 	(allocfunc)PyType_GenericAlloc,         /* tp_alloc */
338 	(newfunc)Variable_new,                  /* tp_new */
339 	(freefunc)PyObject_GC_Del,              /* tp_free */
340 	(inquiry)0,                             /* tp_is_gc */
341 	0,                                      /* tp_bases */
342 	0,                                      /* tp_mro */
343 	0,                                      /* tp_cache */
344 	0,                                      /* tp_subclasses */
345 	0,                                      /* tp_weaklist */
346 	(destructor)0                           /* tp_del */
347 };
348 
349 
import_variable()350 int import_variable()
351 {
352 	return PyType_Ready( &Variable_Type );
353 }
354