diff options
Diffstat (limited to 'Objects/complexobject.c')
-rw-r--r-- | Objects/complexobject.c | 303 |
1 files changed, 290 insertions, 13 deletions
diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 34dbab0..9a66c0c 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -8,6 +8,7 @@ #ifndef WITHOUT_COMPLEX #include "Python.h" +#include "structmember.h" /* Precisions used by repr() and str(), respectively. @@ -182,6 +183,17 @@ c_powi(Py_complex x, long n) } +static PyObject * +complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval) +{ + PyObject *op; + + op = PyType_GenericAlloc(type, 0); + if (op != NULL) + ((PyComplexObject *)op)->cval = cval; + return op; +} + PyObject * PyComplex_FromCComplex(Py_complex cval) { @@ -196,6 +208,15 @@ PyComplex_FromCComplex(Py_complex cval) return (PyObject *) op; } +static PyObject * +complex_subtype_from_doubles(PyTypeObject *type, double real, double imag) +{ + Py_complex c; + c.real = real; + c.imag = imag; + return complex_subtype_from_c_complex(type, c); +} + PyObject * PyComplex_FromDoubles(double real, double imag) { @@ -559,19 +580,261 @@ static PyMethodDef complex_methods[] = { {NULL, NULL} /* sentinel */ }; +static struct memberlist complex_members[] = { + {"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0}, + {"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0}, + {0}, +}; static PyObject * -complex_getattr(PyComplexObject *self, char *name) -{ - if (strcmp(name, "real") == 0) - return (PyObject *)PyFloat_FromDouble(self->cval.real); - else if (strcmp(name, "imag") == 0) - return (PyObject *)PyFloat_FromDouble(self->cval.imag); - else if (strcmp(name, "__members__") == 0) - return Py_BuildValue("[ss]", "imag", "real"); - return Py_FindMethod(complex_methods, (PyObject *)self, name); +complex_subtype_from_string(PyTypeObject *type, PyObject *v) +{ + extern double strtod(const char *, char **); + const char *s, *start; + char *end; + double x=0.0, y=0.0, z; + int got_re=0, got_im=0, done=0; + int digit_or_dot; + int sw_error=0; + int sign; + char buffer[256]; /* For errors */ + char s_buffer[256]; + int len; + + if (PyString_Check(v)) { + s = PyString_AS_STRING(v); + len = PyString_GET_SIZE(v); + } + else if (PyUnicode_Check(v)) { + if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) { + PyErr_SetString(PyExc_ValueError, + "complex() literal too large to convert"); + return NULL; + } + if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), + PyUnicode_GET_SIZE(v), + s_buffer, + NULL)) + return NULL; + s = s_buffer; + len = (int)strlen(s); + } + else if (PyObject_AsCharBuffer(v, &s, &len)) { + PyErr_SetString(PyExc_TypeError, + "complex() arg is not a string"); + return NULL; + } + + /* position on first nonblank */ + start = s; + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (s[0] == '\0') { + PyErr_SetString(PyExc_ValueError, + "complex() arg is an empty string"); + return NULL; + } + + z = -1.0; + sign = 1; + do { + + switch (*s) { + + case '\0': + if (s-start != len) { + PyErr_SetString( + PyExc_ValueError, + "complex() arg contains a null byte"); + return NULL; + } + if(!done) sw_error=1; + break; + + case '-': + sign = -1; + /* Fallthrough */ + case '+': + if (done) sw_error=1; + s++; + if ( *s=='\0'||*s=='+'||*s=='-' || + isspace(Py_CHARMASK(*s)) ) sw_error=1; + break; + + case 'J': + case 'j': + if (got_im || done) { + sw_error = 1; + break; + } + if (z<0.0) { + y=sign; + } + else{ + y=sign*z; + } + got_im=1; + s++; + if (*s!='+' && *s!='-' ) + done=1; + break; + + default: + if (isspace(Py_CHARMASK(*s))) { + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (s[0] != '\0') + sw_error=1; + else + done = 1; + break; + } + digit_or_dot = + (*s=='.' || isdigit(Py_CHARMASK(*s))); + if (done||!digit_or_dot) { + sw_error=1; + break; + } + errno = 0; + PyFPE_START_PROTECT("strtod", return 0) + z = strtod(s, &end) ; + PyFPE_END_PROTECT(z) + if (errno != 0) { + sprintf(buffer, + "float() out of range: %.150s", s); + PyErr_SetString( + PyExc_ValueError, + buffer); + return NULL; + } + s=end; + if (*s=='J' || *s=='j') { + + break; + } + if (got_re) { + sw_error=1; + break; + } + + /* accept a real part */ + x=sign*z; + got_re=1; + if (got_im) done=1; + z = -1.0; + sign = 1; + break; + + } /* end of switch */ + + } while (*s!='\0' && !sw_error); + + if (sw_error) { + PyErr_SetString(PyExc_ValueError, + "complex() arg is a malformed string"); + return NULL; + } + + return complex_subtype_from_doubles(type, x, y); +} + +static PyObject * +complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *r, *i, *tmp; + PyNumberMethods *nbr, *nbi = NULL; + Py_complex cr, ci; + int own_r = 0; + static char *kwlist[] = {"real", "imag", 0}; + + r = Py_False; + i = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:complex", kwlist, + &r, &i)) + return NULL; + if (PyString_Check(r) || PyUnicode_Check(r)) + return complex_subtype_from_string(type, r); + if ((nbr = r->ob_type->tp_as_number) == NULL || + nbr->nb_float == NULL || + (i != NULL && + ((nbi = i->ob_type->tp_as_number) == NULL || + nbi->nb_float == NULL))) { + PyErr_SetString(PyExc_TypeError, + "complex() arg can't be converted to complex"); + return NULL; + } + /* XXX Hack to support classes with __complex__ method */ + if (PyInstance_Check(r)) { + static PyObject *complexstr; + PyObject *f; + if (complexstr == NULL) { + complexstr = PyString_InternFromString("__complex__"); + if (complexstr == NULL) + return NULL; + } + f = PyObject_GetAttr(r, complexstr); + if (f == NULL) + PyErr_Clear(); + else { + PyObject *args = Py_BuildValue("()"); + if (args == NULL) + return NULL; + r = PyEval_CallObject(f, args); + Py_DECREF(args); + Py_DECREF(f); + if (r == NULL) + return NULL; + own_r = 1; + } + } + if (PyComplex_Check(r)) { + cr = ((PyComplexObject*)r)->cval; + if (own_r) { + Py_DECREF(r); + } + } + else { + tmp = PyNumber_Float(r); + if (own_r) { + Py_DECREF(r); + } + if (tmp == NULL) + return NULL; + if (!PyFloat_Check(tmp)) { + PyErr_SetString(PyExc_TypeError, + "float(r) didn't return a float"); + Py_DECREF(tmp); + return NULL; + } + cr.real = PyFloat_AsDouble(tmp); + Py_DECREF(tmp); + cr.imag = 0.0; + } + if (i == NULL) { + ci.real = 0.0; + ci.imag = 0.0; + } + else if (PyComplex_Check(i)) + ci = ((PyComplexObject*)i)->cval; + else { + tmp = (*nbi->nb_float)(i); + if (tmp == NULL) + return NULL; + ci.real = PyFloat_AsDouble(tmp); + Py_DECREF(tmp); + ci.imag = 0.; + } + cr.real -= ci.imag; + cr.imag += ci.real; + return complex_subtype_from_c_complex(type, cr); } +static char complex_doc[] = +"complex(real[, imag]) -> complex number\n\ +\n\ +Create a complex number from a real part and an optional imaginary part.\n\ +This is equivalent to (real + imag*1j) where imag defaults to 0."; + static PyNumberMethods complex_as_number = { (binaryfunc)complex_add, /* nb_add */ (binaryfunc)complex_sub, /* nb_subtract */ @@ -606,7 +869,7 @@ PyTypeObject PyComplex_Type = { 0, (destructor)complex_dealloc, /* tp_dealloc */ (printfunc)complex_print, /* tp_print */ - (getattrfunc)complex_getattr, /* tp_getattr */ + 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)complex_repr, /* tp_repr */ @@ -616,14 +879,28 @@ PyTypeObject PyComplex_Type = { (hashfunc)complex_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc)complex_str, /* tp_str */ - 0, /* tp_getattro */ + PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + complex_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ complex_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + complex_methods, /* tp_methods */ + complex_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + complex_new, /* tp_new */ }; #endif |