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