[Python-checkins] r75559 - in sandbox/trunk/decimal/decimal_in_c: deccoeff.c decimal.py

mark.dickinson python-checkins at python.org
Tue Oct 20 13:33:42 CEST 2009


Author: mark.dickinson
Date: Tue Oct 20 13:33:41 2009
New Revision: 75559

Log:
Remove _Decimal type from deccoeff extension

Modified:
   sandbox/trunk/decimal/decimal_in_c/deccoeff.c
   sandbox/trunk/decimal/decimal_in_c/decimal.py

Modified: sandbox/trunk/decimal/decimal_in_c/deccoeff.c
==============================================================================
--- sandbox/trunk/decimal/decimal_in_c/deccoeff.c	(original)
+++ sandbox/trunk/decimal/decimal_in_c/deccoeff.c	Tue Oct 20 13:33:41 2009
@@ -1,17 +1,12 @@
 /*
- * 'deccoeff' is a Python extension module that exports two classes:
- * _Decimal and Deccoeff.
- *
- * deccoeff._Decimal is a skeletal base class for the decimal.Decimal class.
- * As time goes on, the aim is to move more and more code from the Python
- * decimal.py file to the _Decimal class, and eventually rename _Decimal
- * to Decimal.
+ * 'deccoeff' is a Python extension module that exports two a single class,
+ * 'Deccoeff'.
  *
  * deccoeff.Deccoeff is a class implementing arbitrary-precision unsigned
  * integer arithmetic in a decimal base.  In addition to the usual arithmetic
  * operations, Deccoeff instances support slicing and element access, for
  * retrieving individual digits or sequences of digits.  As the name suggests,
- * Deccoeff instances are intended to be used as the coefficients for _Decimal
+ * Deccoeff instances are intended to be used as the coefficients for Decimal
  * instances.
  *
  * Author: Mark Dickinson (dickinsm at gmail.com).
@@ -897,46 +892,6 @@
     return false;
 }
 
-/*
-   variant of limbs_from_string that accepts a string where all but one of the
-   characters is a decimal digit, and ignores the specified character.
-   (Typically, the character to be ignored is a decimal point.)
-
-   On entry, s is a pointer to a character array of length s_len + 1, 0 <=
-   int_len <= s_len, s[0] through s[int_len-1] and s[int_len+1] through
-   s[s_len] contain decimal digits.  The result is then identical to
-   limbs_from_string applied to the concatenation of s[:int_len] and
-   s[int_len+1:].  No checking is performed, and there is no return value.
-
-   This function is used when parsing _Decimal instances.
- */
-
-static void
-limbs_from_pointed_unicode(limb_t *a, const Py_UNICODE *s, Py_ssize_t s_len,
-                          Py_ssize_t int_len)
-{
-    Py_ssize_t i, k, digits_in_limb;
-    limb_t acc;
-    Py_UNICODE c;
-
-#define GET_DIGIT(i) ((i) < int_len ? s[(i)] : s[(i)+1])
-
-    k = (s_len+LIMB_DIGITS-1) / LIMB_DIGITS;
-    digits_in_limb = (s_len+LIMB_DIGITS-1) % LIMB_DIGITS + 1;
-    acc = LIMB_ZERO;
-    for (i = 0; i < s_len; i++) {
-        c = GET_DIGIT(i);
-        limb_lshift(&acc, acc, 1, wdigit_to_limb(c));
-        digits_in_limb--;
-        if (digits_in_limb == 0) {
-            digits_in_limb = LIMB_DIGITS;
-            a[--k] = acc;
-            acc = LIMB_ZERO;
-        }
-    }
-    assert(digits_in_limb == LIMB_DIGITS);
-}
-
 /* Base conversion, from base PyLong_BASE to base LIMB_BASE.
 
    Convert an array of digits for a Python long to an array of limbs
@@ -1371,33 +1326,6 @@
     return deccoeff_normalize(z);
 }
 
-/* Variant of the above that converts an array of unicode digits containing a
-   decimal point at position int_len (but no sign).  The decimal point is
-   simply ignored.  This is used to parse the coefficient of a Decimal
-   instance. */
-
-static deccoeff *
-_deccoeff_from_pointed_unicode_and_size(const Py_UNICODE *s, Py_ssize_t s_len,
-                                      Py_ssize_t int_len) {
-    Py_ssize_t z_size;
-    deccoeff *z;
-
-    if (s_len > MAX_DIGITS) {
-        PyErr_SetString(PyExc_OverflowError,
-                        "too many digits");
-        return NULL;
-    }
-
-    z_size = (s_len + LIMB_DIGITS - 1) / LIMB_DIGITS;
-    z = _deccoeff_new(z_size);
-    if (z == NULL)
-        return NULL;
-
-    limbs_from_pointed_unicode(z->ob_limbs, s, s_len, int_len);
-    return deccoeff_normalize(z);
-}
-
-
 /***********************************
  * Deccoeff <-> PyLong conversions *
  ***********************************/
@@ -2437,705 +2365,6 @@
 };
 
 
-/*****************
- * _Decimal type *
- *****************/
-
-/* class name */
-#define DECIMAL_NAME "_Decimal"
-
-/* A finite decimal object needs a sign, a coefficient and an exponent.  An
-   infinity has a sign and nothing more; the coefficient and exponent are
-   ignored.  A (quiet or signalling) nan has a sign, and may carry additional
-   information (the payload) in the coefficient.  The exponent is not used. */
-
-#define DEC_FLAGS_NEG (1<<0)
-#define DEC_FLAGS_NONZERO (1<<1) /* currently unused; may want this later */
-#define DEC_FLAGS_SPECIAL (1<<2)
-#define DEC_FLAGS_INF  (1<<3)
-#define DEC_FLAGS_NAN (1<<4)
-#define DEC_FLAGS_SNAN (1<<5)
-#define DEC_FLAGS_QNAN (1<<6)
-
-#define FINITE_FLAGS 0
-#define INF_FLAGS (DEC_FLAGS_SPECIAL | DEC_FLAGS_INF)
-#define QNAN_FLAGS (DEC_FLAGS_SPECIAL | DEC_FLAGS_NAN | DEC_FLAGS_QNAN)
-#define SNAN_FLAGS (DEC_FLAGS_SPECIAL | DEC_FLAGS_NAN | DEC_FLAGS_SNAN)
-
-/* note that FINITE_FLAGS < INF_FLAGS < SNAN_FLAGS < QNAN_FLAGS,
-   corresponding to the standard total ordering of Decimals */
-
-typedef int dec_flag_t;
-typedef Py_ssize_t exp_t;
-
-typedef struct {
-    PyObject_HEAD
-    deccoeff *dec_coeff;   /* coefficient, or NaN payload; NULL for infinity */
-    PyLongObject *dec_exp; /* exponent: NULL for an infinity or NaN */
-    dec_flag_t dec_flags;  /* flags describing sign and number class */
-} _Decimal;
-
-static PyTypeObject deccoeff__DecimalType;
-
-/* create new _Decimal (or instance of a subclass of _Decimal); no
-   validation or conversion---just allocate memory and fill the slots */
-
-static _Decimal *
-__Decimal_new(PyTypeObject *type, dec_flag_t flags, deccoeff *coeff,
-              PyLongObject *exp)
-{
-    _Decimal *self;
-
-    /* sanity checks */
-    assert(
-        ((flags | 1) == (FINITE_FLAGS | 1)) ||    /* finite (poss. zero) */
-        ((flags | 1) == (INF_FLAGS | 1)) ||       /* infinity */
-        ((flags | 1) == (QNAN_FLAGS | 1)) ||      /* quiet nan */
-        ((flags | 1) == (SNAN_FLAGS | 1)));       /* signaling nan */
-
-    /* incref coefficient and exponent, but only if they're non-NULL */
-    if (flags & DEC_FLAGS_INF)
-        assert(coeff == NULL);
-    else {
-        assert(coeff != NULL);
-        Py_INCREF(coeff);
-    }
-    if (flags & DEC_FLAGS_SPECIAL)
-        assert(exp == NULL);
-    else {
-        assert(exp != NULL);
-        Py_INCREF(exp);
-    }
-
-    self = (_Decimal *)type->tp_alloc(type, 0);
-    if (self == NULL)
-        return NULL;
-    self->dec_flags = flags;
-    self->dec_coeff = coeff;
-    self->dec_exp = exp;
-    return self;
-}
-
-/* deallocate _Decimal instance */
-
-static void
-_Decimal_dealloc(PyObject *self)
-{
-    _Decimal *dec;
-    dec = (_Decimal *)self;
-    /* coefficient should be present iff decimal instance is not infinite */
-    if (dec->dec_flags & DEC_FLAGS_INF)
-        assert(dec->dec_coeff == NULL);
-    else {
-        assert(dec->dec_coeff != NULL);
-        Py_DECREF(dec->dec_coeff);
-    }
-    /* exponent is present only for finite numbers */
-    if (dec->dec_flags & DEC_FLAGS_SPECIAL)
-        assert(dec->dec_exp == NULL);
-    else {
-        assert(dec->dec_exp != NULL);
-        Py_DECREF(dec->dec_exp);
-    }
-    self->ob_type->tp_free(self);
-}
-
-/* Macros to create finite, infinite, qnan, and snan _Decimal instances */
-
-#define FINITE_DECIMAL(type, sign, coeff, exp) \
-    (__Decimal_new(type, sign, coeff, exp))
-#define INF_DECIMAL(type, sign) \
-    (__Decimal_new(type, sign | INF_FLAGS, NULL, NULL))
-#define QNAN_DECIMAL(type, sign, payload) \
-    (__Decimal_new(type, sign | QNAN_FLAGS, payload, NULL))
-#define SNAN_DECIMAL(type, sign, payload) \
-    (__Decimal_new(type, sign | SNAN_FLAGS, payload, NULL))
-
-/* create a new finite _Decimal instance */
-
-static PyObject *
-_Decimal_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    /* create a new finite _Decimal instance, given a sequence consisting
-       of its sign (an integer), coefficient and exponent */
-
-    PyObject *ocoeff, *oexp;
-    deccoeff *coeff;
-    PyLongObject *exp;
-    int sign;
-    static char *kwlist[] = {"sign", "coeff", "exp", 0};
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "iOO:" DECIMAL_NAME, kwlist,
-                                     &sign, &ocoeff, &oexp))
-        return NULL;
-    if (!(sign == 0 || sign == 1)) {
-        PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
-        return NULL;
-    }
-    if (ocoeff->ob_type != &deccoeff_DeccoeffType) {
-        PyErr_SetString(PyExc_TypeError, "coeff should have type " CLASS_NAME);
-        return NULL;
-    }
-    coeff = (deccoeff *)ocoeff;
-    if (oexp->ob_type != &PyLong_Type) {
-        PyErr_SetString(PyExc_TypeError, "exp should have type int");
-        return NULL;
-    }
-    exp = (PyLongObject *)oexp;
-    return (PyObject *)FINITE_DECIMAL(type, sign, coeff, exp);
-}
-
-/* Create a _Decimal instance directly from a string; classmethod */
-
-static PyObject *
-_Decimal_from_str(PyTypeObject *cls, PyObject *arg)
-{
-    PyObject *result=NULL;
-    deccoeff *coeff;
-    Py_ssize_t ndigits;
-    Py_UNICODE *coeff_start, *coeff_end, *s_end, *int_end, *exp_start, *s;
-    int sign = 0, exp_sign = 0;
-    PyObject *exp, *temp, *frac_digits;
-    deccoeff *duexp;
-
-    if (!PyUnicode_Check(arg)) {
-        PyErr_SetString(PyExc_TypeError,
-                        "Expected str instance");
-        return NULL;
-    }
-    s = PyUnicode_AS_UNICODE(arg);
-    s_end = s + PyUnicode_GET_SIZE(arg);
-
-    /* Stage 1: parse and validate the string, identifying the points
-       where the coefficients and exponent start and stop */
-
-    /* optional sign */
-    if (*s == '+')
-        s++;
-    else if (*s == '-') {
-        s++;
-        sign = 1;
-    }
-
-    switch(*s) {
-    case 'n':
-    case 'N':
-        /* nan */
-        s++;
-        if (*s == 'a' || *s == 'A')
-            s++;
-        else
-            goto parse_error;
-        if (*s == 'n' || *s == 'N')
-            s++;
-        else
-            goto parse_error;
-        coeff_start = s;
-        while ('0' <= *s && *s <= '9')
-            s++;
-        if (s != s_end)
-            goto parse_error;
-
-        coeff = _deccoeff_from_unicode_and_size(coeff_start, s-coeff_start);
-        if (coeff != NULL) {
-            result = (PyObject *)QNAN_DECIMAL(cls, sign, coeff);
-            Py_DECREF(coeff);
-        }
-        break;
-    case 's':
-    case 'S':
-        /* snan */
-        s++;
-        if (*s == 'n' || *s == 'N')
-            s++;
-        else
-            goto parse_error;
-        if (*s == 'a' || *s == 'A')
-            s++;
-        else
-            goto parse_error;
-        if (*s == 'n' || *s == 'N')
-            s++;
-        else
-            goto parse_error;
-        coeff_start = s;
-        while ('0' <= *s && *s <= '9')
-            s++;
-        if (s != s_end)
-            goto parse_error;
-
-        coeff = _deccoeff_from_unicode_and_size(coeff_start, s-coeff_start);
-        if (coeff != NULL) {
-            result = (PyObject *)SNAN_DECIMAL(cls, sign, coeff);
-            Py_DECREF(coeff);
-        }
-        break;
-    case 'i':
-    case 'I':
-        /* inf[inity] */
-        s++;
-        if (*s == 'n' || *s == 'N')
-            s++;
-        else
-            goto parse_error;
-        if (*s == 'f' || *s == 'F')
-            s++;
-        else
-            goto parse_error;
-        if (*s == 'i' || *s == 'I') {
-            s++;
-            if (*s == 'n' || *s == 'N')
-                s++;
-            else
-                goto parse_error;
-            if (*s == 'i' || *s == 'I')
-                s++;
-            else
-                goto parse_error;
-            if (*s == 't' || *s == 'T')
-                s++;
-            else
-                goto parse_error;
-            if (*s == 'y' || *s == 'Y')
-                s++;
-            else
-                goto parse_error;
-        }
-        /* end of string */
-        if (s != s_end)
-            goto parse_error;
-
-        result = (PyObject *)INF_DECIMAL(cls, sign);
-        break;
-    default:
-        /* numeric part: at least one digit, with an optional decimal point */
-        coeff_start = s;
-        while ('0' <= *s && *s <= '9')
-            s++;
-        int_end = s;
-        if (*s == '.') {
-            s++;
-            while ('0' <= *s && *s <= '9')
-                s++;
-            coeff_end = s-1;
-        }
-        else
-            coeff_end= s;
-
-        ndigits = coeff_end - coeff_start;
-        if (ndigits == 0)
-            goto parse_error;
-
-        /* [e <exponent>] */
-        if (*s == 'e' || *s == 'E') {
-            s++;
-            if (*s == '+')
-                s++;
-            else if (*s == '-') {
-                s++;
-                exp_sign = 1;
-            }
-            exp_start = s;
-            if (!('0' <= *s && *s <= '9'))
-                goto parse_error;
-            s++;
-            while ('0' <= *s && *s <= '9')
-                s++;
-        }
-        else
-            exp_start = s;
-
-        /* end of string */
-        if (s != s_end)
-            goto parse_error;
-
-        /* parse exponent (without sign), returning a deccoeff */
-        duexp = _deccoeff_from_unicode_and_size(exp_start, s-exp_start);
-        if (duexp == NULL)
-            return NULL;
-
-        /* REF: duexp */
-
-        /* Later we'll allow negative deccoeffs, and have the exponent
-           be a deccoeff.   Later  :)
-           For now we have to convert this to a Python long */
-        exp = (PyObject *)deccoeff_long(duexp);
-        Py_DECREF(duexp);
-        if (exp == NULL)
-            return NULL;
-
-        /* REF: exp */
-
-        /* adjust exponent:  include sign, and adjust by length
-           of fractional part of input */
-        if (exp_sign == 1) {
-            /* negate exp */
-            temp = PyNumber_Negative(exp);
-            Py_DECREF(exp);
-            exp = temp;
-            if (exp == NULL)
-                return NULL;
-        }
-
-        /* REF: exp */
-
-        /* subtract frac_digits */
-        frac_digits = PyLong_FromSize_t(coeff_end - int_end);
-        if (frac_digits == NULL) {
-            Py_DECREF(exp);
-            return NULL;
-        }
-
-        /* REF: exp, frac_digits */
-
-        temp = PyNumber_Subtract(exp, frac_digits);
-        Py_DECREF(frac_digits);
-        Py_DECREF(exp);
-        exp = temp;
-        if (exp == NULL)
-            return NULL;
-
-        /* REF: exp */
-
-        /* get coefficient */
-        coeff = _deccoeff_from_pointed_unicode_and_size(coeff_start,
-                            coeff_end - coeff_start, int_end - coeff_start);
-
-        if (coeff == NULL) {
-            Py_DECREF(exp);
-            return NULL;
-        }
-
-        result = (PyObject *)FINITE_DECIMAL(cls, sign, coeff,
-                                              (PyLongObject *)exp);
-        Py_DECREF(coeff);
-        Py_DECREF(exp);
-    }
-    return result;
-
-  parse_error:
-    PyErr_SetString(PyExc_ValueError,
-                    "invalid numeric string");
-    return NULL;
-
-}
-
-/* Create a new finite _Decimal instance; classmethod */
-
-static PyObject *
-_Decimal_finite(PyTypeObject *cls, PyObject *args)
-{
-    PyObject *ocoeff, *oexp;
-    deccoeff *coeff;
-    PyLongObject *exp;
-    int sign;
-
-    if (!PyArg_ParseTuple(args, "iOO:" DECIMAL_NAME, &sign, &ocoeff, &oexp))
-        return NULL;
-    if (ocoeff->ob_type != &deccoeff_DeccoeffType) {
-        PyErr_SetString(PyExc_TypeError, "coeff should have type " CLASS_NAME);
-        return NULL;
-    }
-    coeff = (deccoeff *)ocoeff;
-    if (oexp->ob_type != &PyLong_Type) {
-        PyErr_SetString(PyExc_TypeError, "exp should have type int");
-        return NULL;
-    }
-    exp = (PyLongObject *)oexp;
-    if (!(sign == 0 || sign == 1)) {
-        PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
-        return NULL;
-    }
-    return (PyObject *)FINITE_DECIMAL(cls, sign, coeff, exp);
-}
-
-/* Create a qNaN; classmethod */
-
-static PyObject *
-_Decimal_qNaN(PyTypeObject *cls, PyObject *args) {
-    PyObject *opayload;
-    deccoeff *payload;
-    int sign;
-
-    if (!PyArg_ParseTuple(args, "iO:" DECIMAL_NAME, &sign, &opayload))
-        return NULL;
-    if (opayload->ob_type != &deccoeff_DeccoeffType) {
-        PyErr_SetString(PyExc_TypeError,
-                        "payload should have type " CLASS_NAME);
-        return NULL;
-    }
-    payload = (deccoeff *)opayload;
-    if (!(sign == 0 || sign == 1)) {
-        PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
-        return NULL;
-    }
-    return (PyObject *)QNAN_DECIMAL(cls, sign, payload);
-}
-
-/* Create an sNaN; classmethod */
-
-static PyObject *
-_Decimal_sNaN(PyTypeObject *cls, PyObject *args) {
-    PyObject *opayload;
-    deccoeff *payload;
-    int sign;
-
-    if (!PyArg_ParseTuple(args, "iO:" DECIMAL_NAME, &sign, &opayload))
-        return NULL;
-    if (opayload->ob_type != &deccoeff_DeccoeffType) {
-        PyErr_SetString(PyExc_TypeError,
-                        "payload should have type " CLASS_NAME);
-        return NULL;
-    }
-    payload = (deccoeff *)opayload;
-    if (!(sign == 0 || sign == 1)) {
-        PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
-        return NULL;
-    }
-    return (PyObject *)SNAN_DECIMAL(cls, sign, payload);
-}
-
-/* Create an infinity; classmethod */
-
-static PyObject *
-_Decimal_inf(PyTypeObject *cls, PyObject *args) {
-    int sign;
-
-    if (!PyArg_ParseTuple(args, "i:" DECIMAL_NAME, &sign))
-        return NULL;
-    if (!(sign == 0 || sign == 1)) {
-        PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
-        return NULL;
-    }
-    return (PyObject *)INF_DECIMAL(cls, sign);
-}
-
-/* Return the sign of any _Decimal instance */
-
-static PyObject *
-_Decimal_getsign(_Decimal *self, void *closure)
-{
-    long sign;
-    sign = (long)(self->dec_flags) & DEC_FLAGS_NEG;
-    return PyLong_FromLong(sign);
-}
-
-/* Return the coefficient of a finite _Decimal */
-
-static PyObject *
-_Decimal_getcoeff(_Decimal *self, void *closure)
-{
-    if (self->dec_flags & DEC_FLAGS_SPECIAL) {
-        PyErr_SetString(PyExc_ValueError,
-                        "infinity or NaN has no coefficient");
-        return NULL;
-    }
-    Py_INCREF(self->dec_coeff);
-    return (PyObject *)self->dec_coeff;
-}
-
-/* Return the payload of a NaN */
-
-static PyObject *
-_Decimal_getpayload(_Decimal *self, void *closure)
-{
-    if (self->dec_flags & DEC_FLAGS_NAN) {
-        Py_INCREF(self->dec_coeff);
-        return (PyObject *)self->dec_coeff;
-    }
-    else {
-        PyErr_SetString(PyExc_ValueError,
-                        "argument is not a NaN");
-        return NULL;
-    }
-}
-
-/* Return the exponent of a finite _Decimal instance */
-
-static PyObject *
-_Decimal_getexp(_Decimal *self, void *closure)
-{
-    if (self->dec_flags & DEC_FLAGS_SPECIAL) {
-        PyErr_SetString(PyExc_ValueError,
-                        "infinity or NaN has no exponent");
-        return NULL;
-    }
-    Py_INCREF(self->dec_exp);
-    return (PyObject *)(self->dec_exp);
-}
-
-/* Return True if the given Decimal is special (an infinity or NaN),
-   False otherwise. */
-
-static PyObject *
-_Decimal_getspecial(_Decimal *self, void *closure)
-{
-    if (self->dec_flags & DEC_FLAGS_SPECIAL)
-        Py_RETURN_TRUE;
-    else
-        Py_RETURN_FALSE;
-}
-
-
-static PyObject *
-_Decimal_is_finite(_Decimal *self)
-{
-    if (self->dec_flags & DEC_FLAGS_SPECIAL)
-        Py_RETURN_FALSE;
-    else
-        Py_RETURN_TRUE;
-}
-
-static PyObject *
-_Decimal_is_infinite(_Decimal *self)
-{
-    if (self->dec_flags & DEC_FLAGS_INF)
-        Py_RETURN_TRUE;
-    else
-        Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_nan(_Decimal *self)
-{
-    if (self->dec_flags & DEC_FLAGS_NAN)
-        Py_RETURN_TRUE;
-    else
-        Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_qnan(_Decimal *self)
-{
-    if (self->dec_flags & DEC_FLAGS_QNAN)
-        Py_RETURN_TRUE;
-    else
-        Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_snan(_Decimal *self)
-{
-    if (self->dec_flags & DEC_FLAGS_SNAN)
-        Py_RETURN_TRUE;
-    else
-        Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_signed(_Decimal *self)
-{
-    if (self->dec_flags & DEC_FLAGS_NEG)
-        Py_RETURN_TRUE;
-    else
-        Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_zero(_Decimal *self)
-{
-    if ((self->dec_flags & DEC_FLAGS_SPECIAL) ||
-        deccoeff_bool(self->dec_coeff))
-        Py_RETURN_FALSE;
-    else
-        Py_RETURN_TRUE;
-}
-
-static _Decimal *
-_Decimal_copy(_Decimal *self)
-{
-    return __Decimal_new(&deccoeff__DecimalType, self->dec_flags,
-                         self->dec_coeff, self->dec_exp);
-}
-
-static _Decimal *
-_Decimal_copy_negate(_Decimal *self)
-{
-    return __Decimal_new(&deccoeff__DecimalType, self->dec_flags ^ 1,
-                         self->dec_coeff, self->dec_exp);
-}
-
-static _Decimal *
-_Decimal_copy_abs(_Decimal *self)
-{
-    return __Decimal_new(&deccoeff__DecimalType, self->dec_flags & (~1),
-                         self->dec_coeff, self->dec_exp);
-}
-
-static PyMethodDef _Decimal_methods[] = {
-    {"_finite", (PyCFunction)_Decimal_finite, METH_VARARGS|METH_CLASS, " "},
-    {"_qnan", (PyCFunction)_Decimal_qNaN, METH_VARARGS|METH_CLASS, " "},
-    {"_snan", (PyCFunction)_Decimal_sNaN, METH_VARARGS|METH_CLASS, " "},
-    {"_inf", (PyCFunction)_Decimal_inf, METH_VARARGS|METH_CLASS, " "},
-    {"from_str", (PyCFunction)_Decimal_from_str, METH_O|METH_CLASS, " "},
-    {"is_finite", (PyCFunction)_Decimal_is_finite, METH_NOARGS, " "},
-    {"is_infinite", (PyCFunction)_Decimal_is_infinite, METH_NOARGS, " "},
-    {"is_nan", (PyCFunction)_Decimal_is_nan, METH_NOARGS, " "},
-    {"is_qnan", (PyCFunction)_Decimal_is_qnan, METH_NOARGS, " "},
-    {"is_snan", (PyCFunction)_Decimal_is_snan, METH_NOARGS, " "},
-    {"is_signed", (PyCFunction)_Decimal_is_signed, METH_NOARGS, " "},
-    {"is_zero", (PyCFunction)_Decimal_is_zero, METH_NOARGS, " "},
-    {"copy", (PyCFunction)_Decimal_copy, METH_NOARGS, " "},
-    {"copy_negate", (PyCFunction)_Decimal_copy_negate, METH_NOARGS, " "},
-    {"copy_abs", (PyCFunction)_Decimal_copy_abs, METH_NOARGS, " "},
-    {NULL, NULL}
-};
-
-static PyGetSetDef _Decimal_getsetters[] = {
-    {"_sign", (getter)_Decimal_getsign, NULL, "sign", NULL},
-    {"_int", (getter)_Decimal_getcoeff, NULL,
-     "coefficient (invalid for NaNs and infinites)", NULL},
-    {"_exp", (getter)_Decimal_getexp, NULL,
-     "exponent (invalid for NaNs and infinities)", NULL},
-    {"_payload", (getter)_Decimal_getpayload, NULL,
-     "payload of a NaN (invalid for non-NaNs)", NULL},
-    {"_is_special", (getter)_Decimal_getspecial, NULL,
-     "True for infinities and NaNs, false otherwise", NULL},
-    {NULL}
-};
-
-static PyTypeObject deccoeff__DecimalType = {
-    PyVarObject_HEAD_INIT(&PyType_Type, 0)
-    MODULE_NAME "." DECIMAL_NAME,               /* tp_name */
-    sizeof(_Decimal),                           /* tp_basicsize */
-    0, /* tp_itemsize */
-    _Decimal_dealloc,                           /* tp_dealloc */
-    0, /* tp_print */
-    0, /* tp_getattr */
-    0, /* tp_setattr */
-    0, /* tp_compare */
-    0, /* tp_repr */
-    0, /* tp_as_number */
-    0, /* tp_as_sequence */
-    0, /* tp_as_mapping */
-    0, /* tp_hash */
-    0, /* tp_call */
-    0, /* tp_str */
-    0, /* tp_getattro */
-    0, /* tp_setattro */
-    0, /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
-    "support for Decimal type",                 /* tp_doc */
-    0, /* tp_traverse */
-    0, /* tp_clear */
-    0, /* tp_richcompare */
-    0, /* tp_weaklistoffset */
-    0, /* tp_iter */
-    0, /* tp_iternext */
-    _Decimal_methods,                           /* tp_methods */
-    0, /* tp_members */
-    _Decimal_getsetters,                        /* 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 */
-    _Decimal_new,                               /* tp_new */
-    PyObject_Del,                               /* tp_free */
-};
-
 static PyMethodDef deccoeff_module_methods[] = {
     {NULL, NULL}
 };
@@ -3169,9 +2398,6 @@
     if (PyType_Ready(&deccoeff_DeccoeffType) < 0)
         return NULL;
 
-    if (PyType_Ready(&deccoeff__DecimalType) < 0)
-        return NULL;
-
     m = PyModule_Create(&deccoeff_module);
     if (m == NULL)
         return NULL;
@@ -3182,11 +2408,6 @@
     if (check == -1)
         return NULL;
 
-    Py_INCREF(&deccoeff__DecimalType);
-    check = PyModule_AddObject(m, DECIMAL_NAME,
-                               (PyObject *) &deccoeff__DecimalType);
-    if (check == -1)
-        return NULL;
     check = PyModule_AddIntMacro(m, LIMB_DIGITS);
     if (check == -1)
         return NULL;

Modified: sandbox/trunk/decimal/decimal_in_c/decimal.py
==============================================================================
--- sandbox/trunk/decimal/decimal_in_c/decimal.py	(original)
+++ sandbox/trunk/decimal/decimal_in_c/decimal.py	Tue Oct 20 13:33:41 2009
@@ -132,7 +132,7 @@
     'setcontext', 'getcontext', 'localcontext'
 ]
 
-from deccoeff import Deccoeff, _Decimal
+from deccoeff import Deccoeff
 
 import copy as _copy
 import math as _math
@@ -216,7 +216,7 @@
     """
     def handle(self, context, *args):
         if args:
-            ans = Decimal._qnan(args[0]._sign, args[0]._payload)
+            ans = _dec_from_triple(args[0]._sign, args[0]._int, 'n', True)
             return ans._fix_nan(context)
         return NaN
 
@@ -549,7 +549,7 @@
 # (because Decimals are not interoperable with floats).  See the notes in
 # numbers.py for more detail.
 
-class Decimal(_Decimal):
+class Decimal(object):
     """Floating point class for decimal arithmetic."""
 
     # Generally, the value of the Decimal instance is given by
@@ -575,40 +575,67 @@
         # From a string
         # REs insist on real strings, so we can too.
         if isinstance(value, str):
-            try:
-                m = cls.from_str(value.strip())
-            except ValueError:
+            self = object.__new__(cls)
+
+            m = _parser(value.strip())
+            if m is None:
                 if context is None:
                     context = getcontext()
                 return context._raise_error(ConversionSyntax,
-                                   "Invalid literal for Decimal: %r" % value)
-            return m
+                                "Invalid literal for Decimal: %r" % value)
 
-        # From another decimal
-        if isinstance(value, _Decimal):
-            if value._is_special:
-                if value.is_infinite():
-                    return cls._inf(value._sign)
-                elif value.is_qnan():
-                    return cls._qnan(value._sign, value._payload)
-                elif value.is_snan():
-                    return cls._snan(value._sign, value._payload)
-                else:
-                    assert False, "never get here"
+            if m.group('sign') == "-":
+                self._sign = 1
             else:
-                return cls._finite(value._sign, value._int, value._exp)
+                self._sign = 0
+            intpart = m.group('int')
+            if intpart is not None:
+                # finite number
+                fracpart = m.group('frac') or ''
+                exp = int(m.group('exp') or '0')
+                self._int = Deccoeff(intpart+fracpart)
+                self._exp = exp - len(fracpart)
+                self._is_special = False
+            else:
+                diag = m.group('diag')
+                if diag is not None:
+                    # NaN
+                    self._int = Deccoeff(diag)
+                    if m.group('signal'):
+                        self._exp = 'N'
+                    else:
+                        self._exp = 'n'
+                else:
+                    # infinity
+                    self._int = Deccoeff(0)
+                    self._exp = 'F'
+                self._is_special = True
+            return self
 
         # From an integer
         if isinstance(value, int):
+            self = object.__new__(cls)
             if value >= 0:
-                _sign = 0
+                self._sign = 0
             else:
-                _sign = 1
-            _int = Deccoeff(abs(value))
-            return cls._finite(_sign, _int, 0)
+                self._sign = 1
+            self._exp = 0
+            self._int = Deccoeff(abs(value))
+            self._is_special = False
+            return self
+
+        # From another decimal
+        if isinstance(value, Decimal):
+            self = object.__new__(cls)
+            self._exp = value._exp
+            self._sign = value._sign
+            self._int = value._int
+            self._is_special = value._is_special
+            return self
 
         # tuple/list conversion (possibly from as_tuple())
         if isinstance(value, (list,tuple)):
+            self = object.__new__(cls)
             if len(value) != 3:
                 raise ValueError('Invalid tuple size in creation of Decimal '
                                  'from list or tuple.  The list or tuple '
@@ -618,10 +645,12 @@
                 raise ValueError("Invalid sign.  The first value in the tuple "
                                  "should be an integer; either 0 for a "
                                  "positive number or 1 for a negative number.")
-            _sign = value[0]
+            self._sign = value[0]
             if value[2] == 'F':
                 # infinity: value[1] is ignored
-                return cls._inf(_sign)
+                self._int = Deccoeff(0)
+                self._exp = value[2]
+                self._is_special = True
             else:
                 # process and validate the digits in value[1]
                 digits = []
@@ -632,17 +661,20 @@
                         raise ValueError("The second value in the tuple must "
                                          "be composed of integers in the range "
                                          "0 through 9.")
-                _int = Deccoeff(''.join(digits))
-                if value[2] == 'n':
-                    return cls._qnan(_sign, _int)
-                elif value[2] == 'N':
-                    return cls._snan(_sign, _int)
+                self._int = Deccoeff(''.join(digits))
+                self._exp = value[2]
+                if value[2] in ('n', 'N'):
+                    # NaN
+                    self._is_special = True
                 elif isinstance(value[2], int):
-                    return cls._finite(_sign, _int, value[2])
+                    # finite number
+                    self._is_special = False
                 else:
                     raise ValueError("The third value in the tuple must "
                                      "be an integer, or one of the "
                                      "strings 'F', 'n', 'N'.")
+            return self
+
 
         if isinstance(value, float):
             raise TypeError("Cannot convert float to Decimal.  " +
@@ -749,13 +781,6 @@
                                             other)
         return 0
 
-    def __bool__(self):
-        """Return True if self is nonzero; otherwise return False.
-
-        NaNs and infinities are considered nonzero.
-        """
-        return self._is_special or bool(self._int)
-
     def _cmp(self, other):
         """Compare the two non-NaN decimal instances self and other.
 
@@ -949,8 +974,8 @@
                 coeff = (0,)
                 exp = 'F'
             else: # NaN
-                if self._payload:
-                    coeff = tuple(int(x) for x in str(self._payload))
+                if self._int:
+                    coeff = tuple(int(x) for x in str(self._int))
                 else:
                     coeff = ()
                 if self.is_qnan():
@@ -983,15 +1008,15 @@
             if self.is_infinite():
                 return sign + 'Infinity'
             elif self.is_qnan():
-                if not self._payload:
+                if not self._int:
                     return sign + 'NaN'
                 else:
-                    return sign + 'NaN' + str(self._payload)
+                    return sign + 'NaN' + str(self._int)
             else:
-                if not self._payload:
+                if not self._int:
                     return sign + 'sNaN'
                 else:
-                    return sign + 'sNaN' + str(self._payload)
+                    return sign + 'sNaN' + str(self._int)
 
         # number of digits of self._int to left of decimal point
         si = str(self._int)
@@ -1038,15 +1063,15 @@
             if self.is_infinite():
                 return sign + 'Infinity'
             elif self.is_qnan():
-                if not self._payload:
+                if not self._int:
                     return sign + 'NaN'
                 else:
-                    return sign + 'NaN' + str(self._payload)
+                    return sign + 'NaN' + str(self._int)
             else: # self.is_snan()
-                if not self._payload:
+                if not self._int:
                     return sign + 'sNaN'
                 else:
-                    return sign + 'sNaN' + str(self._payload)
+                    return sign + 'sNaN' + str(self._int)
 
         # deal independently with case of 0
         if self._int:
@@ -1624,8 +1649,7 @@
     def _fix_nan(self, context):
         """Decapitate the payload of a NaN to fit the context"""
         assert self.is_nan()
-
-        payload = self._payload
+        payload = self._int
 
         # maximum length of payload is precision if _clamp=0,
         # precision-1 if _clamp=1.
@@ -1633,11 +1657,7 @@
         if payload.digit_length() > max_payload_len:
             # if payload is too long, take *low order* digits
             payload = payload[:max_payload_len]
-            if self.is_qnan():
-                return Decimal._qnan(self._sign, payload)
-            else:
-                return Decimal._snan(self._sign, payload)
-
+            return _dec_from_triple(self._sign, payload, 'n', True)
         return Decimal(self)
 
     def _fix(self, context, rounding=None):
@@ -2817,8 +2837,8 @@
             return 0
         else: #self_type in (2, 3):
             # nans are ordered by payload
-            if self._payload != other._payload:
-                return [1, -1][self._payload < other._payload]
+            if self._int != other._int:
+                return [1, -1][self._int < other._int]
             else:
                 return 0
 
@@ -2842,15 +2862,18 @@
 
     def _copy(self):
         """Return a copy of self."""
-        return Decimal(_Decimal.copy(self))
+        return _dec_from_triple(self._sign, self._int, self._exp, self._is_special)
 
     def copy_abs(self):
         """Returns a copy with the sign set to 0. """
-        return Decimal(_Decimal.copy_abs(self))
+        return _dec_from_triple(0, self._int, self._exp, self._is_special)
 
     def copy_negate(self):
         """Returns a copy with the sign inverted."""
-        return Decimal(_Decimal.copy_negate(self))
+        if self._sign:
+            return _dec_from_triple(0, self._int, self._exp, self._is_special)
+        else:
+            return _dec_from_triple(1, self._int, self._exp, self._is_special)
 
     def copy_sign(self, other):
         """Returns self with the sign of other."""
@@ -2930,6 +2953,13 @@
 
         return ans
 
+    def __bool__(self):
+        """Return True if self is nonzero; otherwise return False.
+
+        NaNs and infinities are considered nonzero.
+        """
+        return self._is_special or bool(self._int)
+
     def is_canonical(self):
         """Return True if self is canonical; otherwise return False.
 
@@ -2938,22 +2968,54 @@
         """
         return True
 
+    def is_finite(self):
+        """Return True if self is finite; otherwise return False.
+
+        A Decimal instance is considered finite if it is neither
+        infinite nor a NaN.
+        """
+        return not self._is_special
+
+    def is_infinite(self):
+        """Return True if self is infinite; otherwise return False."""
+        return self._exp == 'F'
+
+    def is_nan(self):
+        """Return True if self is a qNaN or sNaN; otherwise return False."""
+        return self._exp in ('n', 'N')
+
     def is_normal(self, context=None):
         """Return True if self is a normal number; otherwise return False."""
-        if self._is_special or not self:
+        if self._is_special or not bool(self._int):
             return False
         if context is None:
             context = getcontext()
-        return context.Emin <= self.adjusted() <= context.Emax
+        return self.adjusted() >= context.Emin
+
+    def is_qnan(self):
+        """Return True if self is a quiet NaN; otherwise return False."""
+        return self._exp == 'n'
+
+    def is_signed(self):
+        """Return True if self is negative; otherwise return False."""
+        return self._sign == 1
+
+    def is_snan(self):
+        """Return True if self is a signaling NaN; otherwise return False."""
+        return self._exp == 'N'
 
     def is_subnormal(self, context=None):
         """Return True if self is subnormal; otherwise return False."""
-        if self._is_special or not self:
+        if self._is_special or not bool(self._int):
             return False
         if context is None:
             context = getcontext()
         return self.adjusted() < context.Emin
 
+    def is_zero(self):
+        """Return True if self is a zero; otherwise return False."""
+        return not self._is_special and not self._int
+
     def _ln_exp_bound(self):
         """Compute a lower bound for the adjusted exponent of self.ln().
         In other words, compute r such that self.ln() >= 10**r.  Assumes
@@ -3610,10 +3672,14 @@
 
     This function is for *internal use only*.
     """
-
     assert type(coefficient) is Deccoeff
-    assert not special
-    return Decimal._finite(sign, coefficient, exponent)
+    self = object.__new__(Decimal)
+    self._sign = sign
+    self._int = coefficient
+    self._exp = exponent
+    self._is_special = special
+
+    return self
 
 # Register Decimal as a kind of Number (an abstract base class).
 # However, do not register it as Real (because Decimals are not
@@ -3788,7 +3854,7 @@
                                      "no trailing or leading whitespace is "
                                      "permitted.")
         d = Decimal(num, context=self)
-        if d.is_nan() and d._payload.digit_length() + self._clamp > self.prec:
+        if d.is_nan() and d._int.digit_length() + self._clamp > self.prec:
             return self._raise_error(ConversionSyntax,
                                      "diagnostic info too long in NaN")
         return d._fix(self)
@@ -5438,6 +5504,29 @@
 # As the flag UNICODE is not enabled here, we're explicitly avoiding any
 # other meaning for \d than the numbers [0-9].
 
+import re
+_parser = re.compile(r"""        # A numeric string consists of:
+#    \s*
+    (?P<sign>[-+])?              # an optional sign, followed by either...
+    (
+        (?=\d|\.\d)              # ...a number (with at least one digit)
+        (?P<int>\d*)             # having a (possibly empty) integer part
+        (\.(?P<frac>\d*))?       # followed by an optional fractional part
+        (E(?P<exp>[-+]?\d+))?    # followed by an optional exponent, or...
+    |
+        Inf(inity)?              # ...an infinity, or...
+    |
+        (?P<signal>s)?           # ...an (optionally signaling)
+        NaN                      # NaN
+        (?P<diag>\d*)            # with (possibly empty) diagnostic info.
+    )
+#    \s*
+    \Z
+""", re.VERBOSE | re.IGNORECASE).match
+
+_all_zeros = re.compile('0*$').match
+_exact_half = re.compile('50*$').match
+
 ##### PEP3101 support functions ##############################################
 # The functions parse_format_specifier and format_align have little to do
 # with the Decimal class, and could potentially be reused for other pure
@@ -5448,8 +5537,6 @@
 #   [[fill]align][sign][0][minimumwidth][.precision][type]
 #
 
-import re
-
 _parse_format_specifier_regex = re.compile(r"""\A
 (?:
    (?P<fill>.)?


More information about the Python-checkins mailing list