[Python-checkins] r46116 - sandbox/trunk/decimal-c/_decimal.c sandbox/trunk/decimal-c/decimal.h sandbox/trunk/decimal-c/decimal.py

georg.brandl python-checkins at python.org
Tue May 23 18:09:05 CEST 2006


Author: georg.brandl
Date: Tue May 23 18:09:04 2006
New Revision: 46116

Modified:
   sandbox/trunk/decimal-c/_decimal.c
   sandbox/trunk/decimal-c/decimal.h
   sandbox/trunk/decimal-c/decimal.py
Log:
Make subclassing possible.



Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c	(original)
+++ sandbox/trunk/decimal-c/_decimal.c	Tue May 23 18:09:04 2006
@@ -178,6 +178,7 @@
 static PyObject *context_new(PyTypeObject *, PyObject *, PyObject *);
 static int decimal_nonzero(decimalobject *);
 static decimalobject *decimal_copy(decimalobject *);
+static decimalobject *_decimal_from_pylong(PyTypeObject *, PyObject *, contextobject *);
 static PyObject * py_context_shallow_copy(PyObject *, PyObject *, PyObject *);
 static contextobject * context_shallow_copy(contextobject *);
 
@@ -185,7 +186,7 @@
 
 
 static decimalobject *
-_new_decimalobj(long ndigits, char sign, long exp)
+_new_decimalobj(PyTypeObject *type, long ndigits, char sign, long exp)
 {
     decimalobject *new;
     char *arr;
@@ -198,7 +199,7 @@
         PyErr_NoMemory();
         return NULL;
     }
-    new = (decimalobject *)PyObject_NEW(decimalobject, &PyDecimal_DecimalType);
+    new = (decimalobject *)type->tp_alloc(type, 0);
     if (new == NULL)
         return NULL;
     new->sign = sign;
@@ -208,6 +209,9 @@
     return new;
 }
 
+#define _NEW_decimalobj(ndigits, sign, exp) \
+  _new_decimalobj(self->ob_type, ndigits, sign, exp)
+
 /* Check whether the number(s) aren't really numbers.
  *
  * If x and/or y are sNaN, signal, possibly storing the result
@@ -275,7 +279,7 @@
         return decimal_copy(self);
     }
 
-    new = _new_decimalobj(self->ob_size + 1,  /* we possibly need a new digit */
+    new = _NEW_decimalobj(self->ob_size + 1,  /* we possibly need a new digit */
                           self->sign, self->exp);
     if (!new) return NULL;
     
@@ -312,7 +316,7 @@
 _round_down(decimalobject *self, long prec, long expdiff, contextobject *ctx)
 {
     long i;
-    decimalobject *new = _new_decimalobj(prec, self->sign, self->exp - expdiff);
+    decimalobject *new = _NEW_decimalobj(prec, self->sign, self->exp - expdiff);
     if (!new) return NULL;
     for (i = 0; i < prec; i++)
         new->digits[i] = self->digits[i];
@@ -324,7 +328,7 @@
 _round_up(decimalobject *self, long prec, long expdiff, contextobject *ctx)
 {
     long i;
-    decimalobject *new = _new_decimalobj(prec, self->sign, self->exp - expdiff);
+    decimalobject *new = _NEW_decimalobj(prec, self->sign, self->exp - expdiff);
     decimalobject *new2 = NULL;
     if (!new) return NULL;
     for (i = 0; i < prec; i++)
@@ -357,7 +361,7 @@
     long i;
     assert(expdiff > 0);
     if (!tmp) {
-        tmp = _new_decimalobj(prec, self->sign, self->exp - expdiff);
+        tmp = _NEW_decimalobj(prec, self->sign, self->exp - expdiff);
         if (!tmp) return NULL;
         for (i = 0; i < prec; i++)
             tmp->digits[i] = self->digits[i];
@@ -383,7 +387,7 @@
     long i;
     decimalobject *tmp;
     assert(expdiff > 0);
-    tmp = _new_decimalobj(prec, self->sign, self->exp - expdiff);
+    tmp = _NEW_decimalobj(prec, self->sign, self->exp - expdiff);
     if (!tmp) return NULL;
     for (i = 0; i < prec; i++)
         tmp->digits[i] = self->digits[i];
@@ -404,7 +408,7 @@
     decimalobject *tmp;
     long i;
     assert(expdiff > 0);
-    tmp = _new_decimalobj(prec, self->sign, self->exp - expdiff);
+    tmp = _NEW_decimalobj(prec, self->sign, self->exp - expdiff);
     if (!tmp) return NULL;
     for (i = 0; i < prec; i++)
         tmp->digits[i] = self->digits[i];
@@ -486,7 +490,7 @@
         else 
             i = prec;
         
-        new = _new_decimalobj(i, self->sign,
+        new = _NEW_decimalobj(i, self->sign,
                               self->ob_size - prec + self->exp);
         if (!new) return NULL;
         while (i--)
@@ -502,14 +506,14 @@
     }
     
     if (prec == 0) {
-        new = _new_decimalobj(self->ob_size+1, self->sign, self->exp);
+        new = _NEW_decimalobj(self->ob_size+1, self->sign, self->exp);
         if (!new) return NULL;
         new->digits[0] = 0;
         for (i = 1; i < new->ob_size; i++)
             new->digits[i] = self->digits[i-1];
         prec = 1;
     } else if (prec < 0) {
-        new = _new_decimalobj(2, self->sign,
+        new = _NEW_decimalobj(2, self->sign,
                               self->exp + self->ob_size - prec - 1);
         if (!new) return NULL;
         new->digits[0] = 0;
@@ -525,7 +529,7 @@
         return new;
     else if (expdiff > 0) {
         /* we need to extend precision */
-        new2 = _new_decimalobj(prec, new->sign, new->exp - expdiff);
+        new2 = _NEW_decimalobj(prec, new->sign, new->exp - expdiff);
         if (!new2) {
             Py_DECREF(new);
             return NULL;
@@ -612,7 +616,7 @@
         return context_raise_error(ctx, S_INV_OPERATION, "rescale(a, INF)", NULL);
 
     if (!decimal_nonzero(self)) {
-        ans = _new_decimalobj(1, self->sign, exp);
+        ans = _NEW_decimalobj(1, self->sign, exp);
         if (!ans)
             return NULL;
         ans->digits[0] = 0;
@@ -627,14 +631,14 @@
 
     digits += 1;
     if (digits < 0) {
-        ans = _new_decimalobj(2, self->sign, self->exp - digits);
+        ans = _NEW_decimalobj(2, self->sign, self->exp - digits);
         if (!ans)
             return NULL;
         ans->digits[0] = 0;
         ans->digits[1] = 1;
         digits = 1;
     } else {
-        ans = _new_decimalobj(self->ob_size+1, self->sign, self->exp);
+        ans = _NEW_decimalobj(self->ob_size+1, self->sign, self->exp);
         if (!ans)
             return NULL;
         for (i = 0; i < self->ob_size; i++)
@@ -796,6 +800,25 @@
     return ans;
 }
 
+/* convert something to a Decimal. Returns NULL on failure, but
+ * does not set an exception! */
+static decimalobject *
+_convert_to_decimal(PyTypeObject *type, PyObject *thing, contextobject *ctx)
+{
+    if (PyDecimal_Check(thing)) {
+        Py_INCREF(thing);
+        return (decimalobject *)thing;
+    } else if (PyInt_Check(thing)) {
+        long val = PyInt_AsLong(thing);
+        if (val == -1 && PyErr_Occurred())
+            return NULL;
+        return (decimalobject *)decimal_from_long(type, val);
+    } else if (PyLong_Check(thing)) {
+        return _decimal_from_pylong(type, thing, ctx);
+    }
+    return NULL;
+}
+
 #define STUB_HEAD static PyObject *
 #define STUB_TAIL  (PyObject *self, PyObject *args) { return NULL; }
 #define STUB_TAIL1 (PyObject *self) { return NULL; }
@@ -804,19 +827,54 @@
 
 static char *ctxkwlist[] = {"context", 0};
 
-#define PARSECONTEXT(methname) \
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:" methname, ctxkwlist, &ctx)) \
-     { return NULL; } \
+#define ENSURE_DECIMAL(methname, dec) \
+  dec = _convert_to_decimal((PyObject *)dec, ctx); \
+  if (!dec) { \
+      PyErr_SetString(PyExc_TypeError, methname ": " #dec " must be a Decimal object"); \
+      return NULL; \
+  }
+
+#define ENSURE_CONTEXT(methname, ctx) \
   if (ctx == NULL) { \
       if (!(ctx = getcontext())) return NULL; \
   } else if (!PyDecimalContext_Check(ctx)) { \
-      PyErr_SetString(PyExc_TypeError, "context must be a Context object"); \
+      PyErr_SetString(PyExc_TypeError, methname ": context must be a Context object"); \
       return NULL; \
   }
 
+#define PARSE_CONTEXT(methname, ctx) \
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:" methname, ctxkwlist, &ctx)) \
+     { return NULL; } \
+  ENSURE_CONTEXT(methname, ctx)
+
 STUB(compare)
-STUB(max)
-STUB(min)
+
+static decimalobject *
+decimal_max(decimalobject *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"other", "context", 0};
+    decimalobject *other = NULL;
+    contextobject *ctx = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:max", kwlist,
+                                     &other, &ctx))
+        return NULL;
+    ENSURE_CONTEXT("max", ctx);
+
+}
+
+static decimalobject *
+decimal_min(decimalobject *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"other", "context", 0};
+    decimalobject *other = NULL;
+    contextobject *ctx = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:min", kwlist,
+                                     &other, &ctx))
+        return NULL;
+    ENSURE_CONTEXT("max", ctx);
+}
 
 /* strip trailing 0s, change anything equal to 0 to 0e0 */
 static decimalobject *
@@ -824,7 +882,7 @@
 {
     decimalobject *dup, *new;
     contextobject *ctx = NULL;
-    PARSECONTEXT("normalize");
+    PARSE_CONTEXT("normalize", ctx);
 
     if (ISSPECIAL(self)) {
         decimalobject *nan = NULL;
@@ -838,7 +896,7 @@
         return dup;
 
     if (!decimal_nonzero(dup)) {
-        new = _new_decimalobj(1, dup->sign, 0);
+        new = _NEW_decimalobj(1, dup->sign, 0);
         Py_DECREF(dup);
         if (!new) return NULL;
         new->digits[0] = 0;
@@ -947,7 +1005,7 @@
     decimalobject *new;
     long size = self->ob_size;
     
-    new = _new_decimalobj(size, self->sign, self->exp);
+    new = _NEW_decimalobj(size, self->sign, self->exp);
     if (!new)
         return NULL;
     while (--size)
@@ -1158,7 +1216,7 @@
 }
 
 static decimalobject *
-_decimal_fromliteralnan(char *str, long len, contextobject *ctx)
+_decimal_fromliteralnan(PyTypeObject *type, char *str, long len, contextobject *ctx)
 {
     char literalsign = 0, sign = 0;
     decimalobject *new;
@@ -1206,7 +1264,7 @@
         return context_raise_error(ctx, C_CONV_SYNTAX, 
                                         "diagnostic info too long", NULL);
 
-    new = _new_decimalobj(size, sign, 0);
+    new = _new_decimalobj(type, size, sign, 0);
     if (!new)
         return NULL;
     for (i = 0; i < size; i++)
@@ -1220,7 +1278,7 @@
 };
 
 static decimalobject *
-_decimal_fromliteralinfinity(char *str)
+_decimal_fromliteralinfinity(PyTypeObject *type, char *str)
 {
     decimalobject *new;
     char **p = infinities;
@@ -1235,7 +1293,7 @@
         }
     } while (*++p);
     if (sign) {
-        new = _new_decimalobj(1, sign, 0);
+        new = _new_decimalobj(type, 1, sign, 0);
         if (!new)
             return NULL;
         new->digits[0] = 0;
@@ -1245,7 +1303,7 @@
 }
 
 static decimalobject *
-_decimal_fromliteral(char *str, long len, contextobject *ctx)
+_decimal_fromliteral(PyTypeObject *type, char *str, long len, contextobject *ctx)
 {
     long ipos = 0;   /* start of integral digits */
     long dpos = -1;  /* decimal point location */
@@ -1317,7 +1375,7 @@
 
 finish:
     ndigits = dend - ipos - (dpos<0 ? 0 : 1);
-    new = _new_decimalobj(ndigits, sign, exp);
+    new = _new_decimalobj(type, ndigits, sign, exp);
     if (!new)
         return NULL;
     i = 0;
@@ -1333,32 +1391,38 @@
                                "invalid literal for Decimal", NULL);
 }
 
-PyObject *
-PyDecimal_FromString(char *buffer, long buf_len, contextobject *ctx)
+static PyObject *
+decimal_from_string(PyTypeObject *type, char *buffer,
+                    long buf_len, contextobject *ctx)
 {
     decimalobject *new;
     
-    new = _decimal_fromliteralinfinity(buffer);
+    new = _decimal_fromliteralinfinity(type, buffer);
     if (new) return (PyObject *)new;
     if (PyErr_Occurred()) return NULL;
     
-    new = _decimal_fromliteralnan(buffer, buf_len, ctx);
+    new = _decimal_fromliteralnan(type, buffer, buf_len, ctx);
     if (new) return (PyObject *)new;
     if (PyErr_Occurred()) return NULL;
     
-    return (PyObject *)_decimal_fromliteral(buffer, buf_len, ctx);
+    return (PyObject *)_decimal_fromliteral(type, buffer, buf_len, ctx);
 }
 
+PyObject *
+PyDecimal_FromString(char *buffer, long buf_len, contextobject *ctx)
+{
+    return decimal_from_string(&PyDecimal_DecimalType, buffer, buf_len, ctx);
+}
 
 PyObject *
-PyDecimal_FromLong(long value)
+_decimal_from_long(PyTypeObject *type, long value)
 {
     decimalobject *new;
     long v = value;
     int ndigits = 0, neg = 0, i = 0;
 
     if (value == 0) {
-        new = _new_decimalobj(1, 0, 0);
+        new = _new_decimalobj(type, 1, 0, 0);
         if (!new) return NULL;
         new->digits[0] = 0;
         return (PyObject *)new;
@@ -1372,7 +1436,7 @@
         v /= 10;
     }
     
-    new = _new_decimalobj(ndigits, (neg ? SIGN_NEG : SIGN_POS), 0);
+    new = _new_decimalobj(type, ndigits, (neg ? SIGN_NEG : SIGN_POS), 0);
     if (!new) return NULL;
     while (value) {
         new->digits[ndigits-i-1] = value % 10;
@@ -1382,9 +1446,15 @@
     return (PyObject *)new;
 }
 
+PyObject *
+PyDecimal_FromLong(long value)
+{
+    return _decimal_from_long(&PyDecimal_DecimalType, value);
+}
+
 /* convert from a 3-tuple of (sign, digits, exp) */
 PyObject *
-PyDecimal_FromSequence(PyObject *seq)
+decimal_from_sequence(PyTypeObject *type, PyObject *seq)
 {
     decimalobject *new = NULL;
     PyObject *tup, *digits, *digtup = NULL, *item;
@@ -1415,7 +1485,7 @@
         PyErr_SetString(PyExc_ValueError, "Invalid arguments");
         goto err;
     }
-    new = _new_decimalobj(PyTuple_GET_SIZE(digtup), sign, exp);
+    new = _new_decimalobj(type, PyTuple_GET_SIZE(digtup), sign, exp);
     for (i = 0; i < new->ob_size; i++) {
         item = PyTuple_GET_ITEM(digtup, i);
         if (PyInt_Check(item)) {
@@ -1448,10 +1518,42 @@
 err:
     Py_XDECREF(digtup);
     Py_DECREF(tup);
-    Py_DECREF(new);
+    Py_XDECREF(new);
     return NULL;
 }
 
+PyObject *
+PyDecimal_FromSequence(PyObject *seq)
+{
+    return decimal_from_sequence(&PyDecimal_DecimalType, seq);
+}
+
+static decimalobject *
+_decimal_from_pylong(PyTypeObject *type, PyObject *val, contextobject *ctx)
+{
+    char *buffer;
+    Py_ssize_t buf_len = 0;
+    PyObject *strval;
+    decimalobject *res;
+
+    strval = PyObject_Str(val);
+    if (!strval)
+        return NULL;
+    if (PyObject_AsCharBuffer(strval, (const char **)&buffer, &buf_len) == -1) {
+        Py_DECREF(strval);
+        return NULL;
+    }
+    if (buf_len > LONG_MAX) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    res = (decimalobject *)decimal_from_string(type, buffer, buf_len, ctx);
+    Py_DECREF(strval);
+    return res;
+}
+
+static PyObject *decimal_new(PyTypeObject *, PyObject *, PyObject *);
+
 static PyObject *
 decimal_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
@@ -1460,20 +1562,18 @@
     PyObject *context = NULL;
     PyObject *repr;
     contextobject *ctx;
-    int decref_value = 0;
     char *buffer;
     Py_ssize_t buf_len = 0;
-    
-    /* XXX
-    if (type != &PyDecimal_DecimalType)
-        return decimal_subtype_new(type, args, kwds);
-    */
+
     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:Decimal",
                                      kwlist, &value, &context))
         return NULL;
+
     if (value == NULL) {
-        value = PyString_FromString("0");
-        decref_value = 1;
+        decimalobject *new = _new_decimalobj(type, 1, 0, 0);
+        if (!new) return NULL;
+        new->digits[0] = 0;
+        return new;
     }
 
     if (PyFloat_Check(value)) {
@@ -1486,42 +1586,28 @@
         return (PyObject *)decimal_copy((decimalobject *)value);
 
     if (PyList_Check(value) || PyTuple_Check(value))
-        return PyDecimal_FromSequence(value);
+        return decimal_from_sequence(type, value);
 
     if (PyInt_Check(value)) {
         long x = PyInt_AsLong(value);
         if (x == -1 && PyErr_Occurred())
             return NULL;
-        return PyDecimal_FromLong(x);
-    }
-
-    if (PyLong_Check(value)) {
-        /* XXX: possibly do div-mod-loop */
-        value = PyObject_Str(value);
-        if (!value)
-            return NULL;
-        decref_value = 1;
+        return decimal_from_long(type, x);
     }
 
     ctx = getcontext();
-    if (!ctx) {
-        if (decref_value) {
-            Py_DECREF(value);
-        }
-        return NULL;
-    }
+    if (!ctx) return NULL;
+
+    if (PyLong_Check(value))
+        return (PyObject *)_decimal_from_pylong(type, value, ctx);
 
     /* try buffer interface (e.g. strings and unicode) */
     if (PyObject_AsCharBuffer(value, (const char **)&buffer, &buf_len) == 0) {
         if (buf_len > LONG_MAX) {
             PyErr_NoMemory();
-            if (decref_value) { Py_DECREF(value); }
             return NULL;
         }
-        PyObject *res = (PyObject *)PyDecimal_FromString(buffer, buf_len, ctx);
-        if (decref_value) {
-            Py_DECREF(value);
-        }
+        PyObject *res = (PyObject *)decimal_from_string(type, buffer, buf_len, ctx);
         return res;
     }
 
@@ -1545,11 +1631,13 @@
 static PyObject *
 decimal_str(decimalobject *d)
 {
-    /* XXX: quick hack */
     char buf[1000];
     char dig[2];
     long i;
-    
+
+    /*if (ISSPECIAL(d)) {
+        if (ISNAN(d))
+    */
     dig[1] = 0;
     PyOS_snprintf(buf, 1000, "sign=%i, exp=%ld, digits=", d->sign, d->exp);
     for (i = 0; i < d->ob_size; i++) {
@@ -1653,7 +1741,7 @@
         PyErr_NoMemory();
         return -1;
     }
-    for (i = 0; i < PyTuple_GET_SIZE(value); i++) {
+    for (i = 0; i < size; i++) {
         item = PyTuple_GET_ITEM(value, i);
         if (!PyInt_Check(item)) {
             PyObject_FREE(arr);
@@ -1695,8 +1783,8 @@
     PyObject_HEAD_INIT(NULL)
     0,                           /* ob_size */
     MODULE_NAME ".Decimal",      /* tp_name */
-    sizeof(decimalobject) - sizeof(char), /* tp_basicsize */
-    sizeof(char),                /* tp_itemsize */
+    sizeof(decimalobject),       /* tp_basicsize */
+    0,                           /* tp_itemsize */
     (destructor)decimal_dealloc, /* tp_dealloc */
     0,                           /* tp_print */
     0,                           /* tp_getattr */
@@ -1730,7 +1818,7 @@
     0,                           /* tp_descr_set */
     0,                           /* tp_dictoffset */
     0,                           /* tp_init */
-    0,                           /* tp_alloc */
+    PyType_GenericAlloc,         /* tp_alloc */
     decimal_new,                 /* tp_new */
     PyObject_Del,                /* tp_free */
 };

Modified: sandbox/trunk/decimal-c/decimal.h
==============================================================================
--- sandbox/trunk/decimal-c/decimal.h	(original)
+++ sandbox/trunk/decimal-c/decimal.h	Tue May 23 18:09:04 2006
@@ -43,6 +43,12 @@
 
 static PyTypeObject PyDecimal_DecimalContextType;
 
+/* functions *****************************************************************/
+
+PyAPI_FUNC(PyObject *) PyDecimal_FromString(char *, long, PyDecimalContextObject *);
+PyAPI_FUNC(PyObject *) PyDecimal_FromLong(long);
+PyAPI_FUNC(PyObject *) PyDecimal_FromSequence(PyObject *);
+
 /* type checking macros ******************************************************/
 
 #define PyDecimal_Check(op) PyObject_TypeCheck((op), &PyDecimal_DecimalType)

Modified: sandbox/trunk/decimal-c/decimal.py
==============================================================================
--- sandbox/trunk/decimal-c/decimal.py	(original)
+++ sandbox/trunk/decimal-c/decimal.py	Tue May 23 18:09:04 2006
@@ -470,10 +470,6 @@
     #  (-1)**_sign * _int * 10**_exp
     # Special values are signified by _is_special == True
 
-    @property
-    def _is_special(self):
-        return (self._sign > 1)
-
 #    # We're immutable, so use __new__ not __init__
 #    def __new__(cls, value="0", context=None):
 #        """Create a decimal point instance.


More information about the Python-checkins mailing list