[Python-checkins] r46105 - 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 14:07:27 CEST 2006


Author: georg.brandl
Date: Tue May 23 14:07:26 2006
New Revision: 46105

Modified:
   sandbox/trunk/decimal-c/_decimal.c
   sandbox/trunk/decimal-c/decimal.h
   sandbox/trunk/decimal-c/decimal.py
Log:
Don't use the PyObject_VAR machinery any longer.



Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c	(original)
+++ sandbox/trunk/decimal-c/_decimal.c	Tue May 23 14:07:26 2006
@@ -181,18 +181,26 @@
 
 
 static decimalobject *
-_new_decimalobj(Py_ssize_t ndigits, char sign, long exp)
+_new_decimalobj(long ndigits, char sign, long exp)
 {
     decimalobject *new;
-    if (ndigits > PY_SSIZE_T_MAX) {
+    char *arr;
+    if (ndigits > LONG_MAX) {
         PyErr_NoMemory();
         return NULL;
     }
-    new = (decimalobject *)PyObject_NEW_VAR(decimalobject, &PyDecimal_DecimalType, ndigits);
+    arr = PyObject_MALLOC(ndigits);
+    if (!arr) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    new = (decimalobject *)PyObject_NEW(decimalobject, &PyDecimal_DecimalType);
     if (new == NULL)
         return NULL;
     new->sign = sign;
     new->exp = exp;
+    new->ob_size = ndigits;
+    new->digits = arr;
     return new;
 }
 
@@ -249,13 +257,14 @@
 static decimalobject *
 _decimal_increment(decimalobject *self, long prec, contextobject *ctx)
 {
+    /* XXX */
 }
 
 /* Round towards 0, that is, truncate digits. */
 static decimalobject *
 _round_down(decimalobject *self, long prec, long expdiff, contextobject *ctx)
 {
-    Py_ssize_t i;
+    long i;
     decimalobject *new = _new_decimalobj(prec, self->sign, self->exp - expdiff);
     if (!new) return NULL;
     for (i = 0; i < prec; i++)
@@ -267,9 +276,9 @@
 static decimalobject *
 _round_up(decimalobject *self, long prec, long expdiff, contextobject *ctx)
 {
-    Py_ssize_t i;
+    long i;
     decimalobject *new = _new_decimalobj(prec, self->sign, self->exp - expdiff);
-    decimalobject *new2;
+    decimalobject *new2 = NULL;
     if (!new) return NULL;
     for (i = 0; i < prec; i++)
         new->digits[i] = self->digits[i];
@@ -290,27 +299,54 @@
 }
 
 /* Actually round half up. Returns a new reference, either on tmp
- * or a new decimalobject. */
+ * or a new decimalobject, and steals one reference on tmp in turn,
+ * if it was passed in so that you can just do
+ * return _do_round_half_up(...) */
 static decimalobject *
 _do_round_half_up(decimalobject *self, long prec, long expdiff,
                     contextobject *ctx, decimalobject *tmp)
 {
-    Py_ssize_t i;
+    decimalobject *new;
+    long i;
     if (!tmp) {
         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];
     }
-    /*if (self->ob_size > prec && self->digits[prec] >= 5) {*/
-
+    if (self->ob_size > prec && self->digits[prec] >= 5) {
+        new = _decimal_increment(tmp, 1, ctx);
+        Py_DECREF(tmp);
+        if (!new) return NULL;
+        if (new->ob_size > prec) {
+            new->ob_size--;
+            new->exp++;
+        }
+        return new;            
+    } else {
+        return tmp;
+    }
 }
 
 /* Round 5 down. */
 static decimalobject *
 _round_half_down(decimalobject *self, long prec, long expdiff, contextobject *ctx)
 {
-    
+    long i;
+    decimalobject *tmp;
+    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];
+    if (self->digits[prec] == 5) {
+        for (i = prec+1; i < self->ob_size; i++) {
+            if (self->digits[i] != 0)
+                return _do_round_half_up(self, prec, expdiff, ctx, tmp);
+        }
+        /* self ends in 5000...., so tmp is okay */
+        return tmp;
+    }
+    return _do_round_half_up(self, prec, expdiff, ctx, tmp);
 }
 
 static decimalobject *
@@ -348,7 +384,7 @@
 {
     decimalobject *new, *new2 = NULL, *errres;
     contextobject *ctx2 = NULL;
-    Py_ssize_t i, expdiff;
+    long i, expdiff;
     round_func rnd_func;
     
     if (ISSPECIAL(self)) {
@@ -482,10 +518,10 @@
 _decimal_rescale(decimalobject *self, long exp, contextobject *ctx,
                  int rounding, int watchexp)
 {
-    decimalobject *ans = NULL, *tmp, *tmp2;
+    decimalobject *ans = NULL, *tmp;
     int ret;
     long diff, adj;
-    Py_ssize_t digits, i;
+    long digits, i;
 
     if (ISSPECIAL(self)) {
         if (ISINF(self))
@@ -833,7 +869,7 @@
 decimal_copy(decimalobject *self)
 {
     decimalobject *new;
-    Py_ssize_t size = self->ob_size;
+    long size = self->ob_size;
     
     new = _new_decimalobj(size, self->sign, self->exp);
     if (!new)
@@ -857,7 +893,7 @@
 decimal_as_tuple(decimalobject *self)
 {
     PyObject *digits, *res, *d;
-    Py_ssize_t i;
+    long i;
 
     digits = PyTuple_New(self->ob_size);
     if (!digits)
@@ -1019,7 +1055,7 @@
 int
 _decimal_isint(decimalobject *d)
 {
-    Py_ssize_t i;
+    long i;
 
     if (d->exp >= 0)
         /* if the exponent is positive, there's no
@@ -1035,17 +1071,19 @@
 }
 
 static void
-decimal_dealloc(PyObject *d)
+decimal_dealloc(decimalobject *d)
 {
+    PyObject_FREE(d->digits);
     d->ob_type->tp_free(d);
 }
 
 static decimalobject *
-_decimal_fromliteralnan(char *str, Py_ssize_t len, contextobject *ctx)
+_decimal_fromliteralnan(char *str, long len, contextobject *ctx)
 {
+    /* XXX: what if buffer is longer than LONG_MAX? */
     char literalsign = 0, sign = 0;
     decimalobject *new;
-    Py_ssize_t size = 0, i;
+    long size = 0, i;
     char *start = NULL, *p;
 
     if (len < 3)
@@ -1128,16 +1166,15 @@
 }
 
 static decimalobject *
-_decimal_fromliteral(char *str, Py_ssize_t len, contextobject *ctx)
+_decimal_fromliteral(char *str, long len, contextobject *ctx)
 {
-    Py_ssize_t ipos = 0;   /* start of integral digits */
-    Py_ssize_t dpos = -1;  /* decimal point location */
-    Py_ssize_t dend = len; /* end of integral/decimal digits */
+    long ipos = 0;   /* start of integral digits */
+    long dpos = -1;  /* decimal point location */
+    long dend = len; /* end of integral/decimal digits */
     char *p = str;
     char sign = 0;
     decimalobject *new;
-    long exp = 0;
-    Py_ssize_t i = 0, ndigits;
+    long exp = 0, i = 0, ndigits;
 
     /* optional sign */
     if (*p == '+') {
@@ -1207,7 +1244,7 @@
 }
 
 PyObject *
-PyDecimal_FromString(char *buffer, Py_ssize_t buf_len, contextobject *ctx)
+PyDecimal_FromString(char *buffer, long buf_len, contextobject *ctx)
 {
     decimalobject *new;
     
@@ -1262,8 +1299,7 @@
     decimalobject *new = NULL;
     PyObject *tup, *digits, *digtup = NULL, *item;
     int sign;
-    long exp;
-    Py_ssize_t i;
+    long i, exp;
 
     if (PyTuple_Check(seq)) {
         tup = seq;
@@ -1387,6 +1423,11 @@
 
     /* 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);
@@ -1417,7 +1458,7 @@
     /* XXX: quick hack */
     char buf[1000];
     char dig[2];
-    Py_ssize_t i;
+    long i;
     
     dig[1] = 0;
     PyOS_snprintf(buf, 1000, "sign=%i, exp=%ld, digits=", d->sign, d->exp);
@@ -1487,6 +1528,40 @@
     return hash;
 }
 
+/* XXX: just for debugging? */
+static PyMemberDef _decimal_members[] = {
+    {"_sign", T_INT, offsetof(decimalobject, sign), 0},
+    {"_exp", T_LONG, offsetof(decimalobject, exp), 0},
+    {NULL}
+};
+
+static PyObject *
+_decimal_get_int(decimalobject *self)
+{
+    PyObject *tup;
+    long i;
+    tup = PyTuple_New(self->ob_size);
+    if (!tup) return NULL;
+    for (i = 0; i < self->ob_size; i++)
+        PyTuple_SET_ITEM(tup, i, PyInt_FromLong(self->digits[i]));
+    return tup;
+}
+
+static PyObject *
+_decimal_is_special(decimalobject *self)
+{
+    if (ISSPECIAL(self))
+        Py_RETURN_TRUE;
+    else
+        Py_RETURN_FALSE;
+}
+
+static PyGetSetDef _decimal_getset[] = {
+    {"_int", (getter)_decimal_get_int, 0},
+    {"_is_special", (getter)_decimal_is_special, 0},
+    {NULL}
+};
+
 
 static PyTypeObject PyDecimal_DecimalType = {
     PyObject_HEAD_INIT(NULL)
@@ -1519,8 +1594,8 @@
     0,                           /* tp_iter */
     0,                           /* tp_iternext */
     decimal_methods,             /* tp_methods */
-    0,                           /* tp_members */
-    0,                           /* tp_getset */
+    _decimal_members,            /* tp_members */
+    _decimal_getset,             /* tp_getset */
     0,                           /* tp_base */
     0,                           /* tp_dict */
     0,                           /* tp_descr_get */

Modified: sandbox/trunk/decimal-c/decimal.h
==============================================================================
--- sandbox/trunk/decimal-c/decimal.h	(original)
+++ sandbox/trunk/decimal-c/decimal.h	Tue May 23 14:07:26 2006
@@ -10,10 +10,11 @@
 /* decimalobject struct ******************************************************/
 
 typedef struct {
-    PyObject_VAR_HEAD
+    PyObject_HEAD
+    long ob_size;    /* number of digits */
     unsigned int sign;     /* see sign contstants above */
     long exp;
-    signed char digits[1]; /* digits are stored as the actual numbers 0-9 */
+    signed char *digits;   /* digits are stored as the actual numbers 0-9 */
 } PyDecimalObject;
 
 static PyTypeObject 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 14:07:26 2006
@@ -466,114 +466,117 @@
 class Decimal(_decimal.Decimal):
     """Floating point class for decimal arithmetic."""
 
-    __slots__ = ('_exp','_int','_sign', '_is_special')
     # Generally, the value of the Decimal instance is given by
     #  (-1)**_sign * _int * 10**_exp
     # Special values are signified by _is_special == True
 
-    # We're immutable, so use __new__ not __init__
-    def __new__(cls, value="0", context=None):
-        """Create a decimal point instance.
-
-        >>> Decimal('3.14')              # string input
-        Decimal("3.14")
-        >>> Decimal((0, (3, 1, 4), -2))  # tuple input (sign, digit_tuple, exponent)
-        Decimal("3.14")
-        >>> Decimal(314)                 # int or long
-        Decimal("314")
-        >>> Decimal(Decimal(314))        # another decimal instance
-        Decimal("314")
-        """
-
-        self = object.__new__(cls)
-        self._is_special = False
-
-        # From an internal working value
-        if isinstance(value, _WorkRep):
-            self._sign = value.sign
-            self._int = tuple(map(int, str(value.int)))
-            self._exp = int(value.exp)
-            return self
-
-        # From another decimal
-        if isinstance(value, Decimal):
-            self._exp  = value._exp
-            self._sign = value._sign
-            self._int  = value._int
-            self._is_special  = value._is_special
-            return self
-
-        # From an integer
-        if isinstance(value, (int,long)):
-            if value >= 0:
-                self._sign = 0
-            else:
-                self._sign = 1
-            self._exp = 0
-            self._int = tuple(map(int, str(abs(value))))
-            return self
-
-        # tuple/list conversion (possibly from as_tuple())
-        if isinstance(value, (list,tuple)):
-            if len(value) != 3:
-                raise ValueError, 'Invalid arguments'
-            if value[0] not in (0,1):
-                raise ValueError, 'Invalid sign'
-            for digit in value[1]:
-                if not isinstance(digit, (int,long)) or digit < 0:
-                    raise ValueError, "The second value in the tuple must be composed of non negative integer elements."
-
-            self._sign = value[0]
-            self._int  = tuple(value[1])
-            if value[2] in ('F','n','N'):
-                self._exp = value[2]
-                self._is_special = True
-            else:
-                self._exp  = int(value[2])
-            return self
-
-        if isinstance(value, float):
-            raise TypeError("Cannot convert float to Decimal.  " +
-                            "First convert the float to a string")
-
-        # Other argument types may require the context during interpretation
-        if context is None:
-            context = getcontext()
-
-        # From a string
-        # REs insist on real strings, so we can too.
-        if isinstance(value, basestring):
-            if _isinfinity(value):
-                self._exp = 'F'
-                self._int = (0,)
-                self._is_special = True
-                if _isinfinity(value) == 1:
-                    self._sign = 0
-                else:
-                    self._sign = 1
-                return self
-            if _isnan(value):
-                sig, sign, diag = _isnan(value)
-                self._is_special = True
-                if len(diag) > context.prec: #Diagnostic info too long
-                    self._sign, self._int, self._exp = \
-                                context._raise_error(ConversionSyntax)
-                    return self
-                if sig == 1:
-                    self._exp = 'n' #qNaN
-                else: #sig == 2
-                    self._exp = 'N' #sNaN
-                self._sign = sign
-                self._int = tuple(map(int, diag)) #Diagnostic info
-                return self
-            try:
-                self._sign, self._int, self._exp = _string2exact(value)
-            except ValueError:
-                self._is_special = True
-                self._sign, self._int, self._exp = context._raise_error(ConversionSyntax)
-            return self
-
-        raise TypeError("Cannot convert %r to Decimal" % value)
+    @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.
+#
+#        >>> Decimal('3.14')              # string input
+#        Decimal("3.14")
+#        >>> Decimal((0, (3, 1, 4), -2))  # tuple input (sign, digit_tuple, exponent)
+#        Decimal("3.14")
+#        >>> Decimal(314)                 # int or long
+#        Decimal("314")
+#        >>> Decimal(Decimal(314))        # another decimal instance
+#        Decimal("314")
+#        """
+#
+#        self = _decimal.Decimal.__new__(cls)
+#        self._is_special = False
+#
+#        # From an internal working value
+#        if isinstance(value, _WorkRep):
+#            self._sign = value.sign
+#            self._int = tuple(map(int, str(value.int)))
+#            self._exp = int(value.exp)
+#            return self
+#
+#        # From another decimal
+#        if isinstance(value, Decimal):
+#            self._exp  = value._exp
+#            self._sign = value._sign
+#            self._int  = value._int
+#            self._is_special  = value._is_special
+#            return self
+#
+#        # From an integer
+#        if isinstance(value, (int,long)):
+#            if value >= 0:
+#                self._sign = 0
+#            else:
+#                self._sign = 1
+#            self._exp = 0
+#            self._int = tuple(map(int, str(abs(value))))
+#            return self
+#
+#        # tuple/list conversion (possibly from as_tuple())
+#        if isinstance(value, (list,tuple)):
+#            if len(value) != 3:
+#                raise ValueError, 'Invalid arguments'
+#            if value[0] not in (0,1):
+#                raise ValueError, 'Invalid sign'
+#            for digit in value[1]:
+#                if not isinstance(digit, (int,long)) or digit < 0:
+#                    raise ValueError, "The second value in the tuple must be composed of non negative integer elements."
+#
+#            self._sign = value[0]
+#            self._int  = tuple(value[1])
+#            if value[2] in ('F','n','N'):
+#                self._exp = value[2]
+#                self._is_special = True
+#            else:
+#                self._exp  = int(value[2])
+#            return self
+#
+#        if isinstance(value, float):
+#            raise TypeError("Cannot convert float to Decimal.  " +
+#                            "First convert the float to a string")
+#
+#        # Other argument types may require the context during interpretation
+#        if context is None:
+#            context = getcontext()
+#
+#        # From a string
+#        # REs insist on real strings, so we can too.
+#        if isinstance(value, basestring):
+#            if _isinfinity(value):
+#                self._exp = 'F'
+#                self._int = (0,)
+#                self._is_special = True
+#                if _isinfinity(value) == 1:
+#                    self._sign = 0
+#                else:
+#                    self._sign = 1
+#                return self
+#            if _isnan(value):
+#                sig, sign, diag = _isnan(value)
+#                self._is_special = True
+#                if len(diag) > context.prec: #Diagnostic info too long
+#                    self._sign, self._int, self._exp = \
+#                                context._raise_error(ConversionSyntax)
+#                    return self
+#                if sig == 1:
+#                    self._exp = 'n' #qNaN
+#                else: #sig == 2
+#                    self._exp = 'N' #sNaN
+#                self._sign = sign
+#                self._int = tuple(map(int, diag)) #Diagnostic info
+#                return self
+#            try:
+#                self._sign, self._int, self._exp = _string2exact(value)
+#            except ValueError:
+#                self._is_special = True
+#                self._sign, self._int, self._exp = context._raise_error(ConversionSyntax)
+#            return self
+#
+#        raise TypeError("Cannot convert %r to Decimal" % value)
 
     def _isnan(self):
         """Returns whether the number is not actually one.


More information about the Python-checkins mailing list