[Python-checkins] r46277 - sandbox/trunk/decimal-c/_decimal.c sandbox/trunk/decimal-c/decimal.h
georg.brandl
python-checkins at python.org
Fri May 26 11:35:32 CEST 2006
Author: georg.brandl
Date: Fri May 26 11:35:31 2006
New Revision: 46277
Modified:
sandbox/trunk/decimal-c/_decimal.c
sandbox/trunk/decimal-c/decimal.h
Log:
Checkpoint.
Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c (original)
+++ sandbox/trunk/decimal-c/_decimal.c Fri May 26 11:35:31 2006
@@ -7,11 +7,15 @@
/* Notable incompatibilities between this and the original decimal.py:
- Rounding constants are integers.
- - There's handle method on the exceptions.
+ - There's no handle method on the exceptions.
- Special values are represented by special sign values, so
the results of as_tuple() differ.
- Many internal "underscore" methods are not accessible on the object.
+*/
+/* This is not yet optimized C code, but mostly translated
+ Python that was not really made for translating, though
+ it originally should have been.
*/
#include "Python.h"
@@ -27,10 +31,6 @@
#define contextobject PyDecimalContextObject
#define decimalobject PyDecimalObject
-/* for context->flags, ->traps, ->ignored */
-#define ISFLAGSET(f, b) (((f) >> b) & 1)
-#define SETFLAG(f, b) (f |= (1 << b))
-#define UNSETFLAG(f, b) (f ^= (1 << b))
/* Checks */
@@ -129,6 +129,38 @@
static PyObject *errors[NUMSIGNALS+NUMCONDITIONS];
+/* for context->flags, ->traps, ->ignored *************************************/
+
+/* XXX: lazy error checking */
+static int
+_is_flag_set(PyObject *d, int f)
+{
+ PyObject *item = PyDict_GetItem(d, errors[f]);
+ if (item)
+ return PyObject_IsTrue(item);
+ return 0;
+}
+
+static int
+_set_flag(PyObject *d, int f, int v)
+{
+ PyObject *i = PyInt_FromLong(v);
+ PyObject *item;
+ int res = 0;
+
+ if (!i) return -1;
+ item = PyDict_GetItem(d, errors[f]);
+ if (item)
+ res = PyObject_IsTrue(item);
+
+ if (PyDict_SetItem(d, errors[f], i) < 0)
+ res = -1;
+ Py_DECREF(i);
+ return res;
+}
+
+
+
/* Forwarding ****************************************************************/
static contextobject *getcontext(void);
@@ -142,18 +174,22 @@
static PyObject *decimal_str(decimalobject *);
static PyObject *_do_decimal_str(decimalobject *, contextobject *, int);
static decimalobject *_new_decimalobj(PyTypeObject *, long, char, long);
+static decimalobject *_do_decimal_subtract(decimalobject *, decimalobject *, contextobject *);
+static contextobject *context_shallow_copy(contextobject *);
+static PyObject *context_ignore_all_flags(contextobject *);
+static decimalobject *_do_decimal_absolute(decimalobject *, contextobject *, int);
/* Exception handlers *********************************************************/
/* Raise the exception if signal is trapped and not ignored. */
-#define HANDLE_ERROR(ctx, cond, expl, onerror) \
- int err = (cond >= NUMSIGNALS ? S_INV_OPERATION : cond); \
- if (! ISFLAGSET(ctx->ignored, err)) { \
- SETFLAG(ctx->flags, err); \
- if (ISFLAGSET(ctx->traps, err)) { \
- PyErr_SetString(errors[err], (expl ? expl : "")); \
- return onerror; \
- } \
+#define HANDLE_ERROR(ctx, cond, expl, onerror) \
+ int err = (cond >= NUMSIGNALS ? S_INV_OPERATION : cond); \
+ if (! _is_flag_set(ctx->ignored, err)) { \
+ _set_flag(ctx->flags, err, 1); \
+ if (_is_flag_set(ctx->traps, err)) { \
+ PyErr_SetString(errors[err], (expl ? expl : "")); \
+ return onerror; \
+ } \
}
@@ -321,24 +357,30 @@
_new_decimalobj(PyTypeObject *type, long ndigits, char sign, long exp)
{
decimalobject *new;
- char *arr;
+ char *arr = NULL;
+
if (ndigits > LONG_MAX) {
PyErr_NoMemory();
return NULL;
}
+
arr = PyObject_MALLOC(ndigits);
if (!arr) {
PyErr_NoMemory();
- return NULL;
+ goto err;
}
new = (decimalobject *)type->tp_alloc(type, 0);
if (new == NULL)
- return NULL;
+ goto err;
new->sign = sign;
new->exp = exp;
new->ob_size = ndigits;
new->digits = arr;
return new;
+
+ err:
+ if (arr) PyObject_FREE(arr);
+ return NULL;
}
/* shortcut for use in methods */
@@ -608,7 +650,7 @@
if (prec == -1)
prec = ctx->prec;
- if (rounding < 0 || rounding > ROUND_CEILING) {
+ if (!VALID_ROUND(rounding)) {
PyErr_SetString(PyExc_ValueError, "invalid rounding mode");
return NULL;
}
@@ -827,7 +869,7 @@
return NULL;
if (handle_Subnormal(ctx, NULL) != 0)
goto err;
- if (ISFLAGSET(ctx->flags, S_INEXACT)) {
+ if (_is_flag_set(ctx->flags, S_INEXACT)) {
if (handle_Underflow(ctx, NULL) != 0)
goto err;
}
@@ -978,19 +1020,159 @@
}
+/* Returns -1, 0, 1. No special error return code, must check
+ PyErr_Occurred() */
+static int
+_do_real_decimal_compare(decimalobject *self, decimalobject *other,
+ contextobject *ctx)
+{
+ long adj1, adj2;
+ long i, minsize;
+ decimalobject *longer, *ans;
+ contextobject *ctx2;
+
+ if (ISSPECIAL(self) || ISSPECIAL(other)) {
+ decimalobject *nan;
+ if (_check_nans(self, other, ctx, &nan) != 0) {
+ Py_XDECREF(nan);
+ /* comparisons with NaN always report self>other */
+ return 1;
+ }
+ }
+
+ /* If both are 0, sign comparison isn't correct. */
+ if (!decimal_nonzero(self) && !decimal_nonzero(other))
+ return 0;
+
+ /* If different signs, neg one is less */
+ if ((other->sign & 1) && !(self->sign & 1))
+ return 1;
+ if ((self->sign & 1) && !(other->sign & 1))
+ return -1;
+
+ adj1 = ADJUSTED(self);
+ adj2 = ADJUSTED(other);
+
+ if (adj1 == adj2) {
+ if (self->ob_size <= other->ob_size) {
+ minsize = self->ob_size;
+ longer = other;
+ } else {
+ minsize = other->ob_size;
+ longer = self;
+ }
+
+ for (i = 0; i < minsize; i++) {
+ if (self->digits[i] != other->digits[i])
+ goto next;
+ }
+ /* Okay, now the remaining digits of the longer
+ one must consist of only digits. */
+ for (i = minsize; i < longer->ob_size; i++)
+ if (longer->digits[i] != 0)
+ goto next;
+ /* All digits match, so they're equal. */
+ return 0;
+ }
+
+ next:
+ /* Adjusted sizes are not equal. */
+ if (adj1 > adj2 && self->digits[0] != 0)
+ return 1 - 2*(self->sign & 1); /* 0 -> 1, 1 -> -1 */
+ else if (adj1 < adj2 && other->digits[0] != 0)
+ return 1 - 2*(other->sign & 1);
+
+ ctx2 = context_shallow_copy(ctx);
+ if (!ctx2) return 0; /* error */
+
+ ctx2->rounding = ROUND_UP; /* away from 0 */
+ if (context_ignore_all_flags(ctx2) == NULL)
+ return 0; /* error */
+
+ /* XXX: WTF? */
+ ans = _do_decimal_subtract(self, other, ctx2);
+ if (!ans) return 0;
+
+ if (decimal_nonzero(ans))
+ i = 0;
+ else if (ans->sign & 1)
+ i = -1;
+ else
+ i = 1;
+ Py_DECREF(ans);
+ return i;
+}
+
static decimalobject *
_do_decimal_compare(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
- /* XXX */
+ int res;
+ if (ISSPECIAL(self) || (decimal_nonzero(other) &&
+ ISSPECIAL(other))) {
+ decimalobject *nan;
+ if (_check_nans(self, other, ctx, &nan) != 0)
+ return nan;
+ }
+
+ res = _do_real_decimal_compare(self, other, ctx);
+ return (decimalobject *)decimal_from_long(self->ob_type, res);
}
DECIMAL_BINARY_FUNC(compare)
+
+static PyObject *
+decimal_richcompare(decimalobject *self, decimalobject *other,
+ int op)
+{
+ int res;
+ contextobject *ctx;
+ ctx = getcontext();
+ if (!ctx) return NULL;
+
+ other = (decimalobject *)_convert_to_decimal(self->ob_type,
+ (PyObject *)other,
+ ctx, 0);
+ if (other == Py_NotImplemented) return other;
+
+ res = _do_real_decimal_compare(self, other, ctx);
+ Py_DECREF(other);
+ if (PyErr_Occurred())
+ return NULL;
+
+ if ( (res == 0 && (op == Py_EQ || op == Py_LE || op == Py_GT)) ||
+ (res == -1 && (op == Py_NE || op == Py_LT || op == Py_LE)) ||
+ (res == 1 && (op == Py_NE || op == Py_GT || op == Py_GE)))
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+
static decimalobject *
_do_decimal_max(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
- /* XXX */
+ decimalobject *ans, *cmp;
+
+ if (ISSPECIAL(self) || ISSPECIAL(other)) {
+ decimalobject *nan;
+ int sn = GETNAN(self);
+ int so = GETNAN(other);
+ if (sn || so) {
+ if (so == 1 && sn != 2) {
+ Py_INCREF(self);
+ return self;
+ } else if (sn == 1 && so != 2) {
+ Py_INCREF(other);
+ return other;
+ }
+ }
+ if (_check_nans(self, other, ctx, &nan) != 0)
+ return nan;
+ }
+
+
}
DECIMAL_BINARY_FUNC(max)
@@ -999,6 +1181,7 @@
contextobject *ctx)
{
/* XXX */
+ Py_RETURN_NONE;
}
DECIMAL_BINARY_FUNC(min)
@@ -1091,6 +1274,7 @@
_do_decimal_remainder_near(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
+ Py_RETURN_NONE;
}
DECIMAL_BINARY_FUNC(remainder_near)
@@ -1143,6 +1327,7 @@
static decimalobject *
_do_decimal_sqrt(decimalobject *self, contextobject *ctx)
{
+ Py_RETURN_NONE;
}
DECIMAL_UNARY_FUNC(sqrt)
@@ -1170,13 +1355,12 @@
Py_INCREF(self);
return self;
}
- rnd = ISFLAGSET(ctx->ignored, S_ROUNDED);
- inex = ISFLAGSET(ctx->ignored, S_INEXACT);
- SETFLAG(ctx->ignored, S_ROUNDED);
- SETFLAG(ctx->ignored, S_INEXACT);
+ /* XXX: slow? */
+ rnd = _set_flag(ctx->ignored, S_ROUNDED, 1);
+ inex =_set_flag(ctx->ignored, S_INEXACT, 1);
ans = _decimal_rescale(self, 0, ctx, rounding, 1);
- if (!rnd) UNSETFLAG(ctx->ignored, S_ROUNDED);
- if (!inex) UNSETFLAG(ctx->ignored, S_INEXACT);
+ if (!rnd) _set_flag(ctx->ignored, S_ROUNDED, rnd);
+ if (!inex) _set_flag(ctx->ignored, S_INEXACT, inex);
return ans;
}
@@ -1500,6 +1684,35 @@
}
#undef SANITY_CHECK
+/* XXX */
+static PyObject *
+decimal_round(decimalobject *self, PyObject *args)
+{
+ contextobject *ctx = NULL;
+ long prec = -1, rnd = -1;
+ if (!PyArg_ParseTuple(args, "|llO", &prec, &rnd, &ctx))
+ return NULL;
+ ENSURE_CONTEXT("_round", ctx);
+ if (prec == -1) prec = ctx->prec;
+ if (rnd == -1) rnd = ctx->rounding;
+
+ return _decimal_round(self, prec, ctx, rnd);
+}
+
+static PyObject *
+decimal_XXX_abs(decimalobject *self, PyObject *args)
+{
+ int round = -1;
+ contextobject *ctx;
+
+ if (!PyArg_ParseTuple(args, "|iO", &round, &ctx))
+ return NULL;
+ ENSURE_CONTEXT("abs", ctx);
+ if (round == -1)
+ round = ctx->rounding;
+ return _do_decimal_absolute(self, ctx, round);
+}
+
static PyMethodDef decimal_methods[] = {
{"adjusted", (PyCFunction)decimal_adjusted,
METH_NOARGS,
@@ -1561,6 +1774,10 @@
METH_NOARGS},
{"__deepcopy__", decimal_deepcopy,
METH_O},
+ /* XXX */
+ {"_round", (PyCFunction)decimal_round,
+ METH_VARARGS},
+ {"abs__", (PyCFunction)decimal_XXX_abs, METH_VARARGS},
{NULL, NULL}
};
@@ -1596,10 +1813,79 @@
_do_decimal_add(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
+ int shouldround, sign, negativezero = 0;
+ long exp, oexp;
+ decimalobject *res, *res2;
+
+ if (ISSPECIAL(self) || ISSPECIAL(other)) {
+ decimalobject *nan;
+ if (_check_nans(self, other, ctx, &nan) != 0)
+ return nan;
+ if (ISINF(self)) {
+ if (((self->sign&1) != (other->sign&1)) &&
+ ISINF(other))
+ return handle_InvalidOperation(self->ob_type, ctx,
+ "-INF + INF", NULL);
+ return _decimal_get_copy(self);
+ } else if (ISINF(other)) {
+ return _decimal_get_copy(other);
+ }
+
+
+ }
+
+ shouldround = (ctx->rounding_dec == ALWAYS_ROUND);
+ exp = (self->exp < other->exp ? self->exp : other->exp);
+
+ if (ctx->rounding == ROUND_FLOOR &&
+ (self->sign & 1) != (other->sign & 1))
+ negativezero = 1;
+
+ if (!decimal_nonzero(self) && !decimal_nonzero(other)) {
+ if (negativezero)
+ sign = 1;
+ else if (self->sign < other->sign)
+ sign = self->sign;
+ else
+ sign = other->sign;
+ res = _new_decimalobj(self->ob_type, 1, sign, exp);
+ if (!res) return NULL;
+ res->digits[0] = 0;
+ return res;
+ }
+ if (!decimal_nonzero(self)) {
+ oexp = other->exp - ctx->prec - 1;
+ exp = (exp > oexp ? exp : oexp);
+ res = _decimal_rescale(other, exp, ctx, 0);
+ if (!res) return NULL;
+ if (shouldround) {
+ res2 = _decimal_fix(res, ctx);
+ Py_DECREF(res);
+ return res2;
+ } else {
+ return res;
+ }
+ }
+ if (!decimal_nonzero(other)) {
+ oexp = self->exp - ctx->prec - 1;
+ exp = (exp > oexp ? exp : oexp);
+ res = _decimal_rescale(self, exp, ctx, 0);
+ if (!res) return NULL;
+ if (shouldround) {
+ res2 = _decimal_fix(res, ctx);
+ Py_DECREF(res);
+ return res2;
+ } else {
+ return res;
+ }
+ }
+
/* XXX */
+ Py_RETURN_NONE;
}
DECIMAL_SPECIAL_2FUNC(decimal_add)
+
static decimalobject *
_do_decimal_subtract(decimalobject *self, decimalobject *other,
contextobject *ctx)
@@ -1627,17 +1913,21 @@
}
DECIMAL_SPECIAL_2FUNC(decimal_subtract)
+
static decimalobject *
_do_decimal_multiply(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
+ Py_RETURN_NONE;
}
DECIMAL_SPECIAL_2FUNC(decimal_multiply)
+
static decimalobject *
_do_decimal_divide(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
+ Py_RETURN_NONE;
}
DECIMAL_SPECIAL_2FUNC(decimal_divide)
@@ -1646,43 +1936,55 @@
_do_decimal_floor_div(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
+ Py_RETURN_NONE;
}
DECIMAL_SPECIAL_2FUNC(decimal_floor_div)
+
static decimalobject *
_do_decimal_true_div(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
+ Py_RETURN_NONE;
}
DECIMAL_SPECIAL_2FUNC(decimal_true_div)
+
static decimalobject *
_do_decimal_remainder(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
+ Py_RETURN_NONE;
}
DECIMAL_SPECIAL_2FUNC(decimal_remainder)
+
static decimalobject *
_do_decimal_divmod(decimalobject *self, decimalobject *other,
contextobject *ctx)
{
+ Py_RETURN_NONE;
}
DECIMAL_SPECIAL_2FUNC(decimal_divmod)
+
static decimalobject *
_do_decimal_power(decimalobject *self, decimalobject *other,
- decimalobject *modulo, contextobject *ctx)
+ decimalobject *modulo, contextobject *ctx)
{
+ Py_RETURN_NONE;
}
+
static PyObject *
decimal_power(PyObject *self, PyObject *other, PyObject *modulo) {
decimalobject *res;
contextobject *ctx = getcontext();
if (!ctx) return NULL;
+
other = _convert_to_decimal(self->ob_type, other, ctx, 0);
if (other == NULL || other == Py_NotImplemented) return other;
+
if (modulo == Py_None) {
Py_INCREF(modulo);
} else {
@@ -1785,16 +2087,18 @@
ctx2 = context_copy(ctx);
if (!ctx2) return NULL;
ctx2->rounding_dec = NEVER_ROUND;
+ ctx = ctx2;
}
if (self->sign & 1)
- ans = _do_decimal_negative(self, ctx2);
+ ans = _do_decimal_negative(self, ctx);
else
- ans = _do_decimal_positive(self, ctx2);
+ ans = _do_decimal_positive(self, ctx);
Py_XDECREF(ctx2);
return ans;
}
+
static PyObject *
decimal_absolute(PyObject *self)
{
@@ -1828,6 +2132,7 @@
return res;
}
+
/* Convert to int, truncating. */
static PyObject *
decimal_int(decimalobject *self)
@@ -1867,7 +2172,8 @@
if (self->sign & 1) res = -res;
return PyInt_FromLong(res);
}
-
+
+
static PyObject *
decimal_float(decimalobject *self)
{
@@ -1880,6 +2186,7 @@
return res;
}
+
static int
decimal_nonzero(decimalobject *self)
{
@@ -1891,6 +2198,7 @@
return 0;
}
+
static PyNumberMethods decimal_as_number = {
decimal_add, /* nb_add */
decimal_subtract, /* nb_subtract */
@@ -1935,13 +2243,6 @@
};
-static PyObject *
-decimal_richcompare(decimalobject *a, decimalobject *b, int op)
-{
- /* XXX */
- return NULL;
-}
-
int
_decimal_isint(decimalobject *d)
{
@@ -1960,6 +2261,7 @@
return 1;
}
+
static void
decimal_dealloc(decimalobject *d)
{
@@ -1967,6 +2269,7 @@
d->ob_type->tp_free(d);
}
+
static decimalobject *
_decimal_fromliteralnan(PyTypeObject *type, char *str, long len, contextobject *ctx)
{
@@ -2023,11 +2326,13 @@
return new;
}
+
static char *infinities[] = {
"inf", "infinity", "+inf", "+infinity",
"-inf", "-infinity", 0
};
+
static decimalobject *
_decimal_fromliteralinfinity(PyTypeObject *type, char *str)
{
@@ -2053,6 +2358,7 @@
return NULL;
}
+
static decimalobject *
_decimal_fromliteral(PyTypeObject *type, char *str, long len, contextobject *ctx)
{
@@ -2197,12 +2503,14 @@
return (PyObject *)new;
}
+
PyObject *
PyDecimal_FromLong(long value)
{
return decimal_from_long(&PyDecimal_DecimalType, value);
}
+
/* convert from a 3-tuple of (sign, digits, exp) */
static PyObject *
decimal_from_sequence(PyTypeObject *type, PyObject *seq)
@@ -2273,12 +2581,14 @@
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)
{
@@ -2303,7 +2613,6 @@
return res;
}
-static PyObject *decimal_new(PyTypeObject *, PyObject *, PyObject *);
static PyObject *
decimal_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
@@ -2379,6 +2688,7 @@
return NULL;
}
+
static PyObject *
decimal_repr(decimalobject *d)
{
@@ -2396,6 +2706,7 @@
return res;
}
+
static long
decimal_hash(decimalobject *d)
{
@@ -2440,6 +2751,7 @@
return hash;
}
+
/* XXX: just for debugging? */
static PyMemberDef _decimal_members[] = {
{"_sign", T_INT, offsetof(decimalobject, sign), 0},
@@ -2447,6 +2759,7 @@
{NULL}
};
+
static PyObject *
_decimal_get_int(decimalobject *self)
{
@@ -2459,6 +2772,7 @@
return tup;
}
+
static int
_decimal_set_int(decimalobject *self, PyObject *value)
{
@@ -2497,6 +2811,7 @@
return 0;
}
+
static PyObject *
_decimal_is_special(decimalobject *self)
{
@@ -2506,6 +2821,7 @@
Py_RETURN_FALSE;
}
+
static PyGetSetDef _decimal_getset[] = {
{"_int", (getter)_decimal_get_int, (setter)_decimal_set_int},
{"_is_special", (getter)_decimal_is_special, 0},
@@ -2539,7 +2855,7 @@
decimal_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* XXX: activate when it's implemented (richcmpfunc)decimal_richcompare,*/ /* tp_richcompare */
+ (richcmpfunc)decimal_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
@@ -2651,14 +2967,50 @@
/* Context object ************************************************************/
static contextobject *
-_new_contextobj(long prec, int rounding, int rounding_dec, int traps,
- int flags, long Emin, long Emax, int capitals,
- int clamp, int ignored)
+_new_contextobj(long prec, int rounding, int rounding_dec, PyObject *traps,
+ PyObject *flags, long Emin, long Emax, int capitals,
+ int clamp, PyObject *ignored, int copy_dicts)
{
contextobject *new;
+ PyObject *f = NULL, *t = NULL, *i = NULL;
+
new = (contextobject *)PyObject_NEW(contextobject, &PyDecimal_DecimalContextType);
if (new == NULL)
return NULL;
+
+ if (!flags) {
+ f = PyDict_New();
+ } else if (copy_dicts) {
+ f = PyDict_Copy(flags);
+ } else {
+ f = flags;
+ Py_INCREF(f);
+ }
+ if (!f) goto err;
+
+ if (!traps) {
+ t = PyDict_New();
+ } else if (copy_dicts) {
+ t = PyDict_Copy(traps);
+ } else {
+ t = traps;
+ Py_INCREF(t);
+ }
+ if (!t) goto err;
+
+ if (!ignored) {
+ i = PyDict_New();
+ } else if (copy_dicts) {
+ i = PyDict_Copy(ignored);
+ } else {
+ i = ignored;
+ Py_INCREF(i);
+ }
+ if (!i) goto err;
+
+ new->flags = f;
+ new->traps = t;
+ new->ignored = i;
new->prec = prec;
new->rounding = rounding;
new->rounding_dec = rounding_dec;
@@ -2666,64 +3018,15 @@
new->Emax = Emax;
new->capitals = capitals;
new->clamp = clamp;
- new->flags = flags;
- new->traps = traps;
- new->ignored = ignored;
return new;
-}
-
-/* Context properties *********************************************************/
-
-
-static PyObject *
-_dict_from_bitmask(int bitmask)
-{
- PyObject *dict = NULL, *val, *dp;
- int i, res;
-
- dict = PyDict_New();
- if (!dict) return NULL;
- for (i = 0; i < NUMSIGNALS; i++) {
- val = PyInt_FromLong(ISFLAGSET(bitmask, i));
- if (!val) goto err;
- res = PyDict_SetItem(dict, errors[i], val);
- Py_DECREF(val);
- if (val < 0) goto err;
- }
- dp = PyDictProxy_New(dict);
- Py_DECREF(dict);
- return dp;
-
+
err:
- Py_XDECREF(dict);
+ Py_XDECREF(f);
+ Py_XDECREF(t);
+ Py_XDECREF(i);
return NULL;
-}
-
-static PyObject *
-context_get_flags(contextobject *self)
-{
- return _dict_from_bitmask(self->flags);
}
-static PyObject *
-context_get_traps(contextobject *self)
-{
- return _dict_from_bitmask(self->traps);
-}
-
-static PyObject *
-context_get_ignored(contextobject *self)
-{
- return _dict_from_bitmask(self->ignored);
-}
-
-static PyGetSetDef context_getset[] = {
- {"flags", (getter)context_get_flags, (setter)0},
- {"traps", (getter)context_get_traps, (setter)0},
- {"_ignored", (getter)context_get_ignored, (setter)0},
- {NULL}
-};
-
/* Context methods ************************************************************/
static PyObject *
@@ -2733,14 +3036,21 @@
Py_RETURN_NONE;
}
-/* As a C Context doesn't have mutable attributes, this is the
- same as Context._shallow_copy. */
+
+static contextobject *
+context_shallow_copy(contextobject *ctx)
+{
+ return _new_contextobj(ctx->prec, ctx->rounding, ctx->rounding_dec, ctx->traps,
+ ctx->flags, ctx->Emin, ctx->Emax, ctx->capitals, ctx->clamp,
+ ctx->ignored, 0);
+}
+
static contextobject *
context_copy(contextobject *ctx)
{
return _new_contextobj(ctx->prec, ctx->rounding, ctx->rounding_dec, ctx->traps,
ctx->flags, ctx->Emin, ctx->Emax, ctx->capitals, ctx->clamp,
- ctx->ignored);
+ ctx->ignored, 1);
}
static decimalobject *
@@ -2986,52 +3296,41 @@
static PyObject *
context_reduce(contextobject *self)
{
- PyObject *flags = NULL, *traps = NULL, *ignored = NULL;
- PyObject *res = NULL;
-
- flags = context_get_flags(self);
- if (!flags) goto err;
- traps = context_get_traps(self);
- if (!traps) goto err;
- ignored = context_get_ignored(self);
- if (!ignored) goto err;
-
- res = Py_BuildValue("(O(liiOOlliiO))", self->ob_type,
- self->prec, self->rounding,
- self->rounding_dec, traps, flags, self->Emin,
- self->Emax, self->capitals, self->clamp,
- ignored);
-
- err:
- Py_XDECREF(flags);
- Py_XDECREF(traps);
- Py_XDECREF(ignored);
- return res;
+ return Py_BuildValue("(O(liiOOlliiO))", self->ob_type,
+ self->prec, self->rounding,
+ self->rounding_dec, self->traps, self->flags,
+ self->Emin, self->Emax, self->capitals,
+ self->clamp, self->ignored);
}
static PyObject *
context_ignore_flags(contextobject *self, PyObject *args)
{
PyObject *flag, *ret_flags;
- Py_ssize_t i, j;
+ long i, j;
/* NB, unlike regard_flags this doesn't accept a sequence as the
first element and regard_flags returns a list-ized version of
its arguments instead of None
*/
+ ret_flags = PyList_New(0);
if (ret_flags == NULL)
return NULL;
+
for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
flag = PyTuple_GET_ITEM(args, i);
for (j = 0; j < NUMSIGNALS; j++) {
if (errors[j] == flag) {
- SETFLAG(self->ignored, j);
- Py_INCREF(flag);
- PyList_SET_ITEM(ret_flags, i, flag);
+ _set_flag(self->ignored, j, 1);
+ if (PyList_Append(ret_flags, flag) < 0) {
+ Py_DECREF(ret_flags);
+ return NULL;
+ }
break;
}
}
+ /* No DECREF of flag here. */
if (j == NUMSIGNALS) {
Py_DECREF(ret_flags);
PyErr_SetString(PyExc_ValueError, "arguments must be valid flags");
@@ -3044,27 +3343,33 @@
static PyObject *
context_ignore_all_flags(contextobject *self)
{
- PyObject *allflags, *flag;
+ PyObject *allflags, *flag, *res;
int i = 0;
allflags = PyTuple_New(NUMSIGNALS);
if (allflags == NULL)
return NULL;
-
+
for (i = 0; i < NUMSIGNALS; i++) {
flag = errors[i];
Py_INCREF(flag);
PyTuple_SET_ITEM(allflags, i, flag);
}
- return context_ignore_flags(self, allflags);
+ res = context_ignore_flags(self, allflags);
+ Py_DECREF(allflags);
+ return res;
}
static PyObject *
context_regard_flags(contextobject *self, PyObject *args)
{
PyObject *flag, *flags;
- Py_ssize_t i, j;
+ long i, j;
+ if (PyTuple_GET_SIZE(args) <= 0) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
/* regard_flags allows a list of flags as the first arg */
flags = PyTuple_GET_ITEM(args, 0);
if (PyTuple_GET_SIZE(args) != 1 && !PySequence_Check(flags))
@@ -3074,10 +3379,11 @@
flag = PySequence_GetItem(flags, i);
for (j = 0; j < NUMSIGNALS; j++) {
if (flag == errors[j]) {
- UNSETFLAG(self->ignored, j);
+ _set_flag(self->ignored, j, 0);
break;
}
}
+ Py_DECREF(flag);
if (j == NUMSIGNALS) {
PyErr_SetString(PyExc_ValueError, "arguments must be valid flags");
return NULL;
@@ -3090,7 +3396,6 @@
context_set_rounding_decision(contextobject *self, PyObject *args)
{
int old_dec, new_dec;
- PyObject *ret;
if (!PyArg_ParseTuple(args, "i:_set_rounding_decision", &new_dec))
return NULL;
@@ -3101,16 +3406,13 @@
old_dec = self->rounding_dec;
self->rounding_dec = new_dec;
- ret = PyInt_FromLong((long)old_dec);
- if (ret == NULL)
- return NULL;
- return ret;
+ return PyInt_FromLong((long)old_dec);
}
+
static PyObject *
context_set_rounding(contextobject *self, PyObject *args)
{
int old_round, new_round;
- PyObject *ret;
if (!PyArg_ParseTuple(args, "i:_set_rounding", &new_round))
return NULL;
@@ -3120,10 +3422,7 @@
}
old_round = self->rounding;
self->rounding = new_round;
- ret = PyInt_FromLong((long)old_round);
- if (ret == NULL)
- return NULL;
- return ret;
+ return PyInt_FromLong((long)old_round);
}
static PyObject *
@@ -3217,7 +3516,7 @@
PyObject *rest = NULL;
PyObject *handler;
PyObject *dummy;
- int flag = -1;
+ int errindex = -1, condindex = -1;
int i;
if (!PyArg_ParseTuple(args, "O|OO:_raise_error", &condition, &explanation, &rest))
@@ -3228,10 +3527,11 @@
return NULL;
- if (explanation == NULL && !PyArg_ParseTupleAndKeywords(dummy, kwds,
+/* if (explanation == NULL && !PyArg_ParseTupleAndKeywords(dummy, kwds,
"O:_raise_error", kwlist,
&explanation))
return NULL;
+*/
if ((condition == ConversionSyntax) ||
(condition == DivisionImpossible) ||
@@ -3242,27 +3542,21 @@
/* reuse the condition */
handler = condition;
}
- for (i = 0; i < NUMSIGNALS; i++) {
- if (errors[i] == handler) {
- flag = i;
- break;
- }
+ /* The condition handle is called based on condition,
+ the exception on handler. */
+ for (i = 0; i < NUMSIGNALS+NUMCONDITIONS; i++) {
+ if (errors[i] == condition)
+ condindex = i;
+ if (errors[i] == handler)
+ errindex = i;
}
- if (ISFLAGSET(self->ignored, flag)) {
- return _do_context_error_dispatch(flag, args);
+ if (_is_flag_set(self->ignored, errindex)) {
+ return _do_context_error_dispatch(condindex, args);
} else {
- SETFLAG(self->ignored, flag);
- if (!ISFLAGSET(self->traps, flag)) {
- for (i = 0; i < NUMSIGNALS; i++) {
- if (errors[i] == condition) {
- flag = i;
- break;
- }
- }
- return _do_context_error_dispatch(flag, args);
-
- }
+ _set_flag(self->flags, errindex, 1);
+ if (!_is_flag_set(self->traps, errindex))
+ return _do_context_error_dispatch(condindex, args);
}
PyErr_SetString(handler, PyString_AsString(explanation));
return NULL;
@@ -3335,7 +3629,7 @@
METH_VARARGS | METH_KEYWORDS},
{"__copy__", (PyCFunction)context_copy,
METH_NOARGS},
- {"_shallow_copy", (PyCFunction)context_copy,
+ {"_shallow_copy", (PyCFunction)context_shallow_copy,
METH_NOARGS},
{"__reduce__", (PyCFunction)context_reduce,
METH_NOARGS},
@@ -3347,18 +3641,21 @@
static void
-context_dealloc(PyObject *c)
+context_dealloc(contextobject *c)
{
+ Py_DECREF(c->flags);
+ Py_DECREF(c->traps);
+ Py_DECREF(c->ignored);
c->ob_type->tp_free(c);
}
#define TEST_AND_CAT(num, name) \
- if (ISFLAGSET(self->flags, num)) { \
+ if (_is_flag_set(self->flags, num)) { \
strcat(flags, name); \
strcat(flags, ", "); \
flaglen += strlen(name) + 2; \
} \
- if (ISFLAGSET(self->traps, num)) { \
+ if (_is_flag_set(self->traps, num)) { \
strcat(traps, name); \
strcat(traps, ", "); \
traplen += strlen(name) + 2; \
@@ -3442,8 +3739,10 @@
long Emin = LONG_MAX, Emax = LONG_MIN;
int rounding = -1, rounding_dec = -1, capitals = -1, clamp = 0;
PyObject *pytraps = NULL, *pyflags = NULL, *pyignored = NULL;
- PyObject *tmp;
- int traps = 0, flags = 0, ignored = 0;
+ PyObject *tmp, *res = NULL;
+ PyObject *_traps = NULL;
+ PyObject *_flags = NULL;
+ PyObject *_ignored = NULL;
int i, j;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|nbbOOnnbbO:Context", kwlist,
@@ -3451,83 +3750,96 @@
&pyflags, &Emin, &Emax, &capitals, &clamp,
&pyignored))
return NULL;
-
+
if (pytraps == NULL) {
- traps = PyDecimal_DefaultContext->traps;
- } else if (!PyDict_Check(pytraps)) {
- for (i = 0; i < NUMSIGNALS; i++) {
- j = PySequence_Contains(pytraps, errors[i]);
- if (j == -1)
- return NULL;
- else if (j == 1)
- SETFLAG(traps, i);
- }
+ _traps = PyDict_Copy(PyDecimal_DefaultContext->traps);
+ if (!_traps) goto err;
} else {
- for (i = 0; i < NUMSIGNALS; i++) {
- j = PyDict_Contains(pytraps, errors[i]);
- if (j == -1)
- return NULL;
- else if (j == 0)
- continue;
- tmp = PyDict_GetItem(pytraps, errors[i]);
- if (!tmp)
- return NULL;
- j = PyObject_IsTrue(tmp);
- if (j == -1)
- return NULL;
- else if (j == 1)
- SETFLAG(traps, i);
+ _traps = PyDict_New();
+ if (!_traps) goto err;
+ if (!PyDict_Check(pytraps)) {
+
+ for (i = 0; i < NUMSIGNALS; i++) {
+ j = PySequence_Contains(pytraps, errors[i]);
+ if (j == -1)
+ goto err;
+ else if (j == 1)
+ _set_flag(_traps, i, 1);
+ }
+ } else {
+ for (i = 0; i < NUMSIGNALS; i++) {
+ j = PyDict_Contains(pytraps, errors[i]);
+ if (j == -1)
+ goto err;
+ else if (j == 0)
+ continue;
+ tmp = PyDict_GetItem(pytraps, errors[i]);
+ if (!tmp)
+ goto err;
+ j = PyObject_IsTrue(tmp);
+ if (j == -1)
+ goto err;
+ else if (j == 1)
+ _set_flag(_traps, i, 1);
+ }
}
}
+ _flags = PyDict_New();
+ if (!_flags) goto err;
+
if (pyflags == NULL) {
/* don't copy flags from default context */
} else if (PyDict_Check(pyflags)) {
for (i = 0; i < NUMSIGNALS; i++) {
j = PyDict_Contains(pyflags, errors[i]);
if (j == -1)
- return NULL;
+ goto err;
else if (j == 0)
continue;
tmp = PyDict_GetItem(pyflags, errors[i]);
if (!tmp)
- return NULL;
+ goto err;
j = PyObject_IsTrue(tmp);
if (j == -1)
- return NULL;
+ goto err;
else if (j == 1)
- SETFLAG(flags, i);
+ _set_flag(_flags, i, 1);
}
} else {
PyErr_SetString(PyExc_TypeError, "initial flags must be a dict");
- return NULL;
+ goto err;
}
+
+ _ignored = PyDict_New();
+ if (!_ignored) goto err;
+
if (pyignored == NULL) {
/* don't copy ignored flags from default context */
} else if (!PyDict_Check(pyignored)) {
for (i = 0; i < NUMSIGNALS; i++) {
j = PySequence_Contains(pyignored, errors[i]);
if (j == -1)
- return NULL;
+ goto err;
else if (j == 1)
- SETFLAG(ignored, i);
+ _set_flag(_ignored, i, 1);
}
} else {
for (i = 0; i < NUMSIGNALS; i++) {
j = PyDict_Contains(pyignored, errors[i]);
if (j == -1)
- return NULL;
+ goto err;
else if (j == 0)
continue;
tmp = PyDict_GetItem(pyignored, errors[i]);
if (!tmp)
- return NULL;
+ goto err;
j = PyObject_IsTrue(tmp);
if (j == -1)
- return NULL;
+ goto err;
else if (j == 1)
- SETFLAG(ignored, i);
+ _set_flag(_ignored, i, 1);
}
}
@@ -3559,9 +3871,14 @@
clamp = clamp & 1;
- return (PyObject *)_new_contextobj(prec, rounding, rounding_dec, traps,
- flags, Emin, Emax, capitals, clamp,
- ignored);
+ res = (PyObject *)_new_contextobj(prec, rounding, rounding_dec, _traps,
+ _flags, Emin, Emax, capitals, clamp,
+ _ignored, 0);
+ err:
+ Py_XDECREF(_flags);
+ Py_XDECREF(_traps);
+ Py_XDECREF(_ignored);
+ return res;
}
@@ -3575,6 +3892,9 @@
{"rounding", T_INT, OFF(rounding), 0},
{"_rounding_decision", T_INT, OFF(rounding_dec), 0},
{"_clamp", T_INT, OFF(clamp), 0},
+ {"flags", T_OBJECT_EX, OFF(flags), 0},
+ {"traps", T_OBJECT_EX, OFF(traps), 0},
+ {"_ignored", T_OBJECT_EX, OFF(ignored), 0},
{NULL}
};
@@ -3610,7 +3930,7 @@
0, /* tp_iternext */
context_methods, /* tp_methods */
context_members, /* tp_members */
- context_getset, /* tp_getset */
+ 0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
@@ -3700,8 +4020,11 @@
PyObject *m; /* a module object */
PyObject *tup;
contextobject *ctx;
- int traps = 0;
+ PyObject *traps;
+ traps = PyDict_New();
+ if (!traps) return;
+
m = Py_InitModule3(MODULE_NAME, module_methods,
"Fast implementation of decimal arithmetic.");
if (m == NULL)
@@ -3718,12 +4041,53 @@
Py_INCREF(&PyDecimal_DecimalContextType);
PyModule_AddObject(m, "Context", (PyObject *) &PyDecimal_DecimalContextType);
+ ADD_CONST(m, ROUND_DOWN);
+ ADD_CONST(m, ROUND_UP);
+ ADD_CONST(m, ROUND_HALF_DOWN);
+ ADD_CONST(m, ROUND_HALF_EVEN);
+ ADD_CONST(m, ROUND_HALF_UP);
+ ADD_CONST(m, ROUND_FLOOR);
+ ADD_CONST(m, ROUND_CEILING);
+ ADD_CONST(m, ALWAYS_ROUND);
+ ADD_CONST(m, NEVER_ROUND);
+
+ INIT_EXC(m, DecimalException, PyExc_ArithmeticError);
+ INIT_EXC(m, Clamped, DecimalException);
+ INIT_EXC(m, InvalidOperation, DecimalException);
+ INIT_EXC(m, ConversionSyntax, InvalidOperation);
+ INIT_EXC(m, DivisionImpossible, InvalidOperation);
+ INIT_EXC_WITH_2TUPLE(m, DivisionUndefined,
+ InvalidOperation, PyExc_ZeroDivisionError);
+ INIT_EXC(m, InvalidContext, InvalidOperation);
+ INIT_EXC_WITH_2TUPLE(m, DivisionByZero,
+ DecimalException, PyExc_ZeroDivisionError);
+ INIT_EXC(m, Inexact, DecimalException);
+ INIT_EXC(m, Rounded, DecimalException);
+ INIT_EXC(m, Subnormal, DecimalException);
+ INIT_EXC_WITH_2TUPLE(m, Overflow, Rounded, Inexact);
+ INIT_EXC_WITH_3TUPLE(m, Underflow,
+ Rounded, Inexact, Subnormal);
+
+ errors[S_INV_OPERATION] = InvalidOperation;
+ errors[S_DIV_BY_ZERO] = DivisionByZero;
+ errors[S_CLAMPED] = Clamped;
+ errors[S_INEXACT] = Inexact;
+ errors[S_ROUNDED] = Rounded;
+ errors[S_SUBNORMAL] = Subnormal;
+ errors[S_OVERFLOW] = Overflow;
+ errors[S_UNDERFLOW] = Underflow;
+ errors[C_INV_CONTEXT] = InvalidContext;
+ errors[C_CONV_SYNTAX] = ConversionSyntax;
+ errors[C_DIV_IMPOSSIBLE]= DivisionImpossible;
+ errors[C_DIV_UNDEFINED] = DivisionUndefined;
+
/* initialize default Context objects */
- SETFLAG(traps, S_DIV_BY_ZERO);
- SETFLAG(traps, S_OVERFLOW);
- SETFLAG(traps, S_INV_OPERATION);
+ _set_flag(traps, S_DIV_BY_ZERO, 1);
+ _set_flag(traps, S_OVERFLOW, 1);
+ _set_flag(traps, S_INV_OPERATION, 1);
PyDecimal_DefaultContext = _new_contextobj(28, ROUND_HALF_EVEN, ALWAYS_ROUND,
- traps, 0, -999999999L, 999999999L, 1, 0, 0);
+ traps, NULL, -999999999L, 999999999L,
+ 1, 0, NULL, 1);
if (!PyDecimal_DefaultContext)
return;
if (PyModule_AddObject(m, "DefaultContext",
@@ -3731,11 +4095,12 @@
return;
/* add flags for BasicContext */
- SETFLAG(traps, S_CLAMPED);
- SETFLAG(traps, S_UNDERFLOW);
+ _set_flag(traps, S_CLAMPED, 1);
+ _set_flag(traps, S_UNDERFLOW, 1);
PyDecimal_BasicContext = _new_contextobj(9, ROUND_HALF_UP, ALWAYS_ROUND,
- traps, 0, -999999999L, 999999999L, 1, 0, 0);
+ traps, NULL, -999999999L, 999999999L,
+ 1, 0, NULL, 1);
if (!PyDecimal_BasicContext)
return;
if (PyModule_AddObject(m, "BasicContext",
@@ -3743,7 +4108,8 @@
return;
PyDecimal_ExtendedContext = _new_contextobj(9, ROUND_HALF_EVEN, ALWAYS_ROUND,
- 0, 0, -999999999L, 999999999L, 1, 0, 0);
+ NULL, NULL, -999999999L, 999999999L,
+ 1, 0, NULL, 1);
if (!PyDecimal_ExtendedContext)
return;
if (PyModule_AddObject(m, "ExtendedContext",
@@ -3769,43 +4135,4 @@
if (PyModule_AddObject(m, "negInf", (PyObject *)PyDecimal_NegInf) < 0)
return;
- ADD_CONST(m, ROUND_DOWN);
- ADD_CONST(m, ROUND_UP);
- ADD_CONST(m, ROUND_HALF_DOWN);
- ADD_CONST(m, ROUND_HALF_EVEN);
- ADD_CONST(m, ROUND_HALF_UP);
- ADD_CONST(m, ROUND_FLOOR);
- ADD_CONST(m, ROUND_CEILING);
- ADD_CONST(m, ALWAYS_ROUND);
- ADD_CONST(m, NEVER_ROUND);
-
- INIT_EXC(m, DecimalException, PyExc_ArithmeticError);
- INIT_EXC(m, Clamped, DecimalException);
- INIT_EXC(m, InvalidOperation, DecimalException);
- INIT_EXC(m, ConversionSyntax, InvalidOperation);
- INIT_EXC(m, DivisionImpossible, InvalidOperation);
- INIT_EXC_WITH_2TUPLE(m, DivisionUndefined,
- InvalidOperation, PyExc_ZeroDivisionError);
- INIT_EXC(m, InvalidContext, InvalidOperation);
- INIT_EXC_WITH_2TUPLE(m, DivisionByZero,
- DecimalException, PyExc_ZeroDivisionError);
- INIT_EXC(m, Inexact, DecimalException);
- INIT_EXC(m, Rounded, DecimalException);
- INIT_EXC(m, Subnormal, DecimalException);
- INIT_EXC_WITH_2TUPLE(m, Overflow, Rounded, Inexact);
- INIT_EXC_WITH_3TUPLE(m, Underflow,
- Rounded, Inexact, Subnormal);
-
- errors[S_INV_OPERATION] = InvalidOperation;
- errors[S_DIV_BY_ZERO] = DivisionByZero;
- errors[S_CLAMPED] = Clamped;
- errors[S_INEXACT] = Inexact;
- errors[S_ROUNDED] = Rounded;
- errors[S_SUBNORMAL] = Subnormal;
- errors[S_OVERFLOW] = Overflow;
- errors[S_UNDERFLOW] = Underflow;
- errors[C_INV_CONTEXT] = InvalidContext;
- errors[C_CONV_SYNTAX] = ConversionSyntax;
- errors[C_DIV_IMPOSSIBLE]= DivisionImpossible;
- errors[C_DIV_UNDEFINED] = DivisionUndefined;
}
Modified: sandbox/trunk/decimal-c/decimal.h
==============================================================================
--- sandbox/trunk/decimal-c/decimal.h (original)
+++ sandbox/trunk/decimal-c/decimal.h Fri May 26 11:35:31 2006
@@ -35,10 +35,10 @@
long Emin;
long Emax;
- /* signal handling -- these are bit fields */
- int traps; /* if a signal is trapped */
- int ignored; /* if a signal is ignored completely */
- int flags; /* if a signal has occurred, but not been trapped */
+ /* signal handling -- these are dicts */
+ PyObject *traps; /* if a signal is trapped */
+ PyObject *flags; /* if a signal has occurred, but not been trapped */
+ PyObject *ignored; /* if a signal is ignored completely */
} PyDecimalContextObject;
static PyTypeObject PyDecimal_DecimalContextType;
@@ -57,9 +57,9 @@
/* static constants **********************************************************/
-static PyObject *PyDecimal_NaN;
-static PyObject *PyDecimal_Inf;
-static PyObject *PyDecimal_NegInf;
+static PyDecimalObject *PyDecimal_NaN;
+static PyDecimalObject *PyDecimal_Inf;
+static PyDecimalObject *PyDecimal_NegInf;
static PyDecimalContextObject *PyDecimal_DefaultContext;
static PyDecimalContextObject *PyDecimal_BasicContext;
More information about the Python-checkins
mailing list