diff Objects/complexobject.c @ 18933:09df3254b49d legacy-trunk

Merge of descr-branch back into trunk.
author Tim Peters <tim.peters@gmail.com>
date Thu, 02 Aug 2001 04:15:00 +0000
parents 2c1be7924b04
children f20727cc3d0f
line wrap: on
line diff
--- a/Objects/complexobject.c	Wed Aug 01 21:44:14 2001 +0000
+++ b/Objects/complexobject.c	Thu Aug 02 04:15:00 2001 +0000
@@ -8,6 +8,7 @@
 #ifndef WITHOUT_COMPLEX
 
 #include "Python.h"
+#include "structmember.h"
 
 /* Precisions used by repr() and str(), respectively.
 
@@ -182,6 +183,17 @@
 
 }
 
+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 @@
 	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 @@
 	{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)
+complex_subtype_from_string(PyTypeObject *type, PyObject *v)
 {
-	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);
+	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 @@
 	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 @@
 	(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