diff options
author | Ori Bernstein <ori@eigenstate.org> | 2021-06-14 00:00:37 +0000 |
---|---|---|
committer | Ori Bernstein <ori@eigenstate.org> | 2021-06-14 00:00:37 +0000 |
commit | a73a964e51247ed169d322c725a3a18859f109a3 (patch) | |
tree | 3f752d117274d444bda44e85609aeac1acf313f3 /sys/src/cmd/python/Objects | |
parent | e64efe273fcb921a61bf27d33b230c4e64fcd425 (diff) |
python, hg: tow outside the environment.
they've served us well, and can ride off into the sunset.
Diffstat (limited to 'sys/src/cmd/python/Objects')
44 files changed, 0 insertions, 60359 deletions
diff --git a/sys/src/cmd/python/Objects/abstract.c b/sys/src/cmd/python/Objects/abstract.c deleted file mode 100644 index f7a3bfefb..000000000 --- a/sys/src/cmd/python/Objects/abstract.c +++ /dev/null @@ -1,2381 +0,0 @@ -/* Abstract Object Interface (many thanks to Jim Fulton) */ - -#include "Python.h" -#include <ctype.h> -#include "structmember.h" /* we need the offsetof() macro from there */ -#include "longintrepr.h" - -#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \ - Py_TPFLAGS_CHECKTYPES) - - -/* Shorthands to return certain errors */ - -static PyObject * -type_error(const char *msg, PyObject *obj) -{ - PyErr_Format(PyExc_TypeError, msg, obj->ob_type->tp_name); - return NULL; -} - -static PyObject * -null_error(void) -{ - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_SystemError, - "null argument to internal routine"); - return NULL; -} - -/* Operations on any object */ - -int -PyObject_Cmp(PyObject *o1, PyObject *o2, int *result) -{ - int r; - - if (o1 == NULL || o2 == NULL) { - null_error(); - return -1; - } - r = PyObject_Compare(o1, o2); - if (PyErr_Occurred()) - return -1; - *result = r; - return 0; -} - -PyObject * -PyObject_Type(PyObject *o) -{ - PyObject *v; - - if (o == NULL) - return null_error(); - v = (PyObject *)o->ob_type; - Py_INCREF(v); - return v; -} - -Py_ssize_t -PyObject_Size(PyObject *o) -{ - PySequenceMethods *m; - - if (o == NULL) { - null_error(); - return -1; - } - - m = o->ob_type->tp_as_sequence; - if (m && m->sq_length) - return m->sq_length(o); - - return PyMapping_Size(o); -} - -#undef PyObject_Length -Py_ssize_t -PyObject_Length(PyObject *o) -{ - return PyObject_Size(o); -} -#define PyObject_Length PyObject_Size - -Py_ssize_t -_PyObject_LengthHint(PyObject *o) -{ - Py_ssize_t rv = PyObject_Size(o); - if (rv != -1) - return rv; - if (PyErr_ExceptionMatches(PyExc_TypeError) || - PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyObject *err_type, *err_value, *err_tb, *ro; - - PyErr_Fetch(&err_type, &err_value, &err_tb); - ro = PyObject_CallMethod(o, "__length_hint__", NULL); - if (ro != NULL) { - rv = PyInt_AsLong(ro); - Py_DECREF(ro); - Py_XDECREF(err_type); - Py_XDECREF(err_value); - Py_XDECREF(err_tb); - return rv; - } - PyErr_Restore(err_type, err_value, err_tb); - } - return -1; -} - -PyObject * -PyObject_GetItem(PyObject *o, PyObject *key) -{ - PyMappingMethods *m; - - if (o == NULL || key == NULL) - return null_error(); - - m = o->ob_type->tp_as_mapping; - if (m && m->mp_subscript) - return m->mp_subscript(o, key); - - if (o->ob_type->tp_as_sequence) { - if (PyIndex_Check(key)) { - Py_ssize_t key_value; - key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); - if (key_value == -1 && PyErr_Occurred()) - return NULL; - return PySequence_GetItem(o, key_value); - } - else if (o->ob_type->tp_as_sequence->sq_item) - return type_error("sequence index must " - "be integer, not '%.200s'", key); - } - - return type_error("'%.200s' object is unsubscriptable", o); -} - -int -PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value) -{ - PyMappingMethods *m; - - if (o == NULL || key == NULL || value == NULL) { - null_error(); - return -1; - } - m = o->ob_type->tp_as_mapping; - if (m && m->mp_ass_subscript) - return m->mp_ass_subscript(o, key, value); - - if (o->ob_type->tp_as_sequence) { - if (PyIndex_Check(key)) { - Py_ssize_t key_value; - key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); - if (key_value == -1 && PyErr_Occurred()) - return -1; - return PySequence_SetItem(o, key_value, value); - } - else if (o->ob_type->tp_as_sequence->sq_ass_item) { - type_error("sequence index must be " - "integer, not '%.200s'", key); - return -1; - } - } - - type_error("'%.200s' object does not support item assignment", o); - return -1; -} - -int -PyObject_DelItem(PyObject *o, PyObject *key) -{ - PyMappingMethods *m; - - if (o == NULL || key == NULL) { - null_error(); - return -1; - } - m = o->ob_type->tp_as_mapping; - if (m && m->mp_ass_subscript) - return m->mp_ass_subscript(o, key, (PyObject*)NULL); - - if (o->ob_type->tp_as_sequence) { - if (PyIndex_Check(key)) { - Py_ssize_t key_value; - key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); - if (key_value == -1 && PyErr_Occurred()) - return -1; - return PySequence_DelItem(o, key_value); - } - else if (o->ob_type->tp_as_sequence->sq_ass_item) { - type_error("sequence index must be " - "integer, not '%.200s'", key); - return -1; - } - } - - type_error("'%.200s' object does not support item deletion", o); - return -1; -} - -int -PyObject_DelItemString(PyObject *o, char *key) -{ - PyObject *okey; - int ret; - - if (o == NULL || key == NULL) { - null_error(); - return -1; - } - okey = PyString_FromString(key); - if (okey == NULL) - return -1; - ret = PyObject_DelItem(o, okey); - Py_DECREF(okey); - return ret; -} - -int -PyObject_AsCharBuffer(PyObject *obj, - const char **buffer, - Py_ssize_t *buffer_len) -{ - PyBufferProcs *pb; - char *pp; - Py_ssize_t len; - - if (obj == NULL || buffer == NULL || buffer_len == NULL) { - null_error(); - return -1; - } - pb = obj->ob_type->tp_as_buffer; - if (pb == NULL || - pb->bf_getcharbuffer == NULL || - pb->bf_getsegcount == NULL) { - PyErr_SetString(PyExc_TypeError, - "expected a character buffer object"); - return -1; - } - if ((*pb->bf_getsegcount)(obj,NULL) != 1) { - PyErr_SetString(PyExc_TypeError, - "expected a single-segment buffer object"); - return -1; - } - len = (*pb->bf_getcharbuffer)(obj, 0, &pp); - if (len < 0) - return -1; - *buffer = pp; - *buffer_len = len; - return 0; -} - -int -PyObject_CheckReadBuffer(PyObject *obj) -{ - PyBufferProcs *pb = obj->ob_type->tp_as_buffer; - - if (pb == NULL || - pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL || - (*pb->bf_getsegcount)(obj, NULL) != 1) - return 0; - return 1; -} - -int PyObject_AsReadBuffer(PyObject *obj, - const void **buffer, - Py_ssize_t *buffer_len) -{ - PyBufferProcs *pb; - void *pp; - Py_ssize_t len; - - if (obj == NULL || buffer == NULL || buffer_len == NULL) { - null_error(); - return -1; - } - pb = obj->ob_type->tp_as_buffer; - if (pb == NULL || - pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL) { - PyErr_SetString(PyExc_TypeError, - "expected a readable buffer object"); - return -1; - } - if ((*pb->bf_getsegcount)(obj, NULL) != 1) { - PyErr_SetString(PyExc_TypeError, - "expected a single-segment buffer object"); - return -1; - } - len = (*pb->bf_getreadbuffer)(obj, 0, &pp); - if (len < 0) - return -1; - *buffer = pp; - *buffer_len = len; - return 0; -} - -int PyObject_AsWriteBuffer(PyObject *obj, - void **buffer, - Py_ssize_t *buffer_len) -{ - PyBufferProcs *pb; - void*pp; - Py_ssize_t len; - - if (obj == NULL || buffer == NULL || buffer_len == NULL) { - null_error(); - return -1; - } - pb = obj->ob_type->tp_as_buffer; - if (pb == NULL || - pb->bf_getwritebuffer == NULL || - pb->bf_getsegcount == NULL) { - PyErr_SetString(PyExc_TypeError, - "expected a writeable buffer object"); - return -1; - } - if ((*pb->bf_getsegcount)(obj, NULL) != 1) { - PyErr_SetString(PyExc_TypeError, - "expected a single-segment buffer object"); - return -1; - } - len = (*pb->bf_getwritebuffer)(obj,0,&pp); - if (len < 0) - return -1; - *buffer = pp; - *buffer_len = len; - return 0; -} - -/* Operations on numbers */ - -int -PyNumber_Check(PyObject *o) -{ - return o && o->ob_type->tp_as_number && - (o->ob_type->tp_as_number->nb_int || - o->ob_type->tp_as_number->nb_float); -} - -/* Binary operators */ - -/* New style number protocol support */ - -#define NB_SLOT(x) offsetof(PyNumberMethods, x) -#define NB_BINOP(nb_methods, slot) \ - (*(binaryfunc*)(& ((char*)nb_methods)[slot])) -#define NB_TERNOP(nb_methods, slot) \ - (*(ternaryfunc*)(& ((char*)nb_methods)[slot])) - -/* - Calling scheme used for binary operations: - - v w Action - ------------------------------------------------------------------- - new new w.op(v,w)[*], v.op(v,w), w.op(v,w) - new old v.op(v,w), coerce(v,w), v.op(v,w) - old new w.op(v,w), coerce(v,w), v.op(v,w) - old old coerce(v,w), v.op(v,w) - - [*] only when v->ob_type != w->ob_type && w->ob_type is a subclass of - v->ob_type - - Legend: - ------- - * new == new style number - * old == old style number - * Action indicates the order in which operations are tried until either - a valid result is produced or an error occurs. - - */ - -static PyObject * -binary_op1(PyObject *v, PyObject *w, const int op_slot) -{ - PyObject *x; - binaryfunc slotv = NULL; - binaryfunc slotw = NULL; - - if (v->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(v)) - slotv = NB_BINOP(v->ob_type->tp_as_number, op_slot); - if (w->ob_type != v->ob_type && - w->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(w)) { - slotw = NB_BINOP(w->ob_type->tp_as_number, op_slot); - if (slotw == slotv) - slotw = NULL; - } - if (slotv) { - if (slotw && PyType_IsSubtype(w->ob_type, v->ob_type)) { - x = slotw(v, w); - if (x != Py_NotImplemented) - return x; - Py_DECREF(x); /* can't do it */ - slotw = NULL; - } - x = slotv(v, w); - if (x != Py_NotImplemented) - return x; - Py_DECREF(x); /* can't do it */ - } - if (slotw) { - x = slotw(v, w); - if (x != Py_NotImplemented) - return x; - Py_DECREF(x); /* can't do it */ - } - if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w)) { - int err = PyNumber_CoerceEx(&v, &w); - if (err < 0) { - return NULL; - } - if (err == 0) { - PyNumberMethods *mv = v->ob_type->tp_as_number; - if (mv) { - binaryfunc slot; - slot = NB_BINOP(mv, op_slot); - if (slot) { - x = slot(v, w); - Py_DECREF(v); - Py_DECREF(w); - return x; - } - } - /* CoerceEx incremented the reference counts */ - Py_DECREF(v); - Py_DECREF(w); - } - } - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -static PyObject * -binop_type_error(PyObject *v, PyObject *w, const char *op_name) -{ - PyErr_Format(PyExc_TypeError, - "unsupported operand type(s) for %.100s: " - "'%.100s' and '%.100s'", - op_name, - v->ob_type->tp_name, - w->ob_type->tp_name); - return NULL; -} - -static PyObject * -binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) -{ - PyObject *result = binary_op1(v, w, op_slot); - if (result == Py_NotImplemented) { - Py_DECREF(result); - return binop_type_error(v, w, op_name); - } - return result; -} - - -/* - Calling scheme used for ternary operations: - - *** In some cases, w.op is called before v.op; see binary_op1. *** - - v w z Action - ------------------------------------------------------------------- - new new new v.op(v,w,z), w.op(v,w,z), z.op(v,w,z) - new old new v.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z) - old new new w.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z) - old old new z.op(v,w,z), coerce(v,w,z), v.op(v,w,z) - new new old v.op(v,w,z), w.op(v,w,z), coerce(v,w,z), v.op(v,w,z) - new old old v.op(v,w,z), coerce(v,w,z), v.op(v,w,z) - old new old w.op(v,w,z), coerce(v,w,z), v.op(v,w,z) - old old old coerce(v,w,z), v.op(v,w,z) - - Legend: - ------- - * new == new style number - * old == old style number - * Action indicates the order in which operations are tried until either - a valid result is produced or an error occurs. - * coerce(v,w,z) actually does: coerce(v,w), coerce(v,z), coerce(w,z) and - only if z != Py_None; if z == Py_None, then it is treated as absent - variable and only coerce(v,w) is tried. - - */ - -static PyObject * -ternary_op(PyObject *v, - PyObject *w, - PyObject *z, - const int op_slot, - const char *op_name) -{ - PyNumberMethods *mv, *mw, *mz; - PyObject *x = NULL; - ternaryfunc slotv = NULL; - ternaryfunc slotw = NULL; - ternaryfunc slotz = NULL; - - mv = v->ob_type->tp_as_number; - mw = w->ob_type->tp_as_number; - if (mv != NULL && NEW_STYLE_NUMBER(v)) - slotv = NB_TERNOP(mv, op_slot); - if (w->ob_type != v->ob_type && - mw != NULL && NEW_STYLE_NUMBER(w)) { - slotw = NB_TERNOP(mw, op_slot); - if (slotw == slotv) - slotw = NULL; - } - if (slotv) { - if (slotw && PyType_IsSubtype(w->ob_type, v->ob_type)) { - x = slotw(v, w, z); - if (x != Py_NotImplemented) - return x; - Py_DECREF(x); /* can't do it */ - slotw = NULL; - } - x = slotv(v, w, z); - if (x != Py_NotImplemented) - return x; - Py_DECREF(x); /* can't do it */ - } - if (slotw) { - x = slotw(v, w, z); - if (x != Py_NotImplemented) - return x; - Py_DECREF(x); /* can't do it */ - } - mz = z->ob_type->tp_as_number; - if (mz != NULL && NEW_STYLE_NUMBER(z)) { - slotz = NB_TERNOP(mz, op_slot); - if (slotz == slotv || slotz == slotw) - slotz = NULL; - if (slotz) { - x = slotz(v, w, z); - if (x != Py_NotImplemented) - return x; - Py_DECREF(x); /* can't do it */ - } - } - - if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w) || - (z != Py_None && !NEW_STYLE_NUMBER(z))) { - /* we have an old style operand, coerce */ - PyObject *v1, *z1, *w2, *z2; - int c; - - c = PyNumber_Coerce(&v, &w); - if (c != 0) - goto error3; - - /* Special case: if the third argument is None, it is - treated as absent argument and not coerced. */ - if (z == Py_None) { - if (v->ob_type->tp_as_number) { - slotz = NB_TERNOP(v->ob_type->tp_as_number, - op_slot); - if (slotz) - x = slotz(v, w, z); - else - c = -1; - } - else - c = -1; - goto error2; - } - v1 = v; - z1 = z; - c = PyNumber_Coerce(&v1, &z1); - if (c != 0) - goto error2; - w2 = w; - z2 = z1; - c = PyNumber_Coerce(&w2, &z2); - if (c != 0) - goto error1; - - if (v1->ob_type->tp_as_number != NULL) { - slotv = NB_TERNOP(v1->ob_type->tp_as_number, - op_slot); - if (slotv) - x = slotv(v1, w2, z2); - else - c = -1; - } - else - c = -1; - - Py_DECREF(w2); - Py_DECREF(z2); - error1: - Py_DECREF(v1); - Py_DECREF(z1); - error2: - Py_DECREF(v); - Py_DECREF(w); - error3: - if (c >= 0) - return x; - } - - if (z == Py_None) - PyErr_Format( - PyExc_TypeError, - "unsupported operand type(s) for ** or pow(): " - "'%.100s' and '%.100s'", - v->ob_type->tp_name, - w->ob_type->tp_name); - else - PyErr_Format( - PyExc_TypeError, - "unsupported operand type(s) for pow(): " - "'%.100s', '%.100s', '%.100s'", - v->ob_type->tp_name, - w->ob_type->tp_name, - z->ob_type->tp_name); - return NULL; -} - -#define BINARY_FUNC(func, op, op_name) \ - PyObject * \ - func(PyObject *v, PyObject *w) { \ - return binary_op(v, w, NB_SLOT(op), op_name); \ - } - -BINARY_FUNC(PyNumber_Or, nb_or, "|") -BINARY_FUNC(PyNumber_Xor, nb_xor, "^") -BINARY_FUNC(PyNumber_And, nb_and, "&") -BINARY_FUNC(PyNumber_Lshift, nb_lshift, "<<") -BINARY_FUNC(PyNumber_Rshift, nb_rshift, ">>") -BINARY_FUNC(PyNumber_Subtract, nb_subtract, "-") -BINARY_FUNC(PyNumber_Divide, nb_divide, "/") -BINARY_FUNC(PyNumber_Divmod, nb_divmod, "divmod()") - -PyObject * -PyNumber_Add(PyObject *v, PyObject *w) -{ - PyObject *result = binary_op1(v, w, NB_SLOT(nb_add)); - if (result == Py_NotImplemented) { - PySequenceMethods *m = v->ob_type->tp_as_sequence; - Py_DECREF(result); - if (m && m->sq_concat) { - return (*m->sq_concat)(v, w); - } - result = binop_type_error(v, w, "+"); - } - return result; -} - -static PyObject * -sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) -{ - Py_ssize_t count; - if (PyIndex_Check(n)) { - count = PyNumber_AsSsize_t(n, PyExc_OverflowError); - if (count == -1 && PyErr_Occurred()) - return NULL; - } - else { - return type_error("can't multiply sequence by " - "non-int of type '%.200s'", n); - } - return (*repeatfunc)(seq, count); -} - -PyObject * -PyNumber_Multiply(PyObject *v, PyObject *w) -{ - PyObject *result = binary_op1(v, w, NB_SLOT(nb_multiply)); - if (result == Py_NotImplemented) { - PySequenceMethods *mv = v->ob_type->tp_as_sequence; - PySequenceMethods *mw = w->ob_type->tp_as_sequence; - Py_DECREF(result); - if (mv && mv->sq_repeat) { - return sequence_repeat(mv->sq_repeat, v, w); - } - else if (mw && mw->sq_repeat) { - return sequence_repeat(mw->sq_repeat, w, v); - } - result = binop_type_error(v, w, "*"); - } - return result; -} - -PyObject * -PyNumber_FloorDivide(PyObject *v, PyObject *w) -{ - /* XXX tp_flags test */ - return binary_op(v, w, NB_SLOT(nb_floor_divide), "//"); -} - -PyObject * -PyNumber_TrueDivide(PyObject *v, PyObject *w) -{ - /* XXX tp_flags test */ - return binary_op(v, w, NB_SLOT(nb_true_divide), "/"); -} - -PyObject * -PyNumber_Remainder(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_remainder), "%"); -} - -PyObject * -PyNumber_Power(PyObject *v, PyObject *w, PyObject *z) -{ - return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()"); -} - -/* Binary in-place operators */ - -/* The in-place operators are defined to fall back to the 'normal', - non in-place operations, if the in-place methods are not in place. - - - If the left hand object has the appropriate struct members, and - they are filled, call the appropriate function and return the - result. No coercion is done on the arguments; the left-hand object - is the one the operation is performed on, and it's up to the - function to deal with the right-hand object. - - - Otherwise, in-place modification is not supported. Handle it exactly as - a non in-place operation of the same kind. - - */ - -#define HASINPLACE(t) \ - PyType_HasFeature((t)->ob_type, Py_TPFLAGS_HAVE_INPLACEOPS) - -static PyObject * -binary_iop1(PyObject *v, PyObject *w, const int iop_slot, const int op_slot) -{ - PyNumberMethods *mv = v->ob_type->tp_as_number; - if (mv != NULL && HASINPLACE(v)) { - binaryfunc slot = NB_BINOP(mv, iop_slot); - if (slot) { - PyObject *x = (slot)(v, w); - if (x != Py_NotImplemented) { - return x; - } - Py_DECREF(x); - } - } - return binary_op1(v, w, op_slot); -} - -static PyObject * -binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot, - const char *op_name) -{ - PyObject *result = binary_iop1(v, w, iop_slot, op_slot); - if (result == Py_NotImplemented) { - Py_DECREF(result); - return binop_type_error(v, w, op_name); - } - return result; -} - -#define INPLACE_BINOP(func, iop, op, op_name) \ - PyObject * \ - func(PyObject *v, PyObject *w) { \ - return binary_iop(v, w, NB_SLOT(iop), NB_SLOT(op), op_name); \ - } - -INPLACE_BINOP(PyNumber_InPlaceOr, nb_inplace_or, nb_or, "|=") -INPLACE_BINOP(PyNumber_InPlaceXor, nb_inplace_xor, nb_xor, "^=") -INPLACE_BINOP(PyNumber_InPlaceAnd, nb_inplace_and, nb_and, "&=") -INPLACE_BINOP(PyNumber_InPlaceLshift, nb_inplace_lshift, nb_lshift, "<<=") -INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=") -INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=") -INPLACE_BINOP(PyNumber_InPlaceDivide, nb_inplace_divide, nb_divide, "/=") - -PyObject * -PyNumber_InPlaceFloorDivide(PyObject *v, PyObject *w) -{ - /* XXX tp_flags test */ - return binary_iop(v, w, NB_SLOT(nb_inplace_floor_divide), - NB_SLOT(nb_floor_divide), "//="); -} - -PyObject * -PyNumber_InPlaceTrueDivide(PyObject *v, PyObject *w) -{ - /* XXX tp_flags test */ - return binary_iop(v, w, NB_SLOT(nb_inplace_true_divide), - NB_SLOT(nb_true_divide), "/="); -} - -PyObject * -PyNumber_InPlaceAdd(PyObject *v, PyObject *w) -{ - PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_add), - NB_SLOT(nb_add)); - if (result == Py_NotImplemented) { - PySequenceMethods *m = v->ob_type->tp_as_sequence; - Py_DECREF(result); - if (m != NULL) { - binaryfunc f = NULL; - if (HASINPLACE(v)) - f = m->sq_inplace_concat; - if (f == NULL) - f = m->sq_concat; - if (f != NULL) - return (*f)(v, w); - } - result = binop_type_error(v, w, "+="); - } - return result; -} - -PyObject * -PyNumber_InPlaceMultiply(PyObject *v, PyObject *w) -{ - PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_multiply), - NB_SLOT(nb_multiply)); - if (result == Py_NotImplemented) { - ssizeargfunc f = NULL; - PySequenceMethods *mv = v->ob_type->tp_as_sequence; - PySequenceMethods *mw = w->ob_type->tp_as_sequence; - Py_DECREF(result); - if (mv != NULL) { - if (HASINPLACE(v)) - f = mv->sq_inplace_repeat; - if (f == NULL) - f = mv->sq_repeat; - if (f != NULL) - return sequence_repeat(f, v, w); - } - else if (mw != NULL) { - /* Note that the right hand operand should not be - * mutated in this case so sq_inplace_repeat is not - * used. */ - if (mw->sq_repeat) - return sequence_repeat(mw->sq_repeat, w, v); - } - result = binop_type_error(v, w, "*="); - } - return result; -} - -PyObject * -PyNumber_InPlaceRemainder(PyObject *v, PyObject *w) -{ - return binary_iop(v, w, NB_SLOT(nb_inplace_remainder), - NB_SLOT(nb_remainder), "%="); -} - -PyObject * -PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z) -{ - if (HASINPLACE(v) && v->ob_type->tp_as_number && - v->ob_type->tp_as_number->nb_inplace_power != NULL) { - return ternary_op(v, w, z, NB_SLOT(nb_inplace_power), "**="); - } - else { - return ternary_op(v, w, z, NB_SLOT(nb_power), "**="); - } -} - - -/* Unary operators and functions */ - -PyObject * -PyNumber_Negative(PyObject *o) -{ - PyNumberMethods *m; - - if (o == NULL) - return null_error(); - m = o->ob_type->tp_as_number; - if (m && m->nb_negative) - return (*m->nb_negative)(o); - - return type_error("bad operand type for unary -: '%.200s'", o); -} - -PyObject * -PyNumber_Positive(PyObject *o) -{ - PyNumberMethods *m; - - if (o == NULL) - return null_error(); - m = o->ob_type->tp_as_number; - if (m && m->nb_positive) - return (*m->nb_positive)(o); - - return type_error("bad operand type for unary +: '%.200s'", o); -} - -PyObject * -PyNumber_Invert(PyObject *o) -{ - PyNumberMethods *m; - - if (o == NULL) - return null_error(); - m = o->ob_type->tp_as_number; - if (m && m->nb_invert) - return (*m->nb_invert)(o); - - return type_error("bad operand type for unary ~: '%.200s'", o); -} - -PyObject * -PyNumber_Absolute(PyObject *o) -{ - PyNumberMethods *m; - - if (o == NULL) - return null_error(); - m = o->ob_type->tp_as_number; - if (m && m->nb_absolute) - return m->nb_absolute(o); - - return type_error("bad operand type for abs(): '%.200s'", o); -} - -/* Add a check for embedded NULL-bytes in the argument. */ -static PyObject * -int_from_string(const char *s, Py_ssize_t len) -{ - char *end; - PyObject *x; - - x = PyInt_FromString((char*)s, &end, 10); - if (x == NULL) - return NULL; - if (end != s + len) { - PyErr_SetString(PyExc_ValueError, - "null byte in argument for int()"); - Py_DECREF(x); - return NULL; - } - return x; -} - -/* Return a Python Int or Long from the object item - Raise TypeError if the result is not an int-or-long - or if the object cannot be interpreted as an index. -*/ -PyObject * -PyNumber_Index(PyObject *item) -{ - PyObject *result = NULL; - if (item == NULL) - return null_error(); - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_INCREF(item); - return item; - } - if (PyIndex_Check(item)) { - result = item->ob_type->tp_as_number->nb_index(item); - if (result && - !PyInt_Check(result) && !PyLong_Check(result)) { - PyErr_Format(PyExc_TypeError, - "__index__ returned non-(int,long) " \ - "(type %.200s)", - result->ob_type->tp_name); - Py_DECREF(result); - return NULL; - } - } - else { - PyErr_Format(PyExc_TypeError, - "'%.200s' object cannot be interpreted " - "as an index", item->ob_type->tp_name); - } - return result; -} - -/* Return an error on Overflow only if err is not NULL*/ - -Py_ssize_t -PyNumber_AsSsize_t(PyObject *item, PyObject *err) -{ - Py_ssize_t result; - PyObject *runerr; - PyObject *value = PyNumber_Index(item); - if (value == NULL) - return -1; - - /* We're done if PyInt_AsSsize_t() returns without error. */ - result = PyInt_AsSsize_t(value); - if (result != -1 || !(runerr = PyErr_Occurred())) - goto finish; - - /* Error handling code -- only manage OverflowError differently */ - if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) - goto finish; - - PyErr_Clear(); - /* If no error-handling desired then the default clipping - is sufficient. - */ - if (!err) { - assert(PyLong_Check(value)); - /* Whether or not it is less than or equal to - zero is determined by the sign of ob_size - */ - if (_PyLong_Sign(value) < 0) - result = PY_SSIZE_T_MIN; - else - result = PY_SSIZE_T_MAX; - } - else { - /* Otherwise replace the error with caller's error object. */ - PyErr_Format(err, - "cannot fit '%.200s' into an index-sized integer", - item->ob_type->tp_name); - } - - finish: - Py_DECREF(value); - return result; -} - - -PyObject * -PyNumber_Int(PyObject *o) -{ - PyNumberMethods *m; - const char *buffer; - Py_ssize_t buffer_len; - - if (o == NULL) - return null_error(); - if (PyInt_CheckExact(o)) { - Py_INCREF(o); - return o; - } - m = o->ob_type->tp_as_number; - if (m && m->nb_int) { /* This should include subclasses of int */ - PyObject *res = m->nb_int(o); - if (res && (!PyInt_Check(res) && !PyLong_Check(res))) { - PyErr_Format(PyExc_TypeError, - "__int__ returned non-int (type %.200s)", - res->ob_type->tp_name); - Py_DECREF(res); - return NULL; - } - return res; - } - if (PyInt_Check(o)) { /* A int subclass without nb_int */ - PyIntObject *io = (PyIntObject*)o; - return PyInt_FromLong(io->ob_ival); - } - if (PyString_Check(o)) - return int_from_string(PyString_AS_STRING(o), - PyString_GET_SIZE(o)); -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(o)) - return PyInt_FromUnicode(PyUnicode_AS_UNICODE(o), - PyUnicode_GET_SIZE(o), - 10); -#endif - if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) - return int_from_string((char*)buffer, buffer_len); - - return type_error("int() argument must be a string or a " - "number, not '%.200s'", o); -} - -/* Add a check for embedded NULL-bytes in the argument. */ -static PyObject * -long_from_string(const char *s, Py_ssize_t len) -{ - char *end; - PyObject *x; - - x = PyLong_FromString((char*)s, &end, 10); - if (x == NULL) - return NULL; - if (end != s + len) { - PyErr_SetString(PyExc_ValueError, - "null byte in argument for long()"); - Py_DECREF(x); - return NULL; - } - return x; -} - -PyObject * -PyNumber_Long(PyObject *o) -{ - PyNumberMethods *m; - const char *buffer; - Py_ssize_t buffer_len; - - if (o == NULL) - return null_error(); - m = o->ob_type->tp_as_number; - if (m && m->nb_long) { /* This should include subclasses of long */ - PyObject *res = m->nb_long(o); - if (res && (!PyInt_Check(res) && !PyLong_Check(res))) { - PyErr_Format(PyExc_TypeError, - "__long__ returned non-long (type %.200s)", - res->ob_type->tp_name); - Py_DECREF(res); - return NULL; - } - return res; - } - if (PyLong_Check(o)) /* A long subclass without nb_long */ - return _PyLong_Copy((PyLongObject *)o); - if (PyString_Check(o)) - /* need to do extra error checking that PyLong_FromString() - * doesn't do. In particular long('9.5') must raise an - * exception, not truncate the float. - */ - return long_from_string(PyString_AS_STRING(o), - PyString_GET_SIZE(o)); -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(o)) - /* The above check is done in PyLong_FromUnicode(). */ - return PyLong_FromUnicode(PyUnicode_AS_UNICODE(o), - PyUnicode_GET_SIZE(o), - 10); -#endif - if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) - return long_from_string(buffer, buffer_len); - - return type_error("long() argument must be a string or a " - "number, not '%.200s'", o); -} - -PyObject * -PyNumber_Float(PyObject *o) -{ - PyNumberMethods *m; - - if (o == NULL) - return null_error(); - m = o->ob_type->tp_as_number; - if (m && m->nb_float) { /* This should include subclasses of float */ - PyObject *res = m->nb_float(o); - if (res && !PyFloat_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__float__ returned non-float (type %.200s)", - res->ob_type->tp_name); - Py_DECREF(res); - return NULL; - } - return res; - } - if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */ - PyFloatObject *po = (PyFloatObject *)o; - return PyFloat_FromDouble(po->ob_fval); - } - return PyFloat_FromString(o, NULL); -} - -/* Operations on sequences */ - -int -PySequence_Check(PyObject *s) -{ - if (s && PyInstance_Check(s)) - return PyObject_HasAttrString(s, "__getitem__"); - if (PyObject_IsInstance(s, (PyObject *)&PyDict_Type)) - return 0; - return s != NULL && s->ob_type->tp_as_sequence && - s->ob_type->tp_as_sequence->sq_item != NULL; -} - -Py_ssize_t -PySequence_Size(PyObject *s) -{ - PySequenceMethods *m; - - if (s == NULL) { - null_error(); - return -1; - } - - m = s->ob_type->tp_as_sequence; - if (m && m->sq_length) - return m->sq_length(s); - - type_error("object of type '%.200s' has no len()", s); - return -1; -} - -#undef PySequence_Length -Py_ssize_t -PySequence_Length(PyObject *s) -{ - return PySequence_Size(s); -} -#define PySequence_Length PySequence_Size - -PyObject * -PySequence_Concat(PyObject *s, PyObject *o) -{ - PySequenceMethods *m; - - if (s == NULL || o == NULL) - return null_error(); - - m = s->ob_type->tp_as_sequence; - if (m && m->sq_concat) - return m->sq_concat(s, o); - - /* Instances of user classes defining an __add__() method only - have an nb_add slot, not an sq_concat slot. So we fall back - to nb_add if both arguments appear to be sequences. */ - if (PySequence_Check(s) && PySequence_Check(o)) { - PyObject *result = binary_op1(s, o, NB_SLOT(nb_add)); - if (result != Py_NotImplemented) - return result; - Py_DECREF(result); - } - return type_error("'%.200s' object can't be concatenated", s); -} - -PyObject * -PySequence_Repeat(PyObject *o, Py_ssize_t count) -{ - PySequenceMethods *m; - - if (o == NULL) - return null_error(); - - m = o->ob_type->tp_as_sequence; - if (m && m->sq_repeat) - return m->sq_repeat(o, count); - - /* Instances of user classes defining a __mul__() method only - have an nb_multiply slot, not an sq_repeat slot. so we fall back - to nb_multiply if o appears to be a sequence. */ - if (PySequence_Check(o)) { - PyObject *n, *result; - n = PyInt_FromSsize_t(count); - if (n == NULL) - return NULL; - result = binary_op1(o, n, NB_SLOT(nb_multiply)); - Py_DECREF(n); - if (result != Py_NotImplemented) - return result; - Py_DECREF(result); - } - return type_error("'%.200s' object can't be repeated", o); -} - -PyObject * -PySequence_InPlaceConcat(PyObject *s, PyObject *o) -{ - PySequenceMethods *m; - - if (s == NULL || o == NULL) - return null_error(); - - m = s->ob_type->tp_as_sequence; - if (m && HASINPLACE(s) && m->sq_inplace_concat) - return m->sq_inplace_concat(s, o); - if (m && m->sq_concat) - return m->sq_concat(s, o); - - if (PySequence_Check(s) && PySequence_Check(o)) { - PyObject *result = binary_iop1(s, o, NB_SLOT(nb_inplace_add), - NB_SLOT(nb_add)); - if (result != Py_NotImplemented) - return result; - Py_DECREF(result); - } - return type_error("'%.200s' object can't be concatenated", s); -} - -PyObject * -PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count) -{ - PySequenceMethods *m; - - if (o == NULL) - return null_error(); - - m = o->ob_type->tp_as_sequence; - if (m && HASINPLACE(o) && m->sq_inplace_repeat) - return m->sq_inplace_repeat(o, count); - if (m && m->sq_repeat) - return m->sq_repeat(o, count); - - if (PySequence_Check(o)) { - PyObject *n, *result; - n = PyInt_FromSsize_t(count); - if (n == NULL) - return NULL; - result = binary_iop1(o, n, NB_SLOT(nb_inplace_multiply), - NB_SLOT(nb_multiply)); - Py_DECREF(n); - if (result != Py_NotImplemented) - return result; - Py_DECREF(result); - } - return type_error("'%.200s' object can't be repeated", o); -} - -PyObject * -PySequence_GetItem(PyObject *s, Py_ssize_t i) -{ - PySequenceMethods *m; - - if (s == NULL) - return null_error(); - - m = s->ob_type->tp_as_sequence; - if (m && m->sq_item) { - if (i < 0) { - if (m->sq_length) { - Py_ssize_t l = (*m->sq_length)(s); - if (l < 0) - return NULL; - i += l; - } - } - return m->sq_item(s, i); - } - - return type_error("'%.200s' object is unindexable", s); -} - -PyObject * -PySequence_GetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) -{ - PySequenceMethods *m; - PyMappingMethods *mp; - - if (!s) return null_error(); - - m = s->ob_type->tp_as_sequence; - if (m && m->sq_slice) { - if (i1 < 0 || i2 < 0) { - if (m->sq_length) { - Py_ssize_t l = (*m->sq_length)(s); - if (l < 0) - return NULL; - if (i1 < 0) - i1 += l; - if (i2 < 0) - i2 += l; - } - } - return m->sq_slice(s, i1, i2); - } else if ((mp = s->ob_type->tp_as_mapping) && mp->mp_subscript) { - PyObject *res; - PyObject *slice = _PySlice_FromIndices(i1, i2); - if (!slice) - return NULL; - res = mp->mp_subscript(s, slice); - Py_DECREF(slice); - return res; - } - - return type_error("'%.200s' object is unsliceable", s); -} - -int -PySequence_SetItem(PyObject *s, Py_ssize_t i, PyObject *o) -{ - PySequenceMethods *m; - - if (s == NULL) { - null_error(); - return -1; - } - - m = s->ob_type->tp_as_sequence; - if (m && m->sq_ass_item) { - if (i < 0) { - if (m->sq_length) { - Py_ssize_t l = (*m->sq_length)(s); - if (l < 0) - return -1; - i += l; - } - } - return m->sq_ass_item(s, i, o); - } - - type_error("'%.200s' object does not support item assignment", s); - return -1; -} - -int -PySequence_DelItem(PyObject *s, Py_ssize_t i) -{ - PySequenceMethods *m; - - if (s == NULL) { - null_error(); - return -1; - } - - m = s->ob_type->tp_as_sequence; - if (m && m->sq_ass_item) { - if (i < 0) { - if (m->sq_length) { - Py_ssize_t l = (*m->sq_length)(s); - if (l < 0) - return -1; - i += l; - } - } - return m->sq_ass_item(s, i, (PyObject *)NULL); - } - - type_error("'%.200s' object doesn't support item deletion", s); - return -1; -} - -int -PySequence_SetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2, PyObject *o) -{ - PySequenceMethods *m; - PyMappingMethods *mp; - - if (s == NULL) { - null_error(); - return -1; - } - - m = s->ob_type->tp_as_sequence; - if (m && m->sq_ass_slice) { - if (i1 < 0 || i2 < 0) { - if (m->sq_length) { - Py_ssize_t l = (*m->sq_length)(s); - if (l < 0) - return -1; - if (i1 < 0) - i1 += l; - if (i2 < 0) - i2 += l; - } - } - return m->sq_ass_slice(s, i1, i2, o); - } else if ((mp = s->ob_type->tp_as_mapping) && mp->mp_ass_subscript) { - int res; - PyObject *slice = _PySlice_FromIndices(i1, i2); - if (!slice) - return -1; - res = mp->mp_ass_subscript(s, slice, o); - Py_DECREF(slice); - return res; - } - - type_error("'%.200s' object doesn't support slice assignment", s); - return -1; -} - -int -PySequence_DelSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) -{ - PySequenceMethods *m; - - if (s == NULL) { - null_error(); - return -1; - } - - m = s->ob_type->tp_as_sequence; - if (m && m->sq_ass_slice) { - if (i1 < 0 || i2 < 0) { - if (m->sq_length) { - Py_ssize_t l = (*m->sq_length)(s); - if (l < 0) - return -1; - if (i1 < 0) - i1 += l; - if (i2 < 0) - i2 += l; - } - } - return m->sq_ass_slice(s, i1, i2, (PyObject *)NULL); - } - type_error("'%.200s' object doesn't support slice deletion", s); - return -1; -} - -PyObject * -PySequence_Tuple(PyObject *v) -{ - PyObject *it; /* iter(v) */ - Py_ssize_t n; /* guess for result tuple size */ - PyObject *result; - Py_ssize_t j; - - if (v == NULL) - return null_error(); - - /* Special-case the common tuple and list cases, for efficiency. */ - if (PyTuple_CheckExact(v)) { - /* Note that we can't know whether it's safe to return - a tuple *subclass* instance as-is, hence the restriction - to exact tuples here. In contrast, lists always make - a copy, so there's no need for exactness below. */ - Py_INCREF(v); - return v; - } - if (PyList_Check(v)) - return PyList_AsTuple(v); - - /* Get iterator. */ - it = PyObject_GetIter(v); - if (it == NULL) - return NULL; - - /* Guess result size and allocate space. */ - n = _PyObject_LengthHint(v); - if (n < 0) { - if (!PyErr_ExceptionMatches(PyExc_TypeError) && - !PyErr_ExceptionMatches(PyExc_AttributeError)) { - Py_DECREF(it); - return NULL; - } - PyErr_Clear(); - n = 10; /* arbitrary */ - } - result = PyTuple_New(n); - if (result == NULL) - goto Fail; - - /* Fill the tuple. */ - for (j = 0; ; ++j) { - PyObject *item = PyIter_Next(it); - if (item == NULL) { - if (PyErr_Occurred()) - goto Fail; - break; - } - if (j >= n) { - Py_ssize_t oldn = n; - /* The over-allocation strategy can grow a bit faster - than for lists because unlike lists the - over-allocation isn't permanent -- we reclaim - the excess before the end of this routine. - So, grow by ten and then add 25%. - */ - n += 10; - n += n >> 2; - if (n < oldn) { - /* Check for overflow */ - PyErr_NoMemory(); - Py_DECREF(item); - goto Fail; - } - if (_PyTuple_Resize(&result, n) != 0) { - Py_DECREF(item); - goto Fail; - } - } - PyTuple_SET_ITEM(result, j, item); - } - - /* Cut tuple back if guess was too large. */ - if (j < n && - _PyTuple_Resize(&result, j) != 0) - goto Fail; - - Py_DECREF(it); - return result; - -Fail: - Py_XDECREF(result); - Py_DECREF(it); - return NULL; -} - -PyObject * -PySequence_List(PyObject *v) -{ - PyObject *result; /* result list */ - PyObject *rv; /* return value from PyList_Extend */ - - if (v == NULL) - return null_error(); - - result = PyList_New(0); - if (result == NULL) - return NULL; - - rv = _PyList_Extend((PyListObject *)result, v); - if (rv == NULL) { - Py_DECREF(result); - return NULL; - } - Py_DECREF(rv); - return result; -} - -PyObject * -PySequence_Fast(PyObject *v, const char *m) -{ - PyObject *it; - - if (v == NULL) - return null_error(); - - if (PyList_CheckExact(v) || PyTuple_CheckExact(v)) { - Py_INCREF(v); - return v; - } - - it = PyObject_GetIter(v); - if (it == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_SetString(PyExc_TypeError, m); - return NULL; - } - - v = PySequence_List(it); - Py_DECREF(it); - - return v; -} - -/* Iterate over seq. Result depends on the operation: - PY_ITERSEARCH_COUNT: -1 if error, else # of times obj appears in seq. - PY_ITERSEARCH_INDEX: 0-based index of first occurence of obj in seq; - set ValueError and return -1 if none found; also return -1 on error. - Py_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on error. -*/ -Py_ssize_t -_PySequence_IterSearch(PyObject *seq, PyObject *obj, int operation) -{ - Py_ssize_t n; - int wrapped; /* for PY_ITERSEARCH_INDEX, true iff n wrapped around */ - PyObject *it; /* iter(seq) */ - - if (seq == NULL || obj == NULL) { - null_error(); - return -1; - } - - it = PyObject_GetIter(seq); - if (it == NULL) { - type_error("argument of type '%.200s' is not iterable", seq); - return -1; - } - - n = wrapped = 0; - for (;;) { - int cmp; - PyObject *item = PyIter_Next(it); - if (item == NULL) { - if (PyErr_Occurred()) - goto Fail; - break; - } - - cmp = PyObject_RichCompareBool(obj, item, Py_EQ); - Py_DECREF(item); - if (cmp < 0) - goto Fail; - if (cmp > 0) { - switch (operation) { - case PY_ITERSEARCH_COUNT: - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "count exceeds C integer size"); - goto Fail; - } - ++n; - break; - - case PY_ITERSEARCH_INDEX: - if (wrapped) { - PyErr_SetString(PyExc_OverflowError, - "index exceeds C integer size"); - goto Fail; - } - goto Done; - - case PY_ITERSEARCH_CONTAINS: - n = 1; - goto Done; - - default: - assert(!"unknown operation"); - } - } - - if (operation == PY_ITERSEARCH_INDEX) { - if (n == PY_SSIZE_T_MAX) - wrapped = 1; - ++n; - } - } - - if (operation != PY_ITERSEARCH_INDEX) - goto Done; - - PyErr_SetString(PyExc_ValueError, - "sequence.index(x): x not in sequence"); - /* fall into failure code */ -Fail: - n = -1; - /* fall through */ -Done: - Py_DECREF(it); - return n; - -} - -/* Return # of times o appears in s. */ -Py_ssize_t -PySequence_Count(PyObject *s, PyObject *o) -{ - return _PySequence_IterSearch(s, o, PY_ITERSEARCH_COUNT); -} - -/* Return -1 if error; 1 if ob in seq; 0 if ob not in seq. - * Use sq_contains if possible, else defer to _PySequence_IterSearch(). - */ -int -PySequence_Contains(PyObject *seq, PyObject *ob) -{ - Py_ssize_t result; - if (PyType_HasFeature(seq->ob_type, Py_TPFLAGS_HAVE_SEQUENCE_IN)) { - PySequenceMethods *sqm = seq->ob_type->tp_as_sequence; - if (sqm != NULL && sqm->sq_contains != NULL) - return (*sqm->sq_contains)(seq, ob); - } - result = _PySequence_IterSearch(seq, ob, PY_ITERSEARCH_CONTAINS); - return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); -} - -/* Backwards compatibility */ -#undef PySequence_In -int -PySequence_In(PyObject *w, PyObject *v) -{ - return PySequence_Contains(w, v); -} - -Py_ssize_t -PySequence_Index(PyObject *s, PyObject *o) -{ - return _PySequence_IterSearch(s, o, PY_ITERSEARCH_INDEX); -} - -/* Operations on mappings */ - -int -PyMapping_Check(PyObject *o) -{ - if (o && PyInstance_Check(o)) - return PyObject_HasAttrString(o, "__getitem__"); - - return o && o->ob_type->tp_as_mapping && - o->ob_type->tp_as_mapping->mp_subscript && - !(o->ob_type->tp_as_sequence && - o->ob_type->tp_as_sequence->sq_slice); -} - -Py_ssize_t -PyMapping_Size(PyObject *o) -{ - PyMappingMethods *m; - - if (o == NULL) { - null_error(); - return -1; - } - - m = o->ob_type->tp_as_mapping; - if (m && m->mp_length) - return m->mp_length(o); - - type_error("object of type '%.200s' has no len()", o); - return -1; -} - -#undef PyMapping_Length -Py_ssize_t -PyMapping_Length(PyObject *o) -{ - return PyMapping_Size(o); -} -#define PyMapping_Length PyMapping_Size - -PyObject * -PyMapping_GetItemString(PyObject *o, char *key) -{ - PyObject *okey, *r; - - if (key == NULL) - return null_error(); - - okey = PyString_FromString(key); - if (okey == NULL) - return NULL; - r = PyObject_GetItem(o, okey); - Py_DECREF(okey); - return r; -} - -int -PyMapping_SetItemString(PyObject *o, char *key, PyObject *value) -{ - PyObject *okey; - int r; - - if (key == NULL) { - null_error(); - return -1; - } - - okey = PyString_FromString(key); - if (okey == NULL) - return -1; - r = PyObject_SetItem(o, okey, value); - Py_DECREF(okey); - return r; -} - -int -PyMapping_HasKeyString(PyObject *o, char *key) -{ - PyObject *v; - - v = PyMapping_GetItemString(o, key); - if (v) { - Py_DECREF(v); - return 1; - } - PyErr_Clear(); - return 0; -} - -int -PyMapping_HasKey(PyObject *o, PyObject *key) -{ - PyObject *v; - - v = PyObject_GetItem(o, key); - if (v) { - Py_DECREF(v); - return 1; - } - PyErr_Clear(); - return 0; -} - -/* Operations on callable objects */ - -/* XXX PyCallable_Check() is in object.c */ - -PyObject * -PyObject_CallObject(PyObject *o, PyObject *a) -{ - return PyEval_CallObjectWithKeywords(o, a, NULL); -} - -PyObject * -PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) -{ - ternaryfunc call; - - if ((call = func->ob_type->tp_call) != NULL) { - PyObject *result = (*call)(func, arg, kw); - if (result == NULL && !PyErr_Occurred()) - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - return result; - } - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - func->ob_type->tp_name); - return NULL; -} - -static PyObject* -call_function_tail(PyObject *callable, PyObject *args) -{ - PyObject *retval; - - if (args == NULL) - return NULL; - - if (!PyTuple_Check(args)) { - PyObject *a; - - a = PyTuple_New(1); - if (a == NULL) { - Py_DECREF(args); - return NULL; - } - PyTuple_SET_ITEM(a, 0, args); - args = a; - } - retval = PyObject_Call(callable, args, NULL); - - Py_DECREF(args); - - return retval; -} - -PyObject * -PyObject_CallFunction(PyObject *callable, char *format, ...) -{ - va_list va; - PyObject *args; - - if (callable == NULL) - return null_error(); - - if (format && *format) { - va_start(va, format); - args = Py_VaBuildValue(format, va); - va_end(va); - } - else - args = PyTuple_New(0); - - return call_function_tail(callable, args); -} - -PyObject * -_PyObject_CallFunction_SizeT(PyObject *callable, char *format, ...) -{ - va_list va; - PyObject *args; - - if (callable == NULL) - return null_error(); - - if (format && *format) { - va_start(va, format); - args = _Py_VaBuildValue_SizeT(format, va); - va_end(va); - } - else - args = PyTuple_New(0); - - return call_function_tail(callable, args); -} - -PyObject * -PyObject_CallMethod(PyObject *o, char *name, char *format, ...) -{ - va_list va; - PyObject *args; - PyObject *func = NULL; - PyObject *retval = NULL; - - if (o == NULL || name == NULL) - return null_error(); - - func = PyObject_GetAttrString(o, name); - if (func == NULL) { - PyErr_SetString(PyExc_AttributeError, name); - return 0; - } - - if (!PyCallable_Check(func)) { - type_error("attribute of type '%.200s' is not callable", func); - goto exit; - } - - if (format && *format) { - va_start(va, format); - args = Py_VaBuildValue(format, va); - va_end(va); - } - else - args = PyTuple_New(0); - - retval = call_function_tail(func, args); - - exit: - /* args gets consumed in call_function_tail */ - Py_XDECREF(func); - - return retval; -} - -PyObject * -_PyObject_CallMethod_SizeT(PyObject *o, char *name, char *format, ...) -{ - va_list va; - PyObject *args; - PyObject *func = NULL; - PyObject *retval = NULL; - - if (o == NULL || name == NULL) - return null_error(); - - func = PyObject_GetAttrString(o, name); - if (func == NULL) { - PyErr_SetString(PyExc_AttributeError, name); - return 0; - } - - if (!PyCallable_Check(func)) { - type_error("attribute of type '%.200s' is not callable", func); - goto exit; - } - - if (format && *format) { - va_start(va, format); - args = _Py_VaBuildValue_SizeT(format, va); - va_end(va); - } - else - args = PyTuple_New(0); - - retval = call_function_tail(func, args); - - exit: - /* args gets consumed in call_function_tail */ - Py_XDECREF(func); - - return retval; -} - - -static PyObject * -objargs_mktuple(va_list va) -{ - int i, n = 0; - va_list countva; - PyObject *result, *tmp; - -#ifdef VA_LIST_IS_ARRAY - memcpy(countva, va, sizeof(va_list)); -#else -#ifdef __va_copy - __va_copy(countva, va); -#else - countva = va; -#endif -#endif - - while (((PyObject *)va_arg(countva, PyObject *)) != NULL) - ++n; - result = PyTuple_New(n); - if (result != NULL && n > 0) { - for (i = 0; i < n; ++i) { - tmp = (PyObject *)va_arg(va, PyObject *); - PyTuple_SET_ITEM(result, i, tmp); - Py_INCREF(tmp); - } - } - return result; -} - -PyObject * -PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) -{ - PyObject *args, *tmp; - va_list vargs; - - if (callable == NULL || name == NULL) - return null_error(); - - callable = PyObject_GetAttr(callable, name); - if (callable == NULL) - return NULL; - - /* count the args */ - va_start(vargs, name); - args = objargs_mktuple(vargs); - va_end(vargs); - if (args == NULL) { - Py_DECREF(callable); - return NULL; - } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - Py_DECREF(callable); - - return tmp; -} - -PyObject * -PyObject_CallFunctionObjArgs(PyObject *callable, ...) -{ - PyObject *args, *tmp; - va_list vargs; - - if (callable == NULL) - return null_error(); - - /* count the args */ - va_start(vargs, callable); - args = objargs_mktuple(vargs); - va_end(vargs); - if (args == NULL) - return NULL; - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - - return tmp; -} - - -/* isinstance(), issubclass() */ - -/* abstract_get_bases() has logically 4 return states, with a sort of 0th - * state that will almost never happen. - * - * 0. creating the __bases__ static string could get a MemoryError - * 1. getattr(cls, '__bases__') could raise an AttributeError - * 2. getattr(cls, '__bases__') could raise some other exception - * 3. getattr(cls, '__bases__') could return a tuple - * 4. getattr(cls, '__bases__') could return something other than a tuple - * - * Only state #3 is a non-error state and only it returns a non-NULL object - * (it returns the retrieved tuple). - * - * Any raised AttributeErrors are masked by clearing the exception and - * returning NULL. If an object other than a tuple comes out of __bases__, - * then again, the return value is NULL. So yes, these two situations - * produce exactly the same results: NULL is returned and no error is set. - * - * If some exception other than AttributeError is raised, then NULL is also - * returned, but the exception is not cleared. That's because we want the - * exception to be propagated along. - * - * Callers are expected to test for PyErr_Occurred() when the return value - * is NULL to decide whether a valid exception should be propagated or not. - * When there's no exception to propagate, it's customary for the caller to - * set a TypeError. - */ -static PyObject * -abstract_get_bases(PyObject *cls) -{ - static PyObject *__bases__ = NULL; - PyObject *bases; - - if (__bases__ == NULL) { - __bases__ = PyString_FromString("__bases__"); - if (__bases__ == NULL) - return NULL; - } - bases = PyObject_GetAttr(cls, __bases__); - if (bases == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) - PyErr_Clear(); - return NULL; - } - if (!PyTuple_Check(bases)) { - Py_DECREF(bases); - return NULL; - } - return bases; -} - - -static int -abstract_issubclass(PyObject *derived, PyObject *cls) -{ - PyObject *bases; - Py_ssize_t i, n; - int r = 0; - - - if (derived == cls) - return 1; - - if (PyTuple_Check(cls)) { - /* Not a general sequence -- that opens up the road to - recursion and stack overflow. */ - n = PyTuple_GET_SIZE(cls); - for (i = 0; i < n; i++) { - if (derived == PyTuple_GET_ITEM(cls, i)) - return 1; - } - } - bases = abstract_get_bases(derived); - if (bases == NULL) { - if (PyErr_Occurred()) - return -1; - return 0; - } - n = PyTuple_GET_SIZE(bases); - for (i = 0; i < n; i++) { - r = abstract_issubclass(PyTuple_GET_ITEM(bases, i), cls); - if (r != 0) - break; - } - - Py_DECREF(bases); - - return r; -} - -static int -check_class(PyObject *cls, const char *error) -{ - PyObject *bases = abstract_get_bases(cls); - if (bases == NULL) { - /* Do not mask errors. */ - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, error); - return 0; - } - Py_DECREF(bases); - return -1; -} - -static int -recursive_isinstance(PyObject *inst, PyObject *cls, int recursion_depth) -{ - PyObject *icls; - static PyObject *__class__ = NULL; - int retval = 0; - - if (__class__ == NULL) { - __class__ = PyString_FromString("__class__"); - if (__class__ == NULL) - return -1; - } - - if (PyClass_Check(cls) && PyInstance_Check(inst)) { - PyObject *inclass = - (PyObject*)((PyInstanceObject*)inst)->in_class; - retval = PyClass_IsSubclass(inclass, cls); - } - else if (PyType_Check(cls)) { - retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); - if (retval == 0) { - PyObject *c = PyObject_GetAttr(inst, __class__); - if (c == NULL) { - PyErr_Clear(); - } - else { - if (c != (PyObject *)(inst->ob_type) && - PyType_Check(c)) - retval = PyType_IsSubtype( - (PyTypeObject *)c, - (PyTypeObject *)cls); - Py_DECREF(c); - } - } - } - else if (PyTuple_Check(cls)) { - Py_ssize_t i, n; - - if (!recursion_depth) { - PyErr_SetString(PyExc_RuntimeError, - "nest level of tuple too deep"); - return -1; - } - - n = PyTuple_GET_SIZE(cls); - for (i = 0; i < n; i++) { - retval = recursive_isinstance( - inst, - PyTuple_GET_ITEM(cls, i), - recursion_depth-1); - if (retval != 0) - break; - } - } - else { - if (!check_class(cls, - "isinstance() arg 2 must be a class, type," - " or tuple of classes and types")) - return -1; - icls = PyObject_GetAttr(inst, __class__); - if (icls == NULL) { - PyErr_Clear(); - retval = 0; - } - else { - retval = abstract_issubclass(icls, cls); - Py_DECREF(icls); - } - } - - return retval; -} - -int -PyObject_IsInstance(PyObject *inst, PyObject *cls) -{ - return recursive_isinstance(inst, cls, Py_GetRecursionLimit()); -} - -static int -recursive_issubclass(PyObject *derived, PyObject *cls, int recursion_depth) -{ - int retval; - - if (!PyClass_Check(derived) || !PyClass_Check(cls)) { - if (!check_class(derived, - "issubclass() arg 1 must be a class")) - return -1; - - if (PyTuple_Check(cls)) { - Py_ssize_t i; - Py_ssize_t n = PyTuple_GET_SIZE(cls); - - if (!recursion_depth) { - PyErr_SetString(PyExc_RuntimeError, - "nest level of tuple too deep"); - return -1; - } - for (i = 0; i < n; ++i) { - retval = recursive_issubclass( - derived, - PyTuple_GET_ITEM(cls, i), - recursion_depth-1); - if (retval != 0) { - /* either found it, or got an error */ - return retval; - } - } - return 0; - } - else { - if (!check_class(cls, - "issubclass() arg 2 must be a class" - " or tuple of classes")) - return -1; - } - - retval = abstract_issubclass(derived, cls); - } - else { - /* shortcut */ - if (!(retval = (derived == cls))) - retval = PyClass_IsSubclass(derived, cls); - } - - return retval; -} - -int -PyObject_IsSubclass(PyObject *derived, PyObject *cls) -{ - return recursive_issubclass(derived, cls, Py_GetRecursionLimit()); -} - - -PyObject * -PyObject_GetIter(PyObject *o) -{ - PyTypeObject *t = o->ob_type; - getiterfunc f = NULL; - if (PyType_HasFeature(t, Py_TPFLAGS_HAVE_ITER)) - f = t->tp_iter; - if (f == NULL) { - if (PySequence_Check(o)) - return PySeqIter_New(o); - return type_error("'%.200s' object is not iterable", o); - } - else { - PyObject *res = (*f)(o); - if (res != NULL && !PyIter_Check(res)) { - PyErr_Format(PyExc_TypeError, - "iter() returned non-iterator " - "of type '%.100s'", - res->ob_type->tp_name); - Py_DECREF(res); - res = NULL; - } - return res; - } -} - -/* Return next item. - * If an error occurs, return NULL. PyErr_Occurred() will be true. - * If the iteration terminates normally, return NULL and clear the - * PyExc_StopIteration exception (if it was set). PyErr_Occurred() - * will be false. - * Else return the next object. PyErr_Occurred() will be false. - */ -PyObject * -PyIter_Next(PyObject *iter) -{ - PyObject *result; - assert(PyIter_Check(iter)); - result = (*iter->ob_type->tp_iternext)(iter); - if (result == NULL && - PyErr_Occurred() && - PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); - return result; -} diff --git a/sys/src/cmd/python/Objects/boolobject.c b/sys/src/cmd/python/Objects/boolobject.c deleted file mode 100644 index 37be295ac..000000000 --- a/sys/src/cmd/python/Objects/boolobject.c +++ /dev/null @@ -1,201 +0,0 @@ -/* Boolean type, a subtype of int */ - -#include "Python.h" - -/* We need to define bool_print to override int_print */ - -static int -bool_print(PyBoolObject *self, FILE *fp, int flags) -{ - fputs(self->ob_ival == 0 ? "False" : "True", fp); - return 0; -} - -/* We define bool_repr to return "False" or "True" */ - -static PyObject *false_str = NULL; -static PyObject *true_str = NULL; - -static PyObject * -bool_repr(PyBoolObject *self) -{ - PyObject *s; - - if (self->ob_ival) - s = true_str ? true_str : - (true_str = PyString_InternFromString("True")); - else - s = false_str ? false_str : - (false_str = PyString_InternFromString("False")); - Py_XINCREF(s); - return s; -} - -/* Function to return a bool from a C long */ - -PyObject *PyBool_FromLong(long ok) -{ - PyObject *result; - - if (ok) - result = Py_True; - else - result = Py_False; - Py_INCREF(result); - return result; -} - -/* We define bool_new to always return either Py_True or Py_False */ - -static PyObject * -bool_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"x", 0}; - PyObject *x = Py_False; - long ok; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:bool", kwlist, &x)) - return NULL; - ok = PyObject_IsTrue(x); - if (ok < 0) - return NULL; - return PyBool_FromLong(ok); -} - -/* Arithmetic operations redefined to return bool if both args are bool. */ - -static PyObject * -bool_and(PyObject *a, PyObject *b) -{ - if (!PyBool_Check(a) || !PyBool_Check(b)) - return PyInt_Type.tp_as_number->nb_and(a, b); - return PyBool_FromLong( - ((PyBoolObject *)a)->ob_ival & ((PyBoolObject *)b)->ob_ival); -} - -static PyObject * -bool_or(PyObject *a, PyObject *b) -{ - if (!PyBool_Check(a) || !PyBool_Check(b)) - return PyInt_Type.tp_as_number->nb_or(a, b); - return PyBool_FromLong( - ((PyBoolObject *)a)->ob_ival | ((PyBoolObject *)b)->ob_ival); -} - -static PyObject * -bool_xor(PyObject *a, PyObject *b) -{ - if (!PyBool_Check(a) || !PyBool_Check(b)) - return PyInt_Type.tp_as_number->nb_xor(a, b); - return PyBool_FromLong( - ((PyBoolObject *)a)->ob_ival ^ ((PyBoolObject *)b)->ob_ival); -} - -/* Doc string */ - -PyDoc_STRVAR(bool_doc, -"bool(x) -> bool\n\ -\n\ -Returns True when the argument x is true, False otherwise.\n\ -The builtins True and False are the only two instances of the class bool.\n\ -The class bool is a subclass of the class int, and cannot be subclassed."); - -/* Arithmetic methods -- only so we can override &, |, ^. */ - -static PyNumberMethods bool_as_number = { - 0, /* nb_add */ - 0, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_divide */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - 0, /* nb_nonzero */ - 0, /* nb_invert */ - 0, /* nb_lshift */ - 0, /* nb_rshift */ - bool_and, /* nb_and */ - bool_xor, /* nb_xor */ - bool_or, /* nb_or */ - 0, /* nb_coerce */ - 0, /* nb_int */ - 0, /* nb_long */ - 0, /* nb_float */ - 0, /* nb_oct */ - 0, /* nb_hex */ - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ - 0, /* nb_inplace_divide */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - 0, /* nb_floor_divide */ - 0, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ -}; - -/* The type object for bool. Note that this cannot be subclassed! */ - -PyTypeObject PyBool_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "bool", - sizeof(PyIntObject), - 0, - 0, /* tp_dealloc */ - (printfunc)bool_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)bool_repr, /* tp_repr */ - &bool_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)bool_repr, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ - bool_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &PyInt_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - bool_new, /* tp_new */ -}; - -/* The objects representing bool values False and True */ - -/* Named Zero for link-level compatibility */ -PyIntObject _Py_ZeroStruct = { - PyObject_HEAD_INIT(&PyBool_Type) - 0 -}; - -PyIntObject _Py_TrueStruct = { - PyObject_HEAD_INIT(&PyBool_Type) - 1 -}; diff --git a/sys/src/cmd/python/Objects/bufferobject.c b/sys/src/cmd/python/Objects/bufferobject.c deleted file mode 100644 index 5f3c7a9ee..000000000 --- a/sys/src/cmd/python/Objects/bufferobject.c +++ /dev/null @@ -1,706 +0,0 @@ - -/* Buffer object implementation */ - -#include "Python.h" - - -typedef struct { - PyObject_HEAD - PyObject *b_base; - void *b_ptr; - Py_ssize_t b_size; - Py_ssize_t b_offset; - int b_readonly; - long b_hash; -} PyBufferObject; - - -enum buffer_t { - READ_BUFFER, - WRITE_BUFFER, - CHAR_BUFFER, - ANY_BUFFER, -}; - -static int -get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size, - enum buffer_t buffer_type) -{ - if (self->b_base == NULL) { - assert (ptr != NULL); - *ptr = self->b_ptr; - *size = self->b_size; - } - else { - Py_ssize_t count, offset; - readbufferproc proc = 0; - PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer; - if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) { - PyErr_SetString(PyExc_TypeError, - "single-segment buffer object expected"); - return 0; - } - if ((buffer_type == READ_BUFFER) || - ((buffer_type == ANY_BUFFER) && self->b_readonly)) - proc = bp->bf_getreadbuffer; - else if ((buffer_type == WRITE_BUFFER) || - (buffer_type == ANY_BUFFER)) - proc = (readbufferproc)bp->bf_getwritebuffer; - else if (buffer_type == CHAR_BUFFER) { - if (!PyType_HasFeature(self->ob_type, - Py_TPFLAGS_HAVE_GETCHARBUFFER)) { - PyErr_SetString(PyExc_TypeError, - "Py_TPFLAGS_HAVE_GETCHARBUFFER needed"); - return 0; - } - proc = (readbufferproc)bp->bf_getcharbuffer; - } - if (!proc) { - char *buffer_type_name; - switch (buffer_type) { - case READ_BUFFER: - buffer_type_name = "read"; - break; - case WRITE_BUFFER: - buffer_type_name = "write"; - break; - case CHAR_BUFFER: - buffer_type_name = "char"; - break; - default: - buffer_type_name = "no"; - break; - } - PyErr_Format(PyExc_TypeError, - "%s buffer type not available", - buffer_type_name); - return 0; - } - if ((count = (*proc)(self->b_base, 0, ptr)) < 0) - return 0; - /* apply constraints to the start/end */ - if (self->b_offset > count) - offset = count; - else - offset = self->b_offset; - *(char **)ptr = *(char **)ptr + offset; - if (self->b_size == Py_END_OF_BUFFER) - *size = count; - else - *size = self->b_size; - if (offset + *size > count) - *size = count - offset; - } - return 1; -} - - -static PyObject * -buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr, - int readonly) -{ - PyBufferObject * b; - - if (size < 0 && size != Py_END_OF_BUFFER) { - PyErr_SetString(PyExc_ValueError, - "size must be zero or positive"); - return NULL; - } - if (offset < 0) { - PyErr_SetString(PyExc_ValueError, - "offset must be zero or positive"); - return NULL; - } - - b = PyObject_NEW(PyBufferObject, &PyBuffer_Type); - if ( b == NULL ) - return NULL; - - Py_XINCREF(base); - b->b_base = base; - b->b_ptr = ptr; - b->b_size = size; - b->b_offset = offset; - b->b_readonly = readonly; - b->b_hash = -1; - - return (PyObject *) b; -} - -static PyObject * -buffer_from_object(PyObject *base, Py_ssize_t size, Py_ssize_t offset, int readonly) -{ - if (offset < 0) { - PyErr_SetString(PyExc_ValueError, - "offset must be zero or positive"); - return NULL; - } - if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) { - /* another buffer, refer to the base object */ - PyBufferObject *b = (PyBufferObject *)base; - if (b->b_size != Py_END_OF_BUFFER) { - Py_ssize_t base_size = b->b_size - offset; - if (base_size < 0) - base_size = 0; - if (size == Py_END_OF_BUFFER || size > base_size) - size = base_size; - } - offset += b->b_offset; - base = b->b_base; - } - return buffer_from_memory(base, size, offset, NULL, readonly); -} - - -PyObject * -PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size) -{ - PyBufferProcs *pb = base->ob_type->tp_as_buffer; - - if ( pb == NULL || - pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL ) - { - PyErr_SetString(PyExc_TypeError, "buffer object expected"); - return NULL; - } - - return buffer_from_object(base, size, offset, 1); -} - -PyObject * -PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size) -{ - PyBufferProcs *pb = base->ob_type->tp_as_buffer; - - if ( pb == NULL || - pb->bf_getwritebuffer == NULL || - pb->bf_getsegcount == NULL ) - { - PyErr_SetString(PyExc_TypeError, "buffer object expected"); - return NULL; - } - - return buffer_from_object(base, size, offset, 0); -} - -PyObject * -PyBuffer_FromMemory(void *ptr, Py_ssize_t size) -{ - return buffer_from_memory(NULL, size, 0, ptr, 1); -} - -PyObject * -PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size) -{ - return buffer_from_memory(NULL, size, 0, ptr, 0); -} - -PyObject * -PyBuffer_New(Py_ssize_t size) -{ - PyObject *o; - PyBufferObject * b; - - if (size < 0) { - PyErr_SetString(PyExc_ValueError, - "size must be zero or positive"); - return NULL; - } - /* XXX: check for overflow in multiply */ - /* Inline PyObject_New */ - o = (PyObject *)PyObject_MALLOC(sizeof(*b) + size); - if ( o == NULL ) - return PyErr_NoMemory(); - b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type); - - b->b_base = NULL; - b->b_ptr = (void *)(b + 1); - b->b_size = size; - b->b_offset = 0; - b->b_readonly = 0; - b->b_hash = -1; - - return o; -} - -/* Methods */ - -static PyObject * -buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw) -{ - PyObject *ob; - Py_ssize_t offset = 0; - Py_ssize_t size = Py_END_OF_BUFFER; - - if (!_PyArg_NoKeywords("buffer()", kw)) - return NULL; - - if (!PyArg_ParseTuple(args, "O|nn:buffer", &ob, &offset, &size)) - return NULL; - return PyBuffer_FromObject(ob, offset, size); -} - -PyDoc_STRVAR(buffer_doc, -"buffer(object [, offset[, size]])\n\ -\n\ -Create a new buffer object which references the given object.\n\ -The buffer will reference a slice of the target object from the\n\ -start of the object (or at the specified offset). The slice will\n\ -extend to the end of the target object (or with the specified size)."); - - -static void -buffer_dealloc(PyBufferObject *self) -{ - Py_XDECREF(self->b_base); - PyObject_DEL(self); -} - -static int -buffer_compare(PyBufferObject *self, PyBufferObject *other) -{ - void *p1, *p2; - Py_ssize_t len_self, len_other, min_len; - int cmp; - - if (!get_buf(self, &p1, &len_self, ANY_BUFFER)) - return -1; - if (!get_buf(other, &p2, &len_other, ANY_BUFFER)) - return -1; - min_len = (len_self < len_other) ? len_self : len_other; - if (min_len > 0) { - cmp = memcmp(p1, p2, min_len); - if (cmp != 0) - return cmp < 0 ? -1 : 1; - } - return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0; -} - -static PyObject * -buffer_repr(PyBufferObject *self) -{ - const char *status = self->b_readonly ? "read-only" : "read-write"; - - if ( self->b_base == NULL ) - return PyString_FromFormat("<%s buffer ptr %p, size %zd at %p>", - status, - self->b_ptr, - self->b_size, - self); - else - return PyString_FromFormat( - "<%s buffer for %p, size %zd, offset %zd at %p>", - status, - self->b_base, - self->b_size, - self->b_offset, - self); -} - -static long -buffer_hash(PyBufferObject *self) -{ - void *ptr; - Py_ssize_t size; - register Py_ssize_t len; - register unsigned char *p; - register long x; - - if ( self->b_hash != -1 ) - return self->b_hash; - - /* XXX potential bugs here, a readonly buffer does not imply that the - * underlying memory is immutable. b_readonly is a necessary but not - * sufficient condition for a buffer to be hashable. Perhaps it would - * be better to only allow hashing if the underlying object is known to - * be immutable (e.g. PyString_Check() is true). Another idea would - * be to call tp_hash on the underlying object and see if it raises - * an error. */ - if ( !self->b_readonly ) - { - PyErr_SetString(PyExc_TypeError, - "writable buffers are not hashable"); - return -1; - } - - if (!get_buf(self, &ptr, &size, ANY_BUFFER)) - return -1; - p = (unsigned char *) ptr; - len = size; - x = *p << 7; - while (--len >= 0) - x = (1000003*x) ^ *p++; - x ^= size; - if (x == -1) - x = -2; - self->b_hash = x; - return x; -} - -static PyObject * -buffer_str(PyBufferObject *self) -{ - void *ptr; - Py_ssize_t size; - if (!get_buf(self, &ptr, &size, ANY_BUFFER)) - return NULL; - return PyString_FromStringAndSize((const char *)ptr, size); -} - -/* Sequence methods */ - -static Py_ssize_t -buffer_length(PyBufferObject *self) -{ - void *ptr; - Py_ssize_t size; - if (!get_buf(self, &ptr, &size, ANY_BUFFER)) - return -1; - return size; -} - -static PyObject * -buffer_concat(PyBufferObject *self, PyObject *other) -{ - PyBufferProcs *pb = other->ob_type->tp_as_buffer; - void *ptr1, *ptr2; - char *p; - PyObject *ob; - Py_ssize_t size, count; - - if ( pb == NULL || - pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL ) - { - PyErr_BadArgument(); - return NULL; - } - if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) - { - /* ### use a different exception type/message? */ - PyErr_SetString(PyExc_TypeError, - "single-segment buffer object expected"); - return NULL; - } - - if (!get_buf(self, &ptr1, &size, ANY_BUFFER)) - return NULL; - - /* optimize special case */ - if ( size == 0 ) - { - Py_INCREF(other); - return other; - } - - if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 ) - return NULL; - - ob = PyString_FromStringAndSize(NULL, size + count); - if ( ob == NULL ) - return NULL; - p = PyString_AS_STRING(ob); - memcpy(p, ptr1, size); - memcpy(p + size, ptr2, count); - - /* there is an extra byte in the string object, so this is safe */ - p[size + count] = '\0'; - - return ob; -} - -static PyObject * -buffer_repeat(PyBufferObject *self, Py_ssize_t count) -{ - PyObject *ob; - register char *p; - void *ptr; - Py_ssize_t size; - - if ( count < 0 ) - count = 0; - if (!get_buf(self, &ptr, &size, ANY_BUFFER)) - return NULL; - ob = PyString_FromStringAndSize(NULL, size * count); - if ( ob == NULL ) - return NULL; - - p = PyString_AS_STRING(ob); - while ( count-- ) - { - memcpy(p, ptr, size); - p += size; - } - - /* there is an extra byte in the string object, so this is safe */ - *p = '\0'; - - return ob; -} - -static PyObject * -buffer_item(PyBufferObject *self, Py_ssize_t idx) -{ - void *ptr; - Py_ssize_t size; - if (!get_buf(self, &ptr, &size, ANY_BUFFER)) - return NULL; - if ( idx < 0 || idx >= size ) { - PyErr_SetString(PyExc_IndexError, "buffer index out of range"); - return NULL; - } - return PyString_FromStringAndSize((char *)ptr + idx, 1); -} - -static PyObject * -buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right) -{ - void *ptr; - Py_ssize_t size; - if (!get_buf(self, &ptr, &size, ANY_BUFFER)) - return NULL; - if ( left < 0 ) - left = 0; - if ( right < 0 ) - right = 0; - if ( right > size ) - right = size; - if ( right < left ) - right = left; - return PyString_FromStringAndSize((char *)ptr + left, - right - left); -} - -static int -buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other) -{ - PyBufferProcs *pb; - void *ptr1, *ptr2; - Py_ssize_t size; - Py_ssize_t count; - - if ( self->b_readonly ) { - PyErr_SetString(PyExc_TypeError, - "buffer is read-only"); - return -1; - } - - if (!get_buf(self, &ptr1, &size, ANY_BUFFER)) - return -1; - - if (idx < 0 || idx >= size) { - PyErr_SetString(PyExc_IndexError, - "buffer assignment index out of range"); - return -1; - } - - pb = other ? other->ob_type->tp_as_buffer : NULL; - if ( pb == NULL || - pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL ) - { - PyErr_BadArgument(); - return -1; - } - if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) - { - /* ### use a different exception type/message? */ - PyErr_SetString(PyExc_TypeError, - "single-segment buffer object expected"); - return -1; - } - - if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 ) - return -1; - if ( count != 1 ) { - PyErr_SetString(PyExc_TypeError, - "right operand must be a single byte"); - return -1; - } - - ((char *)ptr1)[idx] = *(char *)ptr2; - return 0; -} - -static int -buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other) -{ - PyBufferProcs *pb; - void *ptr1, *ptr2; - Py_ssize_t size; - Py_ssize_t slice_len; - Py_ssize_t count; - - if ( self->b_readonly ) { - PyErr_SetString(PyExc_TypeError, - "buffer is read-only"); - return -1; - } - - pb = other ? other->ob_type->tp_as_buffer : NULL; - if ( pb == NULL || - pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL ) - { - PyErr_BadArgument(); - return -1; - } - if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) - { - /* ### use a different exception type/message? */ - PyErr_SetString(PyExc_TypeError, - "single-segment buffer object expected"); - return -1; - } - if (!get_buf(self, &ptr1, &size, ANY_BUFFER)) - return -1; - if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 ) - return -1; - - if ( left < 0 ) - left = 0; - else if ( left > size ) - left = size; - if ( right < left ) - right = left; - else if ( right > size ) - right = size; - slice_len = right - left; - - if ( count != slice_len ) { - PyErr_SetString( - PyExc_TypeError, - "right operand length must match slice length"); - return -1; - } - - if ( slice_len ) - memcpy((char *)ptr1 + left, ptr2, slice_len); - - return 0; -} - -/* Buffer methods */ - -static Py_ssize_t -buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp) -{ - Py_ssize_t size; - if ( idx != 0 ) { - PyErr_SetString(PyExc_SystemError, - "accessing non-existent buffer segment"); - return -1; - } - if (!get_buf(self, pp, &size, READ_BUFFER)) - return -1; - return size; -} - -static Py_ssize_t -buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp) -{ - Py_ssize_t size; - - if ( self->b_readonly ) - { - PyErr_SetString(PyExc_TypeError, "buffer is read-only"); - return -1; - } - - if ( idx != 0 ) { - PyErr_SetString(PyExc_SystemError, - "accessing non-existent buffer segment"); - return -1; - } - if (!get_buf(self, pp, &size, WRITE_BUFFER)) - return -1; - return size; -} - -static Py_ssize_t -buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp) -{ - void *ptr; - Py_ssize_t size; - if (!get_buf(self, &ptr, &size, ANY_BUFFER)) - return -1; - if (lenp) - *lenp = size; - return 1; -} - -static Py_ssize_t -buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp) -{ - void *ptr; - Py_ssize_t size; - if ( idx != 0 ) { - PyErr_SetString(PyExc_SystemError, - "accessing non-existent buffer segment"); - return -1; - } - if (!get_buf(self, &ptr, &size, CHAR_BUFFER)) - return -1; - *pp = (const char *)ptr; - return size; -} - -static PySequenceMethods buffer_as_sequence = { - (lenfunc)buffer_length, /*sq_length*/ - (binaryfunc)buffer_concat, /*sq_concat*/ - (ssizeargfunc)buffer_repeat, /*sq_repeat*/ - (ssizeargfunc)buffer_item, /*sq_item*/ - (ssizessizeargfunc)buffer_slice, /*sq_slice*/ - (ssizeobjargproc)buffer_ass_item, /*sq_ass_item*/ - (ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/ -}; - -static PyBufferProcs buffer_as_buffer = { - (readbufferproc)buffer_getreadbuf, - (writebufferproc)buffer_getwritebuf, - (segcountproc)buffer_getsegcount, - (charbufferproc)buffer_getcharbuf, -}; - -PyTypeObject PyBuffer_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "buffer", - sizeof(PyBufferObject), - 0, - (destructor)buffer_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)buffer_compare, /* tp_compare */ - (reprfunc)buffer_repr, /* tp_repr */ - 0, /* tp_as_number */ - &buffer_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)buffer_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)buffer_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - &buffer_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /* tp_flags */ - buffer_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - buffer_new, /* tp_new */ -}; diff --git a/sys/src/cmd/python/Objects/cellobject.c b/sys/src/cmd/python/Objects/cellobject.c deleted file mode 100644 index 65a29aaca..000000000 --- a/sys/src/cmd/python/Objects/cellobject.c +++ /dev/null @@ -1,133 +0,0 @@ -/* Cell object implementation */ - -#include "Python.h" - -PyObject * -PyCell_New(PyObject *obj) -{ - PyCellObject *op; - - op = (PyCellObject *)PyObject_GC_New(PyCellObject, &PyCell_Type); - if (op == NULL) - return NULL; - op->ob_ref = obj; - Py_XINCREF(obj); - - _PyObject_GC_TRACK(op); - return (PyObject *)op; -} - -PyObject * -PyCell_Get(PyObject *op) -{ - if (!PyCell_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - Py_XINCREF(((PyCellObject*)op)->ob_ref); - return PyCell_GET(op); -} - -int -PyCell_Set(PyObject *op, PyObject *obj) -{ - if (!PyCell_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - Py_XDECREF(((PyCellObject*)op)->ob_ref); - Py_XINCREF(obj); - PyCell_SET(op, obj); - return 0; -} - -static void -cell_dealloc(PyCellObject *op) -{ - _PyObject_GC_UNTRACK(op); - Py_XDECREF(op->ob_ref); - PyObject_GC_Del(op); -} - -static int -cell_compare(PyCellObject *a, PyCellObject *b) -{ - if (a->ob_ref == NULL) { - if (b->ob_ref == NULL) - return 0; - return -1; - } else if (b->ob_ref == NULL) - return 1; - return PyObject_Compare(a->ob_ref, b->ob_ref); -} - -static PyObject * -cell_repr(PyCellObject *op) -{ - if (op->ob_ref == NULL) - return PyString_FromFormat("<cell at %p: empty>", op); - - return PyString_FromFormat("<cell at %p: %.80s object at %p>", - op, op->ob_ref->ob_type->tp_name, - op->ob_ref); -} - -static int -cell_traverse(PyCellObject *op, visitproc visit, void *arg) -{ - Py_VISIT(op->ob_ref); - return 0; -} - -static int -cell_clear(PyCellObject *op) -{ - Py_CLEAR(op->ob_ref); - return 0; -} - -static PyObject * -cell_get_contents(PyCellObject *op, void *closure) -{ - Py_XINCREF(op->ob_ref); - return op->ob_ref; -} - -static PyGetSetDef cell_getsetlist[] = { - {"cell_contents", (getter)cell_get_contents, NULL}, - {NULL} /* sentinel */ -}; - -PyTypeObject PyCell_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "cell", - sizeof(PyCellObject), - 0, - (destructor)cell_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)cell_compare, /* tp_compare */ - (reprfunc)cell_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)cell_traverse, /* tp_traverse */ - (inquiry)cell_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - cell_getsetlist, /* tp_getset */ -}; diff --git a/sys/src/cmd/python/Objects/classobject.c b/sys/src/cmd/python/Objects/classobject.c deleted file mode 100644 index 8560b6842..000000000 --- a/sys/src/cmd/python/Objects/classobject.c +++ /dev/null @@ -1,2580 +0,0 @@ - -/* Class object implementation */ - -#include "Python.h" -#include "structmember.h" - -#define TP_DESCR_GET(t) \ - (PyType_HasFeature(t, Py_TPFLAGS_HAVE_CLASS) ? (t)->tp_descr_get : NULL) - - -/* Forward */ -static PyObject *class_lookup(PyClassObject *, PyObject *, - PyClassObject **); -static PyObject *instance_getattr1(PyInstanceObject *, PyObject *); -static PyObject *instance_getattr2(PyInstanceObject *, PyObject *); - -static PyObject *getattrstr, *setattrstr, *delattrstr; - - -PyObject * -PyClass_New(PyObject *bases, PyObject *dict, PyObject *name) - /* bases is NULL or tuple of classobjects! */ -{ - PyClassObject *op, *dummy; - static PyObject *docstr, *modstr, *namestr; - if (docstr == NULL) { - docstr= PyString_InternFromString("__doc__"); - if (docstr == NULL) - return NULL; - } - if (modstr == NULL) { - modstr= PyString_InternFromString("__module__"); - if (modstr == NULL) - return NULL; - } - if (namestr == NULL) { - namestr= PyString_InternFromString("__name__"); - if (namestr == NULL) - return NULL; - } - if (name == NULL || !PyString_Check(name)) { - PyErr_SetString(PyExc_TypeError, - "PyClass_New: name must be a string"); - return NULL; - } - if (dict == NULL || !PyDict_Check(dict)) { - PyErr_SetString(PyExc_TypeError, - "PyClass_New: dict must be a dictionary"); - return NULL; - } - if (PyDict_GetItem(dict, docstr) == NULL) { - if (PyDict_SetItem(dict, docstr, Py_None) < 0) - return NULL; - } - if (PyDict_GetItem(dict, modstr) == NULL) { - PyObject *globals = PyEval_GetGlobals(); - if (globals != NULL) { - PyObject *modname = PyDict_GetItem(globals, namestr); - if (modname != NULL) { - if (PyDict_SetItem(dict, modstr, modname) < 0) - return NULL; - } - } - } - if (bases == NULL) { - bases = PyTuple_New(0); - if (bases == NULL) - return NULL; - } - else { - Py_ssize_t i, n; - PyObject *base; - if (!PyTuple_Check(bases)) { - PyErr_SetString(PyExc_TypeError, - "PyClass_New: bases must be a tuple"); - return NULL; - } - n = PyTuple_Size(bases); - for (i = 0; i < n; i++) { - base = PyTuple_GET_ITEM(bases, i); - if (!PyClass_Check(base)) { - if (PyCallable_Check( - (PyObject *) base->ob_type)) - return PyObject_CallFunctionObjArgs( - (PyObject *) base->ob_type, - name, bases, dict, NULL); - PyErr_SetString(PyExc_TypeError, - "PyClass_New: base must be a class"); - return NULL; - } - } - Py_INCREF(bases); - } - - if (getattrstr == NULL) { - getattrstr = PyString_InternFromString("__getattr__"); - if (getattrstr == NULL) - goto alloc_error; - setattrstr = PyString_InternFromString("__setattr__"); - if (setattrstr == NULL) - goto alloc_error; - delattrstr = PyString_InternFromString("__delattr__"); - if (delattrstr == NULL) - goto alloc_error; - } - - op = PyObject_GC_New(PyClassObject, &PyClass_Type); - if (op == NULL) { -alloc_error: - Py_DECREF(bases); - return NULL; - } - op->cl_bases = bases; - Py_INCREF(dict); - op->cl_dict = dict; - Py_XINCREF(name); - op->cl_name = name; - - op->cl_getattr = class_lookup(op, getattrstr, &dummy); - op->cl_setattr = class_lookup(op, setattrstr, &dummy); - op->cl_delattr = class_lookup(op, delattrstr, &dummy); - Py_XINCREF(op->cl_getattr); - Py_XINCREF(op->cl_setattr); - Py_XINCREF(op->cl_delattr); - _PyObject_GC_TRACK(op); - return (PyObject *) op; -} - -PyObject * -PyMethod_Function(PyObject *im) -{ - if (!PyMethod_Check(im)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyMethodObject *)im)->im_func; -} - -PyObject * -PyMethod_Self(PyObject *im) -{ - if (!PyMethod_Check(im)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyMethodObject *)im)->im_self; -} - -PyObject * -PyMethod_Class(PyObject *im) -{ - if (!PyMethod_Check(im)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyMethodObject *)im)->im_class; -} - -PyDoc_STRVAR(class_doc, -"classobj(name, bases, dict)\n\ -\n\ -Create a class object. The name must be a string; the second argument\n\ -a tuple of classes, and the third a dictionary."); - -static PyObject * -class_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *name, *bases, *dict; - static char *kwlist[] = {"name", "bases", "dict", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "SOO", kwlist, - &name, &bases, &dict)) - return NULL; - return PyClass_New(bases, dict, name); -} - -/* Class methods */ - -static void -class_dealloc(PyClassObject *op) -{ - _PyObject_GC_UNTRACK(op); - Py_DECREF(op->cl_bases); - Py_DECREF(op->cl_dict); - Py_XDECREF(op->cl_name); - Py_XDECREF(op->cl_getattr); - Py_XDECREF(op->cl_setattr); - Py_XDECREF(op->cl_delattr); - PyObject_GC_Del(op); -} - -static PyObject * -class_lookup(PyClassObject *cp, PyObject *name, PyClassObject **pclass) -{ - Py_ssize_t i, n; - PyObject *value = PyDict_GetItem(cp->cl_dict, name); - if (value != NULL) { - *pclass = cp; - return value; - } - n = PyTuple_Size(cp->cl_bases); - for (i = 0; i < n; i++) { - /* XXX What if one of the bases is not a class? */ - PyObject *v = class_lookup( - (PyClassObject *) - PyTuple_GetItem(cp->cl_bases, i), name, pclass); - if (v != NULL) - return v; - } - return NULL; -} - -static PyObject * -class_getattr(register PyClassObject *op, PyObject *name) -{ - register PyObject *v; - register char *sname = PyString_AsString(name); - PyClassObject *klass; - descrgetfunc f; - - if (sname[0] == '_' && sname[1] == '_') { - if (strcmp(sname, "__dict__") == 0) { - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_RuntimeError, - "class.__dict__ not accessible in restricted mode"); - return NULL; - } - Py_INCREF(op->cl_dict); - return op->cl_dict; - } - if (strcmp(sname, "__bases__") == 0) { - Py_INCREF(op->cl_bases); - return op->cl_bases; - } - if (strcmp(sname, "__name__") == 0) { - if (op->cl_name == NULL) - v = Py_None; - else - v = op->cl_name; - Py_INCREF(v); - return v; - } - } - v = class_lookup(op, name, &klass); - if (v == NULL) { - PyErr_Format(PyExc_AttributeError, - "class %.50s has no attribute '%.400s'", - PyString_AS_STRING(op->cl_name), sname); - return NULL; - } - f = TP_DESCR_GET(v->ob_type); - if (f == NULL) - Py_INCREF(v); - else - v = f(v, (PyObject *)NULL, (PyObject *)op); - return v; -} - -static void -set_slot(PyObject **slot, PyObject *v) -{ - PyObject *temp = *slot; - Py_XINCREF(v); - *slot = v; - Py_XDECREF(temp); -} - -static void -set_attr_slots(PyClassObject *c) -{ - PyClassObject *dummy; - - set_slot(&c->cl_getattr, class_lookup(c, getattrstr, &dummy)); - set_slot(&c->cl_setattr, class_lookup(c, setattrstr, &dummy)); - set_slot(&c->cl_delattr, class_lookup(c, delattrstr, &dummy)); -} - -static char * -set_dict(PyClassObject *c, PyObject *v) -{ - if (v == NULL || !PyDict_Check(v)) - return "__dict__ must be a dictionary object"; - set_slot(&c->cl_dict, v); - set_attr_slots(c); - return ""; -} - -static char * -set_bases(PyClassObject *c, PyObject *v) -{ - Py_ssize_t i, n; - - if (v == NULL || !PyTuple_Check(v)) - return "__bases__ must be a tuple object"; - n = PyTuple_Size(v); - for (i = 0; i < n; i++) { - PyObject *x = PyTuple_GET_ITEM(v, i); - if (!PyClass_Check(x)) - return "__bases__ items must be classes"; - if (PyClass_IsSubclass(x, (PyObject *)c)) - return "a __bases__ item causes an inheritance cycle"; - } - set_slot(&c->cl_bases, v); - set_attr_slots(c); - return ""; -} - -static char * -set_name(PyClassObject *c, PyObject *v) -{ - if (v == NULL || !PyString_Check(v)) - return "__name__ must be a string object"; - if (strlen(PyString_AS_STRING(v)) != (size_t)PyString_GET_SIZE(v)) - return "__name__ must not contain null bytes"; - set_slot(&c->cl_name, v); - return ""; -} - -static int -class_setattr(PyClassObject *op, PyObject *name, PyObject *v) -{ - char *sname; - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_RuntimeError, - "classes are read-only in restricted mode"); - return -1; - } - sname = PyString_AsString(name); - if (sname[0] == '_' && sname[1] == '_') { - Py_ssize_t n = PyString_Size(name); - if (sname[n-1] == '_' && sname[n-2] == '_') { - char *err = NULL; - if (strcmp(sname, "__dict__") == 0) - err = set_dict(op, v); - else if (strcmp(sname, "__bases__") == 0) - err = set_bases(op, v); - else if (strcmp(sname, "__name__") == 0) - err = set_name(op, v); - else if (strcmp(sname, "__getattr__") == 0) - set_slot(&op->cl_getattr, v); - else if (strcmp(sname, "__setattr__") == 0) - set_slot(&op->cl_setattr, v); - else if (strcmp(sname, "__delattr__") == 0) - set_slot(&op->cl_delattr, v); - /* For the last three, we fall through to update the - dictionary as well. */ - if (err != NULL) { - if (*err == '\0') - return 0; - PyErr_SetString(PyExc_TypeError, err); - return -1; - } - } - } - if (v == NULL) { - int rv = PyDict_DelItem(op->cl_dict, name); - if (rv < 0) - PyErr_Format(PyExc_AttributeError, - "class %.50s has no attribute '%.400s'", - PyString_AS_STRING(op->cl_name), sname); - return rv; - } - else - return PyDict_SetItem(op->cl_dict, name, v); -} - -static PyObject * -class_repr(PyClassObject *op) -{ - PyObject *mod = PyDict_GetItemString(op->cl_dict, "__module__"); - char *name; - if (op->cl_name == NULL || !PyString_Check(op->cl_name)) - name = "?"; - else - name = PyString_AsString(op->cl_name); - if (mod == NULL || !PyString_Check(mod)) - return PyString_FromFormat("<class ?.%s at %p>", name, op); - else - return PyString_FromFormat("<class %s.%s at %p>", - PyString_AsString(mod), - name, op); -} - -static PyObject * -class_str(PyClassObject *op) -{ - PyObject *mod = PyDict_GetItemString(op->cl_dict, "__module__"); - PyObject *name = op->cl_name; - PyObject *res; - Py_ssize_t m, n; - - if (name == NULL || !PyString_Check(name)) - return class_repr(op); - if (mod == NULL || !PyString_Check(mod)) { - Py_INCREF(name); - return name; - } - m = PyString_GET_SIZE(mod); - n = PyString_GET_SIZE(name); - res = PyString_FromStringAndSize((char *)NULL, m+1+n); - if (res != NULL) { - char *s = PyString_AS_STRING(res); - memcpy(s, PyString_AS_STRING(mod), m); - s += m; - *s++ = '.'; - memcpy(s, PyString_AS_STRING(name), n); - } - return res; -} - -static int -class_traverse(PyClassObject *o, visitproc visit, void *arg) -{ - Py_VISIT(o->cl_bases); - Py_VISIT(o->cl_dict); - Py_VISIT(o->cl_name); - Py_VISIT(o->cl_getattr); - Py_VISIT(o->cl_setattr); - Py_VISIT(o->cl_delattr); - return 0; -} - -PyTypeObject PyClass_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "classobj", - sizeof(PyClassObject), - 0, - (destructor)class_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)class_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - PyInstance_New, /* tp_call */ - (reprfunc)class_str, /* tp_str */ - (getattrofunc)class_getattr, /* tp_getattro */ - (setattrofunc)class_setattr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - class_doc, /* tp_doc */ - (traverseproc)class_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - class_new, /* tp_new */ -}; - -int -PyClass_IsSubclass(PyObject *klass, PyObject *base) -{ - Py_ssize_t i, n; - PyClassObject *cp; - if (klass == base) - return 1; - if (PyTuple_Check(base)) { - n = PyTuple_GET_SIZE(base); - for (i = 0; i < n; i++) { - if (PyClass_IsSubclass(klass, PyTuple_GET_ITEM(base, i))) - return 1; - } - return 0; - } - if (klass == NULL || !PyClass_Check(klass)) - return 0; - cp = (PyClassObject *)klass; - n = PyTuple_Size(cp->cl_bases); - for (i = 0; i < n; i++) { - if (PyClass_IsSubclass(PyTuple_GetItem(cp->cl_bases, i), base)) - return 1; - } - return 0; -} - - -/* Instance objects */ - -PyObject * -PyInstance_NewRaw(PyObject *klass, PyObject *dict) -{ - PyInstanceObject *inst; - - if (!PyClass_Check(klass)) { - PyErr_BadInternalCall(); - return NULL; - } - if (dict == NULL) { - dict = PyDict_New(); - if (dict == NULL) - return NULL; - } - else { - if (!PyDict_Check(dict)) { - PyErr_BadInternalCall(); - return NULL; - } - Py_INCREF(dict); - } - inst = PyObject_GC_New(PyInstanceObject, &PyInstance_Type); - if (inst == NULL) { - Py_DECREF(dict); - return NULL; - } - inst->in_weakreflist = NULL; - Py_INCREF(klass); - inst->in_class = (PyClassObject *)klass; - inst->in_dict = dict; - _PyObject_GC_TRACK(inst); - return (PyObject *)inst; -} - -PyObject * -PyInstance_New(PyObject *klass, PyObject *arg, PyObject *kw) -{ - register PyInstanceObject *inst; - PyObject *init; - static PyObject *initstr; - - if (initstr == NULL) { - initstr = PyString_InternFromString("__init__"); - if (initstr == NULL) - return NULL; - } - inst = (PyInstanceObject *) PyInstance_NewRaw(klass, NULL); - if (inst == NULL) - return NULL; - init = instance_getattr2(inst, initstr); - if (init == NULL) { - if (PyErr_Occurred()) { - Py_DECREF(inst); - return NULL; - } - if ((arg != NULL && (!PyTuple_Check(arg) || - PyTuple_Size(arg) != 0)) - || (kw != NULL && (!PyDict_Check(kw) || - PyDict_Size(kw) != 0))) { - PyErr_SetString(PyExc_TypeError, - "this constructor takes no arguments"); - Py_DECREF(inst); - inst = NULL; - } - } - else { - PyObject *res = PyEval_CallObjectWithKeywords(init, arg, kw); - Py_DECREF(init); - if (res == NULL) { - Py_DECREF(inst); - inst = NULL; - } - else { - if (res != Py_None) { - PyErr_SetString(PyExc_TypeError, - "__init__() should return None"); - Py_DECREF(inst); - inst = NULL; - } - Py_DECREF(res); - } - } - return (PyObject *)inst; -} - -/* Instance methods */ - -PyDoc_STRVAR(instance_doc, -"instance(class[, dict])\n\ -\n\ -Create an instance without calling its __init__() method.\n\ -The class must be a classic class.\n\ -If present, dict must be a dictionary or None."); - -static PyObject * -instance_new(PyTypeObject* type, PyObject* args, PyObject *kw) -{ - PyObject *klass; - PyObject *dict = Py_None; - - if (!PyArg_ParseTuple(args, "O!|O:instance", - &PyClass_Type, &klass, &dict)) - return NULL; - - if (dict == Py_None) - dict = NULL; - else if (!PyDict_Check(dict)) { - PyErr_SetString(PyExc_TypeError, - "instance() second arg must be dictionary or None"); - return NULL; - } - return PyInstance_NewRaw(klass, dict); -} - - -static void -instance_dealloc(register PyInstanceObject *inst) -{ - PyObject *error_type, *error_value, *error_traceback; - PyObject *del; - static PyObject *delstr; - - _PyObject_GC_UNTRACK(inst); - if (inst->in_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) inst); - - /* Temporarily resurrect the object. */ - assert(inst->ob_type == &PyInstance_Type); - assert(inst->ob_refcnt == 0); - inst->ob_refcnt = 1; - - /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - /* Execute __del__ method, if any. */ - if (delstr == NULL) { - delstr = PyString_InternFromString("__del__"); - if (delstr == NULL) - PyErr_WriteUnraisable((PyObject*)inst); - } - if (delstr && (del = instance_getattr2(inst, delstr)) != NULL) { - PyObject *res = PyEval_CallObject(del, (PyObject *)NULL); - if (res == NULL) - PyErr_WriteUnraisable(del); - else - Py_DECREF(res); - Py_DECREF(del); - } - /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); - - /* Undo the temporary resurrection; can't use DECREF here, it would - * cause a recursive call. - */ - assert(inst->ob_refcnt > 0); - if (--inst->ob_refcnt == 0) { - Py_DECREF(inst->in_class); - Py_XDECREF(inst->in_dict); - PyObject_GC_Del(inst); - } - else { - Py_ssize_t refcnt = inst->ob_refcnt; - /* __del__ resurrected it! Make it look like the original - * Py_DECREF never happened. - */ - _Py_NewReference((PyObject *)inst); - inst->ob_refcnt = refcnt; - _PyObject_GC_TRACK(inst); - /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so - * we need to undo that. */ - _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the - * object chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --inst->ob_type->tp_frees; - --inst->ob_type->tp_allocs; -#endif - } -} - -static PyObject * -instance_getattr1(register PyInstanceObject *inst, PyObject *name) -{ - register PyObject *v; - register char *sname = PyString_AsString(name); - if (sname[0] == '_' && sname[1] == '_') { - if (strcmp(sname, "__dict__") == 0) { - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_RuntimeError, - "instance.__dict__ not accessible in restricted mode"); - return NULL; - } - Py_INCREF(inst->in_dict); - return inst->in_dict; - } - if (strcmp(sname, "__class__") == 0) { - Py_INCREF(inst->in_class); - return (PyObject *)inst->in_class; - } - } - v = instance_getattr2(inst, name); - if (v == NULL && !PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, - "%.50s instance has no attribute '%.400s'", - PyString_AS_STRING(inst->in_class->cl_name), sname); - } - return v; -} - -static PyObject * -instance_getattr2(register PyInstanceObject *inst, PyObject *name) -{ - register PyObject *v; - PyClassObject *klass; - descrgetfunc f; - - v = PyDict_GetItem(inst->in_dict, name); - if (v != NULL) { - Py_INCREF(v); - return v; - } - v = class_lookup(inst->in_class, name, &klass); - if (v != NULL) { - Py_INCREF(v); - f = TP_DESCR_GET(v->ob_type); - if (f != NULL) { - PyObject *w = f(v, (PyObject *)inst, - (PyObject *)(inst->in_class)); - Py_DECREF(v); - v = w; - } - } - return v; -} - -static PyObject * -instance_getattr(register PyInstanceObject *inst, PyObject *name) -{ - register PyObject *func, *res; - res = instance_getattr1(inst, name); - if (res == NULL && (func = inst->in_class->cl_getattr) != NULL) { - PyObject *args; - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - args = PyTuple_Pack(2, inst, name); - if (args == NULL) - return NULL; - res = PyEval_CallObject(func, args); - Py_DECREF(args); - } - return res; -} - -/* See classobject.h comments: this only does dict lookups, and is always - * safe to call. - */ -PyObject * -_PyInstance_Lookup(PyObject *pinst, PyObject *name) -{ - PyObject *v; - PyClassObject *klass; - PyInstanceObject *inst; /* pinst cast to the right type */ - - assert(PyInstance_Check(pinst)); - inst = (PyInstanceObject *)pinst; - - assert(PyString_Check(name)); - - v = PyDict_GetItem(inst->in_dict, name); - if (v == NULL) - v = class_lookup(inst->in_class, name, &klass); - return v; -} - -static int -instance_setattr1(PyInstanceObject *inst, PyObject *name, PyObject *v) -{ - if (v == NULL) { - int rv = PyDict_DelItem(inst->in_dict, name); - if (rv < 0) - PyErr_Format(PyExc_AttributeError, - "%.50s instance has no attribute '%.400s'", - PyString_AS_STRING(inst->in_class->cl_name), - PyString_AS_STRING(name)); - return rv; - } - else - return PyDict_SetItem(inst->in_dict, name, v); -} - -static int -instance_setattr(PyInstanceObject *inst, PyObject *name, PyObject *v) -{ - PyObject *func, *args, *res, *tmp; - char *sname = PyString_AsString(name); - if (sname[0] == '_' && sname[1] == '_') { - Py_ssize_t n = PyString_Size(name); - if (sname[n-1] == '_' && sname[n-2] == '_') { - if (strcmp(sname, "__dict__") == 0) { - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_RuntimeError, - "__dict__ not accessible in restricted mode"); - return -1; - } - if (v == NULL || !PyDict_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "__dict__ must be set to a dictionary"); - return -1; - } - tmp = inst->in_dict; - Py_INCREF(v); - inst->in_dict = v; - Py_DECREF(tmp); - return 0; - } - if (strcmp(sname, "__class__") == 0) { - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_RuntimeError, - "__class__ not accessible in restricted mode"); - return -1; - } - if (v == NULL || !PyClass_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "__class__ must be set to a class"); - return -1; - } - tmp = (PyObject *)(inst->in_class); - Py_INCREF(v); - inst->in_class = (PyClassObject *)v; - Py_DECREF(tmp); - return 0; - } - } - } - if (v == NULL) - func = inst->in_class->cl_delattr; - else - func = inst->in_class->cl_setattr; - if (func == NULL) - return instance_setattr1(inst, name, v); - if (v == NULL) - args = PyTuple_Pack(2, inst, name); - else - args = PyTuple_Pack(3, inst, name, v); - if (args == NULL) - return -1; - res = PyEval_CallObject(func, args); - Py_DECREF(args); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -static PyObject * -instance_repr(PyInstanceObject *inst) -{ - PyObject *func; - PyObject *res; - static PyObject *reprstr; - - if (reprstr == NULL) { - reprstr = PyString_InternFromString("__repr__"); - if (reprstr == NULL) - return NULL; - } - func = instance_getattr(inst, reprstr); - if (func == NULL) { - PyObject *classname, *mod; - char *cname; - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - classname = inst->in_class->cl_name; - mod = PyDict_GetItemString(inst->in_class->cl_dict, - "__module__"); - if (classname != NULL && PyString_Check(classname)) - cname = PyString_AsString(classname); - else - cname = "?"; - if (mod == NULL || !PyString_Check(mod)) - return PyString_FromFormat("<?.%s instance at %p>", - cname, inst); - else - return PyString_FromFormat("<%s.%s instance at %p>", - PyString_AsString(mod), - cname, inst); - } - res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - return res; -} - -static PyObject * -instance_str(PyInstanceObject *inst) -{ - PyObject *func; - PyObject *res; - static PyObject *strstr; - - if (strstr == NULL) { - strstr = PyString_InternFromString("__str__"); - if (strstr == NULL) - return NULL; - } - func = instance_getattr(inst, strstr); - if (func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - return instance_repr(inst); - } - res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - return res; -} - -static long -instance_hash(PyInstanceObject *inst) -{ - PyObject *func; - PyObject *res; - long outcome; - static PyObject *hashstr, *eqstr, *cmpstr; - - if (hashstr == NULL) { - hashstr = PyString_InternFromString("__hash__"); - if (hashstr == NULL) - return -1; - } - func = instance_getattr(inst, hashstr); - if (func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; - PyErr_Clear(); - /* If there is no __eq__ and no __cmp__ method, we hash on the - address. If an __eq__ or __cmp__ method exists, there must - be a __hash__. */ - if (eqstr == NULL) { - eqstr = PyString_InternFromString("__eq__"); - if (eqstr == NULL) - return -1; - } - func = instance_getattr(inst, eqstr); - if (func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; - PyErr_Clear(); - if (cmpstr == NULL) { - cmpstr = PyString_InternFromString("__cmp__"); - if (cmpstr == NULL) - return -1; - } - func = instance_getattr(inst, cmpstr); - if (func == NULL) { - if (!PyErr_ExceptionMatches( - PyExc_AttributeError)) - return -1; - PyErr_Clear(); - return _Py_HashPointer(inst); - } - } - Py_XDECREF(func); - PyErr_SetString(PyExc_TypeError, "unhashable instance"); - return -1; - } - res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - if (res == NULL) - return -1; - if (PyInt_Check(res) || PyLong_Check(res)) - /* This already converts a -1 result to -2. */ - outcome = res->ob_type->tp_hash(res); - else { - PyErr_SetString(PyExc_TypeError, - "__hash__() should return an int"); - outcome = -1; - } - Py_DECREF(res); - return outcome; -} - -static int -instance_traverse(PyInstanceObject *o, visitproc visit, void *arg) -{ - Py_VISIT(o->in_class); - Py_VISIT(o->in_dict); - return 0; -} - -static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr; -static PyObject *iterstr, *nextstr; - -static Py_ssize_t -instance_length(PyInstanceObject *inst) -{ - PyObject *func; - PyObject *res; - Py_ssize_t outcome; - - if (lenstr == NULL) { - lenstr = PyString_InternFromString("__len__"); - if (lenstr == NULL) - return -1; - } - func = instance_getattr(inst, lenstr); - if (func == NULL) - return -1; - res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - if (res == NULL) - return -1; - if (PyInt_Check(res)) { - outcome = PyInt_AsSsize_t(res); - if (outcome == -1 && PyErr_Occurred()) { - Py_DECREF(res); - return -1; - } -#if SIZEOF_SIZE_T < SIZEOF_INT - /* Overflow check -- range of PyInt is more than C int */ - if (outcome != (int)outcome) { - PyErr_SetString(PyExc_OverflowError, - "__len__() should return 0 <= outcome < 2**31"); - outcome = -1; - } - else -#endif - if (outcome < 0) { - PyErr_SetString(PyExc_ValueError, - "__len__() should return >= 0"); - outcome = -1; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "__len__() should return an int"); - outcome = -1; - } - Py_DECREF(res); - return outcome; -} - -static PyObject * -instance_subscript(PyInstanceObject *inst, PyObject *key) -{ - PyObject *func; - PyObject *arg; - PyObject *res; - - if (getitemstr == NULL) { - getitemstr = PyString_InternFromString("__getitem__"); - if (getitemstr == NULL) - return NULL; - } - func = instance_getattr(inst, getitemstr); - if (func == NULL) - return NULL; - arg = PyTuple_Pack(1, key); - if (arg == NULL) { - Py_DECREF(func); - return NULL; - } - res = PyEval_CallObject(func, arg); - Py_DECREF(func); - Py_DECREF(arg); - return res; -} - -static int -instance_ass_subscript(PyInstanceObject *inst, PyObject *key, PyObject *value) -{ - PyObject *func; - PyObject *arg; - PyObject *res; - - if (value == NULL) { - if (delitemstr == NULL) { - delitemstr = PyString_InternFromString("__delitem__"); - if (delitemstr == NULL) - return -1; - } - func = instance_getattr(inst, delitemstr); - } - else { - if (setitemstr == NULL) { - setitemstr = PyString_InternFromString("__setitem__"); - if (setitemstr == NULL) - return -1; - } - func = instance_getattr(inst, setitemstr); - } - if (func == NULL) - return -1; - if (value == NULL) - arg = PyTuple_Pack(1, key); - else - arg = PyTuple_Pack(2, key, value); - if (arg == NULL) { - Py_DECREF(func); - return -1; - } - res = PyEval_CallObject(func, arg); - Py_DECREF(func); - Py_DECREF(arg); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -static PyMappingMethods instance_as_mapping = { - (lenfunc)instance_length, /* mp_length */ - (binaryfunc)instance_subscript, /* mp_subscript */ - (objobjargproc)instance_ass_subscript, /* mp_ass_subscript */ -}; - -static PyObject * -instance_item(PyInstanceObject *inst, Py_ssize_t i) -{ - PyObject *func, *res; - - if (getitemstr == NULL) { - getitemstr = PyString_InternFromString("__getitem__"); - if (getitemstr == NULL) - return NULL; - } - func = instance_getattr(inst, getitemstr); - if (func == NULL) - return NULL; - res = PyObject_CallFunction(func, "n", i); - Py_DECREF(func); - return res; -} - -static PyObject * -instance_slice(PyInstanceObject *inst, Py_ssize_t i, Py_ssize_t j) -{ - PyObject *func, *arg, *res; - static PyObject *getslicestr; - - if (getslicestr == NULL) { - getslicestr = PyString_InternFromString("__getslice__"); - if (getslicestr == NULL) - return NULL; - } - func = instance_getattr(inst, getslicestr); - - if (func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - - if (getitemstr == NULL) { - getitemstr = PyString_InternFromString("__getitem__"); - if (getitemstr == NULL) - return NULL; - } - func = instance_getattr(inst, getitemstr); - if (func == NULL) - return NULL; - arg = Py_BuildValue("(N)", _PySlice_FromIndices(i, j)); - } else - arg = Py_BuildValue("(nn)", i, j); - - if (arg == NULL) { - Py_DECREF(func); - return NULL; - } - res = PyEval_CallObject(func, arg); - Py_DECREF(func); - Py_DECREF(arg); - return res; -} - -static int -instance_ass_item(PyInstanceObject *inst, Py_ssize_t i, PyObject *item) -{ - PyObject *func, *arg, *res; - - if (item == NULL) { - if (delitemstr == NULL) { - delitemstr = PyString_InternFromString("__delitem__"); - if (delitemstr == NULL) - return -1; - } - func = instance_getattr(inst, delitemstr); - } - else { - if (setitemstr == NULL) { - setitemstr = PyString_InternFromString("__setitem__"); - if (setitemstr == NULL) - return -1; - } - func = instance_getattr(inst, setitemstr); - } - if (func == NULL) - return -1; - if (item == NULL) - arg = PyInt_FromSsize_t(i); - else - arg = Py_BuildValue("(nO)", i, item); - if (arg == NULL) { - Py_DECREF(func); - return -1; - } - res = PyEval_CallObject(func, arg); - Py_DECREF(func); - Py_DECREF(arg); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -static int -instance_ass_slice(PyInstanceObject *inst, Py_ssize_t i, Py_ssize_t j, PyObject *value) -{ - PyObject *func, *arg, *res; - static PyObject *setslicestr, *delslicestr; - - if (value == NULL) { - if (delslicestr == NULL) { - delslicestr = - PyString_InternFromString("__delslice__"); - if (delslicestr == NULL) - return -1; - } - func = instance_getattr(inst, delslicestr); - if (func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; - PyErr_Clear(); - if (delitemstr == NULL) { - delitemstr = - PyString_InternFromString("__delitem__"); - if (delitemstr == NULL) - return -1; - } - func = instance_getattr(inst, delitemstr); - if (func == NULL) - return -1; - - arg = Py_BuildValue("(N)", - _PySlice_FromIndices(i, j)); - } else - arg = Py_BuildValue("(nn)", i, j); - } - else { - if (setslicestr == NULL) { - setslicestr = - PyString_InternFromString("__setslice__"); - if (setslicestr == NULL) - return -1; - } - func = instance_getattr(inst, setslicestr); - if (func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; - PyErr_Clear(); - if (setitemstr == NULL) { - setitemstr = - PyString_InternFromString("__setitem__"); - if (setitemstr == NULL) - return -1; - } - func = instance_getattr(inst, setitemstr); - if (func == NULL) - return -1; - - arg = Py_BuildValue("(NO)", - _PySlice_FromIndices(i, j), value); - } else - arg = Py_BuildValue("(nnO)", i, j, value); - } - if (arg == NULL) { - Py_DECREF(func); - return -1; - } - res = PyEval_CallObject(func, arg); - Py_DECREF(func); - Py_DECREF(arg); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -static int -instance_contains(PyInstanceObject *inst, PyObject *member) -{ - static PyObject *__contains__; - PyObject *func; - - /* Try __contains__ first. - * If that can't be done, try iterator-based searching. - */ - - if(__contains__ == NULL) { - __contains__ = PyString_InternFromString("__contains__"); - if(__contains__ == NULL) - return -1; - } - func = instance_getattr(inst, __contains__); - if (func) { - PyObject *res; - int ret; - PyObject *arg = PyTuple_Pack(1, member); - if(arg == NULL) { - Py_DECREF(func); - return -1; - } - res = PyEval_CallObject(func, arg); - Py_DECREF(func); - Py_DECREF(arg); - if(res == NULL) - return -1; - ret = PyObject_IsTrue(res); - Py_DECREF(res); - return ret; - } - - /* Couldn't find __contains__. */ - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - Py_ssize_t rc; - /* Assume the failure was simply due to that there is no - * __contains__ attribute, and try iterating instead. - */ - PyErr_Clear(); - rc = _PySequence_IterSearch((PyObject *)inst, member, - PY_ITERSEARCH_CONTAINS); - if (rc >= 0) - return rc > 0; - } - return -1; -} - -static PySequenceMethods -instance_as_sequence = { - (lenfunc)instance_length, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)instance_item, /* sq_item */ - (ssizessizeargfunc)instance_slice, /* sq_slice */ - (ssizeobjargproc)instance_ass_item, /* sq_ass_item */ - (ssizessizeobjargproc)instance_ass_slice,/* sq_ass_slice */ - (objobjproc)instance_contains, /* sq_contains */ -}; - -static PyObject * -generic_unary_op(PyInstanceObject *self, PyObject *methodname) -{ - PyObject *func, *res; - - if ((func = instance_getattr(self, methodname)) == NULL) - return NULL; - res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - return res; -} - -static PyObject * -generic_binary_op(PyObject *v, PyObject *w, char *opname) -{ - PyObject *result; - PyObject *args; - PyObject *func = PyObject_GetAttrString(v, opname); - if (func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - args = PyTuple_Pack(1, w); - if (args == NULL) { - Py_DECREF(func); - return NULL; - } - result = PyEval_CallObject(func, args); - Py_DECREF(args); - Py_DECREF(func); - return result; -} - - -static PyObject *coerce_obj; - -/* Try one half of a binary operator involving a class instance. */ -static PyObject * -half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc, - int swapped) -{ - PyObject *args; - PyObject *coercefunc; - PyObject *coerced = NULL; - PyObject *v1; - PyObject *result; - - if (!PyInstance_Check(v)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (coerce_obj == NULL) { - coerce_obj = PyString_InternFromString("__coerce__"); - if (coerce_obj == NULL) - return NULL; - } - coercefunc = PyObject_GetAttr(v, coerce_obj); - if (coercefunc == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - return generic_binary_op(v, w, opname); - } - - args = PyTuple_Pack(1, w); - if (args == NULL) { - Py_DECREF(coercefunc); - return NULL; - } - coerced = PyEval_CallObject(coercefunc, args); - Py_DECREF(args); - Py_DECREF(coercefunc); - if (coerced == NULL) { - return NULL; - } - if (coerced == Py_None || coerced == Py_NotImplemented) { - Py_DECREF(coerced); - return generic_binary_op(v, w, opname); - } - if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) { - Py_DECREF(coerced); - PyErr_SetString(PyExc_TypeError, - "coercion should return None or 2-tuple"); - return NULL; - } - v1 = PyTuple_GetItem(coerced, 0); - w = PyTuple_GetItem(coerced, 1); - if (v1->ob_type == v->ob_type && PyInstance_Check(v)) { - /* prevent recursion if __coerce__ returns self as the first - * argument */ - result = generic_binary_op(v1, w, opname); - } else { - if (Py_EnterRecursiveCall(" after coercion")) - return NULL; - if (swapped) - result = (thisfunc)(w, v1); - else - result = (thisfunc)(v1, w); - Py_LeaveRecursiveCall(); - } - Py_DECREF(coerced); - return result; -} - -/* Implement a binary operator involving at least one class instance. */ -static PyObject * -do_binop(PyObject *v, PyObject *w, char *opname, char *ropname, - binaryfunc thisfunc) -{ - PyObject *result = half_binop(v, w, opname, thisfunc, 0); - if (result == Py_NotImplemented) { - Py_DECREF(result); - result = half_binop(w, v, ropname, thisfunc, 1); - } - return result; -} - -static PyObject * -do_binop_inplace(PyObject *v, PyObject *w, char *iopname, char *opname, - char *ropname, binaryfunc thisfunc) -{ - PyObject *result = half_binop(v, w, iopname, thisfunc, 0); - if (result == Py_NotImplemented) { - Py_DECREF(result); - result = do_binop(v, w, opname, ropname, thisfunc); - } - return result; -} - -static int -instance_coerce(PyObject **pv, PyObject **pw) -{ - PyObject *v = *pv; - PyObject *w = *pw; - PyObject *coercefunc; - PyObject *args; - PyObject *coerced; - - if (coerce_obj == NULL) { - coerce_obj = PyString_InternFromString("__coerce__"); - if (coerce_obj == NULL) - return -1; - } - coercefunc = PyObject_GetAttr(v, coerce_obj); - if (coercefunc == NULL) { - /* No __coerce__ method */ - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; - PyErr_Clear(); - return 1; - } - /* Has __coerce__ method: call it */ - args = PyTuple_Pack(1, w); - if (args == NULL) { - return -1; - } - coerced = PyEval_CallObject(coercefunc, args); - Py_DECREF(args); - Py_DECREF(coercefunc); - if (coerced == NULL) { - /* __coerce__ call raised an exception */ - return -1; - } - if (coerced == Py_None || coerced == Py_NotImplemented) { - /* __coerce__ says "I can't do it" */ - Py_DECREF(coerced); - return 1; - } - if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) { - /* __coerce__ return value is malformed */ - Py_DECREF(coerced); - PyErr_SetString(PyExc_TypeError, - "coercion should return None or 2-tuple"); - return -1; - } - /* __coerce__ returned two new values */ - *pv = PyTuple_GetItem(coerced, 0); - *pw = PyTuple_GetItem(coerced, 1); - Py_INCREF(*pv); - Py_INCREF(*pw); - Py_DECREF(coerced); - return 0; -} - -#define UNARY(funcname, methodname) \ -static PyObject *funcname(PyInstanceObject *self) { \ - static PyObject *o; \ - if (o == NULL) { o = PyString_InternFromString(methodname); \ - if (o == NULL) return NULL; } \ - return generic_unary_op(self, o); \ -} - -#define BINARY(f, m, n) \ -static PyObject *f(PyObject *v, PyObject *w) { \ - return do_binop(v, w, "__" m "__", "__r" m "__", n); \ -} - -#define BINARY_INPLACE(f, m, n) \ -static PyObject *f(PyObject *v, PyObject *w) { \ - return do_binop_inplace(v, w, "__i" m "__", "__" m "__", \ - "__r" m "__", n); \ -} - -UNARY(instance_neg, "__neg__") -UNARY(instance_pos, "__pos__") -UNARY(instance_abs, "__abs__") - -BINARY(instance_or, "or", PyNumber_Or) -BINARY(instance_and, "and", PyNumber_And) -BINARY(instance_xor, "xor", PyNumber_Xor) -BINARY(instance_lshift, "lshift", PyNumber_Lshift) -BINARY(instance_rshift, "rshift", PyNumber_Rshift) -BINARY(instance_add, "add", PyNumber_Add) -BINARY(instance_sub, "sub", PyNumber_Subtract) -BINARY(instance_mul, "mul", PyNumber_Multiply) -BINARY(instance_div, "div", PyNumber_Divide) -BINARY(instance_mod, "mod", PyNumber_Remainder) -BINARY(instance_divmod, "divmod", PyNumber_Divmod) -BINARY(instance_floordiv, "floordiv", PyNumber_FloorDivide) -BINARY(instance_truediv, "truediv", PyNumber_TrueDivide) - -BINARY_INPLACE(instance_ior, "or", PyNumber_InPlaceOr) -BINARY_INPLACE(instance_ixor, "xor", PyNumber_InPlaceXor) -BINARY_INPLACE(instance_iand, "and", PyNumber_InPlaceAnd) -BINARY_INPLACE(instance_ilshift, "lshift", PyNumber_InPlaceLshift) -BINARY_INPLACE(instance_irshift, "rshift", PyNumber_InPlaceRshift) -BINARY_INPLACE(instance_iadd, "add", PyNumber_InPlaceAdd) -BINARY_INPLACE(instance_isub, "sub", PyNumber_InPlaceSubtract) -BINARY_INPLACE(instance_imul, "mul", PyNumber_InPlaceMultiply) -BINARY_INPLACE(instance_idiv, "div", PyNumber_InPlaceDivide) -BINARY_INPLACE(instance_imod, "mod", PyNumber_InPlaceRemainder) -BINARY_INPLACE(instance_ifloordiv, "floordiv", PyNumber_InPlaceFloorDivide) -BINARY_INPLACE(instance_itruediv, "truediv", PyNumber_InPlaceTrueDivide) - -/* Try a 3-way comparison, returning an int; v is an instance. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w; - 2 if this particular 3-way comparison is not implemented or undefined. -*/ -static int -half_cmp(PyObject *v, PyObject *w) -{ - static PyObject *cmp_obj; - PyObject *args; - PyObject *cmp_func; - PyObject *result; - long l; - - assert(PyInstance_Check(v)); - - if (cmp_obj == NULL) { - cmp_obj = PyString_InternFromString("__cmp__"); - if (cmp_obj == NULL) - return -2; - } - - cmp_func = PyObject_GetAttr(v, cmp_obj); - if (cmp_func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -2; - PyErr_Clear(); - return 2; - } - - args = PyTuple_Pack(1, w); - if (args == NULL) { - Py_DECREF(cmp_func); - return -2; - } - - result = PyEval_CallObject(cmp_func, args); - Py_DECREF(args); - Py_DECREF(cmp_func); - - if (result == NULL) - return -2; - - if (result == Py_NotImplemented) { - Py_DECREF(result); - return 2; - } - - l = PyInt_AsLong(result); - Py_DECREF(result); - if (l == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "comparison did not return an int"); - return -2; - } - - return l < 0 ? -1 : l > 0 ? 1 : 0; -} - -/* Try a 3-way comparison, returning an int; either v or w is an instance. - We first try a coercion. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w; - 2 if this particular 3-way comparison is not implemented or undefined. - THIS IS ONLY CALLED FROM object.c! -*/ -static int -instance_compare(PyObject *v, PyObject *w) -{ - int c; - - c = PyNumber_CoerceEx(&v, &w); - if (c < 0) - return -2; - if (c == 0) { - /* If neither is now an instance, use regular comparison */ - if (!PyInstance_Check(v) && !PyInstance_Check(w)) { - c = PyObject_Compare(v, w); - Py_DECREF(v); - Py_DECREF(w); - if (PyErr_Occurred()) - return -2; - return c < 0 ? -1 : c > 0 ? 1 : 0; - } - } - else { - /* The coercion didn't do anything. - Treat this the same as returning v and w unchanged. */ - Py_INCREF(v); - Py_INCREF(w); - } - - if (PyInstance_Check(v)) { - c = half_cmp(v, w); - if (c <= 1) { - Py_DECREF(v); - Py_DECREF(w); - return c; - } - } - if (PyInstance_Check(w)) { - c = half_cmp(w, v); - if (c <= 1) { - Py_DECREF(v); - Py_DECREF(w); - if (c >= -1) - c = -c; - return c; - } - } - Py_DECREF(v); - Py_DECREF(w); - return 2; -} - -static int -instance_nonzero(PyInstanceObject *self) -{ - PyObject *func, *res; - long outcome; - static PyObject *nonzerostr; - - if (nonzerostr == NULL) { - nonzerostr = PyString_InternFromString("__nonzero__"); - if (nonzerostr == NULL) - return -1; - } - if ((func = instance_getattr(self, nonzerostr)) == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; - PyErr_Clear(); - if (lenstr == NULL) { - lenstr = PyString_InternFromString("__len__"); - if (lenstr == NULL) - return -1; - } - if ((func = instance_getattr(self, lenstr)) == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; - PyErr_Clear(); - /* Fall back to the default behavior: - all instances are nonzero */ - return 1; - } - } - res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - if (res == NULL) - return -1; - if (!PyInt_Check(res)) { - Py_DECREF(res); - PyErr_SetString(PyExc_TypeError, - "__nonzero__ should return an int"); - return -1; - } - outcome = PyInt_AsLong(res); - Py_DECREF(res); - if (outcome < 0) { - PyErr_SetString(PyExc_ValueError, - "__nonzero__ should return >= 0"); - return -1; - } - return outcome > 0; -} - -static PyObject * -instance_index(PyInstanceObject *self) -{ - PyObject *func, *res; - static PyObject *indexstr = NULL; - - if (indexstr == NULL) { - indexstr = PyString_InternFromString("__index__"); - if (indexstr == NULL) - return NULL; - } - if ((func = instance_getattr(self, indexstr)) == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - PyErr_SetString(PyExc_TypeError, - "object cannot be interpreted as an index"); - return NULL; - } - res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - return res; -} - - -UNARY(instance_invert, "__invert__") -UNARY(instance_int, "__int__") -UNARY(instance_long, "__long__") -UNARY(instance_float, "__float__") -UNARY(instance_oct, "__oct__") -UNARY(instance_hex, "__hex__") - -static PyObject * -bin_power(PyObject *v, PyObject *w) -{ - return PyNumber_Power(v, w, Py_None); -} - -/* This version is for ternary calls only (z != None) */ -static PyObject * -instance_pow(PyObject *v, PyObject *w, PyObject *z) -{ - if (z == Py_None) { - return do_binop(v, w, "__pow__", "__rpow__", bin_power); - } - else { - PyObject *func; - PyObject *args; - PyObject *result; - - /* XXX Doesn't do coercions... */ - func = PyObject_GetAttrString(v, "__pow__"); - if (func == NULL) - return NULL; - args = PyTuple_Pack(2, w, z); - if (args == NULL) { - Py_DECREF(func); - return NULL; - } - result = PyEval_CallObject(func, args); - Py_DECREF(func); - Py_DECREF(args); - return result; - } -} - -static PyObject * -bin_inplace_power(PyObject *v, PyObject *w) -{ - return PyNumber_InPlacePower(v, w, Py_None); -} - - -static PyObject * -instance_ipow(PyObject *v, PyObject *w, PyObject *z) -{ - if (z == Py_None) { - return do_binop_inplace(v, w, "__ipow__", "__pow__", - "__rpow__", bin_inplace_power); - } - else { - /* XXX Doesn't do coercions... */ - PyObject *func; - PyObject *args; - PyObject *result; - - func = PyObject_GetAttrString(v, "__ipow__"); - if (func == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - return instance_pow(v, w, z); - } - args = PyTuple_Pack(2, w, z); - if (args == NULL) { - Py_DECREF(func); - return NULL; - } - result = PyEval_CallObject(func, args); - Py_DECREF(func); - Py_DECREF(args); - return result; - } -} - - -/* Map rich comparison operators to their __xx__ namesakes */ -#define NAME_OPS 6 -static PyObject **name_op = NULL; - -static int -init_name_op(void) -{ - int i; - char *_name_op[] = { - "__lt__", - "__le__", - "__eq__", - "__ne__", - "__gt__", - "__ge__", - }; - - name_op = (PyObject **)malloc(sizeof(PyObject *) * NAME_OPS); - if (name_op == NULL) - return -1; - for (i = 0; i < NAME_OPS; ++i) { - name_op[i] = PyString_InternFromString(_name_op[i]); - if (name_op[i] == NULL) - return -1; - } - return 0; -} - -static PyObject * -half_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *method; - PyObject *args; - PyObject *res; - - assert(PyInstance_Check(v)); - - if (name_op == NULL) { - if (init_name_op() < 0) - return NULL; - } - /* If the instance doesn't define an __getattr__ method, use - instance_getattr2 directly because it will not set an - exception on failure. */ - if (((PyInstanceObject *)v)->in_class->cl_getattr == NULL) - method = instance_getattr2((PyInstanceObject *)v, - name_op[op]); - else - method = PyObject_GetAttr(v, name_op[op]); - if (method == NULL) { - if (PyErr_Occurred()) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - } - res = Py_NotImplemented; - Py_INCREF(res); - return res; - } - - args = PyTuple_Pack(1, w); - if (args == NULL) { - Py_DECREF(method); - return NULL; - } - - res = PyEval_CallObject(method, args); - Py_DECREF(args); - Py_DECREF(method); - - return res; -} - -static PyObject * -instance_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *res; - - if (PyInstance_Check(v)) { - res = half_richcompare(v, w, op); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } - - if (PyInstance_Check(w)) { - res = half_richcompare(w, v, _Py_SwappedOp[op]); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } - - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - - -/* Get the iterator */ -static PyObject * -instance_getiter(PyInstanceObject *self) -{ - PyObject *func; - - if (iterstr == NULL) { - iterstr = PyString_InternFromString("__iter__"); - if (iterstr == NULL) - return NULL; - } - if (getitemstr == NULL) { - getitemstr = PyString_InternFromString("__getitem__"); - if (getitemstr == NULL) - return NULL; - } - - if ((func = instance_getattr(self, iterstr)) != NULL) { - PyObject *res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - if (res != NULL && !PyIter_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__iter__ returned non-iterator " - "of type '%.100s'", - res->ob_type->tp_name); - Py_DECREF(res); - res = NULL; - } - return res; - } - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - if ((func = instance_getattr(self, getitemstr)) == NULL) { - PyErr_SetString(PyExc_TypeError, - "iteration over non-sequence"); - return NULL; - } - Py_DECREF(func); - return PySeqIter_New((PyObject *)self); -} - - -/* Call the iterator's next */ -static PyObject * -instance_iternext(PyInstanceObject *self) -{ - PyObject *func; - - if (nextstr == NULL) { - nextstr = PyString_InternFromString("next"); - if (nextstr == NULL) - return NULL; - } - - if ((func = instance_getattr(self, nextstr)) != NULL) { - PyObject *res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - if (res != NULL) { - return res; - } - if (PyErr_ExceptionMatches(PyExc_StopIteration)) { - PyErr_Clear(); - return NULL; - } - return NULL; - } - PyErr_SetString(PyExc_TypeError, "instance has no next() method"); - return NULL; -} - -static PyObject * -instance_call(PyObject *func, PyObject *arg, PyObject *kw) -{ - PyObject *res, *call = PyObject_GetAttrString(func, "__call__"); - if (call == NULL) { - PyInstanceObject *inst = (PyInstanceObject*) func; - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - PyErr_Format(PyExc_AttributeError, - "%.200s instance has no __call__ method", - PyString_AsString(inst->in_class->cl_name)); - return NULL; - } - /* We must check and increment the recursion depth here. Scenario: - class A: - pass - A.__call__ = A() # that's right - a = A() # ok - a() # infinite recursion - This bounces between instance_call() and PyObject_Call() without - ever hitting eval_frame() (which has the main recursion check). */ - if (Py_EnterRecursiveCall(" in __call__")) { - res = NULL; - } - else { - res = PyObject_Call(call, arg, kw); - Py_LeaveRecursiveCall(); - } - Py_DECREF(call); - return res; -} - - -static PyNumberMethods instance_as_number = { - instance_add, /* nb_add */ - instance_sub, /* nb_subtract */ - instance_mul, /* nb_multiply */ - instance_div, /* nb_divide */ - instance_mod, /* nb_remainder */ - instance_divmod, /* nb_divmod */ - instance_pow, /* nb_power */ - (unaryfunc)instance_neg, /* nb_negative */ - (unaryfunc)instance_pos, /* nb_positive */ - (unaryfunc)instance_abs, /* nb_absolute */ - (inquiry)instance_nonzero, /* nb_nonzero */ - (unaryfunc)instance_invert, /* nb_invert */ - instance_lshift, /* nb_lshift */ - instance_rshift, /* nb_rshift */ - instance_and, /* nb_and */ - instance_xor, /* nb_xor */ - instance_or, /* nb_or */ - instance_coerce, /* nb_coerce */ - (unaryfunc)instance_int, /* nb_int */ - (unaryfunc)instance_long, /* nb_long */ - (unaryfunc)instance_float, /* nb_float */ - (unaryfunc)instance_oct, /* nb_oct */ - (unaryfunc)instance_hex, /* nb_hex */ - instance_iadd, /* nb_inplace_add */ - instance_isub, /* nb_inplace_subtract */ - instance_imul, /* nb_inplace_multiply */ - instance_idiv, /* nb_inplace_divide */ - instance_imod, /* nb_inplace_remainder */ - instance_ipow, /* nb_inplace_power */ - instance_ilshift, /* nb_inplace_lshift */ - instance_irshift, /* nb_inplace_rshift */ - instance_iand, /* nb_inplace_and */ - instance_ixor, /* nb_inplace_xor */ - instance_ior, /* nb_inplace_or */ - instance_floordiv, /* nb_floor_divide */ - instance_truediv, /* nb_true_divide */ - instance_ifloordiv, /* nb_inplace_floor_divide */ - instance_itruediv, /* nb_inplace_true_divide */ - (unaryfunc)instance_index, /* nb_index */ -}; - -PyTypeObject PyInstance_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "instance", - sizeof(PyInstanceObject), - 0, - (destructor)instance_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - instance_compare, /* tp_compare */ - (reprfunc)instance_repr, /* tp_repr */ - &instance_as_number, /* tp_as_number */ - &instance_as_sequence, /* tp_as_sequence */ - &instance_as_mapping, /* tp_as_mapping */ - (hashfunc)instance_hash, /* tp_hash */ - instance_call, /* tp_call */ - (reprfunc)instance_str, /* tp_str */ - (getattrofunc)instance_getattr, /* tp_getattro */ - (setattrofunc)instance_setattr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,/*tp_flags*/ - instance_doc, /* tp_doc */ - (traverseproc)instance_traverse, /* tp_traverse */ - 0, /* tp_clear */ - instance_richcompare, /* tp_richcompare */ - offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */ - (getiterfunc)instance_getiter, /* tp_iter */ - (iternextfunc)instance_iternext, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - instance_new, /* tp_new */ -}; - - -/* Instance method objects are used for two purposes: - (a) as bound instance methods (returned by instancename.methodname) - (b) as unbound methods (returned by ClassName.methodname) - In case (b), im_self is NULL -*/ - -static PyMethodObject *free_list; - -PyObject * -PyMethod_New(PyObject *func, PyObject *self, PyObject *klass) -{ - register PyMethodObject *im; - if (!PyCallable_Check(func)) { - PyErr_BadInternalCall(); - return NULL; - } - im = free_list; - if (im != NULL) { - free_list = (PyMethodObject *)(im->im_self); - PyObject_INIT(im, &PyMethod_Type); - } - else { - im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); - if (im == NULL) - return NULL; - } - im->im_weakreflist = NULL; - Py_INCREF(func); - im->im_func = func; - Py_XINCREF(self); - im->im_self = self; - Py_XINCREF(klass); - im->im_class = klass; - _PyObject_GC_TRACK(im); - return (PyObject *)im; -} - -/* Descriptors for PyMethod attributes */ - -/* im_class, im_func and im_self are stored in the PyMethod object */ - -#define OFF(x) offsetof(PyMethodObject, x) - -static PyMemberDef instancemethod_memberlist[] = { - {"im_class", T_OBJECT, OFF(im_class), READONLY|RESTRICTED, - "the class associated with a method"}, - {"im_func", T_OBJECT, OFF(im_func), READONLY|RESTRICTED, - "the function (or other callable) implementing a method"}, - {"im_self", T_OBJECT, OFF(im_self), READONLY|RESTRICTED, - "the instance to which a method is bound; None for unbound methods"}, - {NULL} /* Sentinel */ -}; - -/* Christian Tismer argued convincingly that method attributes should - (nearly) always override function attributes. - The one exception is __doc__; there's a default __doc__ which - should only be used for the class, not for instances */ - -static PyObject * -instancemethod_get_doc(PyMethodObject *im, void *context) -{ - static PyObject *docstr; - if (docstr == NULL) { - docstr= PyString_InternFromString("__doc__"); - if (docstr == NULL) - return NULL; - } - return PyObject_GetAttr(im->im_func, docstr); -} - -static PyGetSetDef instancemethod_getset[] = { - {"__doc__", (getter)instancemethod_get_doc, NULL, NULL}, - {0} -}; - -static PyObject * -instancemethod_getattro(PyObject *obj, PyObject *name) -{ - PyMethodObject *im = (PyMethodObject *)obj; - PyTypeObject *tp = obj->ob_type; - PyObject *descr = NULL; - - if (PyType_HasFeature(tp, Py_TPFLAGS_HAVE_CLASS)) { - if (tp->tp_dict == NULL) { - if (PyType_Ready(tp) < 0) - return NULL; - } - descr = _PyType_Lookup(tp, name); - } - - if (descr != NULL) { - descrgetfunc f = TP_DESCR_GET(descr->ob_type); - if (f != NULL) - return f(descr, obj, (PyObject *)obj->ob_type); - else { - Py_INCREF(descr); - return descr; - } - } - - return PyObject_GetAttr(im->im_func, name); -} - -PyDoc_STRVAR(instancemethod_doc, -"instancemethod(function, instance, class)\n\ -\n\ -Create an instance method object."); - -static PyObject * -instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw) -{ - PyObject *func; - PyObject *self; - PyObject *classObj = NULL; - - if (!_PyArg_NoKeywords("instancemethod", kw)) - return NULL; - if (!PyArg_UnpackTuple(args, "instancemethod", 2, 3, - &func, &self, &classObj)) - return NULL; - if (!PyCallable_Check(func)) { - PyErr_SetString(PyExc_TypeError, - "first argument must be callable"); - return NULL; - } - if (self == Py_None) - self = NULL; - if (self == NULL && classObj == NULL) { - PyErr_SetString(PyExc_TypeError, - "unbound methods must have non-NULL im_class"); - return NULL; - } - - return PyMethod_New(func, self, classObj); -} - -static void -instancemethod_dealloc(register PyMethodObject *im) -{ - _PyObject_GC_UNTRACK(im); - if (im->im_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *)im); - Py_DECREF(im->im_func); - Py_XDECREF(im->im_self); - Py_XDECREF(im->im_class); - im->im_self = (PyObject *)free_list; - free_list = im; -} - -static int -instancemethod_compare(PyMethodObject *a, PyMethodObject *b) -{ - int cmp; - cmp = PyObject_Compare(a->im_func, b->im_func); - if (cmp) - return cmp; - - if (a->im_self == b->im_self) - return 0; - if (a->im_self == NULL || b->im_self == NULL) - return (a->im_self < b->im_self) ? -1 : 1; - else - return PyObject_Compare(a->im_self, b->im_self); -} - -static PyObject * -instancemethod_repr(PyMethodObject *a) -{ - PyObject *self = a->im_self; - PyObject *func = a->im_func; - PyObject *klass = a->im_class; - PyObject *funcname = NULL, *klassname = NULL, *result = NULL; - char *sfuncname = "?", *sklassname = "?"; - - funcname = PyObject_GetAttrString(func, "__name__"); - if (funcname == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - } - else if (!PyString_Check(funcname)) { - Py_DECREF(funcname); - funcname = NULL; - } - else - sfuncname = PyString_AS_STRING(funcname); - if (klass == NULL) - klassname = NULL; - else { - klassname = PyObject_GetAttrString(klass, "__name__"); - if (klassname == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return NULL; - PyErr_Clear(); - } - else if (!PyString_Check(klassname)) { - Py_DECREF(klassname); - klassname = NULL; - } - else - sklassname = PyString_AS_STRING(klassname); - } - if (self == NULL) - result = PyString_FromFormat("<unbound method %s.%s>", - sklassname, sfuncname); - else { - /* XXX Shouldn't use repr() here! */ - PyObject *selfrepr = PyObject_Repr(self); - if (selfrepr == NULL) - goto fail; - if (!PyString_Check(selfrepr)) { - Py_DECREF(selfrepr); - goto fail; - } - result = PyString_FromFormat("<bound method %s.%s of %s>", - sklassname, sfuncname, - PyString_AS_STRING(selfrepr)); - Py_DECREF(selfrepr); - } - fail: - Py_XDECREF(funcname); - Py_XDECREF(klassname); - return result; -} - -static long -instancemethod_hash(PyMethodObject *a) -{ - long x, y; - if (a->im_self == NULL) - x = PyObject_Hash(Py_None); - else - x = PyObject_Hash(a->im_self); - if (x == -1) - return -1; - y = PyObject_Hash(a->im_func); - if (y == -1) - return -1; - x = x ^ y; - if (x == -1) - x = -2; - return x; -} - -static int -instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg) -{ - Py_VISIT(im->im_func); - Py_VISIT(im->im_self); - Py_VISIT(im->im_class); - return 0; -} - -static void -getclassname(PyObject *klass, char *buf, int bufsize) -{ - PyObject *name; - - assert(bufsize > 1); - strcpy(buf, "?"); /* Default outcome */ - if (klass == NULL) - return; - name = PyObject_GetAttrString(klass, "__name__"); - if (name == NULL) { - /* This function cannot return an exception */ - PyErr_Clear(); - return; - } - if (PyString_Check(name)) { - strncpy(buf, PyString_AS_STRING(name), bufsize); - buf[bufsize-1] = '\0'; - } - Py_DECREF(name); -} - -static void -getinstclassname(PyObject *inst, char *buf, int bufsize) -{ - PyObject *klass; - - if (inst == NULL) { - assert(bufsize > 0 && (size_t)bufsize > strlen("nothing")); - strcpy(buf, "nothing"); - return; - } - - klass = PyObject_GetAttrString(inst, "__class__"); - if (klass == NULL) { - /* This function cannot return an exception */ - PyErr_Clear(); - klass = (PyObject *)(inst->ob_type); - Py_INCREF(klass); - } - getclassname(klass, buf, bufsize); - Py_XDECREF(klass); -} - -static PyObject * -instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw) -{ - PyObject *self = PyMethod_GET_SELF(func); - PyObject *klass = PyMethod_GET_CLASS(func); - PyObject *result; - - func = PyMethod_GET_FUNCTION(func); - if (self == NULL) { - /* Unbound methods must be called with an instance of - the class (or a derived class) as first argument */ - int ok; - if (PyTuple_Size(arg) >= 1) - self = PyTuple_GET_ITEM(arg, 0); - if (self == NULL) - ok = 0; - else { - ok = PyObject_IsInstance(self, klass); - if (ok < 0) - return NULL; - } - if (!ok) { - char clsbuf[256]; - char instbuf[256]; - getclassname(klass, clsbuf, sizeof(clsbuf)); - getinstclassname(self, instbuf, sizeof(instbuf)); - PyErr_Format(PyExc_TypeError, - "unbound method %s%s must be called with " - "%s instance as first argument " - "(got %s%s instead)", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - clsbuf, - instbuf, - self == NULL ? "" : " instance"); - return NULL; - } - Py_INCREF(arg); - } - else { - Py_ssize_t argcount = PyTuple_Size(arg); - PyObject *newarg = PyTuple_New(argcount + 1); - int i; - if (newarg == NULL) - return NULL; - Py_INCREF(self); - PyTuple_SET_ITEM(newarg, 0, self); - for (i = 0; i < argcount; i++) { - PyObject *v = PyTuple_GET_ITEM(arg, i); - Py_XINCREF(v); - PyTuple_SET_ITEM(newarg, i+1, v); - } - arg = newarg; - } - result = PyObject_Call((PyObject *)func, arg, kw); - Py_DECREF(arg); - return result; -} - -static PyObject * -instancemethod_descr_get(PyObject *meth, PyObject *obj, PyObject *cls) -{ - /* Don't rebind an already bound method, or an unbound method - of a class that's not a base class of cls. */ - - if (PyMethod_GET_SELF(meth) != NULL) { - /* Already bound */ - Py_INCREF(meth); - return meth; - } - /* No, it is an unbound method */ - if (PyMethod_GET_CLASS(meth) != NULL && cls != NULL) { - /* Do subclass test. If it fails, return meth unchanged. */ - int ok = PyObject_IsSubclass(cls, PyMethod_GET_CLASS(meth)); - if (ok < 0) - return NULL; - if (!ok) { - Py_INCREF(meth); - return meth; - } - } - /* Bind it to obj */ - return PyMethod_New(PyMethod_GET_FUNCTION(meth), obj, cls); -} - -PyTypeObject PyMethod_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "instancemethod", - sizeof(PyMethodObject), - 0, - (destructor)instancemethod_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)instancemethod_compare, /* tp_compare */ - (reprfunc)instancemethod_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)instancemethod_hash, /* tp_hash */ - instancemethod_call, /* tp_call */ - 0, /* tp_str */ - instancemethod_getattro, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ - instancemethod_doc, /* tp_doc */ - (traverseproc)instancemethod_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - instancemethod_memberlist, /* tp_members */ - instancemethod_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - instancemethod_descr_get, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - instancemethod_new, /* tp_new */ -}; - -/* Clear out the free list */ - -void -PyMethod_Fini(void) -{ - while (free_list) { - PyMethodObject *im = free_list; - free_list = (PyMethodObject *)(im->im_self); - PyObject_GC_Del(im); - } -} diff --git a/sys/src/cmd/python/Objects/cobject.c b/sys/src/cmd/python/Objects/cobject.c deleted file mode 100644 index b2cae9a40..000000000 --- a/sys/src/cmd/python/Objects/cobject.c +++ /dev/null @@ -1,161 +0,0 @@ - -/* Wrap void* pointers to be passed between C modules */ - -#include "Python.h" - - -/* Declarations for objects of type PyCObject */ - -typedef void (*destructor1)(void *); -typedef void (*destructor2)(void *, void*); - -typedef struct { - PyObject_HEAD - void *cobject; - void *desc; - void (*destructor)(void *); -} PyCObject; - -PyObject * -PyCObject_FromVoidPtr(void *cobj, void (*destr)(void *)) -{ - PyCObject *self; - - self = PyObject_NEW(PyCObject, &PyCObject_Type); - if (self == NULL) - return NULL; - self->cobject=cobj; - self->destructor=destr; - self->desc=NULL; - - return (PyObject *)self; -} - -PyObject * -PyCObject_FromVoidPtrAndDesc(void *cobj, void *desc, - void (*destr)(void *, void *)) -{ - PyCObject *self; - - if (!desc) { - PyErr_SetString(PyExc_TypeError, - "PyCObject_FromVoidPtrAndDesc called with null" - " description"); - return NULL; - } - self = PyObject_NEW(PyCObject, &PyCObject_Type); - if (self == NULL) - return NULL; - self->cobject = cobj; - self->destructor = (destructor1)destr; - self->desc = desc; - - return (PyObject *)self; -} - -void * -PyCObject_AsVoidPtr(PyObject *self) -{ - if (self) { - if (self->ob_type == &PyCObject_Type) - return ((PyCObject *)self)->cobject; - PyErr_SetString(PyExc_TypeError, - "PyCObject_AsVoidPtr with non-C-object"); - } - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, - "PyCObject_AsVoidPtr called with null pointer"); - return NULL; -} - -void * -PyCObject_GetDesc(PyObject *self) -{ - if (self) { - if (self->ob_type == &PyCObject_Type) - return ((PyCObject *)self)->desc; - PyErr_SetString(PyExc_TypeError, - "PyCObject_GetDesc with non-C-object"); - } - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, - "PyCObject_GetDesc called with null pointer"); - return NULL; -} - -void * -PyCObject_Import(char *module_name, char *name) -{ - PyObject *m, *c; - void *r = NULL; - - if ((m = PyImport_ImportModule(module_name))) { - if ((c = PyObject_GetAttrString(m,name))) { - r = PyCObject_AsVoidPtr(c); - Py_DECREF(c); - } - Py_DECREF(m); - } - return r; -} - -int -PyCObject_SetVoidPtr(PyObject *self, void *cobj) -{ - PyCObject* cself = (PyCObject*)self; - if (cself == NULL || !PyCObject_Check(cself) || - cself->destructor != NULL) { - PyErr_SetString(PyExc_TypeError, - "Invalid call to PyCObject_SetVoidPtr"); - return 0; - } - cself->cobject = cobj; - return 1; -} - -static void -PyCObject_dealloc(PyCObject *self) -{ - if (self->destructor) { - if(self->desc) - ((destructor2)(self->destructor))(self->cobject, self->desc); - else - (self->destructor)(self->cobject); - } - PyObject_DEL(self); -} - - -PyDoc_STRVAR(PyCObject_Type__doc__, -"C objects to be exported from one extension module to another\n\ -\n\ -C objects are used for communication between extension modules. They\n\ -provide a way for an extension module to export a C interface to other\n\ -extension modules, so that extension modules can use the Python import\n\ -mechanism to link to one another."); - -PyTypeObject PyCObject_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ - "PyCObject", /*tp_name*/ - sizeof(PyCObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)PyCObject_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*/ - 0, /*tp_flags*/ - PyCObject_Type__doc__ /*tp_doc*/ -}; diff --git a/sys/src/cmd/python/Objects/codeobject.c b/sys/src/cmd/python/Objects/codeobject.c deleted file mode 100644 index 89871d6cf..000000000 --- a/sys/src/cmd/python/Objects/codeobject.c +++ /dev/null @@ -1,590 +0,0 @@ -#include "Python.h" -#include "code.h" -#include "structmember.h" - -#define NAME_CHARS \ - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" - -/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */ - -static int -all_name_chars(unsigned char *s) -{ - static char ok_name_char[256]; - static unsigned char *name_chars = (unsigned char *)NAME_CHARS; - - if (ok_name_char[*name_chars] == 0) { - unsigned char *p; - for (p = name_chars; *p; p++) - ok_name_char[*p] = 1; - } - while (*s) { - if (ok_name_char[*s++] == 0) - return 0; - } - return 1; -} - -static void -intern_strings(PyObject *tuple) -{ - Py_ssize_t i; - - for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { - PyObject *v = PyTuple_GET_ITEM(tuple, i); - if (v == NULL || !PyString_CheckExact(v)) { - Py_FatalError("non-string found in code slot"); - } - PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i)); - } -} - - -PyCodeObject * -PyCode_New(int argcount, int nlocals, int stacksize, int flags, - PyObject *code, PyObject *consts, PyObject *names, - PyObject *varnames, PyObject *freevars, PyObject *cellvars, - PyObject *filename, PyObject *name, int firstlineno, - PyObject *lnotab) -{ - PyCodeObject *co; - Py_ssize_t i; - /* Check argument types */ - if (argcount < 0 || nlocals < 0 || - code == NULL || - consts == NULL || !PyTuple_Check(consts) || - names == NULL || !PyTuple_Check(names) || - varnames == NULL || !PyTuple_Check(varnames) || - freevars == NULL || !PyTuple_Check(freevars) || - cellvars == NULL || !PyTuple_Check(cellvars) || - name == NULL || !PyString_Check(name) || - filename == NULL || !PyString_Check(filename) || - lnotab == NULL || !PyString_Check(lnotab) || - !PyObject_CheckReadBuffer(code)) { - PyErr_BadInternalCall(); - return NULL; - } - intern_strings(names); - intern_strings(varnames); - intern_strings(freevars); - intern_strings(cellvars); - /* Intern selected string constants */ - for (i = PyTuple_Size(consts); --i >= 0; ) { - PyObject *v = PyTuple_GetItem(consts, i); - if (!PyString_Check(v)) - continue; - if (!all_name_chars((unsigned char *)PyString_AS_STRING(v))) - continue; - PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); - } - co = PyObject_NEW(PyCodeObject, &PyCode_Type); - if (co != NULL) { - co->co_argcount = argcount; - co->co_nlocals = nlocals; - co->co_stacksize = stacksize; - co->co_flags = flags; - Py_INCREF(code); - co->co_code = code; - Py_INCREF(consts); - co->co_consts = consts; - Py_INCREF(names); - co->co_names = names; - Py_INCREF(varnames); - co->co_varnames = varnames; - Py_INCREF(freevars); - co->co_freevars = freevars; - Py_INCREF(cellvars); - co->co_cellvars = cellvars; - Py_INCREF(filename); - co->co_filename = filename; - Py_INCREF(name); - co->co_name = name; - co->co_firstlineno = firstlineno; - Py_INCREF(lnotab); - co->co_lnotab = lnotab; - co->co_zombieframe = NULL; - } - return co; -} - - -#define OFF(x) offsetof(PyCodeObject, x) - -static PyMemberDef code_memberlist[] = { - {"co_argcount", T_INT, OFF(co_argcount), READONLY}, - {"co_nlocals", T_INT, OFF(co_nlocals), READONLY}, - {"co_stacksize",T_INT, OFF(co_stacksize), READONLY}, - {"co_flags", T_INT, OFF(co_flags), READONLY}, - {"co_code", T_OBJECT, OFF(co_code), READONLY}, - {"co_consts", T_OBJECT, OFF(co_consts), READONLY}, - {"co_names", T_OBJECT, OFF(co_names), READONLY}, - {"co_varnames", T_OBJECT, OFF(co_varnames), READONLY}, - {"co_freevars", T_OBJECT, OFF(co_freevars), READONLY}, - {"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY}, - {"co_filename", T_OBJECT, OFF(co_filename), READONLY}, - {"co_name", T_OBJECT, OFF(co_name), READONLY}, - {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY}, - {"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY}, - {NULL} /* Sentinel */ -}; - -/* Helper for code_new: return a shallow copy of a tuple that is - guaranteed to contain exact strings, by converting string subclasses - to exact strings and complaining if a non-string is found. */ -static PyObject* -validate_and_copy_tuple(PyObject *tup) -{ - PyObject *newtuple; - PyObject *item; - Py_ssize_t i, len; - - len = PyTuple_GET_SIZE(tup); - newtuple = PyTuple_New(len); - if (newtuple == NULL) - return NULL; - - for (i = 0; i < len; i++) { - item = PyTuple_GET_ITEM(tup, i); - if (PyString_CheckExact(item)) { - Py_INCREF(item); - } - else if (!PyString_Check(item)) { - PyErr_Format( - PyExc_TypeError, - "name tuples must contain only " - "strings, not '%.500s'", - item->ob_type->tp_name); - Py_DECREF(newtuple); - return NULL; - } - else { - item = PyString_FromStringAndSize( - PyString_AS_STRING(item), - PyString_GET_SIZE(item)); - if (item == NULL) { - Py_DECREF(newtuple); - return NULL; - } - } - PyTuple_SET_ITEM(newtuple, i, item); - } - - return newtuple; -} - -PyDoc_STRVAR(code_doc, -"code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\ - varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\ -\n\ -Create a code object. Not for the faint of heart."); - -static PyObject * -code_new(PyTypeObject *type, PyObject *args, PyObject *kw) -{ - int argcount; - int nlocals; - int stacksize; - int flags; - PyObject *co = NULL; - PyObject *code; - PyObject *consts; - PyObject *names, *ournames = NULL; - PyObject *varnames, *ourvarnames = NULL; - PyObject *freevars = NULL, *ourfreevars = NULL; - PyObject *cellvars = NULL, *ourcellvars = NULL; - PyObject *filename; - PyObject *name; - int firstlineno; - PyObject *lnotab; - - if (!PyArg_ParseTuple(args, "iiiiSO!O!O!SSiS|O!O!:code", - &argcount, &nlocals, &stacksize, &flags, - &code, - &PyTuple_Type, &consts, - &PyTuple_Type, &names, - &PyTuple_Type, &varnames, - &filename, &name, - &firstlineno, &lnotab, - &PyTuple_Type, &freevars, - &PyTuple_Type, &cellvars)) - return NULL; - - if (argcount < 0) { - PyErr_SetString( - PyExc_ValueError, - "code: argcount must not be negative"); - goto cleanup; - } - - if (nlocals < 0) { - PyErr_SetString( - PyExc_ValueError, - "code: nlocals must not be negative"); - goto cleanup; - } - - ournames = validate_and_copy_tuple(names); - if (ournames == NULL) - goto cleanup; - ourvarnames = validate_and_copy_tuple(varnames); - if (ourvarnames == NULL) - goto cleanup; - if (freevars) - ourfreevars = validate_and_copy_tuple(freevars); - else - ourfreevars = PyTuple_New(0); - if (ourfreevars == NULL) - goto cleanup; - if (cellvars) - ourcellvars = validate_and_copy_tuple(cellvars); - else - ourcellvars = PyTuple_New(0); - if (ourcellvars == NULL) - goto cleanup; - - co = (PyObject *)PyCode_New(argcount, nlocals, stacksize, flags, - code, consts, ournames, ourvarnames, - ourfreevars, ourcellvars, filename, - name, firstlineno, lnotab); - cleanup: - Py_XDECREF(ournames); - Py_XDECREF(ourvarnames); - Py_XDECREF(ourfreevars); - Py_XDECREF(ourcellvars); - return co; -} - -static void -code_dealloc(PyCodeObject *co) -{ - Py_XDECREF(co->co_code); - Py_XDECREF(co->co_consts); - Py_XDECREF(co->co_names); - Py_XDECREF(co->co_varnames); - Py_XDECREF(co->co_freevars); - Py_XDECREF(co->co_cellvars); - Py_XDECREF(co->co_filename); - Py_XDECREF(co->co_name); - Py_XDECREF(co->co_lnotab); - if (co->co_zombieframe != NULL) - PyObject_GC_Del(co->co_zombieframe); - PyObject_DEL(co); -} - -static PyObject * -code_repr(PyCodeObject *co) -{ - char buf[500]; - int lineno = -1; - char *filename = "???"; - char *name = "???"; - - if (co->co_firstlineno != 0) - lineno = co->co_firstlineno; - if (co->co_filename && PyString_Check(co->co_filename)) - filename = PyString_AS_STRING(co->co_filename); - if (co->co_name && PyString_Check(co->co_name)) - name = PyString_AS_STRING(co->co_name); - PyOS_snprintf(buf, sizeof(buf), - "<code object %.100s at %p, file \"%.300s\", line %d>", - name, co, filename, lineno); - return PyString_FromString(buf); -} - -static int -code_compare(PyCodeObject *co, PyCodeObject *cp) -{ - int cmp; - cmp = PyObject_Compare(co->co_name, cp->co_name); - if (cmp) return cmp; - cmp = co->co_argcount - cp->co_argcount; - if (cmp) goto normalize; - cmp = co->co_nlocals - cp->co_nlocals; - if (cmp) goto normalize; - cmp = co->co_flags - cp->co_flags; - if (cmp) goto normalize; - cmp = co->co_firstlineno - cp->co_firstlineno; - if (cmp) goto normalize; - cmp = PyObject_Compare(co->co_code, cp->co_code); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_consts, cp->co_consts); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_names, cp->co_names); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_varnames, cp->co_varnames); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_freevars, cp->co_freevars); - if (cmp) return cmp; - cmp = PyObject_Compare(co->co_cellvars, cp->co_cellvars); - return cmp; - - normalize: - if (cmp > 0) - return 1; - else if (cmp < 0) - return -1; - else - return 0; -} - -static long -code_hash(PyCodeObject *co) -{ - long h, h0, h1, h2, h3, h4, h5, h6; - h0 = PyObject_Hash(co->co_name); - if (h0 == -1) return -1; - h1 = PyObject_Hash(co->co_code); - if (h1 == -1) return -1; - h2 = PyObject_Hash(co->co_consts); - if (h2 == -1) return -1; - h3 = PyObject_Hash(co->co_names); - if (h3 == -1) return -1; - h4 = PyObject_Hash(co->co_varnames); - if (h4 == -1) return -1; - h5 = PyObject_Hash(co->co_freevars); - if (h5 == -1) return -1; - h6 = PyObject_Hash(co->co_cellvars); - if (h6 == -1) return -1; - h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^ - co->co_argcount ^ co->co_nlocals ^ co->co_flags; - if (h == -1) h = -2; - return h; -} - -/* XXX code objects need to participate in GC? */ - -PyTypeObject PyCode_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "code", - sizeof(PyCodeObject), - 0, - (destructor)code_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)code_compare, /* tp_compare */ - (reprfunc)code_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)code_hash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - code_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - code_memberlist, /* tp_members */ - 0, /* 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 */ - code_new, /* tp_new */ -}; - -/* All about c_lnotab. - -c_lnotab is an array of unsigned bytes disguised as a Python string. In -O -mode, SET_LINENO opcodes aren't generated, and bytecode offsets are mapped -to source code line #s (when needed for tracebacks) via c_lnotab instead. -The array is conceptually a list of - (bytecode offset increment, line number increment) -pairs. The details are important and delicate, best illustrated by example: - - byte code offset source code line number - 0 1 - 6 2 - 50 7 - 350 307 - 361 308 - -The first trick is that these numbers aren't stored, only the increments -from one row to the next (this doesn't really work, but it's a start): - - 0, 1, 6, 1, 44, 5, 300, 300, 11, 1 - -The second trick is that an unsigned byte can't hold negative values, or -values larger than 255, so (a) there's a deep assumption that byte code -offsets and their corresponding line #s both increase monotonically, and (b) -if at least one column jumps by more than 255 from one row to the next, more -than one pair is written to the table. In case #b, there's no way to know -from looking at the table later how many were written. That's the delicate -part. A user of c_lnotab desiring to find the source line number -corresponding to a bytecode address A should do something like this - - lineno = addr = 0 - for addr_incr, line_incr in c_lnotab: - addr += addr_incr - if addr > A: - return lineno - lineno += line_incr - -In order for this to work, when the addr field increments by more than 255, -the line # increment in each pair generated must be 0 until the remaining addr -increment is < 256. So, in the example above, com_set_lineno should not (as -was actually done until 2.2) expand 300, 300 to 255, 255, 45, 45, but to -255, 0, 45, 255, 0, 45. -*/ - -int -PyCode_Addr2Line(PyCodeObject *co, int addrq) -{ - int size = PyString_Size(co->co_lnotab) / 2; - unsigned char *p = (unsigned char*)PyString_AsString(co->co_lnotab); - int line = co->co_firstlineno; - int addr = 0; - while (--size >= 0) { - addr += *p++; - if (addr > addrq) - break; - line += *p++; - } - return line; -} - -/* - Check whether the current instruction is at the start of a line. - - */ - - /* The theory of SET_LINENO-less tracing. - - In a nutshell, we use the co_lnotab field of the code object - to tell when execution has moved onto a different line. - - As mentioned above, the basic idea is so set things up so - that - - *instr_lb <= frame->f_lasti < *instr_ub - - is true so long as execution does not change lines. - - This is all fairly simple. Digging the information out of - co_lnotab takes some work, but is conceptually clear. - - Somewhat harder to explain is why we don't *always* call the - line trace function when the above test fails. - - Consider this code: - - 1: def f(a): - 2: if a: - 3: print 1 - 4: else: - 5: print 2 - - which compiles to this: - - 2 0 LOAD_FAST 0 (a) - 3 JUMP_IF_FALSE 9 (to 15) - 6 POP_TOP - - 3 7 LOAD_CONST 1 (1) - 10 PRINT_ITEM - 11 PRINT_NEWLINE - 12 JUMP_FORWARD 6 (to 21) - >> 15 POP_TOP - - 5 16 LOAD_CONST 2 (2) - 19 PRINT_ITEM - 20 PRINT_NEWLINE - >> 21 LOAD_CONST 0 (None) - 24 RETURN_VALUE - - If 'a' is false, execution will jump to instruction at offset - 15 and the co_lnotab will claim that execution has moved to - line 3. This is at best misleading. In this case we could - associate the POP_TOP with line 4, but that doesn't make - sense in all cases (I think). - - What we do is only call the line trace function if the co_lnotab - indicates we have jumped to the *start* of a line, i.e. if the - current instruction offset matches the offset given for the - start of a line by the co_lnotab. - - This also takes care of the situation where 'a' is true. - Execution will jump from instruction offset 12 to offset 21. - Then the co_lnotab would imply that execution has moved to line - 5, which is again misleading. - - Why do we set f_lineno when tracing? Well, consider the code - above when 'a' is true. If stepping through this with 'n' in - pdb, you would stop at line 1 with a "call" type event, then - line events on lines 2 and 3, then a "return" type event -- but - you would be shown line 5 during this event. This is a change - from the behaviour in 2.2 and before, and I've found it - confusing in practice. By setting and using f_lineno when - tracing, one can report a line number different from that - suggested by f_lasti on this one occasion where it's desirable. - */ - - -int -PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds) -{ - int size, addr, line; - unsigned char* p; - - p = (unsigned char*)PyString_AS_STRING(co->co_lnotab); - size = PyString_GET_SIZE(co->co_lnotab) / 2; - - addr = 0; - line = co->co_firstlineno; - assert(line > 0); - - /* possible optimization: if f->f_lasti == instr_ub - (likely to be a common case) then we already know - instr_lb -- if we stored the matching value of p - somwhere we could skip the first while loop. */ - - /* see comments in compile.c for the description of - co_lnotab. A point to remember: increments to p - should come in pairs -- although we don't care about - the line increments here, treating them as byte - increments gets confusing, to say the least. */ - - bounds->ap_lower = 0; - while (size > 0) { - if (addr + *p > lasti) - break; - addr += *p++; - if (*p) - bounds->ap_lower = addr; - line += *p++; - --size; - } - - /* If lasti and addr don't match exactly, we don't want to - change the lineno slot on the frame or execute a trace - function. Return -1 instead. - */ - if (addr != lasti) - line = -1; - - if (size > 0) { - while (--size >= 0) { - addr += *p++; - if (*p++) - break; - } - bounds->ap_upper = addr; - } - else { - bounds->ap_upper = INT_MAX; - } - - return line; -} diff --git a/sys/src/cmd/python/Objects/complexobject.c b/sys/src/cmd/python/Objects/complexobject.c deleted file mode 100644 index 4de1fb658..000000000 --- a/sys/src/cmd/python/Objects/complexobject.c +++ /dev/null @@ -1,1031 +0,0 @@ - -/* Complex object implementation */ - -/* Borrows heavily from floatobject.c */ - -/* Submitted by Jim Hugunin */ - -#include "Python.h" -#include "structmember.h" - -#ifndef WITHOUT_COMPLEX - -/* Precisions used by repr() and str(), respectively. - - The repr() precision (17 significant decimal digits) is the minimal number - that is guaranteed to have enough precision so that if the number is read - back in the exact same binary value is recreated. This is true for IEEE - floating point by design, and also happens to work for all other modern - hardware. - - The str() precision is chosen so that in most cases, the rounding noise - created by various operations is suppressed, while giving plenty of - precision for practical use. -*/ - -#define PREC_REPR 17 -#define PREC_STR 12 - -/* elementary operations on complex numbers */ - -static Py_complex c_1 = {1., 0.}; - -Py_complex -c_sum(Py_complex a, Py_complex b) -{ - Py_complex r; - r.real = a.real + b.real; - r.imag = a.imag + b.imag; - return r; -} - -Py_complex -c_diff(Py_complex a, Py_complex b) -{ - Py_complex r; - r.real = a.real - b.real; - r.imag = a.imag - b.imag; - return r; -} - -Py_complex -c_neg(Py_complex a) -{ - Py_complex r; - r.real = -a.real; - r.imag = -a.imag; - return r; -} - -Py_complex -c_prod(Py_complex a, Py_complex b) -{ - Py_complex r; - r.real = a.real*b.real - a.imag*b.imag; - r.imag = a.real*b.imag + a.imag*b.real; - return r; -} - -Py_complex -c_quot(Py_complex a, Py_complex b) -{ - /****************************************************************** - This was the original algorithm. It's grossly prone to spurious - overflow and underflow errors. It also merrily divides by 0 despite - checking for that(!). The code still serves a doc purpose here, as - the algorithm following is a simple by-cases transformation of this - one: - - Py_complex r; - double d = b.real*b.real + b.imag*b.imag; - if (d == 0.) - errno = EDOM; - r.real = (a.real*b.real + a.imag*b.imag)/d; - r.imag = (a.imag*b.real - a.real*b.imag)/d; - return r; - ******************************************************************/ - - /* This algorithm is better, and is pretty obvious: first divide the - * numerators and denominator by whichever of {b.real, b.imag} has - * larger magnitude. The earliest reference I found was to CACM - * Algorithm 116 (Complex Division, Robert L. Smith, Stanford - * University). As usual, though, we're still ignoring all IEEE - * endcases. - */ - Py_complex r; /* the result */ - const double abs_breal = b.real < 0 ? -b.real : b.real; - const double abs_bimag = b.imag < 0 ? -b.imag : b.imag; - - if (abs_breal >= abs_bimag) { - /* divide tops and bottom by b.real */ - if (abs_breal == 0.0) { - errno = EDOM; - r.real = r.imag = 0.0; - } - else { - const double ratio = b.imag / b.real; - const double denom = b.real + b.imag * ratio; - r.real = (a.real + a.imag * ratio) / denom; - r.imag = (a.imag - a.real * ratio) / denom; - } - } - else { - /* divide tops and bottom by b.imag */ - const double ratio = b.real / b.imag; - const double denom = b.real * ratio + b.imag; - assert(b.imag != 0.0); - r.real = (a.real * ratio + a.imag) / denom; - r.imag = (a.imag * ratio - a.real) / denom; - } - return r; -} - -Py_complex -c_pow(Py_complex a, Py_complex b) -{ - Py_complex r; - double vabs,len,at,phase; - if (b.real == 0. && b.imag == 0.) { - r.real = 1.; - r.imag = 0.; - } - else if (a.real == 0. && a.imag == 0.) { - if (b.imag != 0. || b.real < 0.) - errno = EDOM; - r.real = 0.; - r.imag = 0.; - } - else { - vabs = hypot(a.real,a.imag); - len = pow(vabs,b.real); - at = atan2(a.imag, a.real); - phase = at*b.real; - if (b.imag != 0.0) { - len /= exp(at*b.imag); - phase += b.imag*log(vabs); - } - r.real = len*cos(phase); - r.imag = len*sin(phase); - } - return r; -} - -static Py_complex -c_powu(Py_complex x, long n) -{ - Py_complex r, p; - long mask = 1; - r = c_1; - p = x; - while (mask > 0 && n >= mask) { - if (n & mask) - r = c_prod(r,p); - mask <<= 1; - p = c_prod(p,p); - } - return r; -} - -static Py_complex -c_powi(Py_complex x, long n) -{ - Py_complex cn; - - if (n > 100 || n < -100) { - cn.real = (double) n; - cn.imag = 0.; - return c_pow(x,cn); - } - else if (n > 0) - return c_powu(x,n); - else - return c_quot(c_1,c_powu(x,-n)); - -} - -static PyObject * -complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval) -{ - PyObject *op; - - op = type->tp_alloc(type, 0); - if (op != NULL) - ((PyComplexObject *)op)->cval = cval; - return op; -} - -PyObject * -PyComplex_FromCComplex(Py_complex cval) -{ - register PyComplexObject *op; - - /* Inline PyObject_New */ - op = (PyComplexObject *) PyObject_MALLOC(sizeof(PyComplexObject)); - if (op == NULL) - return PyErr_NoMemory(); - PyObject_INIT(op, &PyComplex_Type); - op->cval = cval; - return (PyObject *) op; -} - -static PyObject * -complex_subtype_from_doubles(PyTypeObject *type, double real, double imag) -{ - Py_complex c; - c.real = real; - c.imag = imag; - return complex_subtype_from_c_complex(type, c); -} - -PyObject * -PyComplex_FromDoubles(double real, double imag) -{ - Py_complex c; - c.real = real; - c.imag = imag; - return PyComplex_FromCComplex(c); -} - -double -PyComplex_RealAsDouble(PyObject *op) -{ - if (PyComplex_Check(op)) { - return ((PyComplexObject *)op)->cval.real; - } - else { - return PyFloat_AsDouble(op); - } -} - -double -PyComplex_ImagAsDouble(PyObject *op) -{ - if (PyComplex_Check(op)) { - return ((PyComplexObject *)op)->cval.imag; - } - else { - return 0.0; - } -} - -Py_complex -PyComplex_AsCComplex(PyObject *op) -{ - Py_complex cv; - if (PyComplex_Check(op)) { - return ((PyComplexObject *)op)->cval; - } - else { - cv.real = PyFloat_AsDouble(op); - cv.imag = 0.; - return cv; - } -} - -static void -complex_dealloc(PyObject *op) -{ - op->ob_type->tp_free(op); -} - - -static void -complex_to_buf(char *buf, int bufsz, PyComplexObject *v, int precision) -{ - char format[32]; - if (v->cval.real == 0.) { - PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); - PyOS_ascii_formatd(buf, bufsz - 1, format, v->cval.imag); - strncat(buf, "j", 1); - } else { - char re[64], im[64]; - /* Format imaginary part with sign, real part without */ - PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); - PyOS_ascii_formatd(re, sizeof(re), format, v->cval.real); - PyOS_snprintf(format, sizeof(format), "%%+.%ig", precision); - PyOS_ascii_formatd(im, sizeof(im), format, v->cval.imag); - PyOS_snprintf(buf, bufsz, "(%s%sj)", re, im); - } -} - -static int -complex_print(PyComplexObject *v, FILE *fp, int flags) -{ - char buf[100]; - complex_to_buf(buf, sizeof(buf), v, - (flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR); - fputs(buf, fp); - return 0; -} - -static PyObject * -complex_repr(PyComplexObject *v) -{ - char buf[100]; - complex_to_buf(buf, sizeof(buf), v, PREC_REPR); - return PyString_FromString(buf); -} - -static PyObject * -complex_str(PyComplexObject *v) -{ - char buf[100]; - complex_to_buf(buf, sizeof(buf), v, PREC_STR); - return PyString_FromString(buf); -} - -static long -complex_hash(PyComplexObject *v) -{ - long hashreal, hashimag, combined; - hashreal = _Py_HashDouble(v->cval.real); - if (hashreal == -1) - return -1; - hashimag = _Py_HashDouble(v->cval.imag); - if (hashimag == -1) - return -1; - /* Note: if the imaginary part is 0, hashimag is 0 now, - * so the following returns hashreal unchanged. This is - * important because numbers of different types that - * compare equal must have the same hash value, so that - * hash(x + 0*j) must equal hash(x). - */ - combined = hashreal + 1000003 * hashimag; - if (combined == -1) - combined = -2; - return combined; -} - -static PyObject * -complex_add(PyComplexObject *v, PyComplexObject *w) -{ - Py_complex result; - PyFPE_START_PROTECT("complex_add", return 0) - result = c_sum(v->cval,w->cval); - PyFPE_END_PROTECT(result) - return PyComplex_FromCComplex(result); -} - -static PyObject * -complex_sub(PyComplexObject *v, PyComplexObject *w) -{ - Py_complex result; - PyFPE_START_PROTECT("complex_sub", return 0) - result = c_diff(v->cval,w->cval); - PyFPE_END_PROTECT(result) - return PyComplex_FromCComplex(result); -} - -static PyObject * -complex_mul(PyComplexObject *v, PyComplexObject *w) -{ - Py_complex result; - PyFPE_START_PROTECT("complex_mul", return 0) - result = c_prod(v->cval,w->cval); - PyFPE_END_PROTECT(result) - return PyComplex_FromCComplex(result); -} - -static PyObject * -complex_div(PyComplexObject *v, PyComplexObject *w) -{ - Py_complex quot; - PyFPE_START_PROTECT("complex_div", return 0) - errno = 0; - quot = c_quot(v->cval,w->cval); - PyFPE_END_PROTECT(quot) - if (errno == EDOM) { - PyErr_SetString(PyExc_ZeroDivisionError, "complex division"); - return NULL; - } - return PyComplex_FromCComplex(quot); -} - -static PyObject * -complex_classic_div(PyComplexObject *v, PyComplexObject *w) -{ - Py_complex quot; - - if (Py_DivisionWarningFlag >= 2 && - PyErr_Warn(PyExc_DeprecationWarning, - "classic complex division") < 0) - return NULL; - - PyFPE_START_PROTECT("complex_classic_div", return 0) - errno = 0; - quot = c_quot(v->cval,w->cval); - PyFPE_END_PROTECT(quot) - if (errno == EDOM) { - PyErr_SetString(PyExc_ZeroDivisionError, "complex division"); - return NULL; - } - return PyComplex_FromCComplex(quot); -} - -static PyObject * -complex_remainder(PyComplexObject *v, PyComplexObject *w) -{ - Py_complex div, mod; - - if (PyErr_Warn(PyExc_DeprecationWarning, - "complex divmod(), // and % are deprecated") < 0) - return NULL; - - errno = 0; - div = c_quot(v->cval,w->cval); /* The raw divisor value. */ - if (errno == EDOM) { - PyErr_SetString(PyExc_ZeroDivisionError, "complex remainder"); - return NULL; - } - div.real = floor(div.real); /* Use the floor of the real part. */ - div.imag = 0.0; - mod = c_diff(v->cval, c_prod(w->cval, div)); - - return PyComplex_FromCComplex(mod); -} - - -static PyObject * -complex_divmod(PyComplexObject *v, PyComplexObject *w) -{ - Py_complex div, mod; - PyObject *d, *m, *z; - - if (PyErr_Warn(PyExc_DeprecationWarning, - "complex divmod(), // and % are deprecated") < 0) - return NULL; - - errno = 0; - div = c_quot(v->cval,w->cval); /* The raw divisor value. */ - if (errno == EDOM) { - PyErr_SetString(PyExc_ZeroDivisionError, "complex divmod()"); - return NULL; - } - div.real = floor(div.real); /* Use the floor of the real part. */ - div.imag = 0.0; - mod = c_diff(v->cval, c_prod(w->cval, div)); - d = PyComplex_FromCComplex(div); - m = PyComplex_FromCComplex(mod); - z = PyTuple_Pack(2, d, m); - Py_XDECREF(d); - Py_XDECREF(m); - return z; -} - -static PyObject * -complex_pow(PyComplexObject *v, PyObject *w, PyComplexObject *z) -{ - Py_complex p; - Py_complex exponent; - long int_exponent; - - if ((PyObject *)z!=Py_None) { - PyErr_SetString(PyExc_ValueError, "complex modulo"); - return NULL; - } - PyFPE_START_PROTECT("complex_pow", return 0) - errno = 0; - exponent = ((PyComplexObject*)w)->cval; - int_exponent = (long)exponent.real; - if (exponent.imag == 0. && exponent.real == int_exponent) - p = c_powi(v->cval,int_exponent); - else - p = c_pow(v->cval,exponent); - - PyFPE_END_PROTECT(p) - Py_ADJUST_ERANGE2(p.real, p.imag); - if (errno == EDOM) { - PyErr_SetString(PyExc_ZeroDivisionError, - "0.0 to a negative or complex power"); - return NULL; - } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, - "complex exponentiation"); - return NULL; - } - return PyComplex_FromCComplex(p); -} - -static PyObject * -complex_int_div(PyComplexObject *v, PyComplexObject *w) -{ - PyObject *t, *r; - - t = complex_divmod(v, w); - if (t != NULL) { - r = PyTuple_GET_ITEM(t, 0); - Py_INCREF(r); - Py_DECREF(t); - return r; - } - return NULL; -} - -static PyObject * -complex_neg(PyComplexObject *v) -{ - Py_complex neg; - neg.real = -v->cval.real; - neg.imag = -v->cval.imag; - return PyComplex_FromCComplex(neg); -} - -static PyObject * -complex_pos(PyComplexObject *v) -{ - if (PyComplex_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return PyComplex_FromCComplex(v->cval); -} - -static PyObject * -complex_abs(PyComplexObject *v) -{ - double result; - PyFPE_START_PROTECT("complex_abs", return 0) - result = hypot(v->cval.real,v->cval.imag); - PyFPE_END_PROTECT(result) - return PyFloat_FromDouble(result); -} - -static int -complex_nonzero(PyComplexObject *v) -{ - return v->cval.real != 0.0 || v->cval.imag != 0.0; -} - -static int -complex_coerce(PyObject **pv, PyObject **pw) -{ - Py_complex cval; - cval.imag = 0.; - if (PyInt_Check(*pw)) { - cval.real = (double)PyInt_AsLong(*pw); - *pw = PyComplex_FromCComplex(cval); - Py_INCREF(*pv); - return 0; - } - else if (PyLong_Check(*pw)) { - cval.real = PyLong_AsDouble(*pw); - if (cval.real == -1.0 && PyErr_Occurred()) - return -1; - *pw = PyComplex_FromCComplex(cval); - Py_INCREF(*pv); - return 0; - } - else if (PyFloat_Check(*pw)) { - cval.real = PyFloat_AsDouble(*pw); - *pw = PyComplex_FromCComplex(cval); - Py_INCREF(*pv); - return 0; - } - else if (PyComplex_Check(*pw)) { - Py_INCREF(*pv); - Py_INCREF(*pw); - return 0; - } - return 1; /* Can't do it */ -} - -static PyObject * -complex_richcompare(PyObject *v, PyObject *w, int op) -{ - int c; - Py_complex i, j; - PyObject *res; - - c = PyNumber_CoerceEx(&v, &w); - if (c < 0) - return NULL; - if (c > 0) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - /* Make sure both arguments are complex. */ - if (!(PyComplex_Check(v) && PyComplex_Check(w))) { - Py_DECREF(v); - Py_DECREF(w); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - i = ((PyComplexObject *)v)->cval; - j = ((PyComplexObject *)w)->cval; - Py_DECREF(v); - Py_DECREF(w); - - if (op != Py_EQ && op != Py_NE) { - PyErr_SetString(PyExc_TypeError, - "no ordering relation is defined for complex numbers"); - return NULL; - } - - if ((i.real == j.real && i.imag == j.imag) == (op == Py_EQ)) - res = Py_True; - else - res = Py_False; - - Py_INCREF(res); - return res; -} - -static PyObject * -complex_int(PyObject *v) -{ - PyErr_SetString(PyExc_TypeError, - "can't convert complex to int; use int(abs(z))"); - return NULL; -} - -static PyObject * -complex_long(PyObject *v) -{ - PyErr_SetString(PyExc_TypeError, - "can't convert complex to long; use long(abs(z))"); - return NULL; -} - -static PyObject * -complex_float(PyObject *v) -{ - PyErr_SetString(PyExc_TypeError, - "can't convert complex to float; use abs(z)"); - return NULL; -} - -static PyObject * -complex_conjugate(PyObject *self) -{ - Py_complex c; - c = ((PyComplexObject *)self)->cval; - c.imag = -c.imag; - return PyComplex_FromCComplex(c); -} - -static PyObject * -complex_getnewargs(PyComplexObject *v) -{ - return Py_BuildValue("(D)", &v->cval); -} - -static PyMethodDef complex_methods[] = { - {"conjugate", (PyCFunction)complex_conjugate, METH_NOARGS}, - {"__getnewargs__", (PyCFunction)complex_getnewargs, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyMemberDef complex_members[] = { - {"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), READONLY, - "the real part of a complex number"}, - {"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), READONLY, - "the imaginary part of a complex number"}, - {0}, -}; - -static PyObject * -complex_subtype_from_string(PyTypeObject *type, PyObject *v) -{ - const char *s, *start; - char *end; - double x=0.0, y=0.0, z; - int got_re=0, got_im=0, done=0; - int digit_or_dot; - int sw_error=0; - int sign; - char buffer[256]; /* For errors */ -#ifdef Py_USING_UNICODE - char s_buffer[256]; -#endif - Py_ssize_t len; - - if (PyString_Check(v)) { - s = PyString_AS_STRING(v); - len = PyString_GET_SIZE(v); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(v)) { - if (PyUnicode_GET_SIZE(v) >= (Py_ssize_t)sizeof(s_buffer)) { - PyErr_SetString(PyExc_ValueError, - "complex() literal too large to convert"); - return NULL; - } - if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), - PyUnicode_GET_SIZE(v), - s_buffer, - NULL)) - return NULL; - s = s_buffer; - len = strlen(s); - } -#endif - else if (PyObject_AsCharBuffer(v, &s, &len)) { - PyErr_SetString(PyExc_TypeError, - "complex() arg is not a string"); - return NULL; - } - - /* position on first nonblank */ - start = s; - while (*s && isspace(Py_CHARMASK(*s))) - s++; - if (s[0] == '\0') { - PyErr_SetString(PyExc_ValueError, - "complex() arg is an empty string"); - return NULL; - } - - z = -1.0; - sign = 1; - do { - - switch (*s) { - - case '\0': - if (s-start != len) { - PyErr_SetString( - PyExc_ValueError, - "complex() arg contains a null byte"); - return NULL; - } - if(!done) sw_error=1; - break; - - case '-': - sign = -1; - /* Fallthrough */ - case '+': - if (done) sw_error=1; - s++; - if ( *s=='\0'||*s=='+'||*s=='-' || - isspace(Py_CHARMASK(*s)) ) sw_error=1; - break; - - case 'J': - case 'j': - if (got_im || done) { - sw_error = 1; - break; - } - if (z<0.0) { - y=sign; - } - else{ - y=sign*z; - } - got_im=1; - s++; - if (*s!='+' && *s!='-' ) - done=1; - break; - - default: - if (isspace(Py_CHARMASK(*s))) { - while (*s && isspace(Py_CHARMASK(*s))) - s++; - if (s[0] != '\0') - sw_error=1; - else - done = 1; - break; - } - digit_or_dot = - (*s=='.' || isdigit(Py_CHARMASK(*s))); - if (done||!digit_or_dot) { - sw_error=1; - break; - } - errno = 0; - PyFPE_START_PROTECT("strtod", return 0) - z = PyOS_ascii_strtod(s, &end) ; - PyFPE_END_PROTECT(z) - if (errno != 0) { - PyOS_snprintf(buffer, sizeof(buffer), - "float() out of range: %.150s", s); - PyErr_SetString( - PyExc_ValueError, - buffer); - return NULL; - } - s=end; - if (*s=='J' || *s=='j') { - - break; - } - if (got_re) { - sw_error=1; - break; - } - - /* accept a real part */ - x=sign*z; - got_re=1; - if (got_im) done=1; - z = -1.0; - sign = 1; - break; - - } /* end of switch */ - - } while (s - start < len && !sw_error); - - if (sw_error) { - PyErr_SetString(PyExc_ValueError, - "complex() arg is a malformed string"); - return NULL; - } - - return complex_subtype_from_doubles(type, x, y); -} - -static PyObject * -complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *r, *i, *tmp, *f; - PyNumberMethods *nbr, *nbi = NULL; - Py_complex cr, ci; - int own_r = 0; - static PyObject *complexstr; - static char *kwlist[] = {"real", "imag", 0}; - - r = Py_False; - i = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:complex", kwlist, - &r, &i)) - return NULL; - - /* Special-case for single argument that is already complex */ - if (PyComplex_CheckExact(r) && i == NULL && - type == &PyComplex_Type) { - /* Note that we can't know whether it's safe to return - a complex *subclass* instance as-is, hence the restriction - to exact complexes here. */ - Py_INCREF(r); - return r; - } - if (PyString_Check(r) || PyUnicode_Check(r)) { - if (i != NULL) { - PyErr_SetString(PyExc_TypeError, - "complex() can't take second arg" - " if first is a string"); - return NULL; - } - return complex_subtype_from_string(type, r); - } - if (i != NULL && (PyString_Check(i) || PyUnicode_Check(i))) { - PyErr_SetString(PyExc_TypeError, - "complex() second arg can't be a string"); - return NULL; - } - - /* XXX Hack to support classes with __complex__ method */ - if (complexstr == NULL) { - complexstr = PyString_InternFromString("__complex__"); - if (complexstr == NULL) - return NULL; - } - f = PyObject_GetAttr(r, complexstr); - if (f == NULL) - PyErr_Clear(); - else { - PyObject *args = PyTuple_New(0); - if (args == NULL) - return NULL; - r = PyEval_CallObject(f, args); - Py_DECREF(args); - Py_DECREF(f); - if (r == NULL) - return NULL; - own_r = 1; - } - nbr = r->ob_type->tp_as_number; - if (i != NULL) - nbi = i->ob_type->tp_as_number; - if (nbr == NULL || nbr->nb_float == NULL || - ((i != NULL) && (nbi == NULL || nbi->nb_float == NULL))) { - PyErr_SetString(PyExc_TypeError, - "complex() argument must be a string or a number"); - if (own_r) { - Py_DECREF(r); - } - return NULL; - } - if (PyComplex_Check(r)) { - /* Note that if r is of a complex subtype, we're only - retaining its real & imag parts here, and the return - value is (properly) of the builtin complex type. */ - cr = ((PyComplexObject*)r)->cval; - if (own_r) { - Py_DECREF(r); - } - } - else { - tmp = PyNumber_Float(r); - if (own_r) { - Py_DECREF(r); - } - if (tmp == NULL) - return NULL; - if (!PyFloat_Check(tmp)) { - PyErr_SetString(PyExc_TypeError, - "float(r) didn't return a float"); - Py_DECREF(tmp); - return NULL; - } - cr.real = PyFloat_AsDouble(tmp); - Py_DECREF(tmp); - cr.imag = 0.0; - } - if (i == NULL) { - ci.real = 0.0; - ci.imag = 0.0; - } - else if (PyComplex_Check(i)) - ci = ((PyComplexObject*)i)->cval; - else { - tmp = (*nbi->nb_float)(i); - if (tmp == NULL) - return NULL; - ci.real = PyFloat_AsDouble(tmp); - Py_DECREF(tmp); - ci.imag = 0.; - } - cr.real -= ci.imag; - cr.imag += ci.real; - return complex_subtype_from_c_complex(type, cr); -} - -PyDoc_STRVAR(complex_doc, -"complex(real[, imag]) -> complex number\n" -"\n" -"Create a complex number from a real part and an optional imaginary part.\n" -"This is equivalent to (real + imag*1j) where imag defaults to 0."); - -static PyNumberMethods complex_as_number = { - (binaryfunc)complex_add, /* nb_add */ - (binaryfunc)complex_sub, /* nb_subtract */ - (binaryfunc)complex_mul, /* nb_multiply */ - (binaryfunc)complex_classic_div, /* nb_divide */ - (binaryfunc)complex_remainder, /* nb_remainder */ - (binaryfunc)complex_divmod, /* nb_divmod */ - (ternaryfunc)complex_pow, /* nb_power */ - (unaryfunc)complex_neg, /* nb_negative */ - (unaryfunc)complex_pos, /* nb_positive */ - (unaryfunc)complex_abs, /* nb_absolute */ - (inquiry)complex_nonzero, /* nb_nonzero */ - 0, /* nb_invert */ - 0, /* nb_lshift */ - 0, /* nb_rshift */ - 0, /* nb_and */ - 0, /* nb_xor */ - 0, /* nb_or */ - complex_coerce, /* nb_coerce */ - complex_int, /* nb_int */ - complex_long, /* nb_long */ - complex_float, /* nb_float */ - 0, /* nb_oct */ - 0, /* nb_hex */ - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply*/ - 0, /* nb_inplace_divide */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - (binaryfunc)complex_int_div, /* nb_floor_divide */ - (binaryfunc)complex_div, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ -}; - -PyTypeObject PyComplex_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "complex", - sizeof(PyComplexObject), - 0, - complex_dealloc, /* tp_dealloc */ - (printfunc)complex_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)complex_repr, /* tp_repr */ - &complex_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)complex_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)complex_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - complex_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - complex_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - complex_methods, /* tp_methods */ - complex_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - complex_new, /* tp_new */ - PyObject_Del, /* tp_free */ -}; - -#endif diff --git a/sys/src/cmd/python/Objects/descrobject.c b/sys/src/cmd/python/Objects/descrobject.c deleted file mode 100644 index 914b6d35a..000000000 --- a/sys/src/cmd/python/Objects/descrobject.c +++ /dev/null @@ -1,1283 +0,0 @@ -/* Descriptors -- a new, flexible way to describe attributes */ - -#include "Python.h" -#include "structmember.h" /* Why is this not included in Python.h? */ - -static void -descr_dealloc(PyDescrObject *descr) -{ - _PyObject_GC_UNTRACK(descr); - Py_XDECREF(descr->d_type); - Py_XDECREF(descr->d_name); - PyObject_GC_Del(descr); -} - -static char * -descr_name(PyDescrObject *descr) -{ - if (descr->d_name != NULL && PyString_Check(descr->d_name)) - return PyString_AS_STRING(descr->d_name); - else - return "?"; -} - -static PyObject * -descr_repr(PyDescrObject *descr, char *format) -{ - return PyString_FromFormat(format, descr_name(descr), - descr->d_type->tp_name); -} - -static PyObject * -method_repr(PyMethodDescrObject *descr) -{ - return descr_repr((PyDescrObject *)descr, - "<method '%s' of '%s' objects>"); -} - -static PyObject * -member_repr(PyMemberDescrObject *descr) -{ - return descr_repr((PyDescrObject *)descr, - "<member '%s' of '%s' objects>"); -} - -static PyObject * -getset_repr(PyGetSetDescrObject *descr) -{ - return descr_repr((PyDescrObject *)descr, - "<attribute '%s' of '%s' objects>"); -} - -static PyObject * -wrapperdescr_repr(PyWrapperDescrObject *descr) -{ - return descr_repr((PyDescrObject *)descr, - "<slot wrapper '%s' of '%s' objects>"); -} - -static int -descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres) -{ - if (obj == NULL) { - Py_INCREF(descr); - *pres = (PyObject *)descr; - return 1; - } - if (!PyObject_TypeCheck(obj, descr->d_type)) { - PyErr_Format(PyExc_TypeError, - "descriptor '%s' for '%s' objects " - "doesn't apply to '%s' object", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name, - obj->ob_type->tp_name); - *pres = NULL; - return 1; - } - return 0; -} - -static PyObject * -classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) -{ - /* Ensure a valid type. Class methods ignore obj. */ - if (type == NULL) { - if (obj != NULL) - type = (PyObject *)obj->ob_type; - else { - /* Wot - no type?! */ - PyErr_Format(PyExc_TypeError, - "descriptor '%s' for type '%s' " - "needs either an object or a type", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name); - return NULL; - } - } - if (!PyType_Check(type)) { - PyErr_Format(PyExc_TypeError, - "descriptor '%s' for type '%s' " - "needs a type, not a '%s' as arg 2", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name, - type->ob_type->tp_name); - return NULL; - } - if (!PyType_IsSubtype((PyTypeObject *)type, descr->d_type)) { - PyErr_Format(PyExc_TypeError, - "descriptor '%s' for type '%s' " - "doesn't apply to type '%s'", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name, - ((PyTypeObject *)type)->tp_name); - return NULL; - } - return PyCFunction_New(descr->d_method, type); -} - -static PyObject * -method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) -{ - PyObject *res; - - if (descr_check((PyDescrObject *)descr, obj, &res)) - return res; - return PyCFunction_New(descr->d_method, obj); -} - -static PyObject * -member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type) -{ - PyObject *res; - - if (descr_check((PyDescrObject *)descr, obj, &res)) - return res; - return PyMember_GetOne((char *)obj, descr->d_member); -} - -static PyObject * -getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) -{ - PyObject *res; - - if (descr_check((PyDescrObject *)descr, obj, &res)) - return res; - if (descr->d_getset->get != NULL) - return descr->d_getset->get(obj, descr->d_getset->closure); - PyErr_Format(PyExc_AttributeError, - "attribute '%.300s' of '%.100s' objects is not readable", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name); - return NULL; -} - -static PyObject * -wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type) -{ - PyObject *res; - - if (descr_check((PyDescrObject *)descr, obj, &res)) - return res; - return PyWrapper_New((PyObject *)descr, obj); -} - -static int -descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value, - int *pres) -{ - assert(obj != NULL); - if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) { - PyErr_Format(PyExc_TypeError, - "descriptor '%.200s' for '%.100s' objects " - "doesn't apply to '%.100s' object", - descr_name(descr), - descr->d_type->tp_name, - obj->ob_type->tp_name); - *pres = -1; - return 1; - } - return 0; -} - -static int -member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value) -{ - int res; - - if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) - return res; - return PyMember_SetOne((char *)obj, descr->d_member, value); -} - -static int -getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) -{ - int res; - - if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) - return res; - if (descr->d_getset->set != NULL) - return descr->d_getset->set(obj, value, - descr->d_getset->closure); - PyErr_Format(PyExc_AttributeError, - "attribute '%.300s' of '%.100s' objects is not writable", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name); - return -1; -} - -static PyObject * -methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) -{ - Py_ssize_t argc; - PyObject *self, *func, *result; - - /* Make sure that the first argument is acceptable as 'self' */ - assert(PyTuple_Check(args)); - argc = PyTuple_GET_SIZE(args); - if (argc < 1) { - PyErr_Format(PyExc_TypeError, - "descriptor '%.300s' of '%.100s' " - "object needs an argument", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name); - return NULL; - } - self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { - PyErr_Format(PyExc_TypeError, - "descriptor '%.200s' " - "requires a '%.100s' object " - "but received a '%.100s'", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name, - self->ob_type->tp_name); - return NULL; - } - - func = PyCFunction_New(descr->d_method, self); - if (func == NULL) - return NULL; - args = PyTuple_GetSlice(args, 1, argc); - if (args == NULL) { - Py_DECREF(func); - return NULL; - } - result = PyEval_CallObjectWithKeywords(func, args, kwds); - Py_DECREF(args); - Py_DECREF(func); - return result; -} - -static PyObject * -classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, - PyObject *kwds) -{ - PyObject *func, *result; - - func = PyCFunction_New(descr->d_method, (PyObject *)descr->d_type); - if (func == NULL) - return NULL; - - result = PyEval_CallObjectWithKeywords(func, args, kwds); - Py_DECREF(func); - return result; -} - -static PyObject * -wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) -{ - Py_ssize_t argc; - PyObject *self, *func, *result; - - /* Make sure that the first argument is acceptable as 'self' */ - assert(PyTuple_Check(args)); - argc = PyTuple_GET_SIZE(args); - if (argc < 1) { - PyErr_Format(PyExc_TypeError, - "descriptor '%.300s' of '%.100s' " - "object needs an argument", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name); - return NULL; - } - self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { - PyErr_Format(PyExc_TypeError, - "descriptor '%.200s' " - "requires a '%.100s' object " - "but received a '%.100s'", - descr_name((PyDescrObject *)descr), - descr->d_type->tp_name, - self->ob_type->tp_name); - return NULL; - } - - func = PyWrapper_New((PyObject *)descr, self); - if (func == NULL) - return NULL; - args = PyTuple_GetSlice(args, 1, argc); - if (args == NULL) { - Py_DECREF(func); - return NULL; - } - result = PyEval_CallObjectWithKeywords(func, args, kwds); - Py_DECREF(args); - Py_DECREF(func); - return result; -} - -static PyObject * -method_get_doc(PyMethodDescrObject *descr, void *closure) -{ - if (descr->d_method->ml_doc == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return PyString_FromString(descr->d_method->ml_doc); -} - -static PyMemberDef descr_members[] = { - {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY}, - {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY}, - {0} -}; - -static PyGetSetDef method_getset[] = { - {"__doc__", (getter)method_get_doc}, - {0} -}; - -static PyObject * -member_get_doc(PyMemberDescrObject *descr, void *closure) -{ - if (descr->d_member->doc == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return PyString_FromString(descr->d_member->doc); -} - -static PyGetSetDef member_getset[] = { - {"__doc__", (getter)member_get_doc}, - {0} -}; - -static PyObject * -getset_get_doc(PyGetSetDescrObject *descr, void *closure) -{ - if (descr->d_getset->doc == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return PyString_FromString(descr->d_getset->doc); -} - -static PyGetSetDef getset_getset[] = { - {"__doc__", (getter)getset_get_doc}, - {0} -}; - -static PyObject * -wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure) -{ - if (descr->d_base->doc == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return PyString_FromString(descr->d_base->doc); -} - -static PyGetSetDef wrapperdescr_getset[] = { - {"__doc__", (getter)wrapperdescr_get_doc}, - {0} -}; - -static int -descr_traverse(PyObject *self, visitproc visit, void *arg) -{ - PyDescrObject *descr = (PyDescrObject *)self; - Py_VISIT(descr->d_type); - return 0; -} - -static PyTypeObject PyMethodDescr_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "method_descriptor", - sizeof(PyMethodDescrObject), - 0, - (destructor)descr_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)method_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)methoddescr_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - descr_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - descr_members, /* tp_members */ - method_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - (descrgetfunc)method_get, /* tp_descr_get */ - 0, /* tp_descr_set */ -}; - -/* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */ -static PyTypeObject PyClassMethodDescr_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "classmethod_descriptor", - sizeof(PyMethodDescrObject), - 0, - (destructor)descr_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)method_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)classmethoddescr_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - descr_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - descr_members, /* tp_members */ - method_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - (descrgetfunc)classmethod_get, /* tp_descr_get */ - 0, /* tp_descr_set */ -}; - -static PyTypeObject PyMemberDescr_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "member_descriptor", - sizeof(PyMemberDescrObject), - 0, - (destructor)descr_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)member_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - descr_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - descr_members, /* tp_members */ - member_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - (descrgetfunc)member_get, /* tp_descr_get */ - (descrsetfunc)member_set, /* tp_descr_set */ -}; - -static PyTypeObject PyGetSetDescr_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "getset_descriptor", - sizeof(PyGetSetDescrObject), - 0, - (destructor)descr_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)getset_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - descr_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - descr_members, /* tp_members */ - getset_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - (descrgetfunc)getset_get, /* tp_descr_get */ - (descrsetfunc)getset_set, /* tp_descr_set */ -}; - -PyTypeObject PyWrapperDescr_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "wrapper_descriptor", - sizeof(PyWrapperDescrObject), - 0, - (destructor)descr_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)wrapperdescr_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)wrapperdescr_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - descr_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - descr_members, /* tp_members */ - wrapperdescr_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - (descrgetfunc)wrapperdescr_get, /* tp_descr_get */ - 0, /* tp_descr_set */ -}; - -static PyDescrObject * -descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name) -{ - PyDescrObject *descr; - - descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0); - if (descr != NULL) { - Py_XINCREF(type); - descr->d_type = type; - descr->d_name = PyString_InternFromString(name); - if (descr->d_name == NULL) { - Py_DECREF(descr); - descr = NULL; - } - } - return descr; -} - -PyObject * -PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method) -{ - PyMethodDescrObject *descr; - - descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type, - type, method->ml_name); - if (descr != NULL) - descr->d_method = method; - return (PyObject *)descr; -} - -PyObject * -PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) -{ - PyMethodDescrObject *descr; - - descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type, - type, method->ml_name); - if (descr != NULL) - descr->d_method = method; - return (PyObject *)descr; -} - -PyObject * -PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member) -{ - PyMemberDescrObject *descr; - - descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type, - type, member->name); - if (descr != NULL) - descr->d_member = member; - return (PyObject *)descr; -} - -PyObject * -PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset) -{ - PyGetSetDescrObject *descr; - - descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type, - type, getset->name); - if (descr != NULL) - descr->d_getset = getset; - return (PyObject *)descr; -} - -PyObject * -PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) -{ - PyWrapperDescrObject *descr; - - descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type, - type, base->name); - if (descr != NULL) { - descr->d_base = base; - descr->d_wrapped = wrapped; - } - return (PyObject *)descr; -} - - -/* --- Readonly proxy for dictionaries (actually any mapping) --- */ - -/* This has no reason to be in this file except that adding new files is a - bit of a pain */ - -typedef struct { - PyObject_HEAD - PyObject *dict; -} proxyobject; - -static Py_ssize_t -proxy_len(proxyobject *pp) -{ - return PyObject_Size(pp->dict); -} - -static PyObject * -proxy_getitem(proxyobject *pp, PyObject *key) -{ - return PyObject_GetItem(pp->dict, key); -} - -static PyMappingMethods proxy_as_mapping = { - (lenfunc)proxy_len, /* mp_length */ - (binaryfunc)proxy_getitem, /* mp_subscript */ - 0, /* mp_ass_subscript */ -}; - -static int -proxy_contains(proxyobject *pp, PyObject *key) -{ - return PyDict_Contains(pp->dict, key); -} - -static PySequenceMethods proxy_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - 0, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)proxy_contains, /* sq_contains */ - 0, /* sq_inplace_concat */ - 0, /* sq_inplace_repeat */ -}; - -static PyObject * -proxy_has_key(proxyobject *pp, PyObject *key) -{ - int res = PyDict_Contains(pp->dict, key); - if (res < 0) - return NULL; - return PyBool_FromLong(res); -} - -static PyObject * -proxy_get(proxyobject *pp, PyObject *args) -{ - PyObject *key, *def = Py_None; - - if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) - return NULL; - return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def); -} - -static PyObject * -proxy_keys(proxyobject *pp) -{ - return PyMapping_Keys(pp->dict); -} - -static PyObject * -proxy_values(proxyobject *pp) -{ - return PyMapping_Values(pp->dict); -} - -static PyObject * -proxy_items(proxyobject *pp) -{ - return PyMapping_Items(pp->dict); -} - -static PyObject * -proxy_iterkeys(proxyobject *pp) -{ - return PyObject_CallMethod(pp->dict, "iterkeys", NULL); -} - -static PyObject * -proxy_itervalues(proxyobject *pp) -{ - return PyObject_CallMethod(pp->dict, "itervalues", NULL); -} - -static PyObject * -proxy_iteritems(proxyobject *pp) -{ - return PyObject_CallMethod(pp->dict, "iteritems", NULL); -} -static PyObject * -proxy_copy(proxyobject *pp) -{ - return PyObject_CallMethod(pp->dict, "copy", NULL); -} - -static PyMethodDef proxy_methods[] = { - {"has_key", (PyCFunction)proxy_has_key, METH_O, - PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")}, - {"get", (PyCFunction)proxy_get, METH_VARARGS, - PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d." - " d defaults to None.")}, - {"keys", (PyCFunction)proxy_keys, METH_NOARGS, - PyDoc_STR("D.keys() -> list of D's keys")}, - {"values", (PyCFunction)proxy_values, METH_NOARGS, - PyDoc_STR("D.values() -> list of D's values")}, - {"items", (PyCFunction)proxy_items, METH_NOARGS, - PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")}, - {"iterkeys", (PyCFunction)proxy_iterkeys, METH_NOARGS, - PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")}, - {"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS, - PyDoc_STR("D.itervalues() -> an iterator over the values of D")}, - {"iteritems", (PyCFunction)proxy_iteritems, METH_NOARGS, - PyDoc_STR("D.iteritems() ->" - " an iterator over the (key, value) items of D")}, - {"copy", (PyCFunction)proxy_copy, METH_NOARGS, - PyDoc_STR("D.copy() -> a shallow copy of D")}, - {0} -}; - -static void -proxy_dealloc(proxyobject *pp) -{ - _PyObject_GC_UNTRACK(pp); - Py_DECREF(pp->dict); - PyObject_GC_Del(pp); -} - -static PyObject * -proxy_getiter(proxyobject *pp) -{ - return PyObject_GetIter(pp->dict); -} - -static PyObject * -proxy_str(proxyobject *pp) -{ - return PyObject_Str(pp->dict); -} - -static int -proxy_traverse(PyObject *self, visitproc visit, void *arg) -{ - proxyobject *pp = (proxyobject *)self; - Py_VISIT(pp->dict); - return 0; -} - -static int -proxy_compare(proxyobject *v, PyObject *w) -{ - return PyObject_Compare(v->dict, w); -} - -static PyObject * -proxy_richcompare(proxyobject *v, PyObject *w, int op) -{ - return PyObject_RichCompare(v->dict, w, op); -} - -static PyTypeObject proxytype = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "dictproxy", /* tp_name */ - sizeof(proxyobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)proxy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)proxy_compare, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &proxy_as_sequence, /* tp_as_sequence */ - &proxy_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)proxy_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - proxy_traverse, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)proxy_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)proxy_getiter, /* tp_iter */ - 0, /* tp_iternext */ - proxy_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ -}; - -PyObject * -PyDictProxy_New(PyObject *dict) -{ - proxyobject *pp; - - pp = PyObject_GC_New(proxyobject, &proxytype); - if (pp != NULL) { - Py_INCREF(dict); - pp->dict = dict; - _PyObject_GC_TRACK(pp); - } - return (PyObject *)pp; -} - - -/* --- Wrapper object for "slot" methods --- */ - -/* This has no reason to be in this file except that adding new files is a - bit of a pain */ - -typedef struct { - PyObject_HEAD - PyWrapperDescrObject *descr; - PyObject *self; -} wrapperobject; - -static void -wrapper_dealloc(wrapperobject *wp) -{ - PyObject_GC_UnTrack(wp); - Py_TRASHCAN_SAFE_BEGIN(wp) - Py_XDECREF(wp->descr); - Py_XDECREF(wp->self); - PyObject_GC_Del(wp); - Py_TRASHCAN_SAFE_END(wp) -} - -static int -wrapper_compare(wrapperobject *a, wrapperobject *b) -{ - if (a->descr == b->descr) - return PyObject_Compare(a->self, b->self); - else - return (a->descr < b->descr) ? -1 : 1; -} - -static long -wrapper_hash(wrapperobject *wp) -{ - int x, y; - x = _Py_HashPointer(wp->descr); - if (x == -1) - return -1; - y = PyObject_Hash(wp->self); - if (y == -1) - return -1; - x = x ^ y; - if (x == -1) - x = -2; - return x; -} - -static PyObject * -wrapper_repr(wrapperobject *wp) -{ - return PyString_FromFormat("<method-wrapper '%s' of %s object at %p>", - wp->descr->d_base->name, - wp->self->ob_type->tp_name, - wp->self); -} - -static PyMemberDef wrapper_members[] = { - {"__self__", T_OBJECT, offsetof(wrapperobject, self), READONLY}, - {0} -}; - -static PyObject * -wrapper_objclass(wrapperobject *wp) -{ - PyObject *c = (PyObject *)wp->descr->d_type; - - Py_INCREF(c); - return c; -} - -static PyObject * -wrapper_name(wrapperobject *wp) -{ - char *s = wp->descr->d_base->name; - - return PyString_FromString(s); -} - -static PyObject * -wrapper_doc(wrapperobject *wp) -{ - char *s = wp->descr->d_base->doc; - - if (s == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - else { - return PyString_FromString(s); - } -} - -static PyGetSetDef wrapper_getsets[] = { - {"__objclass__", (getter)wrapper_objclass}, - {"__name__", (getter)wrapper_name}, - {"__doc__", (getter)wrapper_doc}, - {0} -}; - -static PyObject * -wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) -{ - wrapperfunc wrapper = wp->descr->d_base->wrapper; - PyObject *self = wp->self; - - if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) { - wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper; - return (*wk)(self, args, wp->descr->d_wrapped, kwds); - } - - if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) { - PyErr_Format(PyExc_TypeError, - "wrapper %s doesn't take keyword arguments", - wp->descr->d_base->name); - return NULL; - } - return (*wrapper)(self, args, wp->descr->d_wrapped); -} - -static int -wrapper_traverse(PyObject *self, visitproc visit, void *arg) -{ - wrapperobject *wp = (wrapperobject *)self; - Py_VISIT(wp->descr); - Py_VISIT(wp->self); - return 0; -} - -static PyTypeObject wrappertype = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "method-wrapper", /* tp_name */ - sizeof(wrapperobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)wrapper_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)wrapper_compare, /* tp_compare */ - (reprfunc)wrapper_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)wrapper_hash, /* tp_hash */ - (ternaryfunc)wrapper_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - wrapper_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - wrapper_members, /* tp_members */ - wrapper_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ -}; - -PyObject * -PyWrapper_New(PyObject *d, PyObject *self) -{ - wrapperobject *wp; - PyWrapperDescrObject *descr; - - assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); - descr = (PyWrapperDescrObject *)d; - assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type))); - - wp = PyObject_GC_New(wrapperobject, &wrappertype); - if (wp != NULL) { - Py_INCREF(descr); - wp->descr = descr; - Py_INCREF(self); - wp->self = self; - _PyObject_GC_TRACK(wp); - } - return (PyObject *)wp; -} - - -/* A built-in 'property' type */ - -/* - class property(object): - - def __init__(self, fget=None, fset=None, fdel=None, doc=None): - if doc is None and fget is not None and hasattr(fget, "__doc__"): - doc = fget.__doc__ - self.__get = fget - self.__set = fset - self.__del = fdel - self.__doc__ = doc - - def __get__(self, inst, type=None): - if inst is None: - return self - if self.__get is None: - raise AttributeError, "unreadable attribute" - return self.__get(inst) - - def __set__(self, inst, value): - if self.__set is None: - raise AttributeError, "can't set attribute" - return self.__set(inst, value) - - def __delete__(self, inst): - if self.__del is None: - raise AttributeError, "can't delete attribute" - return self.__del(inst) - -*/ - -typedef struct { - PyObject_HEAD - PyObject *prop_get; - PyObject *prop_set; - PyObject *prop_del; - PyObject *prop_doc; -} propertyobject; - -static PyMemberDef property_members[] = { - {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY}, - {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, - {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, - {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY}, - {0} -}; - - -static void -property_dealloc(PyObject *self) -{ - propertyobject *gs = (propertyobject *)self; - - _PyObject_GC_UNTRACK(self); - Py_XDECREF(gs->prop_get); - Py_XDECREF(gs->prop_set); - Py_XDECREF(gs->prop_del); - Py_XDECREF(gs->prop_doc); - self->ob_type->tp_free(self); -} - -static PyObject * -property_descr_get(PyObject *self, PyObject *obj, PyObject *type) -{ - propertyobject *gs = (propertyobject *)self; - - if (obj == NULL || obj == Py_None) { - Py_INCREF(self); - return self; - } - if (gs->prop_get == NULL) { - PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); - return NULL; - } - return PyObject_CallFunction(gs->prop_get, "(O)", obj); -} - -static int -property_descr_set(PyObject *self, PyObject *obj, PyObject *value) -{ - propertyobject *gs = (propertyobject *)self; - PyObject *func, *res; - - if (value == NULL) - func = gs->prop_del; - else - func = gs->prop_set; - if (func == NULL) { - PyErr_SetString(PyExc_AttributeError, - value == NULL ? - "can't delete attribute" : - "can't set attribute"); - return -1; - } - if (value == NULL) - res = PyObject_CallFunction(func, "(O)", obj); - else - res = PyObject_CallFunction(func, "(OO)", obj, value); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -static int -property_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; - static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; - propertyobject *gs = (propertyobject *)self; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", - kwlist, &get, &set, &del, &doc)) - return -1; - - if (get == Py_None) - get = NULL; - if (set == Py_None) - set = NULL; - if (del == Py_None) - del = NULL; - - Py_XINCREF(get); - Py_XINCREF(set); - Py_XINCREF(del); - Py_XINCREF(doc); - - /* if no docstring given and the getter has one, use that one */ - if ((doc == NULL || doc == Py_None) && get != NULL) { - PyObject *get_doc = PyObject_GetAttrString(get, "__doc__"); - if (get_doc != NULL) { - Py_XDECREF(doc); - doc = get_doc; /* get_doc already INCREF'd by GetAttr */ - } else { - PyErr_Clear(); - } - } - - gs->prop_get = get; - gs->prop_set = set; - gs->prop_del = del; - gs->prop_doc = doc; - - return 0; -} - -PyDoc_STRVAR(property_doc, -"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n" -"\n" -"fget is a function to be used for getting an attribute value, and likewise\n" -"fset is a function for setting, and fdel a function for del'ing, an\n" -"attribute. Typical use is to define a managed attribute x:\n" -"class C(object):\n" -" def getx(self): return self.__x\n" -" def setx(self, value): self.__x = value\n" -" def delx(self): del self.__x\n" -" x = property(getx, setx, delx, \"I'm the 'x' property.\")"); - -static int -property_traverse(PyObject *self, visitproc visit, void *arg) -{ - propertyobject *pp = (propertyobject *)self; - Py_VISIT(pp->prop_get); - Py_VISIT(pp->prop_set); - Py_VISIT(pp->prop_del); - Py_VISIT(pp->prop_doc); - return 0; -} - -PyTypeObject PyProperty_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "property", /* tp_name */ - sizeof(propertyobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - property_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - property_doc, /* tp_doc */ - property_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - property_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - property_descr_get, /* tp_descr_get */ - property_descr_set, /* tp_descr_set */ - 0, /* tp_dictoffset */ - property_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; diff --git a/sys/src/cmd/python/Objects/dictnotes.txt b/sys/src/cmd/python/Objects/dictnotes.txt deleted file mode 100644 index b0e59a7f1..000000000 --- a/sys/src/cmd/python/Objects/dictnotes.txt +++ /dev/null @@ -1,250 +0,0 @@ -NOTES ON OPTIMIZING DICTIONARIES -================================ - - -Principal Use Cases for Dictionaries ------------------------------------- - -Passing keyword arguments - Typically, one read and one write for 1 to 3 elements. - Occurs frequently in normal python code. - -Class method lookup - Dictionaries vary in size with 8 to 16 elements being common. - Usually written once with many lookups. - When base classes are used, there are many failed lookups - followed by a lookup in a base class. - -Instance attribute lookup and Global variables - Dictionaries vary in size. 4 to 10 elements are common. - Both reads and writes are common. - -Builtins - Frequent reads. Almost never written. - Size 126 interned strings (as of Py2.3b1). - A few keys are accessed much more frequently than others. - -Uniquification - Dictionaries of any size. Bulk of work is in creation. - Repeated writes to a smaller set of keys. - Single read of each key. - Some use cases have two consecutive accesses to the same key. - - * Removing duplicates from a sequence. - dict.fromkeys(seqn).keys() - - * Counting elements in a sequence. - for e in seqn: - d[e] = d.get(e,0) + 1 - - * Accumulating references in a dictionary of lists: - - for pagenumber, page in enumerate(pages): - for word in page: - d.setdefault(word, []).append(pagenumber) - - Note, the second example is a use case characterized by a get and set - to the same key. There are similar used cases with a __contains__ - followed by a get, set, or del to the same key. Part of the - justification for d.setdefault is combining the two lookups into one. - -Membership Testing - Dictionaries of any size. Created once and then rarely changes. - Single write to each key. - Many calls to __contains__() or has_key(). - Similar access patterns occur with replacement dictionaries - such as with the % formatting operator. - -Dynamic Mappings - Characterized by deletions interspersed with adds and replacements. - Performance benefits greatly from the re-use of dummy entries. - - -Data Layout (assuming a 32-bit box with 64 bytes per cache line) ----------------------------------------------------------------- - -Smalldicts (8 entries) are attached to the dictobject structure -and the whole group nearly fills two consecutive cache lines. - -Larger dicts use the first half of the dictobject structure (one cache -line) and a separate, continuous block of entries (at 12 bytes each -for a total of 5.333 entries per cache line). - - -Tunable Dictionary Parameters ------------------------------ - -* PyDict_MINSIZE. Currently set to 8. - Must be a power of two. New dicts have to zero-out every cell. - Each additional 8 consumes 1.5 cache lines. Increasing improves - the sparseness of small dictionaries but costs time to read in - the additional cache lines if they are not already in cache. - That case is common when keyword arguments are passed. - -* Maximum dictionary load in PyDict_SetItem. Currently set to 2/3. - Increasing this ratio makes dictionaries more dense resulting - in more collisions. Decreasing it improves sparseness at the - expense of spreading entries over more cache lines and at the - cost of total memory consumed. - - The load test occurs in highly time sensitive code. Efforts - to make the test more complex (for example, varying the load - for different sizes) have degraded performance. - -* Growth rate upon hitting maximum load. Currently set to *2. - Raising this to *4 results in half the number of resizes, - less effort to resize, better sparseness for some (but not - all dict sizes), and potentially doubles memory consumption - depending on the size of the dictionary. Setting to *4 - eliminates every other resize step. - -Tune-ups should be measured across a broad range of applications and -use cases. A change to any parameter will help in some situations and -hurt in others. The key is to find settings that help the most common -cases and do the least damage to the less common cases. Results will -vary dramatically depending on the exact number of keys, whether the -keys are all strings, whether reads or writes dominate, the exact -hash values of the keys (some sets of values have fewer collisions than -others). Any one test or benchmark is likely to prove misleading. - -While making a dictionary more sparse reduces collisions, it impairs -iteration and key listing. Those methods loop over every potential -entry. Doubling the size of dictionary results in twice as many -non-overlapping memory accesses for keys(), items(), values(), -__iter__(), iterkeys(), iteritems(), itervalues(), and update(). -Also, every dictionary iterates at least twice, once for the memset() -when it is created and once by dealloc(). - - -Results of Cache Locality Experiments -------------------------------------- - -When an entry is retrieved from memory, 4.333 adjacent entries are also -retrieved into a cache line. Since accessing items in cache is *much* -cheaper than a cache miss, an enticing idea is to probe the adjacent -entries as a first step in collision resolution. Unfortunately, the -introduction of any regularity into collision searches results in more -collisions than the current random chaining approach. - -Exploiting cache locality at the expense of additional collisions fails -to payoff when the entries are already loaded in cache (the expense -is paid with no compensating benefit). This occurs in small dictionaries -where the whole dictionary fits into a pair of cache lines. It also -occurs frequently in large dictionaries which have a common access pattern -where some keys are accessed much more frequently than others. The -more popular entries *and* their collision chains tend to remain in cache. - -To exploit cache locality, change the collision resolution section -in lookdict() and lookdict_string(). Set i^=1 at the top of the -loop and move the i = (i << 2) + i + perturb + 1 to an unrolled -version of the loop. - -This optimization strategy can be leveraged in several ways: - -* If the dictionary is kept sparse (through the tunable parameters), -then the occurrence of additional collisions is lessened. - -* If lookdict() and lookdict_string() are specialized for small dicts -and for largedicts, then the versions for large_dicts can be given -an alternate search strategy without increasing collisions in small dicts -which already have the maximum benefit of cache locality. - -* If the use case for a dictionary is known to have a random key -access pattern (as opposed to a more common pattern with a Zipf's law -distribution), then there will be more benefit for large dictionaries -because any given key is no more likely than another to already be -in cache. - -* In use cases with paired accesses to the same key, the second access -is always in cache and gets no benefit from efforts to further improve -cache locality. - -Optimizing the Search of Small Dictionaries -------------------------------------------- - -If lookdict() and lookdict_string() are specialized for smaller dictionaries, -then a custom search approach can be implemented that exploits the small -search space and cache locality. - -* The simplest example is a linear search of contiguous entries. This is - simple to implement, guaranteed to terminate rapidly, never searches - the same entry twice, and precludes the need to check for dummy entries. - -* A more advanced example is a self-organizing search so that the most - frequently accessed entries get probed first. The organization - adapts if the access pattern changes over time. Treaps are ideally - suited for self-organization with the most common entries at the - top of the heap and a rapid binary search pattern. Most probes and - results are all located at the top of the tree allowing them all to - be located in one or two cache lines. - -* Also, small dictionaries may be made more dense, perhaps filling all - eight cells to take the maximum advantage of two cache lines. - - -Strategy Pattern ----------------- - -Consider allowing the user to set the tunable parameters or to select a -particular search method. Since some dictionary use cases have known -sizes and access patterns, the user may be able to provide useful hints. - -1) For example, if membership testing or lookups dominate runtime and memory - is not at a premium, the user may benefit from setting the maximum load - ratio at 5% or 10% instead of the usual 66.7%. This will sharply - curtail the number of collisions but will increase iteration time. - The builtin namespace is a prime example of a dictionary that can - benefit from being highly sparse. - -2) Dictionary creation time can be shortened in cases where the ultimate - size of the dictionary is known in advance. The dictionary can be - pre-sized so that no resize operations are required during creation. - Not only does this save resizes, but the key insertion will go - more quickly because the first half of the keys will be inserted into - a more sparse environment than before. The preconditions for this - strategy arise whenever a dictionary is created from a key or item - sequence and the number of *unique* keys is known. - -3) If the key space is large and the access pattern is known to be random, - then search strategies exploiting cache locality can be fruitful. - The preconditions for this strategy arise in simulations and - numerical analysis. - -4) If the keys are fixed and the access pattern strongly favors some of - the keys, then the entries can be stored contiguously and accessed - with a linear search or treap. This exploits knowledge of the data, - cache locality, and a simplified search routine. It also eliminates - the need to test for dummy entries on each probe. The preconditions - for this strategy arise in symbol tables and in the builtin dictionary. - - -Readonly Dictionaries ---------------------- -Some dictionary use cases pass through a build stage and then move to a -more heavily exercised lookup stage with no further changes to the -dictionary. - -An idea that emerged on python-dev is to be able to convert a dictionary -to a read-only state. This can help prevent programming errors and also -provide knowledge that can be exploited for lookup optimization. - -The dictionary can be immediately rebuilt (eliminating dummy entries), -resized (to an appropriate level of sparseness), and the keys can be -jostled (to minimize collisions). The lookdict() routine can then -eliminate the test for dummy entries (saving about 1/4 of the time -spent in the collision resolution loop). - -An additional possibility is to insert links into the empty spaces -so that dictionary iteration can proceed in len(d) steps instead of -(mp->mask + 1) steps. Alternatively, a separate tuple of keys can be -kept just for iteration. - - -Caching Lookups ---------------- -The idea is to exploit key access patterns by anticipating future lookups -based on previous lookups. - -The simplest incarnation is to save the most recently accessed entry. -This gives optimal performance for use cases where every get is followed -by a set or del to the same key. diff --git a/sys/src/cmd/python/Objects/dictobject.c b/sys/src/cmd/python/Objects/dictobject.c deleted file mode 100644 index af0d6f37a..000000000 --- a/sys/src/cmd/python/Objects/dictobject.c +++ /dev/null @@ -1,2486 +0,0 @@ - -/* Dictionary object implementation using a hash table */ - -/* The distribution includes a separate file, Objects/dictnotes.txt, - describing explorations into dictionary design and optimization. - It covers typical dictionary use patterns, the parameters for - tuning dictionaries, and several ideas for possible optimizations. -*/ - -#include "Python.h" - -typedef PyDictEntry dictentry; -typedef PyDictObject dictobject; - -/* Set a key error with the specified argument, wrapping it in a - * tuple automatically so that tuple keys are not unpacked as the - * exception arguments. */ -static void -set_key_error(PyObject *arg) -{ - PyObject *tup; - tup = PyTuple_Pack(1, arg); - if (!tup) - return; /* caller will expect error to be set anyway */ - PyErr_SetObject(PyExc_KeyError, tup); - Py_DECREF(tup); -} - -/* Define this out if you don't want conversion statistics on exit. */ -#undef SHOW_CONVERSION_COUNTS - -/* See large comment block below. This must be >= 1. */ -#define PERTURB_SHIFT 5 - -/* -Major subtleties ahead: Most hash schemes depend on having a "good" hash -function, in the sense of simulating randomness. Python doesn't: its most -important hash functions (for strings and ints) are very regular in common -cases: - ->>> map(hash, (0, 1, 2, 3)) -[0, 1, 2, 3] ->>> map(hash, ("namea", "nameb", "namec", "named")) -[-1658398457, -1658398460, -1658398459, -1658398462] ->>> - -This isn't necessarily bad! To the contrary, in a table of size 2**i, taking -the low-order i bits as the initial table index is extremely fast, and there -are no collisions at all for dicts indexed by a contiguous range of ints. -The same is approximately true when keys are "consecutive" strings. So this -gives better-than-random behavior in common cases, and that's very desirable. - -OTOH, when collisions occur, the tendency to fill contiguous slices of the -hash table makes a good collision resolution strategy crucial. Taking only -the last i bits of the hash code is also vulnerable: for example, consider -[i << 16 for i in range(20000)] as a set of keys. Since ints are their own -hash codes, and this fits in a dict of size 2**15, the last 15 bits of every -hash code are all 0: they *all* map to the same table index. - -But catering to unusual cases should not slow the usual ones, so we just take -the last i bits anyway. It's up to collision resolution to do the rest. If -we *usually* find the key we're looking for on the first try (and, it turns -out, we usually do -- the table load factor is kept under 2/3, so the odds -are solidly in our favor), then it makes best sense to keep the initial index -computation dirt cheap. - -The first half of collision resolution is to visit table indices via this -recurrence: - - j = ((5*j) + 1) mod 2**i - -For any initial j in range(2**i), repeating that 2**i times generates each -int in range(2**i) exactly once (see any text on random-number generation for -proof). By itself, this doesn't help much: like linear probing (setting -j += 1, or j -= 1, on each loop trip), it scans the table entries in a fixed -order. This would be bad, except that's not the only thing we do, and it's -actually *good* in the common cases where hash keys are consecutive. In an -example that's really too small to make this entirely clear, for a table of -size 2**3 the order of indices is: - - 0 -> 1 -> 6 -> 7 -> 4 -> 5 -> 2 -> 3 -> 0 [and here it's repeating] - -If two things come in at index 5, the first place we look after is index 2, -not 6, so if another comes in at index 6 the collision at 5 didn't hurt it. -Linear probing is deadly in this case because there the fixed probe order -is the *same* as the order consecutive keys are likely to arrive. But it's -extremely unlikely hash codes will follow a 5*j+1 recurrence by accident, -and certain that consecutive hash codes do not. - -The other half of the strategy is to get the other bits of the hash code -into play. This is done by initializing a (unsigned) vrbl "perturb" to the -full hash code, and changing the recurrence to: - - j = (5*j) + 1 + perturb; - perturb >>= PERTURB_SHIFT; - use j % 2**i as the next table index; - -Now the probe sequence depends (eventually) on every bit in the hash code, -and the pseudo-scrambling property of recurring on 5*j+1 is more valuable, -because it quickly magnifies small differences in the bits that didn't affect -the initial index. Note that because perturb is unsigned, if the recurrence -is executed often enough perturb eventually becomes and remains 0. At that -point (very rarely reached) the recurrence is on (just) 5*j+1 again, and -that's certain to find an empty slot eventually (since it generates every int -in range(2**i), and we make sure there's always at least one empty slot). - -Selecting a good value for PERTURB_SHIFT is a balancing act. You want it -small so that the high bits of the hash code continue to affect the probe -sequence across iterations; but you want it large so that in really bad cases -the high-order hash bits have an effect on early iterations. 5 was "the -best" in minimizing total collisions across experiments Tim Peters ran (on -both normal and pathological cases), but 4 and 6 weren't significantly worse. - -Historical: Reimer Behrends contributed the idea of using a polynomial-based -approach, using repeated multiplication by x in GF(2**n) where an irreducible -polynomial for each table size was chosen such that x was a primitive root. -Christian Tismer later extended that to use division by x instead, as an -efficient way to get the high bits of the hash code into play. This scheme -also gave excellent collision statistics, but was more expensive: two -if-tests were required inside the loop; computing "the next" index took about -the same number of operations but without as much potential parallelism -(e.g., computing 5*j can go on at the same time as computing 1+perturb in the -above, and then shifting perturb can be done while the table index is being -masked); and the dictobject struct required a member to hold the table's -polynomial. In Tim's experiments the current scheme ran faster, produced -equally good collision statistics, needed less code & used less memory. - -Theoretical Python 2.5 headache: hash codes are only C "long", but -sizeof(Py_ssize_t) > sizeof(long) may be possible. In that case, and if a -dict is genuinely huge, then only the slots directly reachable via indexing -by a C long can be the first slot in a probe sequence. The probe sequence -will still eventually reach every slot in the table, but the collision rate -on initial probes may be much higher than this scheme was designed for. -Getting a hash code as fat as Py_ssize_t is the only real cure. But in -practice, this probably won't make a lick of difference for many years (at -which point everyone will have terabytes of RAM on 64-bit boxes). -*/ - -/* Object used as dummy key to fill deleted entries */ -static PyObject *dummy = NULL; /* Initialized by first call to newdictobject() */ - -#ifdef Py_REF_DEBUG -PyObject * -_PyDict_Dummy(void) -{ - return dummy; -} -#endif - -/* forward declarations */ -static dictentry * -lookdict_string(dictobject *mp, PyObject *key, long hash); - -#ifdef SHOW_CONVERSION_COUNTS -static long created = 0L; -static long converted = 0L; - -static void -show_counts(void) -{ - fprintf(stderr, "created %ld string dicts\n", created); - fprintf(stderr, "converted %ld to normal dicts\n", converted); - fprintf(stderr, "%.2f%% conversion rate\n", (100.0*converted)/created); -} -#endif - -/* Initialization macros. - There are two ways to create a dict: PyDict_New() is the main C API - function, and the tp_new slot maps to dict_new(). In the latter case we - can save a little time over what PyDict_New does because it's guaranteed - that the PyDictObject struct is already zeroed out. - Everyone except dict_new() should use EMPTY_TO_MINSIZE (unless they have - an excellent reason not to). -*/ - -#define INIT_NONZERO_DICT_SLOTS(mp) do { \ - (mp)->ma_table = (mp)->ma_smalltable; \ - (mp)->ma_mask = PyDict_MINSIZE - 1; \ - } while(0) - -#define EMPTY_TO_MINSIZE(mp) do { \ - memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \ - (mp)->ma_used = (mp)->ma_fill = 0; \ - INIT_NONZERO_DICT_SLOTS(mp); \ - } while(0) - -/* Dictionary reuse scheme to save calls to malloc, free, and memset */ -#define MAXFREEDICTS 80 -static PyDictObject *free_dicts[MAXFREEDICTS]; -static int num_free_dicts = 0; - -PyObject * -PyDict_New(void) -{ - register dictobject *mp; - if (dummy == NULL) { /* Auto-initialize dummy */ - dummy = PyString_FromString("<dummy key>"); - if (dummy == NULL) - return NULL; -#ifdef SHOW_CONVERSION_COUNTS - Py_AtExit(show_counts); -#endif - } - if (num_free_dicts) { - mp = free_dicts[--num_free_dicts]; - assert (mp != NULL); - assert (mp->ob_type == &PyDict_Type); - _Py_NewReference((PyObject *)mp); - if (mp->ma_fill) { - EMPTY_TO_MINSIZE(mp); - } - assert (mp->ma_used == 0); - assert (mp->ma_table == mp->ma_smalltable); - assert (mp->ma_mask == PyDict_MINSIZE - 1); - } else { - mp = PyObject_GC_New(dictobject, &PyDict_Type); - if (mp == NULL) - return NULL; - EMPTY_TO_MINSIZE(mp); - } - mp->ma_lookup = lookdict_string; -#ifdef SHOW_CONVERSION_COUNTS - ++created; -#endif - _PyObject_GC_TRACK(mp); - return (PyObject *)mp; -} - -/* -The basic lookup function used by all operations. -This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4. -Open addressing is preferred over chaining since the link overhead for -chaining would be substantial (100% with typical malloc overhead). - -The initial probe index is computed as hash mod the table size. Subsequent -probe indices are computed as explained earlier. - -All arithmetic on hash should ignore overflow. - -(The details in this version are due to Tim Peters, building on many past -contributions by Reimer Behrends, Jyrki Alakuijala, Vladimir Marangozov and -Christian Tismer). - -lookdict() is general-purpose, and may return NULL if (and only if) a -comparison raises an exception (this was new in Python 2.5). -lookdict_string() below is specialized to string keys, comparison of which can -never raise an exception; that function can never return NULL. For both, when -the key isn't found a dictentry* is returned for which the me_value field is -NULL; this is the slot in the dict at which the key would have been found, and -the caller can (if it wishes) add the <key, value> pair to the returned -dictentry*. -*/ -static dictentry * -lookdict(dictobject *mp, PyObject *key, register long hash) -{ - register size_t i; - register size_t perturb; - register dictentry *freeslot; - register size_t mask = (size_t)mp->ma_mask; - dictentry *ep0 = mp->ma_table; - register dictentry *ep; - register int cmp; - PyObject *startkey; - - i = (size_t)hash & mask; - ep = &ep0[i]; - if (ep->me_key == NULL || ep->me_key == key) - return ep; - - if (ep->me_key == dummy) - freeslot = ep; - else { - if (ep->me_hash == hash) { - startkey = ep->me_key; - cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); - if (cmp < 0) - return NULL; - if (ep0 == mp->ma_table && ep->me_key == startkey) { - if (cmp > 0) - return ep; - } - else { - /* The compare did major nasty stuff to the - * dict: start over. - * XXX A clever adversary could prevent this - * XXX from terminating. - */ - return lookdict(mp, key, hash); - } - } - freeslot = NULL; - } - - /* In the loop, me_key == dummy is by far (factor of 100s) the - least likely outcome, so test for that last. */ - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - ep = &ep0[i & mask]; - if (ep->me_key == NULL) - return freeslot == NULL ? ep : freeslot; - if (ep->me_key == key) - return ep; - if (ep->me_hash == hash && ep->me_key != dummy) { - startkey = ep->me_key; - cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); - if (cmp < 0) - return NULL; - if (ep0 == mp->ma_table && ep->me_key == startkey) { - if (cmp > 0) - return ep; - } - else { - /* The compare did major nasty stuff to the - * dict: start over. - * XXX A clever adversary could prevent this - * XXX from terminating. - */ - return lookdict(mp, key, hash); - } - } - else if (ep->me_key == dummy && freeslot == NULL) - freeslot = ep; - } - assert(0); /* NOT REACHED */ - return 0; -} - -/* - * Hacked up version of lookdict which can assume keys are always strings; - * this assumption allows testing for errors during PyObject_RichCompareBool() - * to be dropped; string-string comparisons never raise exceptions. This also - * means we don't need to go through PyObject_RichCompareBool(); we can always - * use _PyString_Eq() directly. - * - * This is valuable because dicts with only string keys are very common. - */ -static dictentry * -lookdict_string(dictobject *mp, PyObject *key, register long hash) -{ - register size_t i; - register size_t perturb; - register dictentry *freeslot; - register size_t mask = (size_t)mp->ma_mask; - dictentry *ep0 = mp->ma_table; - register dictentry *ep; - - /* Make sure this function doesn't have to handle non-string keys, - including subclasses of str; e.g., one reason to subclass - strings is to override __eq__, and for speed we don't cater to - that here. */ - if (!PyString_CheckExact(key)) { -#ifdef SHOW_CONVERSION_COUNTS - ++converted; -#endif - mp->ma_lookup = lookdict; - return lookdict(mp, key, hash); - } - i = hash & mask; - ep = &ep0[i]; - if (ep->me_key == NULL || ep->me_key == key) - return ep; - if (ep->me_key == dummy) - freeslot = ep; - else { - if (ep->me_hash == hash && _PyString_Eq(ep->me_key, key)) - return ep; - freeslot = NULL; - } - - /* In the loop, me_key == dummy is by far (factor of 100s) the - least likely outcome, so test for that last. */ - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - ep = &ep0[i & mask]; - if (ep->me_key == NULL) - return freeslot == NULL ? ep : freeslot; - if (ep->me_key == key - || (ep->me_hash == hash - && ep->me_key != dummy - && _PyString_Eq(ep->me_key, key))) - return ep; - if (ep->me_key == dummy && freeslot == NULL) - freeslot = ep; - } - assert(0); /* NOT REACHED */ - return 0; -} - -/* -Internal routine to insert a new item into the table. -Used both by the internal resize routine and by the public insert routine. -Eats a reference to key and one to value. -Returns -1 if an error occurred, or 0 on success. -*/ -static int -insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value) -{ - PyObject *old_value; - register dictentry *ep; - typedef PyDictEntry *(*lookupfunc)(PyDictObject *, PyObject *, long); - - assert(mp->ma_lookup != NULL); - ep = mp->ma_lookup(mp, key, hash); - if (ep == NULL) { - Py_DECREF(key); - Py_DECREF(value); - return -1; - } - if (ep->me_value != NULL) { - old_value = ep->me_value; - ep->me_value = value; - Py_DECREF(old_value); /* which **CAN** re-enter */ - Py_DECREF(key); - } - else { - if (ep->me_key == NULL) - mp->ma_fill++; - else { - assert(ep->me_key == dummy); - Py_DECREF(dummy); - } - ep->me_key = key; - ep->me_hash = (Py_ssize_t)hash; - ep->me_value = value; - mp->ma_used++; - } - return 0; -} - -/* -Internal routine used by dictresize() to insert an item which is -known to be absent from the dict. This routine also assumes that -the dict contains no deleted entries. Besides the performance benefit, -using insertdict() in dictresize() is dangerous (SF bug #1456209). -Note that no refcounts are changed by this routine; if needed, the caller -is responsible for incref'ing `key` and `value`. -*/ -static void -insertdict_clean(register dictobject *mp, PyObject *key, long hash, - PyObject *value) -{ - register size_t i; - register size_t perturb; - register size_t mask = (size_t)mp->ma_mask; - dictentry *ep0 = mp->ma_table; - register dictentry *ep; - - i = hash & mask; - ep = &ep0[i]; - for (perturb = hash; ep->me_key != NULL; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - ep = &ep0[i & mask]; - } - assert(ep->me_value == NULL); - mp->ma_fill++; - ep->me_key = key; - ep->me_hash = (Py_ssize_t)hash; - ep->me_value = value; - mp->ma_used++; -} - -/* -Restructure the table by allocating a new table and reinserting all -items again. When entries have been deleted, the new table may -actually be smaller than the old one. -*/ -static int -dictresize(dictobject *mp, Py_ssize_t minused) -{ - Py_ssize_t newsize; - dictentry *oldtable, *newtable, *ep; - Py_ssize_t i; - int is_oldtable_malloced; - dictentry small_copy[PyDict_MINSIZE]; - - assert(minused >= 0); - - /* Find the smallest table size > minused. */ - for (newsize = PyDict_MINSIZE; - newsize <= minused && newsize > 0; - newsize <<= 1) - ; - if (newsize <= 0) { - PyErr_NoMemory(); - return -1; - } - - /* Get space for a new table. */ - oldtable = mp->ma_table; - assert(oldtable != NULL); - is_oldtable_malloced = oldtable != mp->ma_smalltable; - - if (newsize == PyDict_MINSIZE) { - /* A large table is shrinking, or we can't get any smaller. */ - newtable = mp->ma_smalltable; - if (newtable == oldtable) { - if (mp->ma_fill == mp->ma_used) { - /* No dummies, so no point doing anything. */ - return 0; - } - /* We're not going to resize it, but rebuild the - table anyway to purge old dummy entries. - Subtle: This is *necessary* if fill==size, - as lookdict needs at least one virgin slot to - terminate failing searches. If fill < size, it's - merely desirable, as dummies slow searches. */ - assert(mp->ma_fill > mp->ma_used); - memcpy(small_copy, oldtable, sizeof(small_copy)); - oldtable = small_copy; - } - } - else { - newtable = PyMem_NEW(dictentry, newsize); - if (newtable == NULL) { - PyErr_NoMemory(); - return -1; - } - } - - /* Make the dict empty, using the new table. */ - assert(newtable != oldtable); - mp->ma_table = newtable; - mp->ma_mask = newsize - 1; - memset(newtable, 0, sizeof(dictentry) * newsize); - mp->ma_used = 0; - i = mp->ma_fill; - mp->ma_fill = 0; - - /* Copy the data over; this is refcount-neutral for active entries; - dummy entries aren't copied over, of course */ - for (ep = oldtable; i > 0; ep++) { - if (ep->me_value != NULL) { /* active entry */ - --i; - insertdict_clean(mp, ep->me_key, (long)ep->me_hash, - ep->me_value); - } - else if (ep->me_key != NULL) { /* dummy entry */ - --i; - assert(ep->me_key == dummy); - Py_DECREF(ep->me_key); - } - /* else key == value == NULL: nothing to do */ - } - - if (is_oldtable_malloced) - PyMem_DEL(oldtable); - return 0; -} - -/* Note that, for historical reasons, PyDict_GetItem() suppresses all errors - * that may occur (originally dicts supported only string keys, and exceptions - * weren't possible). So, while the original intent was that a NULL return - * meant the key wasn't present, in reality it can mean that, or that an error - * (suppressed) occurred while computing the key's hash, or that some error - * (suppressed) occurred when comparing keys in the dict's internal probe - * sequence. A nasty example of the latter is when a Python-coded comparison - * function hits a stack-depth error, which can cause this to return NULL - * even if the key is present. - */ -PyObject * -PyDict_GetItem(PyObject *op, PyObject *key) -{ - long hash; - dictobject *mp = (dictobject *)op; - dictentry *ep; - PyThreadState *tstate; - if (!PyDict_Check(op)) - return NULL; - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) - { - hash = PyObject_Hash(key); - if (hash == -1) { - PyErr_Clear(); - return NULL; - } - } - - /* We can arrive here with a NULL tstate during initialization: - try running "python -Wi" for an example related to string - interning. Let's just hope that no exception occurs then... */ - tstate = _PyThreadState_Current; - if (tstate != NULL && tstate->curexc_type != NULL) { - /* preserve the existing exception */ - PyObject *err_type, *err_value, *err_tb; - PyErr_Fetch(&err_type, &err_value, &err_tb); - ep = (mp->ma_lookup)(mp, key, hash); - /* ignore errors */ - PyErr_Restore(err_type, err_value, err_tb); - if (ep == NULL) - return NULL; - } - else { - ep = (mp->ma_lookup)(mp, key, hash); - if (ep == NULL) { - PyErr_Clear(); - return NULL; - } - } - return ep->me_value; -} - -/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the - * dictionary if it's merely replacing the value for an existing key. - * This means that it's safe to loop over a dictionary with PyDict_Next() - * and occasionally replace a value -- but you can't insert new keys or - * remove them. - */ -int -PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value) -{ - register dictobject *mp; - register long hash; - register Py_ssize_t n_used; - - if (!PyDict_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - assert(key); - assert(value); - mp = (dictobject *)op; - if (PyString_CheckExact(key)) { - hash = ((PyStringObject *)key)->ob_shash; - if (hash == -1) - hash = PyObject_Hash(key); - } - else { - hash = PyObject_Hash(key); - if (hash == -1) - return -1; - } - assert(mp->ma_fill <= mp->ma_mask); /* at least one empty slot */ - n_used = mp->ma_used; - Py_INCREF(value); - Py_INCREF(key); - if (insertdict(mp, key, hash, value) != 0) - return -1; - /* If we added a key, we can safely resize. Otherwise just return! - * If fill >= 2/3 size, adjust size. Normally, this doubles or - * quaduples the size, but it's also possible for the dict to shrink - * (if ma_fill is much larger than ma_used, meaning a lot of dict - * keys have been * deleted). - * - * Quadrupling the size improves average dictionary sparseness - * (reducing collisions) at the cost of some memory and iteration - * speed (which loops over every possible entry). It also halves - * the number of expensive resize operations in a growing dictionary. - * - * Very large dictionaries (over 50K items) use doubling instead. - * This may help applications with severe memory constraints. - */ - if (!(mp->ma_used > n_used && mp->ma_fill*3 >= (mp->ma_mask+1)*2)) - return 0; - return dictresize(mp, (mp->ma_used > 50000 ? 2 : 4) * mp->ma_used); -} - -int -PyDict_DelItem(PyObject *op, PyObject *key) -{ - register dictobject *mp; - register long hash; - register dictentry *ep; - PyObject *old_value, *old_key; - - if (!PyDict_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - assert(key); - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return -1; - } - mp = (dictobject *)op; - ep = (mp->ma_lookup)(mp, key, hash); - if (ep == NULL) - return -1; - if (ep->me_value == NULL) { - set_key_error(key); - return -1; - } - old_key = ep->me_key; - Py_INCREF(dummy); - ep->me_key = dummy; - old_value = ep->me_value; - ep->me_value = NULL; - mp->ma_used--; - Py_DECREF(old_value); - Py_DECREF(old_key); - return 0; -} - -void -PyDict_Clear(PyObject *op) -{ - dictobject *mp; - dictentry *ep, *table; - int table_is_malloced; - Py_ssize_t fill; - dictentry small_copy[PyDict_MINSIZE]; -#ifdef Py_DEBUG - Py_ssize_t i, n; -#endif - - if (!PyDict_Check(op)) - return; - mp = (dictobject *)op; -#ifdef Py_DEBUG - n = mp->ma_mask + 1; - i = 0; -#endif - - table = mp->ma_table; - assert(table != NULL); - table_is_malloced = table != mp->ma_smalltable; - - /* This is delicate. During the process of clearing the dict, - * decrefs can cause the dict to mutate. To avoid fatal confusion - * (voice of experience), we have to make the dict empty before - * clearing the slots, and never refer to anything via mp->xxx while - * clearing. - */ - fill = mp->ma_fill; - if (table_is_malloced) - EMPTY_TO_MINSIZE(mp); - - else if (fill > 0) { - /* It's a small table with something that needs to be cleared. - * Afraid the only safe way is to copy the dict entries into - * another small table first. - */ - memcpy(small_copy, table, sizeof(small_copy)); - table = small_copy; - EMPTY_TO_MINSIZE(mp); - } - /* else it's a small table that's already empty */ - - /* Now we can finally clear things. If C had refcounts, we could - * assert that the refcount on table is 1 now, i.e. that this function - * has unique access to it, so decref side-effects can't alter it. - */ - for (ep = table; fill > 0; ++ep) { -#ifdef Py_DEBUG - assert(i < n); - ++i; -#endif - if (ep->me_key) { - --fill; - Py_DECREF(ep->me_key); - Py_XDECREF(ep->me_value); - } -#ifdef Py_DEBUG - else - assert(ep->me_value == NULL); -#endif - } - - if (table_is_malloced) - PyMem_DEL(table); -} - -/* - * Iterate over a dict. Use like so: - * - * Py_ssize_t i; - * PyObject *key, *value; - * i = 0; # important! i should not otherwise be changed by you - * while (PyDict_Next(yourdict, &i, &key, &value)) { - * Refer to borrowed references in key and value. - * } - * - * CAUTION: In general, it isn't safe to use PyDict_Next in a loop that - * mutates the dict. One exception: it is safe if the loop merely changes - * the values associated with the keys (but doesn't insert new keys or - * delete keys), via PyDict_SetItem(). - */ -int -PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue) -{ - register Py_ssize_t i; - register Py_ssize_t mask; - register dictentry *ep; - - if (!PyDict_Check(op)) - return 0; - i = *ppos; - if (i < 0) - return 0; - ep = ((dictobject *)op)->ma_table; - mask = ((dictobject *)op)->ma_mask; - while (i <= mask && ep[i].me_value == NULL) - i++; - *ppos = i+1; - if (i > mask) - return 0; - if (pkey) - *pkey = ep[i].me_key; - if (pvalue) - *pvalue = ep[i].me_value; - return 1; -} - -/* Internal version of PyDict_Next that returns a hash value in addition to the key and value.*/ -int -_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue, long *phash) -{ - register Py_ssize_t i; - register Py_ssize_t mask; - register dictentry *ep; - - if (!PyDict_Check(op)) - return 0; - i = *ppos; - if (i < 0) - return 0; - ep = ((dictobject *)op)->ma_table; - mask = ((dictobject *)op)->ma_mask; - while (i <= mask && ep[i].me_value == NULL) - i++; - *ppos = i+1; - if (i > mask) - return 0; - *phash = (long)(ep[i].me_hash); - if (pkey) - *pkey = ep[i].me_key; - if (pvalue) - *pvalue = ep[i].me_value; - return 1; -} - -/* Methods */ - -static void -dict_dealloc(register dictobject *mp) -{ - register dictentry *ep; - Py_ssize_t fill = mp->ma_fill; - PyObject_GC_UnTrack(mp); - Py_TRASHCAN_SAFE_BEGIN(mp) - for (ep = mp->ma_table; fill > 0; ep++) { - if (ep->me_key) { - --fill; - Py_DECREF(ep->me_key); - Py_XDECREF(ep->me_value); - } - } - if (mp->ma_table != mp->ma_smalltable) - PyMem_DEL(mp->ma_table); - if (num_free_dicts < MAXFREEDICTS && mp->ob_type == &PyDict_Type) - free_dicts[num_free_dicts++] = mp; - else - mp->ob_type->tp_free((PyObject *)mp); - Py_TRASHCAN_SAFE_END(mp) -} - -static int -dict_print(register dictobject *mp, register FILE *fp, register int flags) -{ - register Py_ssize_t i; - register Py_ssize_t any; - int status; - - status = Py_ReprEnter((PyObject*)mp); - if (status != 0) { - if (status < 0) - return status; - fprintf(fp, "{...}"); - return 0; - } - - fprintf(fp, "{"); - any = 0; - for (i = 0; i <= mp->ma_mask; i++) { - dictentry *ep = mp->ma_table + i; - PyObject *pvalue = ep->me_value; - if (pvalue != NULL) { - /* Prevent PyObject_Repr from deleting value during - key format */ - Py_INCREF(pvalue); - if (any++ > 0) - fprintf(fp, ", "); - if (PyObject_Print((PyObject *)ep->me_key, fp, 0)!=0) { - Py_DECREF(pvalue); - Py_ReprLeave((PyObject*)mp); - return -1; - } - fprintf(fp, ": "); - if (PyObject_Print(pvalue, fp, 0) != 0) { - Py_DECREF(pvalue); - Py_ReprLeave((PyObject*)mp); - return -1; - } - Py_DECREF(pvalue); - } - } - fprintf(fp, "}"); - Py_ReprLeave((PyObject*)mp); - return 0; -} - -static PyObject * -dict_repr(dictobject *mp) -{ - Py_ssize_t i; - PyObject *s, *temp, *colon = NULL; - PyObject *pieces = NULL, *result = NULL; - PyObject *key, *value; - - i = Py_ReprEnter((PyObject *)mp); - if (i != 0) { - return i > 0 ? PyString_FromString("{...}") : NULL; - } - - if (mp->ma_used == 0) { - result = PyString_FromString("{}"); - goto Done; - } - - pieces = PyList_New(0); - if (pieces == NULL) - goto Done; - - colon = PyString_FromString(": "); - if (colon == NULL) - goto Done; - - /* Do repr() on each key+value pair, and insert ": " between them. - Note that repr may mutate the dict. */ - i = 0; - while (PyDict_Next((PyObject *)mp, &i, &key, &value)) { - int status; - /* Prevent repr from deleting value during key format. */ - Py_INCREF(value); - s = PyObject_Repr(key); - PyString_Concat(&s, colon); - PyString_ConcatAndDel(&s, PyObject_Repr(value)); - Py_DECREF(value); - if (s == NULL) - goto Done; - status = PyList_Append(pieces, s); - Py_DECREF(s); /* append created a new ref */ - if (status < 0) - goto Done; - } - - /* Add "{}" decorations to the first and last items. */ - assert(PyList_GET_SIZE(pieces) > 0); - s = PyString_FromString("{"); - if (s == NULL) - goto Done; - temp = PyList_GET_ITEM(pieces, 0); - PyString_ConcatAndDel(&s, temp); - PyList_SET_ITEM(pieces, 0, s); - if (s == NULL) - goto Done; - - s = PyString_FromString("}"); - if (s == NULL) - goto Done; - temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1); - PyString_ConcatAndDel(&temp, s); - PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp); - if (temp == NULL) - goto Done; - - /* Paste them all together with ", " between. */ - s = PyString_FromString(", "); - if (s == NULL) - goto Done; - result = _PyString_Join(s, pieces); - Py_DECREF(s); - -Done: - Py_XDECREF(pieces); - Py_XDECREF(colon); - Py_ReprLeave((PyObject *)mp); - return result; -} - -static Py_ssize_t -dict_length(dictobject *mp) -{ - return mp->ma_used; -} - -static PyObject * -dict_subscript(dictobject *mp, register PyObject *key) -{ - PyObject *v; - long hash; - dictentry *ep; - assert(mp->ma_table != NULL); - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return NULL; - } - ep = (mp->ma_lookup)(mp, key, hash); - if (ep == NULL) - return NULL; - v = ep->me_value; - if (v == NULL) { - if (!PyDict_CheckExact(mp)) { - /* Look up __missing__ method if we're a subclass. */ - PyObject *missing; - static PyObject *missing_str = NULL; - if (missing_str == NULL) - missing_str = - PyString_InternFromString("__missing__"); - missing = _PyType_Lookup(mp->ob_type, missing_str); - if (missing != NULL) - return PyObject_CallFunctionObjArgs(missing, - (PyObject *)mp, key, NULL); - } - set_key_error(key); - return NULL; - } - else - Py_INCREF(v); - return v; -} - -static int -dict_ass_sub(dictobject *mp, PyObject *v, PyObject *w) -{ - if (w == NULL) - return PyDict_DelItem((PyObject *)mp, v); - else - return PyDict_SetItem((PyObject *)mp, v, w); -} - -static PyMappingMethods dict_as_mapping = { - (lenfunc)dict_length, /*mp_length*/ - (binaryfunc)dict_subscript, /*mp_subscript*/ - (objobjargproc)dict_ass_sub, /*mp_ass_subscript*/ -}; - -static PyObject * -dict_keys(register dictobject *mp) -{ - register PyObject *v; - register Py_ssize_t i, j; - dictentry *ep; - Py_ssize_t mask, n; - - again: - n = mp->ma_used; - v = PyList_New(n); - if (v == NULL) - return NULL; - if (n != mp->ma_used) { - /* Durnit. The allocations caused the dict to resize. - * Just start over, this shouldn't normally happen. - */ - Py_DECREF(v); - goto again; - } - ep = mp->ma_table; - mask = mp->ma_mask; - for (i = 0, j = 0; i <= mask; i++) { - if (ep[i].me_value != NULL) { - PyObject *key = ep[i].me_key; - Py_INCREF(key); - PyList_SET_ITEM(v, j, key); - j++; - } - } - assert(j == n); - return v; -} - -static PyObject * -dict_values(register dictobject *mp) -{ - register PyObject *v; - register Py_ssize_t i, j; - dictentry *ep; - Py_ssize_t mask, n; - - again: - n = mp->ma_used; - v = PyList_New(n); - if (v == NULL) - return NULL; - if (n != mp->ma_used) { - /* Durnit. The allocations caused the dict to resize. - * Just start over, this shouldn't normally happen. - */ - Py_DECREF(v); - goto again; - } - ep = mp->ma_table; - mask = mp->ma_mask; - for (i = 0, j = 0; i <= mask; i++) { - if (ep[i].me_value != NULL) { - PyObject *value = ep[i].me_value; - Py_INCREF(value); - PyList_SET_ITEM(v, j, value); - j++; - } - } - assert(j == n); - return v; -} - -static PyObject * -dict_items(register dictobject *mp) -{ - register PyObject *v; - register Py_ssize_t i, j, n; - Py_ssize_t mask; - PyObject *item, *key, *value; - dictentry *ep; - - /* Preallocate the list of tuples, to avoid allocations during - * the loop over the items, which could trigger GC, which - * could resize the dict. :-( - */ - again: - n = mp->ma_used; - v = PyList_New(n); - if (v == NULL) - return NULL; - for (i = 0; i < n; i++) { - item = PyTuple_New(2); - if (item == NULL) { - Py_DECREF(v); - return NULL; - } - PyList_SET_ITEM(v, i, item); - } - if (n != mp->ma_used) { - /* Durnit. The allocations caused the dict to resize. - * Just start over, this shouldn't normally happen. - */ - Py_DECREF(v); - goto again; - } - /* Nothing we do below makes any function calls. */ - ep = mp->ma_table; - mask = mp->ma_mask; - for (i = 0, j = 0; i <= mask; i++) { - if ((value=ep[i].me_value) != NULL) { - key = ep[i].me_key; - item = PyList_GET_ITEM(v, j); - Py_INCREF(key); - PyTuple_SET_ITEM(item, 0, key); - Py_INCREF(value); - PyTuple_SET_ITEM(item, 1, value); - j++; - } - } - assert(j == n); - return v; -} - -static PyObject * -dict_fromkeys(PyObject *cls, PyObject *args) -{ - PyObject *seq; - PyObject *value = Py_None; - PyObject *it; /* iter(seq) */ - PyObject *key; - PyObject *d; - int status; - - if (!PyArg_UnpackTuple(args, "fromkeys", 1, 2, &seq, &value)) - return NULL; - - d = PyObject_CallObject(cls, NULL); - if (d == NULL) - return NULL; - - if (PyDict_CheckExact(d) && PyAnySet_CheckExact(seq)) { - dictobject *mp = (dictobject *)d; - Py_ssize_t pos = 0; - PyObject *key; - long hash; - - if (dictresize(mp, PySet_GET_SIZE(seq))) - return NULL; - - while (_PySet_NextEntry(seq, &pos, &key, &hash)) { - Py_INCREF(key); - Py_INCREF(value); - if (insertdict(mp, key, hash, value)) - return NULL; - } - return d; - } - - it = PyObject_GetIter(seq); - if (it == NULL){ - Py_DECREF(d); - return NULL; - } - - for (;;) { - key = PyIter_Next(it); - if (key == NULL) { - if (PyErr_Occurred()) - goto Fail; - break; - } - status = PyObject_SetItem(d, key, value); - Py_DECREF(key); - if (status < 0) - goto Fail; - } - - Py_DECREF(it); - return d; - -Fail: - Py_DECREF(it); - Py_DECREF(d); - return NULL; -} - -static int -dict_update_common(PyObject *self, PyObject *args, PyObject *kwds, char *methname) -{ - PyObject *arg = NULL; - int result = 0; - - if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) - result = -1; - - else if (arg != NULL) { - if (PyObject_HasAttrString(arg, "keys")) - result = PyDict_Merge(self, arg, 1); - else - result = PyDict_MergeFromSeq2(self, arg, 1); - } - if (result == 0 && kwds != NULL) - result = PyDict_Merge(self, kwds, 1); - return result; -} - -static PyObject * -dict_update(PyObject *self, PyObject *args, PyObject *kwds) -{ - if (dict_update_common(self, args, kwds, "update") != -1) - Py_RETURN_NONE; - return NULL; -} - -/* Update unconditionally replaces existing items. - Merge has a 3rd argument 'override'; if set, it acts like Update, - otherwise it leaves existing items unchanged. - - PyDict_{Update,Merge} update/merge from a mapping object. - - PyDict_MergeFromSeq2 updates/merges from any iterable object - producing iterable objects of length 2. -*/ - -int -PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override) -{ - PyObject *it; /* iter(seq2) */ - Py_ssize_t i; /* index into seq2 of current element */ - PyObject *item; /* seq2[i] */ - PyObject *fast; /* item as a 2-tuple or 2-list */ - - assert(d != NULL); - assert(PyDict_Check(d)); - assert(seq2 != NULL); - - it = PyObject_GetIter(seq2); - if (it == NULL) - return -1; - - for (i = 0; ; ++i) { - PyObject *key, *value; - Py_ssize_t n; - - fast = NULL; - item = PyIter_Next(it); - if (item == NULL) { - if (PyErr_Occurred()) - goto Fail; - break; - } - - /* Convert item to sequence, and verify length 2. */ - fast = PySequence_Fast(item, ""); - if (fast == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_Format(PyExc_TypeError, - "cannot convert dictionary update " - "sequence element #%zd to a sequence", - i); - goto Fail; - } - n = PySequence_Fast_GET_SIZE(fast); - if (n != 2) { - PyErr_Format(PyExc_ValueError, - "dictionary update sequence element #%zd " - "has length %zd; 2 is required", - i, n); - goto Fail; - } - - /* Update/merge with this (key, value) pair. */ - key = PySequence_Fast_GET_ITEM(fast, 0); - value = PySequence_Fast_GET_ITEM(fast, 1); - if (override || PyDict_GetItem(d, key) == NULL) { - int status = PyDict_SetItem(d, key, value); - if (status < 0) - goto Fail; - } - Py_DECREF(fast); - Py_DECREF(item); - } - - i = 0; - goto Return; -Fail: - Py_XDECREF(item); - Py_XDECREF(fast); - i = -1; -Return: - Py_DECREF(it); - return Py_SAFE_DOWNCAST(i, Py_ssize_t, int); -} - -int -PyDict_Update(PyObject *a, PyObject *b) -{ - return PyDict_Merge(a, b, 1); -} - -int -PyDict_Merge(PyObject *a, PyObject *b, int override) -{ - register PyDictObject *mp, *other; - register Py_ssize_t i; - dictentry *entry; - - /* We accept for the argument either a concrete dictionary object, - * or an abstract "mapping" object. For the former, we can do - * things quite efficiently. For the latter, we only require that - * PyMapping_Keys() and PyObject_GetItem() be supported. - */ - if (a == NULL || !PyDict_Check(a) || b == NULL) { - PyErr_BadInternalCall(); - return -1; - } - mp = (dictobject*)a; - if (PyDict_Check(b)) { - other = (dictobject*)b; - if (other == mp || other->ma_used == 0) - /* a.update(a) or a.update({}); nothing to do */ - return 0; - if (mp->ma_used == 0) - /* Since the target dict is empty, PyDict_GetItem() - * always returns NULL. Setting override to 1 - * skips the unnecessary test. - */ - override = 1; - /* Do one big resize at the start, rather than - * incrementally resizing as we insert new items. Expect - * that there will be no (or few) overlapping keys. - */ - if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) { - if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) - return -1; - } - for (i = 0; i <= other->ma_mask; i++) { - entry = &other->ma_table[i]; - if (entry->me_value != NULL && - (override || - PyDict_GetItem(a, entry->me_key) == NULL)) { - Py_INCREF(entry->me_key); - Py_INCREF(entry->me_value); - if (insertdict(mp, entry->me_key, - (long)entry->me_hash, - entry->me_value) != 0) - return -1; - } - } - } - else { - /* Do it the generic, slower way */ - PyObject *keys = PyMapping_Keys(b); - PyObject *iter; - PyObject *key, *value; - int status; - - if (keys == NULL) - /* Docstring says this is equivalent to E.keys() so - * if E doesn't have a .keys() method we want - * AttributeError to percolate up. Might as well - * do the same for any other error. - */ - return -1; - - iter = PyObject_GetIter(keys); - Py_DECREF(keys); - if (iter == NULL) - return -1; - - for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) { - if (!override && PyDict_GetItem(a, key) != NULL) { - Py_DECREF(key); - continue; - } - value = PyObject_GetItem(b, key); - if (value == NULL) { - Py_DECREF(iter); - Py_DECREF(key); - return -1; - } - status = PyDict_SetItem(a, key, value); - Py_DECREF(key); - Py_DECREF(value); - if (status < 0) { - Py_DECREF(iter); - return -1; - } - } - Py_DECREF(iter); - if (PyErr_Occurred()) - /* Iterator completed, via error */ - return -1; - } - return 0; -} - -static PyObject * -dict_copy(register dictobject *mp) -{ - return PyDict_Copy((PyObject*)mp); -} - -PyObject * -PyDict_Copy(PyObject *o) -{ - PyObject *copy; - - if (o == NULL || !PyDict_Check(o)) { - PyErr_BadInternalCall(); - return NULL; - } - copy = PyDict_New(); - if (copy == NULL) - return NULL; - if (PyDict_Merge(copy, o, 1) == 0) - return copy; - Py_DECREF(copy); - return NULL; -} - -Py_ssize_t -PyDict_Size(PyObject *mp) -{ - if (mp == NULL || !PyDict_Check(mp)) { - PyErr_BadInternalCall(); - return -1; - } - return ((dictobject *)mp)->ma_used; -} - -PyObject * -PyDict_Keys(PyObject *mp) -{ - if (mp == NULL || !PyDict_Check(mp)) { - PyErr_BadInternalCall(); - return NULL; - } - return dict_keys((dictobject *)mp); -} - -PyObject * -PyDict_Values(PyObject *mp) -{ - if (mp == NULL || !PyDict_Check(mp)) { - PyErr_BadInternalCall(); - return NULL; - } - return dict_values((dictobject *)mp); -} - -PyObject * -PyDict_Items(PyObject *mp) -{ - if (mp == NULL || !PyDict_Check(mp)) { - PyErr_BadInternalCall(); - return NULL; - } - return dict_items((dictobject *)mp); -} - -/* Subroutine which returns the smallest key in a for which b's value - is different or absent. The value is returned too, through the - pval argument. Both are NULL if no key in a is found for which b's status - differs. The refcounts on (and only on) non-NULL *pval and function return - values must be decremented by the caller (characterize() increments them - to ensure that mutating comparison and PyDict_GetItem calls can't delete - them before the caller is done looking at them). */ - -static PyObject * -characterize(dictobject *a, dictobject *b, PyObject **pval) -{ - PyObject *akey = NULL; /* smallest key in a s.t. a[akey] != b[akey] */ - PyObject *aval = NULL; /* a[akey] */ - Py_ssize_t i; - int cmp; - - for (i = 0; i <= a->ma_mask; i++) { - PyObject *thiskey, *thisaval, *thisbval; - if (a->ma_table[i].me_value == NULL) - continue; - thiskey = a->ma_table[i].me_key; - Py_INCREF(thiskey); /* keep alive across compares */ - if (akey != NULL) { - cmp = PyObject_RichCompareBool(akey, thiskey, Py_LT); - if (cmp < 0) { - Py_DECREF(thiskey); - goto Fail; - } - if (cmp > 0 || - i > a->ma_mask || - a->ma_table[i].me_value == NULL) - { - /* Not the *smallest* a key; or maybe it is - * but the compare shrunk the dict so we can't - * find its associated value anymore; or - * maybe it is but the compare deleted the - * a[thiskey] entry. - */ - Py_DECREF(thiskey); - continue; - } - } - - /* Compare a[thiskey] to b[thiskey]; cmp <- true iff equal. */ - thisaval = a->ma_table[i].me_value; - assert(thisaval); - Py_INCREF(thisaval); /* keep alive */ - thisbval = PyDict_GetItem((PyObject *)b, thiskey); - if (thisbval == NULL) - cmp = 0; - else { - /* both dicts have thiskey: same values? */ - cmp = PyObject_RichCompareBool( - thisaval, thisbval, Py_EQ); - if (cmp < 0) { - Py_DECREF(thiskey); - Py_DECREF(thisaval); - goto Fail; - } - } - if (cmp == 0) { - /* New winner. */ - Py_XDECREF(akey); - Py_XDECREF(aval); - akey = thiskey; - aval = thisaval; - } - else { - Py_DECREF(thiskey); - Py_DECREF(thisaval); - } - } - *pval = aval; - return akey; - -Fail: - Py_XDECREF(akey); - Py_XDECREF(aval); - *pval = NULL; - return NULL; -} - -static int -dict_compare(dictobject *a, dictobject *b) -{ - PyObject *adiff, *bdiff, *aval, *bval; - int res; - - /* Compare lengths first */ - if (a->ma_used < b->ma_used) - return -1; /* a is shorter */ - else if (a->ma_used > b->ma_used) - return 1; /* b is shorter */ - - /* Same length -- check all keys */ - bdiff = bval = NULL; - adiff = characterize(a, b, &aval); - if (adiff == NULL) { - assert(!aval); - /* Either an error, or a is a subset with the same length so - * must be equal. - */ - res = PyErr_Occurred() ? -1 : 0; - goto Finished; - } - bdiff = characterize(b, a, &bval); - if (bdiff == NULL && PyErr_Occurred()) { - assert(!bval); - res = -1; - goto Finished; - } - res = 0; - if (bdiff) { - /* bdiff == NULL "should be" impossible now, but perhaps - * the last comparison done by the characterize() on a had - * the side effect of making the dicts equal! - */ - res = PyObject_Compare(adiff, bdiff); - } - if (res == 0 && bval != NULL) - res = PyObject_Compare(aval, bval); - -Finished: - Py_XDECREF(adiff); - Py_XDECREF(bdiff); - Py_XDECREF(aval); - Py_XDECREF(bval); - return res; -} - -/* Return 1 if dicts equal, 0 if not, -1 if error. - * Gets out as soon as any difference is detected. - * Uses only Py_EQ comparison. - */ -static int -dict_equal(dictobject *a, dictobject *b) -{ - Py_ssize_t i; - - if (a->ma_used != b->ma_used) - /* can't be equal if # of entries differ */ - return 0; - - /* Same # of entries -- check all of 'em. Exit early on any diff. */ - for (i = 0; i <= a->ma_mask; i++) { - PyObject *aval = a->ma_table[i].me_value; - if (aval != NULL) { - int cmp; - PyObject *bval; - PyObject *key = a->ma_table[i].me_key; - /* temporarily bump aval's refcount to ensure it stays - alive until we're done with it */ - Py_INCREF(aval); - /* ditto for key */ - Py_INCREF(key); - bval = PyDict_GetItem((PyObject *)b, key); - Py_DECREF(key); - if (bval == NULL) { - Py_DECREF(aval); - return 0; - } - cmp = PyObject_RichCompareBool(aval, bval, Py_EQ); - Py_DECREF(aval); - if (cmp <= 0) /* error or not equal */ - return cmp; - } - } - return 1; - } - -static PyObject * -dict_richcompare(PyObject *v, PyObject *w, int op) -{ - int cmp; - PyObject *res; - - if (!PyDict_Check(v) || !PyDict_Check(w)) { - res = Py_NotImplemented; - } - else if (op == Py_EQ || op == Py_NE) { - cmp = dict_equal((dictobject *)v, (dictobject *)w); - if (cmp < 0) - return NULL; - res = (cmp == (op == Py_EQ)) ? Py_True : Py_False; - } - else - res = Py_NotImplemented; - Py_INCREF(res); - return res; - } - -static PyObject * -dict_has_key(register dictobject *mp, PyObject *key) -{ - long hash; - dictentry *ep; - - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return NULL; - } - ep = (mp->ma_lookup)(mp, key, hash); - if (ep == NULL) - return NULL; - return PyBool_FromLong(ep->me_value != NULL); -} - -static PyObject * -dict_get(register dictobject *mp, PyObject *args) -{ - PyObject *key; - PyObject *failobj = Py_None; - PyObject *val = NULL; - long hash; - dictentry *ep; - - if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj)) - return NULL; - - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return NULL; - } - ep = (mp->ma_lookup)(mp, key, hash); - if (ep == NULL) - return NULL; - val = ep->me_value; - if (val == NULL) - val = failobj; - Py_INCREF(val); - return val; -} - - -static PyObject * -dict_setdefault(register dictobject *mp, PyObject *args) -{ - PyObject *key; - PyObject *failobj = Py_None; - PyObject *val = NULL; - long hash; - dictentry *ep; - - if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &failobj)) - return NULL; - - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return NULL; - } - ep = (mp->ma_lookup)(mp, key, hash); - if (ep == NULL) - return NULL; - val = ep->me_value; - if (val == NULL) { - val = failobj; - if (PyDict_SetItem((PyObject*)mp, key, failobj)) - val = NULL; - } - Py_XINCREF(val); - return val; -} - - -static PyObject * -dict_clear(register dictobject *mp) -{ - PyDict_Clear((PyObject *)mp); - Py_RETURN_NONE; -} - -static PyObject * -dict_pop(dictobject *mp, PyObject *args) -{ - long hash; - dictentry *ep; - PyObject *old_value, *old_key; - PyObject *key, *deflt = NULL; - - if(!PyArg_UnpackTuple(args, "pop", 1, 2, &key, &deflt)) - return NULL; - if (mp->ma_used == 0) { - if (deflt) { - Py_INCREF(deflt); - return deflt; - } - PyErr_SetString(PyExc_KeyError, - "pop(): dictionary is empty"); - return NULL; - } - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return NULL; - } - ep = (mp->ma_lookup)(mp, key, hash); - if (ep == NULL) - return NULL; - if (ep->me_value == NULL) { - if (deflt) { - Py_INCREF(deflt); - return deflt; - } - set_key_error(key); - return NULL; - } - old_key = ep->me_key; - Py_INCREF(dummy); - ep->me_key = dummy; - old_value = ep->me_value; - ep->me_value = NULL; - mp->ma_used--; - Py_DECREF(old_key); - return old_value; -} - -static PyObject * -dict_popitem(dictobject *mp) -{ - Py_ssize_t i = 0; - dictentry *ep; - PyObject *res; - - /* Allocate the result tuple before checking the size. Believe it - * or not, this allocation could trigger a garbage collection which - * could empty the dict, so if we checked the size first and that - * happened, the result would be an infinite loop (searching for an - * entry that no longer exists). Note that the usual popitem() - * idiom is "while d: k, v = d.popitem()". so needing to throw the - * tuple away if the dict *is* empty isn't a significant - * inefficiency -- possible, but unlikely in practice. - */ - res = PyTuple_New(2); - if (res == NULL) - return NULL; - if (mp->ma_used == 0) { - Py_DECREF(res); - PyErr_SetString(PyExc_KeyError, - "popitem(): dictionary is empty"); - return NULL; - } - /* Set ep to "the first" dict entry with a value. We abuse the hash - * field of slot 0 to hold a search finger: - * If slot 0 has a value, use slot 0. - * Else slot 0 is being used to hold a search finger, - * and we use its hash value as the first index to look. - */ - ep = &mp->ma_table[0]; - if (ep->me_value == NULL) { - i = ep->me_hash; - /* The hash field may be a real hash value, or it may be a - * legit search finger, or it may be a once-legit search - * finger that's out of bounds now because it wrapped around - * or the table shrunk -- simply make sure it's in bounds now. - */ - if (i > mp->ma_mask || i < 1) - i = 1; /* skip slot 0 */ - while ((ep = &mp->ma_table[i])->me_value == NULL) { - i++; - if (i > mp->ma_mask) - i = 1; - } - } - PyTuple_SET_ITEM(res, 0, ep->me_key); - PyTuple_SET_ITEM(res, 1, ep->me_value); - Py_INCREF(dummy); - ep->me_key = dummy; - ep->me_value = NULL; - mp->ma_used--; - assert(mp->ma_table[0].me_value == NULL); - mp->ma_table[0].me_hash = i + 1; /* next place to start */ - return res; -} - -static int -dict_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_ssize_t i = 0; - PyObject *pk; - PyObject *pv; - - while (PyDict_Next(op, &i, &pk, &pv)) { - Py_VISIT(pk); - Py_VISIT(pv); - } - return 0; -} - -static int -dict_tp_clear(PyObject *op) -{ - PyDict_Clear(op); - return 0; -} - - -extern PyTypeObject PyDictIterKey_Type; /* Forward */ -extern PyTypeObject PyDictIterValue_Type; /* Forward */ -extern PyTypeObject PyDictIterItem_Type; /* Forward */ -static PyObject *dictiter_new(dictobject *, PyTypeObject *); - -static PyObject * -dict_iterkeys(dictobject *dict) -{ - return dictiter_new(dict, &PyDictIterKey_Type); -} - -static PyObject * -dict_itervalues(dictobject *dict) -{ - return dictiter_new(dict, &PyDictIterValue_Type); -} - -static PyObject * -dict_iteritems(dictobject *dict) -{ - return dictiter_new(dict, &PyDictIterItem_Type); -} - - -PyDoc_STRVAR(has_key__doc__, -"D.has_key(k) -> True if D has a key k, else False"); - -PyDoc_STRVAR(contains__doc__, -"D.__contains__(k) -> True if D has a key k, else False"); - -PyDoc_STRVAR(getitem__doc__, "x.__getitem__(y) <==> x[y]"); - -PyDoc_STRVAR(get__doc__, -"D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."); - -PyDoc_STRVAR(setdefault_doc__, -"D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"); - -PyDoc_STRVAR(pop__doc__, -"D.pop(k[,d]) -> v, remove specified key and return the corresponding value\n\ -If key is not found, d is returned if given, otherwise KeyError is raised"); - -PyDoc_STRVAR(popitem__doc__, -"D.popitem() -> (k, v), remove and return some (key, value) pair as a\n\ -2-tuple; but raise KeyError if D is empty"); - -PyDoc_STRVAR(keys__doc__, -"D.keys() -> list of D's keys"); - -PyDoc_STRVAR(items__doc__, -"D.items() -> list of D's (key, value) pairs, as 2-tuples"); - -PyDoc_STRVAR(values__doc__, -"D.values() -> list of D's values"); - -PyDoc_STRVAR(update__doc__, -"D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] = E[k]\n\ -(if E has keys else: for (k, v) in E: D[k] = v) then: for k in F: D[k] = F[k]"); - -PyDoc_STRVAR(fromkeys__doc__, -"dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.\n\ -v defaults to None."); - -PyDoc_STRVAR(clear__doc__, -"D.clear() -> None. Remove all items from D."); - -PyDoc_STRVAR(copy__doc__, -"D.copy() -> a shallow copy of D"); - -PyDoc_STRVAR(iterkeys__doc__, -"D.iterkeys() -> an iterator over the keys of D"); - -PyDoc_STRVAR(itervalues__doc__, -"D.itervalues() -> an iterator over the values of D"); - -PyDoc_STRVAR(iteritems__doc__, -"D.iteritems() -> an iterator over the (key, value) items of D"); - -static PyMethodDef mapp_methods[] = { - {"__contains__",(PyCFunction)dict_has_key, METH_O | METH_COEXIST, - contains__doc__}, - {"__getitem__", (PyCFunction)dict_subscript, METH_O | METH_COEXIST, - getitem__doc__}, - {"has_key", (PyCFunction)dict_has_key, METH_O, - has_key__doc__}, - {"get", (PyCFunction)dict_get, METH_VARARGS, - get__doc__}, - {"setdefault", (PyCFunction)dict_setdefault, METH_VARARGS, - setdefault_doc__}, - {"pop", (PyCFunction)dict_pop, METH_VARARGS, - pop__doc__}, - {"popitem", (PyCFunction)dict_popitem, METH_NOARGS, - popitem__doc__}, - {"keys", (PyCFunction)dict_keys, METH_NOARGS, - keys__doc__}, - {"items", (PyCFunction)dict_items, METH_NOARGS, - items__doc__}, - {"values", (PyCFunction)dict_values, METH_NOARGS, - values__doc__}, - {"update", (PyCFunction)dict_update, METH_VARARGS | METH_KEYWORDS, - update__doc__}, - {"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS | METH_CLASS, - fromkeys__doc__}, - {"clear", (PyCFunction)dict_clear, METH_NOARGS, - clear__doc__}, - {"copy", (PyCFunction)dict_copy, METH_NOARGS, - copy__doc__}, - {"iterkeys", (PyCFunction)dict_iterkeys, METH_NOARGS, - iterkeys__doc__}, - {"itervalues", (PyCFunction)dict_itervalues, METH_NOARGS, - itervalues__doc__}, - {"iteritems", (PyCFunction)dict_iteritems, METH_NOARGS, - iteritems__doc__}, - {NULL, NULL} /* sentinel */ -}; - -/* Return 1 if `key` is in dict `op`, 0 if not, and -1 on error. */ -int -PyDict_Contains(PyObject *op, PyObject *key) -{ - long hash; - dictobject *mp = (dictobject *)op; - dictentry *ep; - - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return -1; - } - ep = (mp->ma_lookup)(mp, key, hash); - return ep == NULL ? -1 : (ep->me_value != NULL); -} - -/* Internal version of PyDict_Contains used when the hash value is already known */ -int -_PyDict_Contains(PyObject *op, PyObject *key, long hash) -{ - dictobject *mp = (dictobject *)op; - dictentry *ep; - - ep = (mp->ma_lookup)(mp, key, hash); - return ep == NULL ? -1 : (ep->me_value != NULL); -} - -/* Hack to implement "key in dict" */ -static PySequenceMethods dict_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - 0, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - PyDict_Contains, /* sq_contains */ - 0, /* sq_inplace_concat */ - 0, /* sq_inplace_repeat */ -}; - -static PyObject * -dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *self; - - assert(type != NULL && type->tp_alloc != NULL); - self = type->tp_alloc(type, 0); - if (self != NULL) { - PyDictObject *d = (PyDictObject *)self; - /* It's guaranteed that tp->alloc zeroed out the struct. */ - assert(d->ma_table == NULL && d->ma_fill == 0 && d->ma_used == 0); - INIT_NONZERO_DICT_SLOTS(d); - d->ma_lookup = lookdict_string; -#ifdef SHOW_CONVERSION_COUNTS - ++created; -#endif - } - return self; -} - -static int -dict_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - return dict_update_common(self, args, kwds, "dict"); -} - -static long -dict_nohash(PyObject *self) -{ - PyErr_SetString(PyExc_TypeError, "dict objects are unhashable"); - return -1; -} - -static PyObject * -dict_iter(dictobject *dict) -{ - return dictiter_new(dict, &PyDictIterKey_Type); -} - -PyDoc_STRVAR(dictionary_doc, -"dict() -> new empty dictionary.\n" -"dict(mapping) -> new dictionary initialized from a mapping object's\n" -" (key, value) pairs.\n" -"dict(seq) -> new dictionary initialized as if via:\n" -" d = {}\n" -" for k, v in seq:\n" -" d[k] = v\n" -"dict(**kwargs) -> new dictionary initialized with the name=value pairs\n" -" in the keyword argument list. For example: dict(one=1, two=2)"); - -PyTypeObject PyDict_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "dict", - sizeof(dictobject), - 0, - (destructor)dict_dealloc, /* tp_dealloc */ - (printfunc)dict_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)dict_compare, /* tp_compare */ - (reprfunc)dict_repr, /* tp_repr */ - 0, /* tp_as_number */ - &dict_as_sequence, /* tp_as_sequence */ - &dict_as_mapping, /* tp_as_mapping */ - dict_nohash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - dictionary_doc, /* tp_doc */ - dict_traverse, /* tp_traverse */ - dict_tp_clear, /* tp_clear */ - dict_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)dict_iter, /* tp_iter */ - 0, /* tp_iternext */ - mapp_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - dict_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - dict_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - -/* For backward compatibility with old dictionary interface */ - -PyObject * -PyDict_GetItemString(PyObject *v, const char *key) -{ - PyObject *kv, *rv; - kv = PyString_FromString(key); - if (kv == NULL) - return NULL; - rv = PyDict_GetItem(v, kv); - Py_DECREF(kv); - return rv; -} - -int -PyDict_SetItemString(PyObject *v, const char *key, PyObject *item) -{ - PyObject *kv; - int err; - kv = PyString_FromString(key); - if (kv == NULL) - return -1; - PyString_InternInPlace(&kv); /* XXX Should we really? */ - err = PyDict_SetItem(v, kv, item); - Py_DECREF(kv); - return err; -} - -int -PyDict_DelItemString(PyObject *v, const char *key) -{ - PyObject *kv; - int err; - kv = PyString_FromString(key); - if (kv == NULL) - return -1; - err = PyDict_DelItem(v, kv); - Py_DECREF(kv); - return err; -} - -/* Dictionary iterator types */ - -typedef struct { - PyObject_HEAD - dictobject *di_dict; /* Set to NULL when iterator is exhausted */ - Py_ssize_t di_used; - Py_ssize_t di_pos; - PyObject* di_result; /* reusable result tuple for iteritems */ - Py_ssize_t len; -} dictiterobject; - -static PyObject * -dictiter_new(dictobject *dict, PyTypeObject *itertype) -{ - dictiterobject *di; - di = PyObject_New(dictiterobject, itertype); - if (di == NULL) - return NULL; - Py_INCREF(dict); - di->di_dict = dict; - di->di_used = dict->ma_used; - di->di_pos = 0; - di->len = dict->ma_used; - if (itertype == &PyDictIterItem_Type) { - di->di_result = PyTuple_Pack(2, Py_None, Py_None); - if (di->di_result == NULL) { - Py_DECREF(di); - return NULL; - } - } - else - di->di_result = NULL; - return (PyObject *)di; -} - -static void -dictiter_dealloc(dictiterobject *di) -{ - Py_XDECREF(di->di_dict); - Py_XDECREF(di->di_result); - PyObject_Del(di); -} - -static PyObject * -dictiter_len(dictiterobject *di) -{ - Py_ssize_t len = 0; - if (di->di_dict != NULL && di->di_used == di->di_dict->ma_used) - len = di->len; - return PyInt_FromSize_t(len); -} - -PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - -static PyMethodDef dictiter_methods[] = { - {"__length_hint__", (PyCFunction)dictiter_len, METH_NOARGS, length_hint_doc}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject *dictiter_iternextkey(dictiterobject *di) -{ - PyObject *key; - register Py_ssize_t i, mask; - register dictentry *ep; - dictobject *d = di->di_dict; - - if (d == NULL) - return NULL; - assert (PyDict_Check(d)); - - if (di->di_used != d->ma_used) { - PyErr_SetString(PyExc_RuntimeError, - "dictionary changed size during iteration"); - di->di_used = -1; /* Make this state sticky */ - return NULL; - } - - i = di->di_pos; - if (i < 0) - goto fail; - ep = d->ma_table; - mask = d->ma_mask; - while (i <= mask && ep[i].me_value == NULL) - i++; - di->di_pos = i+1; - if (i > mask) - goto fail; - di->len--; - key = ep[i].me_key; - Py_INCREF(key); - return key; - -fail: - Py_DECREF(d); - di->di_dict = NULL; - return NULL; -} - -PyTypeObject PyDictIterKey_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "dictionary-keyiterator", /* tp_name */ - sizeof(dictiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dictiter_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)dictiter_iternextkey, /* tp_iternext */ - dictiter_methods, /* tp_methods */ - 0, -}; - -static PyObject *dictiter_iternextvalue(dictiterobject *di) -{ - PyObject *value; - register Py_ssize_t i, mask; - register dictentry *ep; - dictobject *d = di->di_dict; - - if (d == NULL) - return NULL; - assert (PyDict_Check(d)); - - if (di->di_used != d->ma_used) { - PyErr_SetString(PyExc_RuntimeError, - "dictionary changed size during iteration"); - di->di_used = -1; /* Make this state sticky */ - return NULL; - } - - i = di->di_pos; - mask = d->ma_mask; - if (i < 0 || i > mask) - goto fail; - ep = d->ma_table; - while ((value=ep[i].me_value) == NULL) { - i++; - if (i > mask) - goto fail; - } - di->di_pos = i+1; - di->len--; - Py_INCREF(value); - return value; - -fail: - Py_DECREF(d); - di->di_dict = NULL; - return NULL; -} - -PyTypeObject PyDictIterValue_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "dictionary-valueiterator", /* tp_name */ - sizeof(dictiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dictiter_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)dictiter_iternextvalue, /* tp_iternext */ - dictiter_methods, /* tp_methods */ - 0, -}; - -static PyObject *dictiter_iternextitem(dictiterobject *di) -{ - PyObject *key, *value, *result = di->di_result; - register Py_ssize_t i, mask; - register dictentry *ep; - dictobject *d = di->di_dict; - - if (d == NULL) - return NULL; - assert (PyDict_Check(d)); - - if (di->di_used != d->ma_used) { - PyErr_SetString(PyExc_RuntimeError, - "dictionary changed size during iteration"); - di->di_used = -1; /* Make this state sticky */ - return NULL; - } - - i = di->di_pos; - if (i < 0) - goto fail; - ep = d->ma_table; - mask = d->ma_mask; - while (i <= mask && ep[i].me_value == NULL) - i++; - di->di_pos = i+1; - if (i > mask) - goto fail; - - if (result->ob_refcnt == 1) { - Py_INCREF(result); - Py_DECREF(PyTuple_GET_ITEM(result, 0)); - Py_DECREF(PyTuple_GET_ITEM(result, 1)); - } else { - result = PyTuple_New(2); - if (result == NULL) - return NULL; - } - di->len--; - key = ep[i].me_key; - value = ep[i].me_value; - Py_INCREF(key); - Py_INCREF(value); - PyTuple_SET_ITEM(result, 0, key); - PyTuple_SET_ITEM(result, 1, value); - return result; - -fail: - Py_DECREF(d); - di->di_dict = NULL; - return NULL; -} - -PyTypeObject PyDictIterItem_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "dictionary-itemiterator", /* tp_name */ - sizeof(dictiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dictiter_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)dictiter_iternextitem, /* tp_iternext */ - dictiter_methods, /* tp_methods */ - 0, -}; diff --git a/sys/src/cmd/python/Objects/enumobject.c b/sys/src/cmd/python/Objects/enumobject.c deleted file mode 100644 index a456c9daf..000000000 --- a/sys/src/cmd/python/Objects/enumobject.c +++ /dev/null @@ -1,298 +0,0 @@ -/* enumerate object */ - -#include "Python.h" - -typedef struct { - PyObject_HEAD - long en_index; /* current index of enumeration */ - PyObject* en_sit; /* secondary iterator of enumeration */ - PyObject* en_result; /* result tuple */ -} enumobject; - -static PyObject * -enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - enumobject *en; - PyObject *seq = NULL; - static char *kwlist[] = {"sequence", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:enumerate", kwlist, - &seq)) - return NULL; - - en = (enumobject *)type->tp_alloc(type, 0); - if (en == NULL) - return NULL; - en->en_index = 0; - en->en_sit = PyObject_GetIter(seq); - if (en->en_sit == NULL) { - Py_DECREF(en); - return NULL; - } - en->en_result = PyTuple_Pack(2, Py_None, Py_None); - if (en->en_result == NULL) { - Py_DECREF(en); - return NULL; - } - return (PyObject *)en; -} - -static void -enum_dealloc(enumobject *en) -{ - PyObject_GC_UnTrack(en); - Py_XDECREF(en->en_sit); - Py_XDECREF(en->en_result); - en->ob_type->tp_free(en); -} - -static int -enum_traverse(enumobject *en, visitproc visit, void *arg) -{ - Py_VISIT(en->en_sit); - Py_VISIT(en->en_result); - return 0; -} - -static PyObject * -enum_next(enumobject *en) -{ - PyObject *next_index; - PyObject *next_item; - PyObject *result = en->en_result; - PyObject *it = en->en_sit; - - if (en->en_index == LONG_MAX) { - PyErr_SetString(PyExc_OverflowError, - "enumerate() is limited to LONG_MAX items"); - return NULL; - } - - next_item = (*it->ob_type->tp_iternext)(it); - if (next_item == NULL) - return NULL; - - next_index = PyInt_FromLong(en->en_index); - if (next_index == NULL) { - Py_DECREF(next_item); - return NULL; - } - en->en_index++; - - if (result->ob_refcnt == 1) { - Py_INCREF(result); - Py_DECREF(PyTuple_GET_ITEM(result, 0)); - Py_DECREF(PyTuple_GET_ITEM(result, 1)); - } else { - result = PyTuple_New(2); - if (result == NULL) { - Py_DECREF(next_index); - Py_DECREF(next_item); - return NULL; - } - } - PyTuple_SET_ITEM(result, 0, next_index); - PyTuple_SET_ITEM(result, 1, next_item); - return result; -} - -PyDoc_STRVAR(enum_doc, -"enumerate(iterable) -> iterator for index, value of iterable\n" -"\n" -"Return an enumerate object. iterable must be an other object that supports\n" -"iteration. The enumerate object yields pairs containing a count (from\n" -"zero) and a value yielded by the iterable argument. enumerate is useful\n" -"for obtaining an indexed list: (0, seq[0]), (1, seq[1]), (2, seq[2]), ..."); - -PyTypeObject PyEnum_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "enumerate", /* tp_name */ - sizeof(enumobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)enum_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - enum_doc, /* tp_doc */ - (traverseproc)enum_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)enum_next, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - enum_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - -/* Reversed Object ***************************************************************/ - -typedef struct { - PyObject_HEAD - Py_ssize_t index; - PyObject* seq; -} reversedobject; - -static PyObject * -reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Py_ssize_t n; - PyObject *seq; - reversedobject *ro; - - if (!PyArg_UnpackTuple(args, "reversed", 1, 1, &seq)) - return NULL; - - if (PyObject_HasAttrString(seq, "__reversed__")) - return PyObject_CallMethod(seq, "__reversed__", NULL); - - if (!PySequence_Check(seq)) { - PyErr_SetString(PyExc_TypeError, - "argument to reversed() must be a sequence"); - return NULL; - } - - n = PySequence_Size(seq); - if (n == -1) - return NULL; - - ro = (reversedobject *)type->tp_alloc(type, 0); - if (ro == NULL) - return NULL; - - ro->index = n-1; - Py_INCREF(seq); - ro->seq = seq; - return (PyObject *)ro; -} - -static void -reversed_dealloc(reversedobject *ro) -{ - PyObject_GC_UnTrack(ro); - Py_XDECREF(ro->seq); - ro->ob_type->tp_free(ro); -} - -static int -reversed_traverse(reversedobject *ro, visitproc visit, void *arg) -{ - Py_VISIT(ro->seq); - return 0; -} - -static PyObject * -reversed_next(reversedobject *ro) -{ - PyObject *item; - Py_ssize_t index = ro->index; - - if (index >= 0) { - item = PySequence_GetItem(ro->seq, index); - if (item != NULL) { - ro->index--; - return item; - } - if (PyErr_ExceptionMatches(PyExc_IndexError) || - PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); - } - ro->index = -1; - Py_CLEAR(ro->seq); - return NULL; -} - -PyDoc_STRVAR(reversed_doc, -"reversed(sequence) -> reverse iterator over values of the sequence\n" -"\n" -"Return a reverse iterator"); - -static PyObject * -reversed_len(reversedobject *ro) -{ - Py_ssize_t position, seqsize; - - if (ro->seq == NULL) - return PyInt_FromLong(0); - seqsize = PySequence_Size(ro->seq); - if (seqsize == -1) - return NULL; - position = ro->index + 1; - return PyInt_FromSsize_t((seqsize < position) ? 0 : position); -} - -PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - -static PyMethodDef reversediter_methods[] = { - {"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc}, - {NULL, NULL} /* sentinel */ -}; - -PyTypeObject PyReversed_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "reversed", /* tp_name */ - sizeof(reversedobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)reversed_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - reversed_doc, /* tp_doc */ - (traverseproc)reversed_traverse,/* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)reversed_next, /* tp_iternext */ - reversediter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - reversed_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; diff --git a/sys/src/cmd/python/Objects/exceptions.c b/sys/src/cmd/python/Objects/exceptions.c deleted file mode 100644 index 0cd819c5a..000000000 --- a/sys/src/cmd/python/Objects/exceptions.c +++ /dev/null @@ -1,2147 +0,0 @@ -/* - * New exceptions.c written in Iceland by Richard Jones and Georg Brandl. - * - * Thanks go to Tim Peters and Michael Hudson for debugging. - */ - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include "structmember.h" -#include "osdefs.h" - -#define MAKE_IT_NONE(x) (x) = Py_None; Py_INCREF(Py_None); -#define EXC_MODULE_NAME "exceptions." - -/* NOTE: If the exception class hierarchy changes, don't forget to update - * Lib/test/exception_hierarchy.txt - */ - -PyDoc_STRVAR(exceptions_doc, "Python's standard exception class hierarchy.\n\ -\n\ -Exceptions found here are defined both in the exceptions module and the\n\ -built-in namespace. It is recommended that user-defined exceptions\n\ -inherit from Exception. See the documentation for the exception\n\ -inheritance hierarchy.\n\ -"); - -/* - * BaseException - */ -static PyObject * -BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyBaseExceptionObject *self; - - self = (PyBaseExceptionObject *)type->tp_alloc(type, 0); - /* the dict is created on the fly in PyObject_GenericSetAttr */ - self->message = self->dict = NULL; - - self->args = PyTuple_New(0); - if (!self->args) { - Py_DECREF(self); - return NULL; - } - - self->message = PyString_FromString(""); - if (!self->message) { - Py_DECREF(self); - return NULL; - } - - return (PyObject *)self; -} - -static int -BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds) -{ - if (!_PyArg_NoKeywords(self->ob_type->tp_name, kwds)) - return -1; - - Py_DECREF(self->args); - self->args = args; - Py_INCREF(self->args); - - if (PyTuple_GET_SIZE(self->args) == 1) { - Py_CLEAR(self->message); - self->message = PyTuple_GET_ITEM(self->args, 0); - Py_INCREF(self->message); - } - return 0; -} - -static int -BaseException_clear(PyBaseExceptionObject *self) -{ - Py_CLEAR(self->dict); - Py_CLEAR(self->args); - Py_CLEAR(self->message); - return 0; -} - -static void -BaseException_dealloc(PyBaseExceptionObject *self) -{ - _PyObject_GC_UNTRACK(self); - BaseException_clear(self); - self->ob_type->tp_free((PyObject *)self); -} - -static int -BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg) -{ - Py_VISIT(self->dict); - Py_VISIT(self->args); - Py_VISIT(self->message); - return 0; -} - -static PyObject * -BaseException_str(PyBaseExceptionObject *self) -{ - PyObject *out; - - switch (PyTuple_GET_SIZE(self->args)) { - case 0: - out = PyString_FromString(""); - break; - case 1: - out = PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); - break; - default: - out = PyObject_Str(self->args); - break; - } - - return out; -} - -static PyObject * -BaseException_repr(PyBaseExceptionObject *self) -{ - PyObject *repr_suffix; - PyObject *repr; - char *name; - char *dot; - - repr_suffix = PyObject_Repr(self->args); - if (!repr_suffix) - return NULL; - - name = (char *)self->ob_type->tp_name; - dot = strrchr(name, '.'); - if (dot != NULL) name = dot+1; - - repr = PyString_FromString(name); - if (!repr) { - Py_DECREF(repr_suffix); - return NULL; - } - - PyString_ConcatAndDel(&repr, repr_suffix); - return repr; -} - -/* Pickling support */ -static PyObject * -BaseException_reduce(PyBaseExceptionObject *self) -{ - if (self->args && self->dict) - return PyTuple_Pack(3, self->ob_type, self->args, self->dict); - else - return PyTuple_Pack(2, self->ob_type, self->args); -} - -/* - * Needed for backward compatibility, since exceptions used to store - * all their attributes in the __dict__. Code is taken from cPickle's - * load_build function. - */ -static PyObject * -BaseException_setstate(PyObject *self, PyObject *state) -{ - PyObject *d_key, *d_value; - Py_ssize_t i = 0; - - if (state != Py_None) { - if (!PyDict_Check(state)) { - PyErr_SetString(PyExc_TypeError, "state is not a dictionary"); - return NULL; - } - while (PyDict_Next(state, &i, &d_key, &d_value)) { - if (PyObject_SetAttr(self, d_key, d_value) < 0) - return NULL; - } - } - Py_RETURN_NONE; -} - - -static PyMethodDef BaseException_methods[] = { - {"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS }, - {"__setstate__", (PyCFunction)BaseException_setstate, METH_O }, - {NULL, NULL, 0, NULL}, -}; - - - -static PyObject * -BaseException_getitem(PyBaseExceptionObject *self, Py_ssize_t index) -{ - return PySequence_GetItem(self->args, index); -} - -static PyObject * -BaseException_getslice(PyBaseExceptionObject *self, - Py_ssize_t start, Py_ssize_t stop) -{ - return PySequence_GetSlice(self->args, start, stop); -} - -static PySequenceMethods BaseException_as_sequence = { - 0, /* sq_length; */ - 0, /* sq_concat; */ - 0, /* sq_repeat; */ - (ssizeargfunc)BaseException_getitem, /* sq_item; */ - (ssizessizeargfunc)BaseException_getslice, /* sq_slice; */ - 0, /* sq_ass_item; */ - 0, /* sq_ass_slice; */ - 0, /* sq_contains; */ - 0, /* sq_inplace_concat; */ - 0 /* sq_inplace_repeat; */ -}; - -static PyMemberDef BaseException_members[] = { - {"message", T_OBJECT, offsetof(PyBaseExceptionObject, message), 0, - PyDoc_STR("exception message")}, - {NULL} /* Sentinel */ -}; - - -static PyObject * -BaseException_get_dict(PyBaseExceptionObject *self) -{ - if (self->dict == NULL) { - self->dict = PyDict_New(); - if (!self->dict) - return NULL; - } - Py_INCREF(self->dict); - return self->dict; -} - -static int -BaseException_set_dict(PyBaseExceptionObject *self, PyObject *val) -{ - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted"); - return -1; - } - if (!PyDict_Check(val)) { - PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary"); - return -1; - } - Py_CLEAR(self->dict); - Py_INCREF(val); - self->dict = val; - return 0; -} - -static PyObject * -BaseException_get_args(PyBaseExceptionObject *self) -{ - if (self->args == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - Py_INCREF(self->args); - return self->args; -} - -static int -BaseException_set_args(PyBaseExceptionObject *self, PyObject *val) -{ - PyObject *seq; - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "args may not be deleted"); - return -1; - } - seq = PySequence_Tuple(val); - if (!seq) return -1; - Py_CLEAR(self->args); - self->args = seq; - return 0; -} - -static PyGetSetDef BaseException_getset[] = { - {"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict}, - {"args", (getter)BaseException_get_args, (setter)BaseException_set_args}, - {NULL}, -}; - - -static PyTypeObject _PyExc_BaseException = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - EXC_MODULE_NAME "BaseException", /*tp_name*/ - sizeof(PyBaseExceptionObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)BaseException_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /* tp_compare; */ - (reprfunc)BaseException_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - &BaseException_as_sequence, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - (reprfunc)BaseException_str, /*tp_str*/ - PyObject_GenericGetAttr, /*tp_getattro*/ - PyObject_GenericSetAttr, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - PyDoc_STR("Common base class for all exceptions"), /* tp_doc */ - (traverseproc)BaseException_traverse, /* tp_traverse */ - (inquiry)BaseException_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - BaseException_methods, /* tp_methods */ - BaseException_members, /* tp_members */ - BaseException_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(PyBaseExceptionObject, dict), /* tp_dictoffset */ - (initproc)BaseException_init, /* tp_init */ - 0, /* tp_alloc */ - BaseException_new, /* tp_new */ -}; -/* the CPython API expects exceptions to be (PyObject *) - both a hold-over -from the previous implmentation and also allowing Python objects to be used -in the API */ -PyObject *PyExc_BaseException = (PyObject *)&_PyExc_BaseException; - -/* note these macros omit the last semicolon so the macro invocation may - * include it and not look strange. - */ -#define SimpleExtendsException(EXCBASE, EXCNAME, EXCDOC) \ -static PyTypeObject _PyExc_ ## EXCNAME = { \ - PyObject_HEAD_INIT(NULL) \ - 0, \ - EXC_MODULE_NAME # EXCNAME, \ - sizeof(PyBaseExceptionObject), \ - 0, (destructor)BaseException_dealloc, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, \ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ - PyDoc_STR(EXCDOC), (traverseproc)BaseException_traverse, \ - (inquiry)BaseException_clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ - 0, 0, 0, offsetof(PyBaseExceptionObject, dict), \ - (initproc)BaseException_init, 0, BaseException_new,\ -}; \ -PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME - -#define MiddlingExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCDOC) \ -static PyTypeObject _PyExc_ ## EXCNAME = { \ - PyObject_HEAD_INIT(NULL) \ - 0, \ - EXC_MODULE_NAME # EXCNAME, \ - sizeof(Py ## EXCSTORE ## Object), \ - 0, (destructor)EXCSTORE ## _dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, \ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ - PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ - (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ - 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ - (initproc)EXCSTORE ## _init, 0, BaseException_new,\ -}; \ -PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME - -#define ComplexExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCDEALLOC, EXCMETHODS, EXCMEMBERS, EXCSTR, EXCDOC) \ -static PyTypeObject _PyExc_ ## EXCNAME = { \ - PyObject_HEAD_INIT(NULL) \ - 0, \ - EXC_MODULE_NAME # EXCNAME, \ - sizeof(Py ## EXCSTORE ## Object), 0, \ - (destructor)EXCSTORE ## _dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - (reprfunc)EXCSTR, 0, 0, 0, \ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ - PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ - (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, EXCMETHODS, \ - EXCMEMBERS, 0, &_ ## EXCBASE, \ - 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ - (initproc)EXCSTORE ## _init, 0, BaseException_new,\ -}; \ -PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME - - -/* - * Exception extends BaseException - */ -SimpleExtendsException(PyExc_BaseException, Exception, - "Common base class for all non-exit exceptions."); - - -/* - * StandardError extends Exception - */ -SimpleExtendsException(PyExc_Exception, StandardError, - "Base class for all standard Python exceptions that do not represent\n" - "interpreter exiting."); - - -/* - * TypeError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, TypeError, - "Inappropriate argument type."); - - -/* - * StopIteration extends Exception - */ -SimpleExtendsException(PyExc_Exception, StopIteration, - "Signal the end from iterator.next()."); - - -/* - * GeneratorExit extends Exception - */ -SimpleExtendsException(PyExc_Exception, GeneratorExit, - "Request that a generator exit."); - - -/* - * SystemExit extends BaseException - */ - -static int -SystemExit_init(PySystemExitObject *self, PyObject *args, PyObject *kwds) -{ - Py_ssize_t size = PyTuple_GET_SIZE(args); - - if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) - return -1; - - if (size == 0) - return 0; - Py_CLEAR(self->code); - if (size == 1) - self->code = PyTuple_GET_ITEM(args, 0); - else if (size > 1) - self->code = args; - Py_INCREF(self->code); - return 0; -} - -static int -SystemExit_clear(PySystemExitObject *self) -{ - Py_CLEAR(self->code); - return BaseException_clear((PyBaseExceptionObject *)self); -} - -static void -SystemExit_dealloc(PySystemExitObject *self) -{ - _PyObject_GC_UNTRACK(self); - SystemExit_clear(self); - self->ob_type->tp_free((PyObject *)self); -} - -static int -SystemExit_traverse(PySystemExitObject *self, visitproc visit, void *arg) -{ - Py_VISIT(self->code); - return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); -} - -static PyMemberDef SystemExit_members[] = { - {"message", T_OBJECT, offsetof(PySystemExitObject, message), 0, - PyDoc_STR("exception message")}, - {"code", T_OBJECT, offsetof(PySystemExitObject, code), 0, - PyDoc_STR("exception code")}, - {NULL} /* Sentinel */ -}; - -ComplexExtendsException(PyExc_BaseException, SystemExit, SystemExit, - SystemExit_dealloc, 0, SystemExit_members, 0, - "Request to exit from the interpreter."); - -/* - * KeyboardInterrupt extends BaseException - */ -SimpleExtendsException(PyExc_BaseException, KeyboardInterrupt, - "Program interrupted by user."); - - -/* - * ImportError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, ImportError, - "Import can't find module, or can't find name in module."); - - -/* - * EnvironmentError extends StandardError - */ - -/* Where a function has a single filename, such as open() or some - * of the os module functions, PyErr_SetFromErrnoWithFilename() is - * called, giving a third argument which is the filename. But, so - * that old code using in-place unpacking doesn't break, e.g.: - * - * except IOError, (errno, strerror): - * - * we hack args so that it only contains two items. This also - * means we need our own __str__() which prints out the filename - * when it was supplied. - */ -static int -EnvironmentError_init(PyEnvironmentErrorObject *self, PyObject *args, - PyObject *kwds) -{ - PyObject *myerrno = NULL, *strerror = NULL, *filename = NULL; - PyObject *subslice = NULL; - - if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) - return -1; - - if (PyTuple_GET_SIZE(args) <= 1 || PyTuple_GET_SIZE(args) > 3) { - return 0; - } - - if (!PyArg_UnpackTuple(args, "EnvironmentError", 2, 3, - &myerrno, &strerror, &filename)) { - return -1; - } - Py_CLEAR(self->myerrno); /* replacing */ - self->myerrno = myerrno; - Py_INCREF(self->myerrno); - - Py_CLEAR(self->strerror); /* replacing */ - self->strerror = strerror; - Py_INCREF(self->strerror); - - /* self->filename will remain Py_None otherwise */ - if (filename != NULL) { - Py_CLEAR(self->filename); /* replacing */ - self->filename = filename; - Py_INCREF(self->filename); - - subslice = PyTuple_GetSlice(args, 0, 2); - if (!subslice) - return -1; - - Py_DECREF(self->args); /* replacing args */ - self->args = subslice; - } - return 0; -} - -static int -EnvironmentError_clear(PyEnvironmentErrorObject *self) -{ - Py_CLEAR(self->myerrno); - Py_CLEAR(self->strerror); - Py_CLEAR(self->filename); - return BaseException_clear((PyBaseExceptionObject *)self); -} - -static void -EnvironmentError_dealloc(PyEnvironmentErrorObject *self) -{ - _PyObject_GC_UNTRACK(self); - EnvironmentError_clear(self); - self->ob_type->tp_free((PyObject *)self); -} - -static int -EnvironmentError_traverse(PyEnvironmentErrorObject *self, visitproc visit, - void *arg) -{ - Py_VISIT(self->myerrno); - Py_VISIT(self->strerror); - Py_VISIT(self->filename); - return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); -} - -static PyObject * -EnvironmentError_str(PyEnvironmentErrorObject *self) -{ - PyObject *rtnval = NULL; - - if (self->filename) { - PyObject *fmt; - PyObject *repr; - PyObject *tuple; - - fmt = PyString_FromString("[Errno %s] %s: %s"); - if (!fmt) - return NULL; - - repr = PyObject_Repr(self->filename); - if (!repr) { - Py_DECREF(fmt); - return NULL; - } - tuple = PyTuple_New(3); - if (!tuple) { - Py_DECREF(repr); - Py_DECREF(fmt); - return NULL; - } - - if (self->myerrno) { - Py_INCREF(self->myerrno); - PyTuple_SET_ITEM(tuple, 0, self->myerrno); - } - else { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(tuple, 0, Py_None); - } - if (self->strerror) { - Py_INCREF(self->strerror); - PyTuple_SET_ITEM(tuple, 1, self->strerror); - } - else { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(tuple, 1, Py_None); - } - - PyTuple_SET_ITEM(tuple, 2, repr); - - rtnval = PyString_Format(fmt, tuple); - - Py_DECREF(fmt); - Py_DECREF(tuple); - } - else if (self->myerrno && self->strerror) { - PyObject *fmt; - PyObject *tuple; - - fmt = PyString_FromString("[Errno %s] %s"); - if (!fmt) - return NULL; - - tuple = PyTuple_New(2); - if (!tuple) { - Py_DECREF(fmt); - return NULL; - } - - if (self->myerrno) { - Py_INCREF(self->myerrno); - PyTuple_SET_ITEM(tuple, 0, self->myerrno); - } - else { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(tuple, 0, Py_None); - } - if (self->strerror) { - Py_INCREF(self->strerror); - PyTuple_SET_ITEM(tuple, 1, self->strerror); - } - else { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(tuple, 1, Py_None); - } - - rtnval = PyString_Format(fmt, tuple); - - Py_DECREF(fmt); - Py_DECREF(tuple); - } - else - rtnval = BaseException_str((PyBaseExceptionObject *)self); - - return rtnval; -} - -static PyMemberDef EnvironmentError_members[] = { - {"message", T_OBJECT, offsetof(PyEnvironmentErrorObject, message), 0, - PyDoc_STR("exception message")}, - {"errno", T_OBJECT, offsetof(PyEnvironmentErrorObject, myerrno), 0, - PyDoc_STR("exception errno")}, - {"strerror", T_OBJECT, offsetof(PyEnvironmentErrorObject, strerror), 0, - PyDoc_STR("exception strerror")}, - {"filename", T_OBJECT, offsetof(PyEnvironmentErrorObject, filename), 0, - PyDoc_STR("exception filename")}, - {NULL} /* Sentinel */ -}; - - -static PyObject * -EnvironmentError_reduce(PyEnvironmentErrorObject *self) -{ - PyObject *args = self->args; - PyObject *res = NULL, *tmp; - - /* self->args is only the first two real arguments if there was a - * file name given to EnvironmentError. */ - if (PyTuple_GET_SIZE(args) == 2 && self->filename) { - args = PyTuple_New(3); - if (!args) return NULL; - - tmp = PyTuple_GET_ITEM(self->args, 0); - Py_INCREF(tmp); - PyTuple_SET_ITEM(args, 0, tmp); - - tmp = PyTuple_GET_ITEM(self->args, 1); - Py_INCREF(tmp); - PyTuple_SET_ITEM(args, 1, tmp); - - Py_INCREF(self->filename); - PyTuple_SET_ITEM(args, 2, self->filename); - } else - Py_INCREF(args); - - if (self->dict) - res = PyTuple_Pack(3, self->ob_type, args, self->dict); - else - res = PyTuple_Pack(2, self->ob_type, args); - Py_DECREF(args); - return res; -} - - -static PyMethodDef EnvironmentError_methods[] = { - {"__reduce__", (PyCFunction)EnvironmentError_reduce, METH_NOARGS}, - {NULL} -}; - -ComplexExtendsException(PyExc_StandardError, EnvironmentError, - EnvironmentError, EnvironmentError_dealloc, - EnvironmentError_methods, EnvironmentError_members, - EnvironmentError_str, - "Base class for I/O related errors."); - - -/* - * IOError extends EnvironmentError - */ -MiddlingExtendsException(PyExc_EnvironmentError, IOError, - EnvironmentError, "I/O operation failed."); - - -/* - * OSError extends EnvironmentError - */ -MiddlingExtendsException(PyExc_EnvironmentError, OSError, - EnvironmentError, "OS system call failed."); - - -/* - * WindowsError extends OSError - */ -#ifdef MS_WINDOWS -#include "errmap.h" - -static int -WindowsError_clear(PyWindowsErrorObject *self) -{ - Py_CLEAR(self->myerrno); - Py_CLEAR(self->strerror); - Py_CLEAR(self->filename); - Py_CLEAR(self->winerror); - return BaseException_clear((PyBaseExceptionObject *)self); -} - -static void -WindowsError_dealloc(PyWindowsErrorObject *self) -{ - _PyObject_GC_UNTRACK(self); - WindowsError_clear(self); - self->ob_type->tp_free((PyObject *)self); -} - -static int -WindowsError_traverse(PyWindowsErrorObject *self, visitproc visit, void *arg) -{ - Py_VISIT(self->myerrno); - Py_VISIT(self->strerror); - Py_VISIT(self->filename); - Py_VISIT(self->winerror); - return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); -} - -static int -WindowsError_init(PyWindowsErrorObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *o_errcode = NULL; - long errcode; - long posix_errno; - - if (EnvironmentError_init((PyEnvironmentErrorObject *)self, args, kwds) - == -1) - return -1; - - if (self->myerrno == NULL) - return 0; - - /* Set errno to the POSIX errno, and winerror to the Win32 - error code. */ - errcode = PyInt_AsLong(self->myerrno); - if (errcode == -1 && PyErr_Occurred()) - return -1; - posix_errno = winerror_to_errno(errcode); - - Py_CLEAR(self->winerror); - self->winerror = self->myerrno; - - o_errcode = PyInt_FromLong(posix_errno); - if (!o_errcode) - return -1; - - self->myerrno = o_errcode; - - return 0; -} - - -static PyObject * -WindowsError_str(PyWindowsErrorObject *self) -{ - PyObject *rtnval = NULL; - - if (self->filename) { - PyObject *fmt; - PyObject *repr; - PyObject *tuple; - - fmt = PyString_FromString("[Error %s] %s: %s"); - if (!fmt) - return NULL; - - repr = PyObject_Repr(self->filename); - if (!repr) { - Py_DECREF(fmt); - return NULL; - } - tuple = PyTuple_New(3); - if (!tuple) { - Py_DECREF(repr); - Py_DECREF(fmt); - return NULL; - } - - if (self->winerror) { - Py_INCREF(self->winerror); - PyTuple_SET_ITEM(tuple, 0, self->winerror); - } - else { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(tuple, 0, Py_None); - } - if (self->strerror) { - Py_INCREF(self->strerror); - PyTuple_SET_ITEM(tuple, 1, self->strerror); - } - else { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(tuple, 1, Py_None); - } - - PyTuple_SET_ITEM(tuple, 2, repr); - - rtnval = PyString_Format(fmt, tuple); - - Py_DECREF(fmt); - Py_DECREF(tuple); - } - else if (self->winerror && self->strerror) { - PyObject *fmt; - PyObject *tuple; - - fmt = PyString_FromString("[Error %s] %s"); - if (!fmt) - return NULL; - - tuple = PyTuple_New(2); - if (!tuple) { - Py_DECREF(fmt); - return NULL; - } - - if (self->winerror) { - Py_INCREF(self->winerror); - PyTuple_SET_ITEM(tuple, 0, self->winerror); - } - else { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(tuple, 0, Py_None); - } - if (self->strerror) { - Py_INCREF(self->strerror); - PyTuple_SET_ITEM(tuple, 1, self->strerror); - } - else { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(tuple, 1, Py_None); - } - - rtnval = PyString_Format(fmt, tuple); - - Py_DECREF(fmt); - Py_DECREF(tuple); - } - else - rtnval = EnvironmentError_str((PyEnvironmentErrorObject *)self); - - return rtnval; -} - -static PyMemberDef WindowsError_members[] = { - {"message", T_OBJECT, offsetof(PyWindowsErrorObject, message), 0, - PyDoc_STR("exception message")}, - {"errno", T_OBJECT, offsetof(PyWindowsErrorObject, myerrno), 0, - PyDoc_STR("POSIX exception code")}, - {"strerror", T_OBJECT, offsetof(PyWindowsErrorObject, strerror), 0, - PyDoc_STR("exception strerror")}, - {"filename", T_OBJECT, offsetof(PyWindowsErrorObject, filename), 0, - PyDoc_STR("exception filename")}, - {"winerror", T_OBJECT, offsetof(PyWindowsErrorObject, winerror), 0, - PyDoc_STR("Win32 exception code")}, - {NULL} /* Sentinel */ -}; - -ComplexExtendsException(PyExc_OSError, WindowsError, WindowsError, - WindowsError_dealloc, 0, WindowsError_members, - WindowsError_str, "MS-Windows OS system call failed."); - -#endif /* MS_WINDOWS */ - - -/* - * VMSError extends OSError (I think) - */ -#ifdef __VMS -MiddlingExtendsException(PyExc_OSError, VMSError, EnvironmentError, - "OpenVMS OS system call failed."); -#endif - - -/* - * EOFError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, EOFError, - "Read beyond end of file."); - - -/* - * RuntimeError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, RuntimeError, - "Unspecified run-time error."); - - -/* - * NotImplementedError extends RuntimeError - */ -SimpleExtendsException(PyExc_RuntimeError, NotImplementedError, - "Method or function hasn't been implemented yet."); - -/* - * NameError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, NameError, - "Name not found globally."); - -/* - * UnboundLocalError extends NameError - */ -SimpleExtendsException(PyExc_NameError, UnboundLocalError, - "Local name referenced but not bound to a value."); - -/* - * AttributeError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, AttributeError, - "Attribute not found."); - - -/* - * SyntaxError extends StandardError - */ - -static int -SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *info = NULL; - Py_ssize_t lenargs = PyTuple_GET_SIZE(args); - - if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) - return -1; - - if (lenargs >= 1) { - Py_CLEAR(self->msg); - self->msg = PyTuple_GET_ITEM(args, 0); - Py_INCREF(self->msg); - } - if (lenargs == 2) { - info = PyTuple_GET_ITEM(args, 1); - info = PySequence_Tuple(info); - if (!info) return -1; - - if (PyTuple_GET_SIZE(info) != 4) { - /* not a very good error message, but it's what Python 2.4 gives */ - PyErr_SetString(PyExc_IndexError, "tuple index out of range"); - Py_DECREF(info); - return -1; - } - - Py_CLEAR(self->filename); - self->filename = PyTuple_GET_ITEM(info, 0); - Py_INCREF(self->filename); - - Py_CLEAR(self->lineno); - self->lineno = PyTuple_GET_ITEM(info, 1); - Py_INCREF(self->lineno); - - Py_CLEAR(self->offset); - self->offset = PyTuple_GET_ITEM(info, 2); - Py_INCREF(self->offset); - - Py_CLEAR(self->text); - self->text = PyTuple_GET_ITEM(info, 3); - Py_INCREF(self->text); - - Py_DECREF(info); - } - return 0; -} - -static int -SyntaxError_clear(PySyntaxErrorObject *self) -{ - Py_CLEAR(self->msg); - Py_CLEAR(self->filename); - Py_CLEAR(self->lineno); - Py_CLEAR(self->offset); - Py_CLEAR(self->text); - Py_CLEAR(self->print_file_and_line); - return BaseException_clear((PyBaseExceptionObject *)self); -} - -static void -SyntaxError_dealloc(PySyntaxErrorObject *self) -{ - _PyObject_GC_UNTRACK(self); - SyntaxError_clear(self); - self->ob_type->tp_free((PyObject *)self); -} - -static int -SyntaxError_traverse(PySyntaxErrorObject *self, visitproc visit, void *arg) -{ - Py_VISIT(self->msg); - Py_VISIT(self->filename); - Py_VISIT(self->lineno); - Py_VISIT(self->offset); - Py_VISIT(self->text); - Py_VISIT(self->print_file_and_line); - return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); -} - -/* This is called "my_basename" instead of just "basename" to avoid name - conflicts with glibc; basename is already prototyped if _GNU_SOURCE is - defined, and Python does define that. */ -static char * -my_basename(char *name) -{ - char *cp = name; - char *result = name; - - if (name == NULL) - return "???"; - while (*cp != '\0') { - if (*cp == SEP) - result = cp + 1; - ++cp; - } - return result; -} - - -static PyObject * -SyntaxError_str(PySyntaxErrorObject *self) -{ - PyObject *str; - PyObject *result; - int have_filename = 0; - int have_lineno = 0; - char *buffer = NULL; - Py_ssize_t bufsize; - - if (self->msg) - str = PyObject_Str(self->msg); - else - str = PyObject_Str(Py_None); - if (!str) return NULL; - /* Don't fiddle with non-string return (shouldn't happen anyway) */ - if (!PyString_Check(str)) return str; - - /* XXX -- do all the additional formatting with filename and - lineno here */ - - have_filename = (self->filename != NULL) && - PyString_Check(self->filename); - have_lineno = (self->lineno != NULL) && PyInt_Check(self->lineno); - - if (!have_filename && !have_lineno) - return str; - - bufsize = PyString_GET_SIZE(str) + 64; - if (have_filename) - bufsize += PyString_GET_SIZE(self->filename); - - buffer = PyMem_MALLOC(bufsize); - if (buffer == NULL) - return str; - - if (have_filename && have_lineno) - PyOS_snprintf(buffer, bufsize, "%s (%s, line %ld)", - PyString_AS_STRING(str), - my_basename(PyString_AS_STRING(self->filename)), - PyInt_AsLong(self->lineno)); - else if (have_filename) - PyOS_snprintf(buffer, bufsize, "%s (%s)", - PyString_AS_STRING(str), - my_basename(PyString_AS_STRING(self->filename))); - else /* only have_lineno */ - PyOS_snprintf(buffer, bufsize, "%s (line %ld)", - PyString_AS_STRING(str), - PyInt_AsLong(self->lineno)); - - result = PyString_FromString(buffer); - PyMem_FREE(buffer); - - if (result == NULL) - result = str; - else - Py_DECREF(str); - return result; -} - -static PyMemberDef SyntaxError_members[] = { - {"message", T_OBJECT, offsetof(PySyntaxErrorObject, message), 0, - PyDoc_STR("exception message")}, - {"msg", T_OBJECT, offsetof(PySyntaxErrorObject, msg), 0, - PyDoc_STR("exception msg")}, - {"filename", T_OBJECT, offsetof(PySyntaxErrorObject, filename), 0, - PyDoc_STR("exception filename")}, - {"lineno", T_OBJECT, offsetof(PySyntaxErrorObject, lineno), 0, - PyDoc_STR("exception lineno")}, - {"offset", T_OBJECT, offsetof(PySyntaxErrorObject, offset), 0, - PyDoc_STR("exception offset")}, - {"text", T_OBJECT, offsetof(PySyntaxErrorObject, text), 0, - PyDoc_STR("exception text")}, - {"print_file_and_line", T_OBJECT, - offsetof(PySyntaxErrorObject, print_file_and_line), 0, - PyDoc_STR("exception print_file_and_line")}, - {NULL} /* Sentinel */ -}; - -ComplexExtendsException(PyExc_StandardError, SyntaxError, SyntaxError, - SyntaxError_dealloc, 0, SyntaxError_members, - SyntaxError_str, "Invalid syntax."); - - -/* - * IndentationError extends SyntaxError - */ -MiddlingExtendsException(PyExc_SyntaxError, IndentationError, SyntaxError, - "Improper indentation."); - - -/* - * TabError extends IndentationError - */ -MiddlingExtendsException(PyExc_IndentationError, TabError, SyntaxError, - "Improper mixture of spaces and tabs."); - - -/* - * LookupError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, LookupError, - "Base class for lookup errors."); - - -/* - * IndexError extends LookupError - */ -SimpleExtendsException(PyExc_LookupError, IndexError, - "Sequence index out of range."); - - -/* - * KeyError extends LookupError - */ -static PyObject * -KeyError_str(PyBaseExceptionObject *self) -{ - /* If args is a tuple of exactly one item, apply repr to args[0]. - This is done so that e.g. the exception raised by {}[''] prints - KeyError: '' - rather than the confusing - KeyError - alone. The downside is that if KeyError is raised with an explanatory - string, that string will be displayed in quotes. Too bad. - If args is anything else, use the default BaseException__str__(). - */ - if (PyTuple_GET_SIZE(self->args) == 1) { - return PyObject_Repr(PyTuple_GET_ITEM(self->args, 0)); - } - return BaseException_str(self); -} - -ComplexExtendsException(PyExc_LookupError, KeyError, BaseException, - 0, 0, 0, KeyError_str, "Mapping key not found."); - - -/* - * ValueError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, ValueError, - "Inappropriate argument value (of correct type)."); - -/* - * UnicodeError extends ValueError - */ - -SimpleExtendsException(PyExc_ValueError, UnicodeError, - "Unicode related error."); - -#ifdef Py_USING_UNICODE -static int -get_int(PyObject *attr, Py_ssize_t *value, const char *name) -{ - if (!attr) { - PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); - return -1; - } - - if (PyInt_Check(attr)) { - *value = PyInt_AS_LONG(attr); - } else if (PyLong_Check(attr)) { - *value = _PyLong_AsSsize_t(attr); - if (*value == -1 && PyErr_Occurred()) - return -1; - } else { - PyErr_Format(PyExc_TypeError, "%.200s attribute must be int", name); - return -1; - } - return 0; -} - -static int -set_ssize_t(PyObject **attr, Py_ssize_t value) -{ - PyObject *obj = PyInt_FromSsize_t(value); - if (!obj) - return -1; - Py_CLEAR(*attr); - *attr = obj; - return 0; -} - -static PyObject * -get_string(PyObject *attr, const char *name) -{ - if (!attr) { - PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); - return NULL; - } - - if (!PyString_Check(attr)) { - PyErr_Format(PyExc_TypeError, "%.200s attribute must be str", name); - return NULL; - } - Py_INCREF(attr); - return attr; -} - - -static int -set_string(PyObject **attr, const char *value) -{ - PyObject *obj = PyString_FromString(value); - if (!obj) - return -1; - Py_CLEAR(*attr); - *attr = obj; - return 0; -} - - -static PyObject * -get_unicode(PyObject *attr, const char *name) -{ - if (!attr) { - PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); - return NULL; - } - - if (!PyUnicode_Check(attr)) { - PyErr_Format(PyExc_TypeError, - "%.200s attribute must be unicode", name); - return NULL; - } - Py_INCREF(attr); - return attr; -} - -PyObject * -PyUnicodeEncodeError_GetEncoding(PyObject *exc) -{ - return get_string(((PyUnicodeErrorObject *)exc)->encoding, "encoding"); -} - -PyObject * -PyUnicodeDecodeError_GetEncoding(PyObject *exc) -{ - return get_string(((PyUnicodeErrorObject *)exc)->encoding, "encoding"); -} - -PyObject * -PyUnicodeEncodeError_GetObject(PyObject *exc) -{ - return get_unicode(((PyUnicodeErrorObject *)exc)->object, "object"); -} - -PyObject * -PyUnicodeDecodeError_GetObject(PyObject *exc) -{ - return get_string(((PyUnicodeErrorObject *)exc)->object, "object"); -} - -PyObject * -PyUnicodeTranslateError_GetObject(PyObject *exc) -{ - return get_unicode(((PyUnicodeErrorObject *)exc)->object, "object"); -} - -int -PyUnicodeEncodeError_GetStart(PyObject *exc, Py_ssize_t *start) -{ - if (!get_int(((PyUnicodeErrorObject *)exc)->start, start, "start")) { - Py_ssize_t size; - PyObject *obj = get_unicode(((PyUnicodeErrorObject *)exc)->object, - "object"); - if (!obj) return -1; - size = PyUnicode_GET_SIZE(obj); - if (*start<0) - *start = 0; /*XXX check for values <0*/ - if (*start>=size) - *start = size-1; - Py_DECREF(obj); - return 0; - } - return -1; -} - - -int -PyUnicodeDecodeError_GetStart(PyObject *exc, Py_ssize_t *start) -{ - if (!get_int(((PyUnicodeErrorObject *)exc)->start, start, "start")) { - Py_ssize_t size; - PyObject *obj = get_string(((PyUnicodeErrorObject *)exc)->object, - "object"); - if (!obj) return -1; - size = PyString_GET_SIZE(obj); - if (*start<0) - *start = 0; - if (*start>=size) - *start = size-1; - Py_DECREF(obj); - return 0; - } - return -1; -} - - -int -PyUnicodeTranslateError_GetStart(PyObject *exc, Py_ssize_t *start) -{ - return PyUnicodeEncodeError_GetStart(exc, start); -} - - -int -PyUnicodeEncodeError_SetStart(PyObject *exc, Py_ssize_t start) -{ - return set_ssize_t(&((PyUnicodeErrorObject *)exc)->start, start); -} - - -int -PyUnicodeDecodeError_SetStart(PyObject *exc, Py_ssize_t start) -{ - return set_ssize_t(&((PyUnicodeErrorObject *)exc)->start, start); -} - - -int -PyUnicodeTranslateError_SetStart(PyObject *exc, Py_ssize_t start) -{ - return set_ssize_t(&((PyUnicodeErrorObject *)exc)->start, start); -} - - -int -PyUnicodeEncodeError_GetEnd(PyObject *exc, Py_ssize_t *end) -{ - if (!get_int(((PyUnicodeErrorObject *)exc)->end, end, "end")) { - Py_ssize_t size; - PyObject *obj = get_unicode(((PyUnicodeErrorObject *)exc)->object, - "object"); - if (!obj) return -1; - size = PyUnicode_GET_SIZE(obj); - if (*end<1) - *end = 1; - if (*end>size) - *end = size; - Py_DECREF(obj); - return 0; - } - return -1; -} - - -int -PyUnicodeDecodeError_GetEnd(PyObject *exc, Py_ssize_t *end) -{ - if (!get_int(((PyUnicodeErrorObject *)exc)->end, end, "end")) { - Py_ssize_t size; - PyObject *obj = get_string(((PyUnicodeErrorObject *)exc)->object, - "object"); - if (!obj) return -1; - size = PyString_GET_SIZE(obj); - if (*end<1) - *end = 1; - if (*end>size) - *end = size; - Py_DECREF(obj); - return 0; - } - return -1; -} - - -int -PyUnicodeTranslateError_GetEnd(PyObject *exc, Py_ssize_t *start) -{ - return PyUnicodeEncodeError_GetEnd(exc, start); -} - - -int -PyUnicodeEncodeError_SetEnd(PyObject *exc, Py_ssize_t end) -{ - return set_ssize_t(&((PyUnicodeErrorObject *)exc)->end, end); -} - - -int -PyUnicodeDecodeError_SetEnd(PyObject *exc, Py_ssize_t end) -{ - return set_ssize_t(&((PyUnicodeErrorObject *)exc)->end, end); -} - - -int -PyUnicodeTranslateError_SetEnd(PyObject *exc, Py_ssize_t end) -{ - return set_ssize_t(&((PyUnicodeErrorObject *)exc)->end, end); -} - -PyObject * -PyUnicodeEncodeError_GetReason(PyObject *exc) -{ - return get_string(((PyUnicodeErrorObject *)exc)->reason, "reason"); -} - - -PyObject * -PyUnicodeDecodeError_GetReason(PyObject *exc) -{ - return get_string(((PyUnicodeErrorObject *)exc)->reason, "reason"); -} - - -PyObject * -PyUnicodeTranslateError_GetReason(PyObject *exc) -{ - return get_string(((PyUnicodeErrorObject *)exc)->reason, "reason"); -} - - -int -PyUnicodeEncodeError_SetReason(PyObject *exc, const char *reason) -{ - return set_string(&((PyUnicodeErrorObject *)exc)->reason, reason); -} - - -int -PyUnicodeDecodeError_SetReason(PyObject *exc, const char *reason) -{ - return set_string(&((PyUnicodeErrorObject *)exc)->reason, reason); -} - - -int -PyUnicodeTranslateError_SetReason(PyObject *exc, const char *reason) -{ - return set_string(&((PyUnicodeErrorObject *)exc)->reason, reason); -} - - -static int -UnicodeError_init(PyUnicodeErrorObject *self, PyObject *args, PyObject *kwds, - PyTypeObject *objecttype) -{ - Py_CLEAR(self->encoding); - Py_CLEAR(self->object); - Py_CLEAR(self->start); - Py_CLEAR(self->end); - Py_CLEAR(self->reason); - - if (!PyArg_ParseTuple(args, "O!O!O!O!O!", - &PyString_Type, &self->encoding, - objecttype, &self->object, - &PyInt_Type, &self->start, - &PyInt_Type, &self->end, - &PyString_Type, &self->reason)) { - self->encoding = self->object = self->start = self->end = - self->reason = NULL; - return -1; - } - - Py_INCREF(self->encoding); - Py_INCREF(self->object); - Py_INCREF(self->start); - Py_INCREF(self->end); - Py_INCREF(self->reason); - - return 0; -} - -static int -UnicodeError_clear(PyUnicodeErrorObject *self) -{ - Py_CLEAR(self->encoding); - Py_CLEAR(self->object); - Py_CLEAR(self->start); - Py_CLEAR(self->end); - Py_CLEAR(self->reason); - return BaseException_clear((PyBaseExceptionObject *)self); -} - -static void -UnicodeError_dealloc(PyUnicodeErrorObject *self) -{ - _PyObject_GC_UNTRACK(self); - UnicodeError_clear(self); - self->ob_type->tp_free((PyObject *)self); -} - -static int -UnicodeError_traverse(PyUnicodeErrorObject *self, visitproc visit, void *arg) -{ - Py_VISIT(self->encoding); - Py_VISIT(self->object); - Py_VISIT(self->start); - Py_VISIT(self->end); - Py_VISIT(self->reason); - return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); -} - -static PyMemberDef UnicodeError_members[] = { - {"message", T_OBJECT, offsetof(PyUnicodeErrorObject, message), 0, - PyDoc_STR("exception message")}, - {"encoding", T_OBJECT, offsetof(PyUnicodeErrorObject, encoding), 0, - PyDoc_STR("exception encoding")}, - {"object", T_OBJECT, offsetof(PyUnicodeErrorObject, object), 0, - PyDoc_STR("exception object")}, - {"start", T_OBJECT, offsetof(PyUnicodeErrorObject, start), 0, - PyDoc_STR("exception start")}, - {"end", T_OBJECT, offsetof(PyUnicodeErrorObject, end), 0, - PyDoc_STR("exception end")}, - {"reason", T_OBJECT, offsetof(PyUnicodeErrorObject, reason), 0, - PyDoc_STR("exception reason")}, - {NULL} /* Sentinel */ -}; - - -/* - * UnicodeEncodeError extends UnicodeError - */ - -static int -UnicodeEncodeError_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) - return -1; - return UnicodeError_init((PyUnicodeErrorObject *)self, args, - kwds, &PyUnicode_Type); -} - -static PyObject * -UnicodeEncodeError_str(PyObject *self) -{ - Py_ssize_t start; - Py_ssize_t end; - - if (PyUnicodeEncodeError_GetStart(self, &start)) - return NULL; - - if (PyUnicodeEncodeError_GetEnd(self, &end)) - return NULL; - - if (end==start+1) { - int badchar = (int)PyUnicode_AS_UNICODE(((PyUnicodeErrorObject *)self)->object)[start]; - char badchar_str[20]; - if (badchar <= 0xff) - PyOS_snprintf(badchar_str, sizeof(badchar_str), "x%02x", badchar); - else if (badchar <= 0xffff) - PyOS_snprintf(badchar_str, sizeof(badchar_str), "u%04x", badchar); - else - PyOS_snprintf(badchar_str, sizeof(badchar_str), "U%08x", badchar); - return PyString_FromFormat( - "'%.400s' codec can't encode character u'\\%s' in position %zd: %.400s", - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), - badchar_str, - start, - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); - } - return PyString_FromFormat( - "'%.400s' codec can't encode characters in position %zd-%zd: %.400s", - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), - start, - (end-1), - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); -} - -static PyTypeObject _PyExc_UnicodeEncodeError = { - PyObject_HEAD_INIT(NULL) - 0, - EXC_MODULE_NAME "UnicodeEncodeError", - sizeof(PyUnicodeErrorObject), 0, - (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - (reprfunc)UnicodeEncodeError_str, 0, 0, 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - PyDoc_STR("Unicode encoding error."), (traverseproc)UnicodeError_traverse, - (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, - 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), - (initproc)UnicodeEncodeError_init, 0, BaseException_new, -}; -PyObject *PyExc_UnicodeEncodeError = (PyObject *)&_PyExc_UnicodeEncodeError; - -PyObject * -PyUnicodeEncodeError_Create( - const char *encoding, const Py_UNICODE *object, Py_ssize_t length, - Py_ssize_t start, Py_ssize_t end, const char *reason) -{ - return PyObject_CallFunction(PyExc_UnicodeEncodeError, "su#nns", - encoding, object, length, start, end, reason); -} - - -/* - * UnicodeDecodeError extends UnicodeError - */ - -static int -UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) - return -1; - return UnicodeError_init((PyUnicodeErrorObject *)self, args, - kwds, &PyString_Type); -} - -static PyObject * -UnicodeDecodeError_str(PyObject *self) -{ - Py_ssize_t start = 0; - Py_ssize_t end = 0; - - if (PyUnicodeDecodeError_GetStart(self, &start)) - return NULL; - - if (PyUnicodeDecodeError_GetEnd(self, &end)) - return NULL; - - if (end==start+1) { - /* FromFormat does not support %02x, so format that separately */ - char byte[4]; - PyOS_snprintf(byte, sizeof(byte), "%02x", - ((int)PyString_AS_STRING(((PyUnicodeErrorObject *)self)->object)[start])&0xff); - return PyString_FromFormat( - "'%.400s' codec can't decode byte 0x%s in position %zd: %.400s", - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), - byte, - start, - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); - } - return PyString_FromFormat( - "'%.400s' codec can't decode bytes in position %zd-%zd: %.400s", - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), - start, - (end-1), - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); -} - -static PyTypeObject _PyExc_UnicodeDecodeError = { - PyObject_HEAD_INIT(NULL) - 0, - EXC_MODULE_NAME "UnicodeDecodeError", - sizeof(PyUnicodeErrorObject), 0, - (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - (reprfunc)UnicodeDecodeError_str, 0, 0, 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - PyDoc_STR("Unicode decoding error."), (traverseproc)UnicodeError_traverse, - (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, - 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), - (initproc)UnicodeDecodeError_init, 0, BaseException_new, -}; -PyObject *PyExc_UnicodeDecodeError = (PyObject *)&_PyExc_UnicodeDecodeError; - -PyObject * -PyUnicodeDecodeError_Create( - const char *encoding, const char *object, Py_ssize_t length, - Py_ssize_t start, Py_ssize_t end, const char *reason) -{ - assert(length < INT_MAX); - assert(start < INT_MAX); - assert(end < INT_MAX); - return PyObject_CallFunction(PyExc_UnicodeDecodeError, "ss#nns", - encoding, object, length, start, end, reason); -} - - -/* - * UnicodeTranslateError extends UnicodeError - */ - -static int -UnicodeTranslateError_init(PyUnicodeErrorObject *self, PyObject *args, - PyObject *kwds) -{ - if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) - return -1; - - Py_CLEAR(self->object); - Py_CLEAR(self->start); - Py_CLEAR(self->end); - Py_CLEAR(self->reason); - - if (!PyArg_ParseTuple(args, "O!O!O!O!", - &PyUnicode_Type, &self->object, - &PyInt_Type, &self->start, - &PyInt_Type, &self->end, - &PyString_Type, &self->reason)) { - self->object = self->start = self->end = self->reason = NULL; - return -1; - } - - Py_INCREF(self->object); - Py_INCREF(self->start); - Py_INCREF(self->end); - Py_INCREF(self->reason); - - return 0; -} - - -static PyObject * -UnicodeTranslateError_str(PyObject *self) -{ - Py_ssize_t start; - Py_ssize_t end; - - if (PyUnicodeTranslateError_GetStart(self, &start)) - return NULL; - - if (PyUnicodeTranslateError_GetEnd(self, &end)) - return NULL; - - if (end==start+1) { - int badchar = (int)PyUnicode_AS_UNICODE(((PyUnicodeErrorObject *)self)->object)[start]; - char badchar_str[20]; - if (badchar <= 0xff) - PyOS_snprintf(badchar_str, sizeof(badchar_str), "x%02x", badchar); - else if (badchar <= 0xffff) - PyOS_snprintf(badchar_str, sizeof(badchar_str), "u%04x", badchar); - else - PyOS_snprintf(badchar_str, sizeof(badchar_str), "U%08x", badchar); - return PyString_FromFormat( - "can't translate character u'\\%s' in position %zd: %.400s", - badchar_str, - start, - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); - } - return PyString_FromFormat( - "can't translate characters in position %zd-%zd: %.400s", - start, - (end-1), - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); -} - -static PyTypeObject _PyExc_UnicodeTranslateError = { - PyObject_HEAD_INIT(NULL) - 0, - EXC_MODULE_NAME "UnicodeTranslateError", - sizeof(PyUnicodeErrorObject), 0, - (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - (reprfunc)UnicodeTranslateError_str, 0, 0, 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - PyDoc_STR("Unicode translation error."), (traverseproc)UnicodeError_traverse, - (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, - 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), - (initproc)UnicodeTranslateError_init, 0, BaseException_new, -}; -PyObject *PyExc_UnicodeTranslateError = (PyObject *)&_PyExc_UnicodeTranslateError; - -PyObject * -PyUnicodeTranslateError_Create( - const Py_UNICODE *object, Py_ssize_t length, - Py_ssize_t start, Py_ssize_t end, const char *reason) -{ - return PyObject_CallFunction(PyExc_UnicodeTranslateError, "u#nns", - object, length, start, end, reason); -} -#endif - - -/* - * AssertionError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, AssertionError, - "Assertion failed."); - - -/* - * ArithmeticError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, ArithmeticError, - "Base class for arithmetic errors."); - - -/* - * FloatingPointError extends ArithmeticError - */ -SimpleExtendsException(PyExc_ArithmeticError, FloatingPointError, - "Floating point operation failed."); - - -/* - * OverflowError extends ArithmeticError - */ -SimpleExtendsException(PyExc_ArithmeticError, OverflowError, - "Result too large to be represented."); - - -/* - * ZeroDivisionError extends ArithmeticError - */ -SimpleExtendsException(PyExc_ArithmeticError, ZeroDivisionError, - "Second argument to a division or modulo operation was zero."); - - -/* - * SystemError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, SystemError, - "Internal error in the Python interpreter.\n" - "\n" - "Please report this to the Python maintainer, along with the traceback,\n" - "the Python version, and the hardware/OS platform and version."); - - -/* - * ReferenceError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, ReferenceError, - "Weak ref proxy used after referent went away."); - - -/* - * MemoryError extends StandardError - */ -SimpleExtendsException(PyExc_StandardError, MemoryError, "Out of memory."); - - -/* Warning category docstrings */ - -/* - * Warning extends Exception - */ -SimpleExtendsException(PyExc_Exception, Warning, - "Base class for warning categories."); - - -/* - * UserWarning extends Warning - */ -SimpleExtendsException(PyExc_Warning, UserWarning, - "Base class for warnings generated by user code."); - - -/* - * DeprecationWarning extends Warning - */ -SimpleExtendsException(PyExc_Warning, DeprecationWarning, - "Base class for warnings about deprecated features."); - - -/* - * PendingDeprecationWarning extends Warning - */ -SimpleExtendsException(PyExc_Warning, PendingDeprecationWarning, - "Base class for warnings about features which will be deprecated\n" - "in the future."); - - -/* - * SyntaxWarning extends Warning - */ -SimpleExtendsException(PyExc_Warning, SyntaxWarning, - "Base class for warnings about dubious syntax."); - - -/* - * RuntimeWarning extends Warning - */ -SimpleExtendsException(PyExc_Warning, RuntimeWarning, - "Base class for warnings about dubious runtime behavior."); - - -/* - * FutureWarning extends Warning - */ -SimpleExtendsException(PyExc_Warning, FutureWarning, - "Base class for warnings about constructs that will change semantically\n" - "in the future."); - - -/* - * ImportWarning extends Warning - */ -SimpleExtendsException(PyExc_Warning, ImportWarning, - "Base class for warnings about probable mistakes in module imports"); - - -/* - * UnicodeWarning extends Warning - */ -SimpleExtendsException(PyExc_Warning, UnicodeWarning, - "Base class for warnings about Unicode related problems, mostly\n" - "related to conversion problems."); - - -/* Pre-computed MemoryError instance. Best to create this as early as - * possible and not wait until a MemoryError is actually raised! - */ -PyObject *PyExc_MemoryErrorInst=NULL; - -/* module global functions */ -static PyMethodDef functions[] = { - /* Sentinel */ - {NULL, NULL} -}; - -#define PRE_INIT(TYPE) if (PyType_Ready(&_PyExc_ ## TYPE) < 0) \ - Py_FatalError("exceptions bootstrapping error."); - -#define POST_INIT(TYPE) Py_INCREF(PyExc_ ## TYPE); \ - PyModule_AddObject(m, # TYPE, PyExc_ ## TYPE); \ - if (PyDict_SetItemString(bdict, # TYPE, PyExc_ ## TYPE)) \ - Py_FatalError("Module dictionary insertion problem."); - -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) -/* crt variable checking in VisualStudio .NET 2005 */ -#include <crtdbg.h> - -static int prevCrtReportMode; -static _invalid_parameter_handler prevCrtHandler; - -/* Invalid parameter handler. Sets a ValueError exception */ -static void -InvalidParameterHandler( - const wchar_t * expression, - const wchar_t * function, - const wchar_t * file, - unsigned int line, - uintptr_t pReserved) -{ - /* Do nothing, allow execution to continue. Usually this - * means that the CRT will set errno to EINVAL - */ -} -#endif - - -PyMODINIT_FUNC -_PyExc_Init(void) -{ - PyObject *m, *bltinmod, *bdict; - - PRE_INIT(BaseException) - PRE_INIT(Exception) - PRE_INIT(StandardError) - PRE_INIT(TypeError) - PRE_INIT(StopIteration) - PRE_INIT(GeneratorExit) - PRE_INIT(SystemExit) - PRE_INIT(KeyboardInterrupt) - PRE_INIT(ImportError) - PRE_INIT(EnvironmentError) - PRE_INIT(IOError) - PRE_INIT(OSError) -#ifdef MS_WINDOWS - PRE_INIT(WindowsError) -#endif -#ifdef __VMS - PRE_INIT(VMSError) -#endif - PRE_INIT(EOFError) - PRE_INIT(RuntimeError) - PRE_INIT(NotImplementedError) - PRE_INIT(NameError) - PRE_INIT(UnboundLocalError) - PRE_INIT(AttributeError) - PRE_INIT(SyntaxError) - PRE_INIT(IndentationError) - PRE_INIT(TabError) - PRE_INIT(LookupError) - PRE_INIT(IndexError) - PRE_INIT(KeyError) - PRE_INIT(ValueError) - PRE_INIT(UnicodeError) -#ifdef Py_USING_UNICODE - PRE_INIT(UnicodeEncodeError) - PRE_INIT(UnicodeDecodeError) - PRE_INIT(UnicodeTranslateError) -#endif - PRE_INIT(AssertionError) - PRE_INIT(ArithmeticError) - PRE_INIT(FloatingPointError) - PRE_INIT(OverflowError) - PRE_INIT(ZeroDivisionError) - PRE_INIT(SystemError) - PRE_INIT(ReferenceError) - PRE_INIT(MemoryError) - PRE_INIT(Warning) - PRE_INIT(UserWarning) - PRE_INIT(DeprecationWarning) - PRE_INIT(PendingDeprecationWarning) - PRE_INIT(SyntaxWarning) - PRE_INIT(RuntimeWarning) - PRE_INIT(FutureWarning) - PRE_INIT(ImportWarning) - PRE_INIT(UnicodeWarning) - - m = Py_InitModule4("exceptions", functions, exceptions_doc, - (PyObject *)NULL, PYTHON_API_VERSION); - if (m == NULL) return; - - bltinmod = PyImport_ImportModule("__builtin__"); - if (bltinmod == NULL) - Py_FatalError("exceptions bootstrapping error."); - bdict = PyModule_GetDict(bltinmod); - if (bdict == NULL) - Py_FatalError("exceptions bootstrapping error."); - - POST_INIT(BaseException) - POST_INIT(Exception) - POST_INIT(StandardError) - POST_INIT(TypeError) - POST_INIT(StopIteration) - POST_INIT(GeneratorExit) - POST_INIT(SystemExit) - POST_INIT(KeyboardInterrupt) - POST_INIT(ImportError) - POST_INIT(EnvironmentError) - POST_INIT(IOError) - POST_INIT(OSError) -#ifdef MS_WINDOWS - POST_INIT(WindowsError) -#endif -#ifdef __VMS - POST_INIT(VMSError) -#endif - POST_INIT(EOFError) - POST_INIT(RuntimeError) - POST_INIT(NotImplementedError) - POST_INIT(NameError) - POST_INIT(UnboundLocalError) - POST_INIT(AttributeError) - POST_INIT(SyntaxError) - POST_INIT(IndentationError) - POST_INIT(TabError) - POST_INIT(LookupError) - POST_INIT(IndexError) - POST_INIT(KeyError) - POST_INIT(ValueError) - POST_INIT(UnicodeError) -#ifdef Py_USING_UNICODE - POST_INIT(UnicodeEncodeError) - POST_INIT(UnicodeDecodeError) - POST_INIT(UnicodeTranslateError) -#endif - POST_INIT(AssertionError) - POST_INIT(ArithmeticError) - POST_INIT(FloatingPointError) - POST_INIT(OverflowError) - POST_INIT(ZeroDivisionError) - POST_INIT(SystemError) - POST_INIT(ReferenceError) - POST_INIT(MemoryError) - POST_INIT(Warning) - POST_INIT(UserWarning) - POST_INIT(DeprecationWarning) - POST_INIT(PendingDeprecationWarning) - POST_INIT(SyntaxWarning) - POST_INIT(RuntimeWarning) - POST_INIT(FutureWarning) - POST_INIT(ImportWarning) - POST_INIT(UnicodeWarning) - - PyExc_MemoryErrorInst = BaseException_new(&_PyExc_MemoryError, NULL, NULL); - if (!PyExc_MemoryErrorInst) - Py_FatalError("Cannot pre-allocate MemoryError instance\n"); - - Py_DECREF(bltinmod); - -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - /* Set CRT argument error handler */ - prevCrtHandler = _set_invalid_parameter_handler(InvalidParameterHandler); - /* turn off assertions in debug mode */ - prevCrtReportMode = _CrtSetReportMode(_CRT_ASSERT, 0); -#endif -} - -void -_PyExc_Fini(void) -{ - Py_XDECREF(PyExc_MemoryErrorInst); - PyExc_MemoryErrorInst = NULL; -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - /* reset CRT error handling */ - _set_invalid_parameter_handler(prevCrtHandler); - _CrtSetReportMode(_CRT_ASSERT, prevCrtReportMode); -#endif -} diff --git a/sys/src/cmd/python/Objects/fileobject.c b/sys/src/cmd/python/Objects/fileobject.c deleted file mode 100644 index 124767ccd..000000000 --- a/sys/src/cmd/python/Objects/fileobject.c +++ /dev/null @@ -1,2487 +0,0 @@ -/* File object implementation */ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" -#include "structmember.h" - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif /* HAVE_SYS_TYPES_H */ - -#ifdef MS_WINDOWS -#define fileno _fileno -/* can simulate truncate with Win32 API functions; see file_truncate */ -#define HAVE_FTRUNCATE -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#endif - -#ifdef _MSC_VER -/* Need GetVersion to see if on NT so safe to use _wfopen */ -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#endif /* _MSC_VER */ - -#if defined(PYOS_OS2) && defined(PYCC_GCC) -#include <io.h> -#endif - -#define BUF(v) PyString_AS_STRING((PyStringObject *)v) - -#ifndef DONT_HAVE_ERRNO_H -#include <errno.h> -#endif - -#ifdef HAVE_GETC_UNLOCKED -#define GETC(f) getc_unlocked(f) -#define FLOCKFILE(f) flockfile(f) -#define FUNLOCKFILE(f) funlockfile(f) -#else -#define GETC(f) getc(f) -#define FLOCKFILE(f) -#define FUNLOCKFILE(f) -#endif - -/* Bits in f_newlinetypes */ -#define NEWLINE_UNKNOWN 0 /* No newline seen, yet */ -#define NEWLINE_CR 1 /* \r newline seen */ -#define NEWLINE_LF 2 /* \n newline seen */ -#define NEWLINE_CRLF 4 /* \r\n newline seen */ - -#ifdef __cplusplus -extern "C" { -#endif - -FILE * -PyFile_AsFile(PyObject *f) -{ - if (f == NULL || !PyFile_Check(f)) - return NULL; - else - return ((PyFileObject *)f)->f_fp; -} - -PyObject * -PyFile_Name(PyObject *f) -{ - if (f == NULL || !PyFile_Check(f)) - return NULL; - else - return ((PyFileObject *)f)->f_name; -} - -/* On Unix, fopen will succeed for directories. - In Python, there should be no file objects referring to - directories, so we need a check. */ - -static PyFileObject* -dircheck(PyFileObject* f) -{ -#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) - struct stat buf; - if (f->f_fp == NULL) - return f; - if (fstat(fileno(f->f_fp), &buf) == 0 && - S_ISDIR(buf.st_mode)) { -#ifdef HAVE_STRERROR - char *msg = strerror(EISDIR); -#else - char *msg = "Is a directory"; -#endif - PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(is)", - EISDIR, msg); - PyErr_SetObject(PyExc_IOError, exc); - Py_XDECREF(exc); - return NULL; - } -#endif - return f; -} - - -static PyObject * -fill_file_fields(PyFileObject *f, FILE *fp, PyObject *name, char *mode, - int (*close)(FILE *)) -{ - assert(name != NULL); - assert(f != NULL); - assert(PyFile_Check(f)); - assert(f->f_fp == NULL); - - Py_DECREF(f->f_name); - Py_DECREF(f->f_mode); - Py_DECREF(f->f_encoding); - - Py_INCREF(name); - f->f_name = name; - - f->f_mode = PyString_FromString(mode); - - f->f_close = close; - f->f_softspace = 0; - f->f_binary = strchr(mode,'b') != NULL; - f->f_buf = NULL; - f->f_univ_newline = (strchr(mode, 'U') != NULL); - f->f_newlinetypes = NEWLINE_UNKNOWN; - f->f_skipnextlf = 0; - Py_INCREF(Py_None); - f->f_encoding = Py_None; - - if (f->f_mode == NULL) - return NULL; - f->f_fp = fp; - f = dircheck(f); - return (PyObject *) f; -} - -/* check for known incorrect mode strings - problem is, platforms are - free to accept any mode characters they like and are supposed to - ignore stuff they don't understand... write or append mode with - universal newline support is expressly forbidden by PEP 278. - Additionally, remove the 'U' from the mode string as platforms - won't know what it is. */ -/* zero return is kewl - one is un-kewl */ -static int -sanitize_the_mode(char *mode) -{ - char *upos; - size_t len = strlen(mode); - - if (!len) { - PyErr_SetString(PyExc_ValueError, "empty mode string"); - return 1; - } - - upos = strchr(mode, 'U'); - if (upos) { - memmove(upos, upos+1, len-(upos-mode)); /* incl null char */ - - if (mode[0] == 'w' || mode[0] == 'a') { - PyErr_Format(PyExc_ValueError, "universal newline " - "mode can only be used with modes " - "starting with 'r'"); - return 1; - } - - if (mode[0] != 'r') { - memmove(mode+1, mode, strlen(mode)+1); - mode[0] = 'r'; - } - - if (!strchr(mode, 'b')) { - memmove(mode+2, mode+1, strlen(mode)); - mode[1] = 'b'; - } - } else if (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a') { - PyErr_Format(PyExc_ValueError, "mode string must begin with " - "one of 'r', 'w', 'a' or 'U', not '%.200s'", mode); - return 1; - } - - return 0; -} - -static PyObject * -open_the_file(PyFileObject *f, char *name, char *mode) -{ - char *newmode; - assert(f != NULL); - assert(PyFile_Check(f)); -#ifdef MS_WINDOWS - /* windows ignores the passed name in order to support Unicode */ - assert(f->f_name != NULL); -#else - assert(name != NULL); -#endif - assert(mode != NULL); - assert(f->f_fp == NULL); - - /* probably need to replace 'U' by 'rb' */ - newmode = PyMem_MALLOC(strlen(mode) + 3); - if (!newmode) { - PyErr_NoMemory(); - return NULL; - } - strcpy(newmode, mode); - - if (sanitize_the_mode(newmode)) { - f = NULL; - goto cleanup; - } - - /* rexec.py can't stop a user from getting the file() constructor -- - all they have to do is get *any* file object f, and then do - type(f). Here we prevent them from doing damage with it. */ - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_IOError, - "file() constructor not accessible in restricted mode"); - f = NULL; - goto cleanup; - } - errno = 0; - -#ifdef MS_WINDOWS - if (PyUnicode_Check(f->f_name)) { - PyObject *wmode; - wmode = PyUnicode_DecodeASCII(newmode, strlen(newmode), NULL); - if (f->f_name && wmode) { - Py_BEGIN_ALLOW_THREADS - /* PyUnicode_AS_UNICODE OK without thread - lock as it is a simple dereference. */ - f->f_fp = _wfopen(PyUnicode_AS_UNICODE(f->f_name), - PyUnicode_AS_UNICODE(wmode)); - Py_END_ALLOW_THREADS - } - Py_XDECREF(wmode); - } -#endif - if (NULL == f->f_fp && NULL != name) { - Py_BEGIN_ALLOW_THREADS - f->f_fp = fopen(name, newmode); - Py_END_ALLOW_THREADS - } - - if (f->f_fp == NULL) { -#if defined _MSC_VER && (_MSC_VER < 1400 || !defined(__STDC_SECURE_LIB__)) - /* MSVC 6 (Microsoft) leaves errno at 0 for bad mode strings, - * across all Windows flavors. When it sets EINVAL varies - * across Windows flavors, the exact conditions aren't - * documented, and the answer lies in the OS's implementation - * of Win32's CreateFile function (whose source is secret). - * Seems the best we can do is map EINVAL to ENOENT. - * Starting with Visual Studio .NET 2005, EINVAL is correctly - * set by our CRT error handler (set in exceptions.c.) - */ - if (errno == 0) /* bad mode string */ - errno = EINVAL; - else if (errno == EINVAL) /* unknown, but not a mode string */ - errno = ENOENT; -#endif - if (errno == EINVAL) - PyErr_Format(PyExc_IOError, "invalid mode: %s", - mode); - else - PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, f->f_name); - f = NULL; - } - if (f != NULL) - f = dircheck(f); - -cleanup: - PyMem_FREE(newmode); - - return (PyObject *)f; -} - -PyObject * -PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE *)) -{ - PyFileObject *f = (PyFileObject *)PyFile_Type.tp_new(&PyFile_Type, - NULL, NULL); - if (f != NULL) { - PyObject *o_name = PyString_FromString(name); - if (o_name == NULL) - return NULL; - if (fill_file_fields(f, fp, o_name, mode, close) == NULL) { - Py_DECREF(f); - f = NULL; - } - Py_DECREF(o_name); - } - return (PyObject *) f; -} - -PyObject * -PyFile_FromString(char *name, char *mode) -{ - extern int fclose(FILE *); - PyFileObject *f; - - f = (PyFileObject *)PyFile_FromFile((FILE *)NULL, name, mode, fclose); - if (f != NULL) { - if (open_the_file(f, name, mode) == NULL) { - Py_DECREF(f); - f = NULL; - } - } - return (PyObject *)f; -} - -void -PyFile_SetBufSize(PyObject *f, int bufsize) -{ - PyFileObject *file = (PyFileObject *)f; - if (bufsize >= 0) { - int type; - switch (bufsize) { - case 0: - type = _IONBF; - break; -#ifdef HAVE_SETVBUF - case 1: - type = _IOLBF; - bufsize = BUFSIZ; - break; -#endif - default: - type = _IOFBF; -#ifndef HAVE_SETVBUF - bufsize = BUFSIZ; -#endif - break; - } - fflush(file->f_fp); - if (type == _IONBF) { - PyMem_Free(file->f_setbuf); - file->f_setbuf = NULL; - } else { - file->f_setbuf = (char *)PyMem_Realloc(file->f_setbuf, - bufsize); - } -#ifdef HAVE_SETVBUF - setvbuf(file->f_fp, file->f_setbuf, type, bufsize); -#else /* !HAVE_SETVBUF */ - setbuf(file->f_fp, file->f_setbuf); -#endif /* !HAVE_SETVBUF */ - } -} - -/* Set the encoding used to output Unicode strings. - Returh 1 on success, 0 on failure. */ - -int -PyFile_SetEncoding(PyObject *f, const char *enc) -{ - PyFileObject *file = (PyFileObject*)f; - PyObject *str = PyString_FromString(enc); - - assert(PyFile_Check(f)); - if (!str) - return 0; - Py_DECREF(file->f_encoding); - file->f_encoding = str; - return 1; -} - -static PyObject * -err_closed(void) -{ - PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); - return NULL; -} - -/* Refuse regular file I/O if there's data in the iteration-buffer. - * Mixing them would cause data to arrive out of order, as the read* - * methods don't use the iteration buffer. */ -static PyObject * -err_iterbuffered(void) -{ - PyErr_SetString(PyExc_ValueError, - "Mixing iteration and read methods would lose data"); - return NULL; -} - -static void drop_readahead(PyFileObject *); - -/* Methods */ - -static void -file_dealloc(PyFileObject *f) -{ - int sts = 0; - if (f->weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) f); - if (f->f_fp != NULL && f->f_close != NULL) { - Py_BEGIN_ALLOW_THREADS - sts = (*f->f_close)(f->f_fp); - Py_END_ALLOW_THREADS - if (sts == EOF) -#ifdef HAVE_STRERROR - PySys_WriteStderr("close failed: [Errno %d] %s\n", errno, strerror(errno)); -#else - PySys_WriteStderr("close failed: [Errno %d]\n", errno); -#endif - } - PyMem_Free(f->f_setbuf); - Py_XDECREF(f->f_name); - Py_XDECREF(f->f_mode); - Py_XDECREF(f->f_encoding); - drop_readahead(f); - f->ob_type->tp_free((PyObject *)f); -} - -static PyObject * -file_repr(PyFileObject *f) -{ - if (PyUnicode_Check(f->f_name)) { -#ifdef Py_USING_UNICODE - PyObject *ret = NULL; - PyObject *name = PyUnicode_AsUnicodeEscapeString(f->f_name); - const char *name_str = name ? PyString_AsString(name) : "?"; - ret = PyString_FromFormat("<%s file u'%s', mode '%s' at %p>", - f->f_fp == NULL ? "closed" : "open", - name_str, - PyString_AsString(f->f_mode), - f); - Py_XDECREF(name); - return ret; -#endif - } else { - return PyString_FromFormat("<%s file '%s', mode '%s' at %p>", - f->f_fp == NULL ? "closed" : "open", - PyString_AsString(f->f_name), - PyString_AsString(f->f_mode), - f); - } -} - -static PyObject * -file_close(PyFileObject *f) -{ - int sts = 0; - if (f->f_fp != NULL) { - if (f->f_close != NULL) { - Py_BEGIN_ALLOW_THREADS - errno = 0; - sts = (*f->f_close)(f->f_fp); - Py_END_ALLOW_THREADS - } - f->f_fp = NULL; - } - PyMem_Free(f->f_setbuf); - f->f_setbuf = NULL; - if (sts == EOF) - return PyErr_SetFromErrno(PyExc_IOError); - if (sts != 0) - return PyInt_FromLong((long)sts); - Py_INCREF(Py_None); - return Py_None; -} - - -/* Our very own off_t-like type, 64-bit if possible */ -#if !defined(HAVE_LARGEFILE_SUPPORT) -typedef off_t Py_off_t; -#elif SIZEOF_OFF_T >= 8 -typedef off_t Py_off_t; -#elif SIZEOF_FPOS_T >= 8 -typedef fpos_t Py_off_t; -#else -#error "Large file support, but neither off_t nor fpos_t is large enough." -#endif - - -/* a portable fseek() function - return 0 on success, non-zero on failure (with errno set) */ -static int -_portable_fseek(FILE *fp, Py_off_t offset, int whence) -{ -#if !defined(HAVE_LARGEFILE_SUPPORT) - return fseek(fp, offset, whence); -#elif defined(HAVE_FSEEKO) && SIZEOF_OFF_T >= 8 - return fseeko(fp, offset, whence); -#elif defined(HAVE_FSEEK64) - return fseek64(fp, offset, whence); -#elif defined(__BEOS__) - return _fseek(fp, offset, whence); -#elif SIZEOF_FPOS_T >= 8 - /* lacking a 64-bit capable fseek(), use a 64-bit capable fsetpos() - and fgetpos() to implement fseek()*/ - fpos_t pos; - switch (whence) { - case SEEK_END: -#ifdef MS_WINDOWS - fflush(fp); - if (_lseeki64(fileno(fp), 0, 2) == -1) - return -1; -#else - if (fseek(fp, 0, SEEK_END) != 0) - return -1; -#endif - /* fall through */ - case SEEK_CUR: - if (fgetpos(fp, &pos) != 0) - return -1; - offset += pos; - break; - /* case SEEK_SET: break; */ - } - return fsetpos(fp, &offset); -#else -#error "Large file support, but no way to fseek." -#endif -} - - -/* a portable ftell() function - Return -1 on failure with errno set appropriately, current file - position on success */ -static Py_off_t -_portable_ftell(FILE* fp) -{ -#if !defined(HAVE_LARGEFILE_SUPPORT) - return ftell(fp); -#elif defined(HAVE_FTELLO) && SIZEOF_OFF_T >= 8 - return ftello(fp); -#elif defined(HAVE_FTELL64) - return ftell64(fp); -#elif SIZEOF_FPOS_T >= 8 - fpos_t pos; - if (fgetpos(fp, &pos) != 0) - return -1; - return pos; -#else -#error "Large file support, but no way to ftell." -#endif -} - - -static PyObject * -file_seek(PyFileObject *f, PyObject *args) -{ - int whence; - int ret; - Py_off_t offset; - PyObject *offobj; - - if (f->f_fp == NULL) - return err_closed(); - drop_readahead(f); - whence = 0; - if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &whence)) - return NULL; -#if !defined(HAVE_LARGEFILE_SUPPORT) - offset = PyInt_AsLong(offobj); -#else - if(PyLong_Check(offobj)) - offset = PyLong_AsLongLong(offobj); - else - offset = PyInt_AsLong(offobj); -#endif - if (PyErr_Occurred()) - return NULL; - - Py_BEGIN_ALLOW_THREADS - errno = 0; - ret = _portable_fseek(f->f_fp, offset, whence); - Py_END_ALLOW_THREADS - - if (ret != 0) { - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - return NULL; - } - f->f_skipnextlf = 0; - Py_INCREF(Py_None); - return Py_None; -} - - -#ifdef HAVE_FTRUNCATE -static PyObject * -file_truncate(PyFileObject *f, PyObject *args) -{ - Py_off_t newsize; - PyObject *newsizeobj = NULL; - Py_off_t initialpos; - int ret; - - if (f->f_fp == NULL) - return err_closed(); - if (!PyArg_UnpackTuple(args, "truncate", 0, 1, &newsizeobj)) - return NULL; - - /* Get current file position. If the file happens to be open for - * update and the last operation was an input operation, C doesn't - * define what the later fflush() will do, but we promise truncate() - * won't change the current position (and fflush() *does* change it - * then at least on Windows). The easiest thing is to capture - * current pos now and seek back to it at the end. - */ - Py_BEGIN_ALLOW_THREADS - errno = 0; - initialpos = _portable_ftell(f->f_fp); - Py_END_ALLOW_THREADS - if (initialpos == -1) - goto onioerror; - - /* Set newsize to current postion if newsizeobj NULL, else to the - * specified value. - */ - if (newsizeobj != NULL) { -#if !defined(HAVE_LARGEFILE_SUPPORT) - newsize = PyInt_AsLong(newsizeobj); -#else - if(PyLong_Check(newsizeobj)) - newsize = PyLong_AsLongLong(newsizeobj); - else - newsize = PyInt_AsLong(newsizeobj); -#endif - if (PyErr_Occurred()) - return NULL; - } - else /* default to current position */ - newsize = initialpos; - - /* Flush the stream. We're mixing stream-level I/O with lower-level - * I/O, and a flush may be necessary to synch both platform views - * of the current file state. - */ - Py_BEGIN_ALLOW_THREADS - errno = 0; - ret = fflush(f->f_fp); - Py_END_ALLOW_THREADS - if (ret != 0) - goto onioerror; - -#ifdef MS_WINDOWS - /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, - so don't even try using it. */ - { - HANDLE hFile; - - /* Have to move current pos to desired endpoint on Windows. */ - Py_BEGIN_ALLOW_THREADS - errno = 0; - ret = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0; - Py_END_ALLOW_THREADS - if (ret) - goto onioerror; - - /* Truncate. Note that this may grow the file! */ - Py_BEGIN_ALLOW_THREADS - errno = 0; - hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp)); - ret = hFile == (HANDLE)-1; - if (ret == 0) { - ret = SetEndOfFile(hFile) == 0; - if (ret) - errno = EACCES; - } - Py_END_ALLOW_THREADS - if (ret) - goto onioerror; - } -#else - Py_BEGIN_ALLOW_THREADS - errno = 0; - ret = ftruncate(fileno(f->f_fp), newsize); - Py_END_ALLOW_THREADS - if (ret != 0) - goto onioerror; -#endif /* !MS_WINDOWS */ - - /* Restore original file position. */ - Py_BEGIN_ALLOW_THREADS - errno = 0; - ret = _portable_fseek(f->f_fp, initialpos, SEEK_SET) != 0; - Py_END_ALLOW_THREADS - if (ret) - goto onioerror; - - Py_INCREF(Py_None); - return Py_None; - -onioerror: - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - return NULL; -} -#endif /* HAVE_FTRUNCATE */ - -static PyObject * -file_tell(PyFileObject *f) -{ - Py_off_t pos; - - if (f->f_fp == NULL) - return err_closed(); - Py_BEGIN_ALLOW_THREADS - errno = 0; - pos = _portable_ftell(f->f_fp); - Py_END_ALLOW_THREADS - if (pos == -1) { - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - return NULL; - } - if (f->f_skipnextlf) { - int c; - c = GETC(f->f_fp); - if (c == '\n') { - pos++; - f->f_skipnextlf = 0; - } else if (c != EOF) ungetc(c, f->f_fp); - } -#if !defined(HAVE_LARGEFILE_SUPPORT) - return PyInt_FromLong(pos); -#else - return PyLong_FromLongLong(pos); -#endif -} - -static PyObject * -file_fileno(PyFileObject *f) -{ - if (f->f_fp == NULL) - return err_closed(); - return PyInt_FromLong((long) fileno(f->f_fp)); -} - -static PyObject * -file_flush(PyFileObject *f) -{ - int res; - - if (f->f_fp == NULL) - return err_closed(); - Py_BEGIN_ALLOW_THREADS - errno = 0; - res = fflush(f->f_fp); - Py_END_ALLOW_THREADS - if (res != 0) { - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - return NULL; - } - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -file_isatty(PyFileObject *f) -{ - long res; - if (f->f_fp == NULL) - return err_closed(); - Py_BEGIN_ALLOW_THREADS - res = isatty((int)fileno(f->f_fp)); - Py_END_ALLOW_THREADS - return PyBool_FromLong(res); -} - - -#if BUFSIZ < 8192 -#define SMALLCHUNK 8192 -#else -#define SMALLCHUNK BUFSIZ -#endif - -#if SIZEOF_INT < 4 -#define BIGCHUNK (512 * 32) -#else -#define BIGCHUNK (512 * 1024) -#endif - -static size_t -new_buffersize(PyFileObject *f, size_t currentsize) -{ -#ifdef HAVE_FSTAT - off_t pos, end; - struct stat st; - if (fstat(fileno(f->f_fp), &st) == 0) { - end = st.st_size; - /* The following is not a bug: we really need to call lseek() - *and* ftell(). The reason is that some stdio libraries - mistakenly flush their buffer when ftell() is called and - the lseek() call it makes fails, thereby throwing away - data that cannot be recovered in any way. To avoid this, - we first test lseek(), and only call ftell() if lseek() - works. We can't use the lseek() value either, because we - need to take the amount of buffered data into account. - (Yet another reason why stdio stinks. :-) */ - pos = lseek(fileno(f->f_fp), 0L, SEEK_CUR); - if (pos >= 0) { - pos = ftell(f->f_fp); - } - if (pos < 0) - clearerr(f->f_fp); - if (end > pos && pos >= 0) - return currentsize + end - pos + 1; - /* Add 1 so if the file were to grow we'd notice. */ - } -#endif - if (currentsize > SMALLCHUNK) { - /* Keep doubling until we reach BIGCHUNK; - then keep adding BIGCHUNK. */ - if (currentsize <= BIGCHUNK) - return currentsize + currentsize; - else - return currentsize + BIGCHUNK; - } - return currentsize + SMALLCHUNK; -} - -#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN -#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK || (x) == EAGAIN) -#else -#ifdef EWOULDBLOCK -#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK) -#else -#ifdef EAGAIN -#define BLOCKED_ERRNO(x) ((x) == EAGAIN) -#else -#define BLOCKED_ERRNO(x) 0 -#endif -#endif -#endif - -static PyObject * -file_read(PyFileObject *f, PyObject *args) -{ - long bytesrequested = -1; - size_t bytesread, buffersize, chunksize; - PyObject *v; - - if (f->f_fp == NULL) - return err_closed(); - /* refuse to mix with f.next() */ - if (f->f_buf != NULL && - (f->f_bufend - f->f_bufptr) > 0 && - f->f_buf[0] != '\0') - return err_iterbuffered(); - if (!PyArg_ParseTuple(args, "|l:read", &bytesrequested)) - return NULL; - if (bytesrequested < 0) - buffersize = new_buffersize(f, (size_t)0); - else - buffersize = bytesrequested; - if (buffersize > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "requested number of bytes is more than a Python string can hold"); - return NULL; - } - v = PyString_FromStringAndSize((char *)NULL, buffersize); - if (v == NULL) - return NULL; - bytesread = 0; - for (;;) { - Py_BEGIN_ALLOW_THREADS - errno = 0; - chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread, - buffersize - bytesread, f->f_fp, (PyObject *)f); - Py_END_ALLOW_THREADS - if (chunksize == 0) { - if (!ferror(f->f_fp)) - break; - clearerr(f->f_fp); - /* When in non-blocking mode, data shouldn't - * be discarded if a blocking signal was - * received. That will also happen if - * chunksize != 0, but bytesread < buffersize. */ - if (bytesread > 0 && BLOCKED_ERRNO(errno)) - break; - PyErr_SetFromErrno(PyExc_IOError); - Py_DECREF(v); - return NULL; - } - bytesread += chunksize; - if (bytesread < buffersize) { - clearerr(f->f_fp); - break; - } - if (bytesrequested < 0) { - buffersize = new_buffersize(f, buffersize); - if (_PyString_Resize(&v, buffersize) < 0) - return NULL; - } else { - /* Got what was requested. */ - break; - } - } - if (bytesread != buffersize) - _PyString_Resize(&v, bytesread); - return v; -} - -static PyObject * -file_readinto(PyFileObject *f, PyObject *args) -{ - char *ptr; - Py_ssize_t ntodo; - Py_ssize_t ndone, nnow; - - if (f->f_fp == NULL) - return err_closed(); - /* refuse to mix with f.next() */ - if (f->f_buf != NULL && - (f->f_bufend - f->f_bufptr) > 0 && - f->f_buf[0] != '\0') - return err_iterbuffered(); - if (!PyArg_ParseTuple(args, "w#", &ptr, &ntodo)) - return NULL; - ndone = 0; - while (ntodo > 0) { - Py_BEGIN_ALLOW_THREADS - errno = 0; - nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp, - (PyObject *)f); - Py_END_ALLOW_THREADS - if (nnow == 0) { - if (!ferror(f->f_fp)) - break; - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - return NULL; - } - ndone += nnow; - ntodo -= nnow; - } - return PyInt_FromSsize_t(ndone); -} - -/************************************************************************** -Routine to get next line using platform fgets(). - -Under MSVC 6: - -+ MS threadsafe getc is very slow (multiple layers of function calls before+ - after each character, to lock+unlock the stream). -+ The stream-locking functions are MS-internal -- can't access them from user - code. -+ There's nothing Tim could find in the MS C or platform SDK libraries that - can worm around this. -+ MS fgets locks/unlocks only once per line; it's the only hook we have. - -So we use fgets for speed(!), despite that it's painful. - -MS realloc is also slow. - -Reports from other platforms on this method vs getc_unlocked (which MS doesn't -have): - Linux a wash - Solaris a wash - Tru64 Unix getline_via_fgets significantly faster - -CAUTION: The C std isn't clear about this: in those cases where fgets -writes something into the buffer, can it write into any position beyond the -required trailing null byte? MSVC 6 fgets does not, and no platform is (yet) -known on which it does; and it would be a strange way to code fgets. Still, -getline_via_fgets may not work correctly if it does. The std test -test_bufio.py should fail if platform fgets() routinely writes beyond the -trailing null byte. #define DONT_USE_FGETS_IN_GETLINE to disable this code. -**************************************************************************/ - -/* Use this routine if told to, or by default on non-get_unlocked() - * platforms unless told not to. Yikes! Let's spell that out: - * On a platform with getc_unlocked(): - * By default, use getc_unlocked(). - * If you want to use fgets() instead, #define USE_FGETS_IN_GETLINE. - * On a platform without getc_unlocked(): - * By default, use fgets(). - * If you don't want to use fgets(), #define DONT_USE_FGETS_IN_GETLINE. - */ -#if !defined(USE_FGETS_IN_GETLINE) && !defined(HAVE_GETC_UNLOCKED) -#define USE_FGETS_IN_GETLINE -#endif - -#if defined(DONT_USE_FGETS_IN_GETLINE) && defined(USE_FGETS_IN_GETLINE) -#undef USE_FGETS_IN_GETLINE -#endif - -#ifdef USE_FGETS_IN_GETLINE -static PyObject* -getline_via_fgets(FILE *fp) -{ -/* INITBUFSIZE is the maximum line length that lets us get away with the fast - * no-realloc, one-fgets()-call path. Boosting it isn't free, because we have - * to fill this much of the buffer with a known value in order to figure out - * how much of the buffer fgets() overwrites. So if INITBUFSIZE is larger - * than "most" lines, we waste time filling unused buffer slots. 100 is - * surely adequate for most peoples' email archives, chewing over source code, - * etc -- "regular old text files". - * MAXBUFSIZE is the maximum line length that lets us get away with the less - * fast (but still zippy) no-realloc, two-fgets()-call path. See above for - * cautions about boosting that. 300 was chosen because the worst real-life - * text-crunching job reported on Python-Dev was a mail-log crawler where over - * half the lines were 254 chars. - */ -#define INITBUFSIZE 100 -#define MAXBUFSIZE 300 - char* p; /* temp */ - char buf[MAXBUFSIZE]; - PyObject* v; /* the string object result */ - char* pvfree; /* address of next free slot */ - char* pvend; /* address one beyond last free slot */ - size_t nfree; /* # of free buffer slots; pvend-pvfree */ - size_t total_v_size; /* total # of slots in buffer */ - size_t increment; /* amount to increment the buffer */ - size_t prev_v_size; - - /* Optimize for normal case: avoid _PyString_Resize if at all - * possible via first reading into stack buffer "buf". - */ - total_v_size = INITBUFSIZE; /* start small and pray */ - pvfree = buf; - for (;;) { - Py_BEGIN_ALLOW_THREADS - pvend = buf + total_v_size; - nfree = pvend - pvfree; - memset(pvfree, '\n', nfree); - assert(nfree < INT_MAX); /* Should be atmost MAXBUFSIZE */ - p = fgets(pvfree, (int)nfree, fp); - Py_END_ALLOW_THREADS - - if (p == NULL) { - clearerr(fp); - if (PyErr_CheckSignals()) - return NULL; - v = PyString_FromStringAndSize(buf, pvfree - buf); - return v; - } - /* fgets read *something* */ - p = memchr(pvfree, '\n', nfree); - if (p != NULL) { - /* Did the \n come from fgets or from us? - * Since fgets stops at the first \n, and then writes - * \0, if it's from fgets a \0 must be next. But if - * that's so, it could not have come from us, since - * the \n's we filled the buffer with have only more - * \n's to the right. - */ - if (p+1 < pvend && *(p+1) == '\0') { - /* It's from fgets: we win! In particular, - * we haven't done any mallocs yet, and can - * build the final result on the first try. - */ - ++p; /* include \n from fgets */ - } - else { - /* Must be from us: fgets didn't fill the - * buffer and didn't find a newline, so it - * must be the last and newline-free line of - * the file. - */ - assert(p > pvfree && *(p-1) == '\0'); - --p; /* don't include \0 from fgets */ - } - v = PyString_FromStringAndSize(buf, p - buf); - return v; - } - /* yuck: fgets overwrote all the newlines, i.e. the entire - * buffer. So this line isn't over yet, or maybe it is but - * we're exactly at EOF. If we haven't already, try using the - * rest of the stack buffer. - */ - assert(*(pvend-1) == '\0'); - if (pvfree == buf) { - pvfree = pvend - 1; /* overwrite trailing null */ - total_v_size = MAXBUFSIZE; - } - else - break; - } - - /* The stack buffer isn't big enough; malloc a string object and read - * into its buffer. - */ - total_v_size = MAXBUFSIZE << 1; - v = PyString_FromStringAndSize((char*)NULL, (int)total_v_size); - if (v == NULL) - return v; - /* copy over everything except the last null byte */ - memcpy(BUF(v), buf, MAXBUFSIZE-1); - pvfree = BUF(v) + MAXBUFSIZE - 1; - - /* Keep reading stuff into v; if it ever ends successfully, break - * after setting p one beyond the end of the line. The code here is - * very much like the code above, except reads into v's buffer; see - * the code above for detailed comments about the logic. - */ - for (;;) { - Py_BEGIN_ALLOW_THREADS - pvend = BUF(v) + total_v_size; - nfree = pvend - pvfree; - memset(pvfree, '\n', nfree); - assert(nfree < INT_MAX); - p = fgets(pvfree, (int)nfree, fp); - Py_END_ALLOW_THREADS - - if (p == NULL) { - clearerr(fp); - if (PyErr_CheckSignals()) { - Py_DECREF(v); - return NULL; - } - p = pvfree; - break; - } - p = memchr(pvfree, '\n', nfree); - if (p != NULL) { - if (p+1 < pvend && *(p+1) == '\0') { - /* \n came from fgets */ - ++p; - break; - } - /* \n came from us; last line of file, no newline */ - assert(p > pvfree && *(p-1) == '\0'); - --p; - break; - } - /* expand buffer and try again */ - assert(*(pvend-1) == '\0'); - increment = total_v_size >> 2; /* mild exponential growth */ - prev_v_size = total_v_size; - total_v_size += increment; - /* check for overflow */ - if (total_v_size <= prev_v_size || - total_v_size > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "line is longer than a Python string can hold"); - Py_DECREF(v); - return NULL; - } - if (_PyString_Resize(&v, (int)total_v_size) < 0) - return NULL; - /* overwrite the trailing null byte */ - pvfree = BUF(v) + (prev_v_size - 1); - } - if (BUF(v) + total_v_size != p) - _PyString_Resize(&v, p - BUF(v)); - return v; -#undef INITBUFSIZE -#undef MAXBUFSIZE -} -#endif /* ifdef USE_FGETS_IN_GETLINE */ - -/* Internal routine to get a line. - Size argument interpretation: - > 0: max length; - <= 0: read arbitrary line -*/ - -static PyObject * -get_line(PyFileObject *f, int n) -{ - FILE *fp = f->f_fp; - int c; - char *buf, *end; - size_t total_v_size; /* total # of slots in buffer */ - size_t used_v_size; /* # used slots in buffer */ - size_t increment; /* amount to increment the buffer */ - PyObject *v; - int newlinetypes = f->f_newlinetypes; - int skipnextlf = f->f_skipnextlf; - int univ_newline = f->f_univ_newline; - -#if defined(USE_FGETS_IN_GETLINE) - if (n <= 0 && !univ_newline ) - return getline_via_fgets(fp); -#endif - total_v_size = n > 0 ? n : 100; - v = PyString_FromStringAndSize((char *)NULL, total_v_size); - if (v == NULL) - return NULL; - buf = BUF(v); - end = buf + total_v_size; - - for (;;) { - Py_BEGIN_ALLOW_THREADS - FLOCKFILE(fp); - if (univ_newline) { - c = 'x'; /* Shut up gcc warning */ - while ( buf != end && (c = GETC(fp)) != EOF ) { - if (skipnextlf ) { - skipnextlf = 0; - if (c == '\n') { - /* Seeing a \n here with - * skipnextlf true means we - * saw a \r before. - */ - newlinetypes |= NEWLINE_CRLF; - c = GETC(fp); - if (c == EOF) break; - } else { - newlinetypes |= NEWLINE_CR; - } - } - if (c == '\r') { - skipnextlf = 1; - c = '\n'; - } else if ( c == '\n') - newlinetypes |= NEWLINE_LF; - *buf++ = c; - if (c == '\n') break; - } - if ( c == EOF && skipnextlf ) - newlinetypes |= NEWLINE_CR; - } else /* If not universal newlines use the normal loop */ - while ((c = GETC(fp)) != EOF && - (*buf++ = c) != '\n' && - buf != end) - ; - FUNLOCKFILE(fp); - Py_END_ALLOW_THREADS - f->f_newlinetypes = newlinetypes; - f->f_skipnextlf = skipnextlf; - if (c == '\n') - break; - if (c == EOF) { - if (ferror(fp)) { - PyErr_SetFromErrno(PyExc_IOError); - clearerr(fp); - Py_DECREF(v); - return NULL; - } - clearerr(fp); - if (PyErr_CheckSignals()) { - Py_DECREF(v); - return NULL; - } - break; - } - /* Must be because buf == end */ - if (n > 0) - break; - used_v_size = total_v_size; - increment = total_v_size >> 2; /* mild exponential growth */ - total_v_size += increment; - if (total_v_size > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "line is longer than a Python string can hold"); - Py_DECREF(v); - return NULL; - } - if (_PyString_Resize(&v, total_v_size) < 0) - return NULL; - buf = BUF(v) + used_v_size; - end = BUF(v) + total_v_size; - } - - used_v_size = buf - BUF(v); - if (used_v_size != total_v_size) - _PyString_Resize(&v, used_v_size); - return v; -} - -/* External C interface */ - -PyObject * -PyFile_GetLine(PyObject *f, int n) -{ - PyObject *result; - - if (f == NULL) { - PyErr_BadInternalCall(); - return NULL; - } - - if (PyFile_Check(f)) { - PyFileObject *fo = (PyFileObject *)f; - if (fo->f_fp == NULL) - return err_closed(); - /* refuse to mix with f.next() */ - if (fo->f_buf != NULL && - (fo->f_bufend - fo->f_bufptr) > 0 && - fo->f_buf[0] != '\0') - return err_iterbuffered(); - result = get_line(fo, n); - } - else { - PyObject *reader; - PyObject *args; - - reader = PyObject_GetAttrString(f, "readline"); - if (reader == NULL) - return NULL; - if (n <= 0) - args = PyTuple_New(0); - else - args = Py_BuildValue("(i)", n); - if (args == NULL) { - Py_DECREF(reader); - return NULL; - } - result = PyEval_CallObject(reader, args); - Py_DECREF(reader); - Py_DECREF(args); - if (result != NULL && !PyString_Check(result) && - !PyUnicode_Check(result)) { - Py_DECREF(result); - result = NULL; - PyErr_SetString(PyExc_TypeError, - "object.readline() returned non-string"); - } - } - - if (n < 0 && result != NULL && PyString_Check(result)) { - char *s = PyString_AS_STRING(result); - Py_ssize_t len = PyString_GET_SIZE(result); - if (len == 0) { - Py_DECREF(result); - result = NULL; - PyErr_SetString(PyExc_EOFError, - "EOF when reading a line"); - } - else if (s[len-1] == '\n') { - if (result->ob_refcnt == 1) - _PyString_Resize(&result, len-1); - else { - PyObject *v; - v = PyString_FromStringAndSize(s, len-1); - Py_DECREF(result); - result = v; - } - } - } -#ifdef Py_USING_UNICODE - if (n < 0 && result != NULL && PyUnicode_Check(result)) { - Py_UNICODE *s = PyUnicode_AS_UNICODE(result); - Py_ssize_t len = PyUnicode_GET_SIZE(result); - if (len == 0) { - Py_DECREF(result); - result = NULL; - PyErr_SetString(PyExc_EOFError, - "EOF when reading a line"); - } - else if (s[len-1] == '\n') { - if (result->ob_refcnt == 1) - PyUnicode_Resize(&result, len-1); - else { - PyObject *v; - v = PyUnicode_FromUnicode(s, len-1); - Py_DECREF(result); - result = v; - } - } - } -#endif - return result; -} - -/* Python method */ - -static PyObject * -file_readline(PyFileObject *f, PyObject *args) -{ - int n = -1; - - if (f->f_fp == NULL) - return err_closed(); - /* refuse to mix with f.next() */ - if (f->f_buf != NULL && - (f->f_bufend - f->f_bufptr) > 0 && - f->f_buf[0] != '\0') - return err_iterbuffered(); - if (!PyArg_ParseTuple(args, "|i:readline", &n)) - return NULL; - if (n == 0) - return PyString_FromString(""); - if (n < 0) - n = 0; - return get_line(f, n); -} - -static PyObject * -file_readlines(PyFileObject *f, PyObject *args) -{ - long sizehint = 0; - PyObject *list; - PyObject *line; - char small_buffer[SMALLCHUNK]; - char *buffer = small_buffer; - size_t buffersize = SMALLCHUNK; - PyObject *big_buffer = NULL; - size_t nfilled = 0; - size_t nread; - size_t totalread = 0; - char *p, *q, *end; - int err; - int shortread = 0; - - if (f->f_fp == NULL) - return err_closed(); - /* refuse to mix with f.next() */ - if (f->f_buf != NULL && - (f->f_bufend - f->f_bufptr) > 0 && - f->f_buf[0] != '\0') - return err_iterbuffered(); - if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint)) - return NULL; - if ((list = PyList_New(0)) == NULL) - return NULL; - for (;;) { - if (shortread) - nread = 0; - else { - Py_BEGIN_ALLOW_THREADS - errno = 0; - nread = Py_UniversalNewlineFread(buffer+nfilled, - buffersize-nfilled, f->f_fp, (PyObject *)f); - Py_END_ALLOW_THREADS - shortread = (nread < buffersize-nfilled); - } - if (nread == 0) { - sizehint = 0; - if (!ferror(f->f_fp)) - break; - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - error: - Py_DECREF(list); - list = NULL; - goto cleanup; - } - totalread += nread; - p = (char *)memchr(buffer+nfilled, '\n', nread); - if (p == NULL) { - /* Need a larger buffer to fit this line */ - nfilled += nread; - buffersize *= 2; - if (buffersize > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "line is longer than a Python string can hold"); - goto error; - } - if (big_buffer == NULL) { - /* Create the big buffer */ - big_buffer = PyString_FromStringAndSize( - NULL, buffersize); - if (big_buffer == NULL) - goto error; - buffer = PyString_AS_STRING(big_buffer); - memcpy(buffer, small_buffer, nfilled); - } - else { - /* Grow the big buffer */ - if ( _PyString_Resize(&big_buffer, buffersize) < 0 ) - goto error; - buffer = PyString_AS_STRING(big_buffer); - } - continue; - } - end = buffer+nfilled+nread; - q = buffer; - do { - /* Process complete lines */ - p++; - line = PyString_FromStringAndSize(q, p-q); - if (line == NULL) - goto error; - err = PyList_Append(list, line); - Py_DECREF(line); - if (err != 0) - goto error; - q = p; - p = (char *)memchr(q, '\n', end-q); - } while (p != NULL); - /* Move the remaining incomplete line to the start */ - nfilled = end-q; - memmove(buffer, q, nfilled); - if (sizehint > 0) - if (totalread >= (size_t)sizehint) - break; - } - if (nfilled != 0) { - /* Partial last line */ - line = PyString_FromStringAndSize(buffer, nfilled); - if (line == NULL) - goto error; - if (sizehint > 0) { - /* Need to complete the last line */ - PyObject *rest = get_line(f, 0); - if (rest == NULL) { - Py_DECREF(line); - goto error; - } - PyString_Concat(&line, rest); - Py_DECREF(rest); - if (line == NULL) - goto error; - } - err = PyList_Append(list, line); - Py_DECREF(line); - if (err != 0) - goto error; - } - cleanup: - Py_XDECREF(big_buffer); - return list; -} - -static PyObject * -file_write(PyFileObject *f, PyObject *args) -{ - char *s; - Py_ssize_t n, n2; - if (f->f_fp == NULL) - return err_closed(); - if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n)) - return NULL; - f->f_softspace = 0; - Py_BEGIN_ALLOW_THREADS - errno = 0; - n2 = fwrite(s, 1, n, f->f_fp); - Py_END_ALLOW_THREADS - if (n2 != n) { - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - return NULL; - } - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -file_writelines(PyFileObject *f, PyObject *seq) -{ -#define CHUNKSIZE 1000 - PyObject *list, *line; - PyObject *it; /* iter(seq) */ - PyObject *result; - int index, islist; - Py_ssize_t i, j, nwritten, len; - - assert(seq != NULL); - if (f->f_fp == NULL) - return err_closed(); - - result = NULL; - list = NULL; - islist = PyList_Check(seq); - if (islist) - it = NULL; - else { - it = PyObject_GetIter(seq); - if (it == NULL) { - PyErr_SetString(PyExc_TypeError, - "writelines() requires an iterable argument"); - return NULL; - } - /* From here on, fail by going to error, to reclaim "it". */ - list = PyList_New(CHUNKSIZE); - if (list == NULL) - goto error; - } - - /* Strategy: slurp CHUNKSIZE lines into a private list, - checking that they are all strings, then write that list - without holding the interpreter lock, then come back for more. */ - for (index = 0; ; index += CHUNKSIZE) { - if (islist) { - Py_XDECREF(list); - list = PyList_GetSlice(seq, index, index+CHUNKSIZE); - if (list == NULL) - goto error; - j = PyList_GET_SIZE(list); - } - else { - for (j = 0; j < CHUNKSIZE; j++) { - line = PyIter_Next(it); - if (line == NULL) { - if (PyErr_Occurred()) - goto error; - break; - } - PyList_SetItem(list, j, line); - } - } - if (j == 0) - break; - - /* Check that all entries are indeed strings. If not, - apply the same rules as for file.write() and - convert the results to strings. This is slow, but - seems to be the only way since all conversion APIs - could potentially execute Python code. */ - for (i = 0; i < j; i++) { - PyObject *v = PyList_GET_ITEM(list, i); - if (!PyString_Check(v)) { - const char *buffer; - if (((f->f_binary && - PyObject_AsReadBuffer(v, - (const void**)&buffer, - &len)) || - PyObject_AsCharBuffer(v, - &buffer, - &len))) { - PyErr_SetString(PyExc_TypeError, - "writelines() argument must be a sequence of strings"); - goto error; - } - line = PyString_FromStringAndSize(buffer, - len); - if (line == NULL) - goto error; - Py_DECREF(v); - PyList_SET_ITEM(list, i, line); - } - } - - /* Since we are releasing the global lock, the - following code may *not* execute Python code. */ - Py_BEGIN_ALLOW_THREADS - f->f_softspace = 0; - errno = 0; - for (i = 0; i < j; i++) { - line = PyList_GET_ITEM(list, i); - len = PyString_GET_SIZE(line); - nwritten = fwrite(PyString_AS_STRING(line), - 1, len, f->f_fp); - if (nwritten != len) { - Py_BLOCK_THREADS - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - goto error; - } - } - Py_END_ALLOW_THREADS - - if (j < CHUNKSIZE) - break; - } - - Py_INCREF(Py_None); - result = Py_None; - error: - Py_XDECREF(list); - Py_XDECREF(it); - return result; -#undef CHUNKSIZE -} - -static PyObject * -file_self(PyFileObject *f) -{ - if (f->f_fp == NULL) - return err_closed(); - Py_INCREF(f); - return (PyObject *)f; -} - -static PyObject * -file_exit(PyFileObject *f, PyObject *args) -{ - PyObject *ret = file_close(f); - if (!ret) - /* If error occurred, pass through */ - return NULL; - Py_DECREF(ret); - /* We cannot return the result of close since a true - * value will be interpreted as "yes, swallow the - * exception if one was raised inside the with block". */ - Py_RETURN_NONE; -} - -PyDoc_STRVAR(readline_doc, -"readline([size]) -> next line from the file, as a string.\n" -"\n" -"Retain newline. A non-negative size argument limits the maximum\n" -"number of bytes to return (an incomplete line may be returned then).\n" -"Return an empty string at EOF."); - -PyDoc_STRVAR(read_doc, -"read([size]) -> read at most size bytes, returned as a string.\n" -"\n" -"If the size argument is negative or omitted, read until EOF is reached.\n" -"Notice that when in non-blocking mode, less data than what was requested\n" -"may be returned, even if no size parameter was given."); - -PyDoc_STRVAR(write_doc, -"write(str) -> None. Write string str to file.\n" -"\n" -"Note that due to buffering, flush() or close() may be needed before\n" -"the file on disk reflects the data written."); - -PyDoc_STRVAR(fileno_doc, -"fileno() -> integer \"file descriptor\".\n" -"\n" -"This is needed for lower-level file interfaces, such os.read()."); - -PyDoc_STRVAR(seek_doc, -"seek(offset[, whence]) -> None. Move to new file position.\n" -"\n" -"Argument offset is a byte count. Optional argument whence defaults to\n" -"0 (offset from start of file, offset should be >= 0); other values are 1\n" -"(move relative to current position, positive or negative), and 2 (move\n" -"relative to end of file, usually negative, although many platforms allow\n" -"seeking beyond the end of a file). If the file is opened in text mode,\n" -"only offsets returned by tell() are legal. Use of other offsets causes\n" -"undefined behavior." -"\n" -"Note that not all file objects are seekable."); - -#ifdef HAVE_FTRUNCATE -PyDoc_STRVAR(truncate_doc, -"truncate([size]) -> None. Truncate the file to at most size bytes.\n" -"\n" -"Size defaults to the current file position, as returned by tell()."); -#endif - -PyDoc_STRVAR(tell_doc, -"tell() -> current file position, an integer (may be a long integer)."); - -PyDoc_STRVAR(readinto_doc, -"readinto() -> Undocumented. Don't use this; it may go away."); - -PyDoc_STRVAR(readlines_doc, -"readlines([size]) -> list of strings, each a line from the file.\n" -"\n" -"Call readline() repeatedly and return a list of the lines so read.\n" -"The optional size argument, if given, is an approximate bound on the\n" -"total number of bytes in the lines returned."); - -PyDoc_STRVAR(xreadlines_doc, -"xreadlines() -> returns self.\n" -"\n" -"For backward compatibility. File objects now include the performance\n" -"optimizations previously implemented in the xreadlines module."); - -PyDoc_STRVAR(writelines_doc, -"writelines(sequence_of_strings) -> None. Write the strings to the file.\n" -"\n" -"Note that newlines are not added. The sequence can be any iterable object\n" -"producing strings. This is equivalent to calling write() for each string."); - -PyDoc_STRVAR(flush_doc, -"flush() -> None. Flush the internal I/O buffer."); - -PyDoc_STRVAR(close_doc, -"close() -> None or (perhaps) an integer. Close the file.\n" -"\n" -"Sets data attribute .closed to True. A closed file cannot be used for\n" -"further I/O operations. close() may be called more than once without\n" -"error. Some kinds of file objects (for example, opened by popen())\n" -"may return an exit status upon closing."); - -PyDoc_STRVAR(isatty_doc, -"isatty() -> true or false. True if the file is connected to a tty device."); - -PyDoc_STRVAR(enter_doc, - "__enter__() -> self."); - -PyDoc_STRVAR(exit_doc, - "__exit__(*excinfo) -> None. Closes the file."); - -static PyMethodDef file_methods[] = { - {"readline", (PyCFunction)file_readline, METH_VARARGS, readline_doc}, - {"read", (PyCFunction)file_read, METH_VARARGS, read_doc}, - {"write", (PyCFunction)file_write, METH_VARARGS, write_doc}, - {"fileno", (PyCFunction)file_fileno, METH_NOARGS, fileno_doc}, - {"seek", (PyCFunction)file_seek, METH_VARARGS, seek_doc}, -#ifdef HAVE_FTRUNCATE - {"truncate", (PyCFunction)file_truncate, METH_VARARGS, truncate_doc}, -#endif - {"tell", (PyCFunction)file_tell, METH_NOARGS, tell_doc}, - {"readinto", (PyCFunction)file_readinto, METH_VARARGS, readinto_doc}, - {"readlines", (PyCFunction)file_readlines,METH_VARARGS, readlines_doc}, - {"xreadlines",(PyCFunction)file_self, METH_NOARGS, xreadlines_doc}, - {"writelines",(PyCFunction)file_writelines, METH_O, writelines_doc}, - {"flush", (PyCFunction)file_flush, METH_NOARGS, flush_doc}, - {"close", (PyCFunction)file_close, METH_NOARGS, close_doc}, - {"isatty", (PyCFunction)file_isatty, METH_NOARGS, isatty_doc}, - {"__enter__", (PyCFunction)file_self, METH_NOARGS, enter_doc}, - {"__exit__", (PyCFunction)file_exit, METH_VARARGS, exit_doc}, - {NULL, NULL} /* sentinel */ -}; - -#define OFF(x) offsetof(PyFileObject, x) - -static PyMemberDef file_memberlist[] = { - {"softspace", T_INT, OFF(f_softspace), 0, - "flag indicating that a space needs to be printed; used by print"}, - {"mode", T_OBJECT, OFF(f_mode), RO, - "file mode ('r', 'U', 'w', 'a', possibly with 'b' or '+' added)"}, - {"name", T_OBJECT, OFF(f_name), RO, - "file name"}, - {"encoding", T_OBJECT, OFF(f_encoding), RO, - "file encoding"}, - /* getattr(f, "closed") is implemented without this table */ - {NULL} /* Sentinel */ -}; - -static PyObject * -get_closed(PyFileObject *f, void *closure) -{ - return PyBool_FromLong((long)(f->f_fp == 0)); -} -static PyObject * -get_newlines(PyFileObject *f, void *closure) -{ - switch (f->f_newlinetypes) { - case NEWLINE_UNKNOWN: - Py_INCREF(Py_None); - return Py_None; - case NEWLINE_CR: - return PyString_FromString("\r"); - case NEWLINE_LF: - return PyString_FromString("\n"); - case NEWLINE_CR|NEWLINE_LF: - return Py_BuildValue("(ss)", "\r", "\n"); - case NEWLINE_CRLF: - return PyString_FromString("\r\n"); - case NEWLINE_CR|NEWLINE_CRLF: - return Py_BuildValue("(ss)", "\r", "\r\n"); - case NEWLINE_LF|NEWLINE_CRLF: - return Py_BuildValue("(ss)", "\n", "\r\n"); - case NEWLINE_CR|NEWLINE_LF|NEWLINE_CRLF: - return Py_BuildValue("(sss)", "\r", "\n", "\r\n"); - default: - PyErr_Format(PyExc_SystemError, - "Unknown newlines value 0x%x\n", - f->f_newlinetypes); - return NULL; - } -} - -static PyGetSetDef file_getsetlist[] = { - {"closed", (getter)get_closed, NULL, "True if the file is closed"}, - {"newlines", (getter)get_newlines, NULL, - "end-of-line convention used in this file"}, - {0}, -}; - -static void -drop_readahead(PyFileObject *f) -{ - if (f->f_buf != NULL) { - PyMem_Free(f->f_buf); - f->f_buf = NULL; - } -} - -/* Make sure that file has a readahead buffer with at least one byte - (unless at EOF) and no more than bufsize. Returns negative value on - error, will set MemoryError if bufsize bytes cannot be allocated. */ -static int -readahead(PyFileObject *f, int bufsize) -{ - Py_ssize_t chunksize; - - if (f->f_buf != NULL) { - if( (f->f_bufend - f->f_bufptr) >= 1) - return 0; - else - drop_readahead(f); - } - if ((f->f_buf = (char *)PyMem_Malloc(bufsize)) == NULL) { - PyErr_NoMemory(); - return -1; - } - Py_BEGIN_ALLOW_THREADS - errno = 0; - chunksize = Py_UniversalNewlineFread( - f->f_buf, bufsize, f->f_fp, (PyObject *)f); - Py_END_ALLOW_THREADS - if (chunksize == 0) { - if (ferror(f->f_fp)) { - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - drop_readahead(f); - return -1; - } - } - f->f_bufptr = f->f_buf; - f->f_bufend = f->f_buf + chunksize; - return 0; -} - -/* Used by file_iternext. The returned string will start with 'skip' - uninitialized bytes followed by the remainder of the line. Don't be - horrified by the recursive call: maximum recursion depth is limited by - logarithmic buffer growth to about 50 even when reading a 1gb line. */ - -static PyStringObject * -readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) -{ - PyStringObject* s; - char *bufptr; - char *buf; - Py_ssize_t len; - - if (f->f_buf == NULL) - if (readahead(f, bufsize) < 0) - return NULL; - - len = f->f_bufend - f->f_bufptr; - if (len == 0) - return (PyStringObject *) - PyString_FromStringAndSize(NULL, skip); - bufptr = (char *)memchr(f->f_bufptr, '\n', len); - if (bufptr != NULL) { - bufptr++; /* Count the '\n' */ - len = bufptr - f->f_bufptr; - s = (PyStringObject *) - PyString_FromStringAndSize(NULL, skip+len); - if (s == NULL) - return NULL; - memcpy(PyString_AS_STRING(s)+skip, f->f_bufptr, len); - f->f_bufptr = bufptr; - if (bufptr == f->f_bufend) - drop_readahead(f); - } else { - bufptr = f->f_bufptr; - buf = f->f_buf; - f->f_buf = NULL; /* Force new readahead buffer */ - assert(skip+len < INT_MAX); - s = readahead_get_line_skip( - f, (int)(skip+len), bufsize + (bufsize>>2) ); - if (s == NULL) { - PyMem_Free(buf); - return NULL; - } - memcpy(PyString_AS_STRING(s)+skip, bufptr, len); - PyMem_Free(buf); - } - return s; -} - -/* A larger buffer size may actually decrease performance. */ -#define READAHEAD_BUFSIZE 8192 - -static PyObject * -file_iternext(PyFileObject *f) -{ - PyStringObject* l; - - if (f->f_fp == NULL) - return err_closed(); - - l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE); - if (l == NULL || PyString_GET_SIZE(l) == 0) { - Py_XDECREF(l); - return NULL; - } - return (PyObject *)l; -} - - -static PyObject * -file_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *self; - static PyObject *not_yet_string; - - assert(type != NULL && type->tp_alloc != NULL); - - if (not_yet_string == NULL) { - not_yet_string = PyString_FromString("<uninitialized file>"); - if (not_yet_string == NULL) - return NULL; - } - - self = type->tp_alloc(type, 0); - if (self != NULL) { - /* Always fill in the name and mode, so that nobody else - needs to special-case NULLs there. */ - Py_INCREF(not_yet_string); - ((PyFileObject *)self)->f_name = not_yet_string; - Py_INCREF(not_yet_string); - ((PyFileObject *)self)->f_mode = not_yet_string; - Py_INCREF(Py_None); - ((PyFileObject *)self)->f_encoding = Py_None; - ((PyFileObject *)self)->weakreflist = NULL; - } - return self; -} - -static int -file_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - PyFileObject *foself = (PyFileObject *)self; - int ret = 0; - static char *kwlist[] = {"name", "mode", "buffering", 0}; - char *name = NULL; - char *mode = "r"; - int bufsize = -1; - int wideargument = 0; - - assert(PyFile_Check(self)); - if (foself->f_fp != NULL) { - /* Have to close the existing file first. */ - PyObject *closeresult = file_close(foself); - if (closeresult == NULL) - return -1; - Py_DECREF(closeresult); - } - -#ifdef Py_WIN_WIDE_FILENAMES - if (GetVersion() < 0x80000000) { /* On NT, so wide API available */ - PyObject *po; - if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:file", - kwlist, &po, &mode, &bufsize)) { - wideargument = 1; - if (fill_file_fields(foself, NULL, po, mode, - fclose) == NULL) - goto Error; - } else { - /* Drop the argument parsing error as narrow - strings are also valid. */ - PyErr_Clear(); - } - } -#endif - - if (!wideargument) { - PyObject *o_name; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:file", kwlist, - Py_FileSystemDefaultEncoding, - &name, - &mode, &bufsize)) - return -1; - - /* We parse again to get the name as a PyObject */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:file", - kwlist, &o_name, &mode, - &bufsize)) - goto Error; - - if (fill_file_fields(foself, NULL, o_name, mode, - fclose) == NULL) - goto Error; - } - if (open_the_file(foself, name, mode) == NULL) - goto Error; - foself->f_setbuf = NULL; - PyFile_SetBufSize(self, bufsize); - goto Done; - -Error: - ret = -1; - /* fall through */ -Done: - PyMem_Free(name); /* free the encoded string */ - return ret; -} - -PyDoc_VAR(file_doc) = -PyDoc_STR( -"file(name[, mode[, buffering]]) -> file object\n" -"\n" -"Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n" -"writing or appending. The file will be created if it doesn't exist\n" -"when opened for writing or appending; it will be truncated when\n" -"opened for writing. Add a 'b' to the mode for binary files.\n" -"Add a '+' to the mode to allow simultaneous reading and writing.\n" -"If the buffering argument is given, 0 means unbuffered, 1 means line\n" -"buffered, and larger numbers specify the buffer size.\n" -) -PyDoc_STR( -"Add a 'U' to mode to open the file for input with universal newline\n" -"support. Any line ending in the input file will be seen as a '\\n'\n" -"in Python. Also, a file so opened gains the attribute 'newlines';\n" -"the value for this attribute is one of None (no newline read yet),\n" -"'\\r', '\\n', '\\r\\n' or a tuple containing all the newline types seen.\n" -"\n" -"'U' cannot be combined with 'w' or '+' mode.\n" -); - -PyTypeObject PyFile_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "file", - sizeof(PyFileObject), - 0, - (destructor)file_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)file_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - /* softspace is writable: we must supply tp_setattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ - file_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyFileObject, weakreflist), /* tp_weaklistoffset */ - (getiterfunc)file_self, /* tp_iter */ - (iternextfunc)file_iternext, /* tp_iternext */ - file_methods, /* tp_methods */ - file_memberlist, /* tp_members */ - file_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - file_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - file_new, /* tp_new */ - PyObject_Del, /* tp_free */ -}; - -/* Interface for the 'soft space' between print items. */ - -int -PyFile_SoftSpace(PyObject *f, int newflag) -{ - long oldflag = 0; - if (f == NULL) { - /* Do nothing */ - } - else if (PyFile_Check(f)) { - oldflag = ((PyFileObject *)f)->f_softspace; - ((PyFileObject *)f)->f_softspace = newflag; - } - else { - PyObject *v; - v = PyObject_GetAttrString(f, "softspace"); - if (v == NULL) - PyErr_Clear(); - else { - if (PyInt_Check(v)) - oldflag = PyInt_AsLong(v); - assert(oldflag < INT_MAX); - Py_DECREF(v); - } - v = PyInt_FromLong((long)newflag); - if (v == NULL) - PyErr_Clear(); - else { - if (PyObject_SetAttrString(f, "softspace", v) != 0) - PyErr_Clear(); - Py_DECREF(v); - } - } - return (int)oldflag; -} - -/* Interfaces to write objects/strings to file-like objects */ - -int -PyFile_WriteObject(PyObject *v, PyObject *f, int flags) -{ - PyObject *writer, *value, *args, *result; - if (f == NULL) { - PyErr_SetString(PyExc_TypeError, "writeobject with NULL file"); - return -1; - } - else if (PyFile_Check(f)) { - FILE *fp = PyFile_AsFile(f); -#ifdef Py_USING_UNICODE - PyObject *enc = ((PyFileObject*)f)->f_encoding; - int result; -#endif - if (fp == NULL) { - err_closed(); - return -1; - } -#ifdef Py_USING_UNICODE - if ((flags & Py_PRINT_RAW) && - PyUnicode_Check(v) && enc != Py_None) { - char *cenc = PyString_AS_STRING(enc); - value = PyUnicode_AsEncodedString(v, cenc, "strict"); - if (value == NULL) - return -1; - } else { - value = v; - Py_INCREF(value); - } - result = PyObject_Print(value, fp, flags); - Py_DECREF(value); - return result; -#else - return PyObject_Print(v, fp, flags); -#endif - } - writer = PyObject_GetAttrString(f, "write"); - if (writer == NULL) - return -1; - if (flags & Py_PRINT_RAW) { - if (PyUnicode_Check(v)) { - value = v; - Py_INCREF(value); - } else - value = PyObject_Str(v); - } - else - value = PyObject_Repr(v); - if (value == NULL) { - Py_DECREF(writer); - return -1; - } - args = PyTuple_Pack(1, value); - if (args == NULL) { - Py_DECREF(value); - Py_DECREF(writer); - return -1; - } - result = PyEval_CallObject(writer, args); - Py_DECREF(args); - Py_DECREF(value); - Py_DECREF(writer); - if (result == NULL) - return -1; - Py_DECREF(result); - return 0; -} - -int -PyFile_WriteString(const char *s, PyObject *f) -{ - if (f == NULL) { - /* Should be caused by a pre-existing error */ - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_SystemError, - "null file for PyFile_WriteString"); - return -1; - } - else if (PyFile_Check(f)) { - FILE *fp = PyFile_AsFile(f); - if (fp == NULL) { - err_closed(); - return -1; - } - fputs(s, fp); - return 0; - } - else if (!PyErr_Occurred()) { - PyObject *v = PyString_FromString(s); - int err; - if (v == NULL) - return -1; - err = PyFile_WriteObject(v, f, Py_PRINT_RAW); - Py_DECREF(v); - return err; - } - else - return -1; -} - -/* Try to get a file-descriptor from a Python object. If the object - is an integer or long integer, its value is returned. If not, the - object's fileno() method is called if it exists; the method must return - an integer or long integer, which is returned as the file descriptor value. - -1 is returned on failure. -*/ - -int PyObject_AsFileDescriptor(PyObject *o) -{ - int fd; - PyObject *meth; - - if (PyInt_Check(o)) { - fd = PyInt_AsLong(o); - } - else if (PyLong_Check(o)) { - fd = PyLong_AsLong(o); - } - else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL) - { - PyObject *fno = PyEval_CallObject(meth, NULL); - Py_DECREF(meth); - if (fno == NULL) - return -1; - - if (PyInt_Check(fno)) { - fd = PyInt_AsLong(fno); - Py_DECREF(fno); - } - else if (PyLong_Check(fno)) { - fd = PyLong_AsLong(fno); - Py_DECREF(fno); - } - else { - PyErr_SetString(PyExc_TypeError, - "fileno() returned a non-integer"); - Py_DECREF(fno); - return -1; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "argument must be an int, or have a fileno() method."); - return -1; - } - - if (fd < 0) { - PyErr_Format(PyExc_ValueError, - "file descriptor cannot be a negative integer (%i)", - fd); - return -1; - } - return fd; -} - -/* From here on we need access to the real fgets and fread */ -#undef fgets -#undef fread - -/* -** Py_UniversalNewlineFgets is an fgets variation that understands -** all of \r, \n and \r\n conventions. -** The stream should be opened in binary mode. -** If fobj is NULL the routine always does newline conversion, and -** it may peek one char ahead to gobble the second char in \r\n. -** If fobj is non-NULL it must be a PyFileObject. In this case there -** is no readahead but in stead a flag is used to skip a following -** \n on the next read. Also, if the file is open in binary mode -** the whole conversion is skipped. Finally, the routine keeps track of -** the different types of newlines seen. -** Note that we need no error handling: fgets() treats error and eof -** identically. -*/ -char * -Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) -{ - char *p = buf; - int c; - int newlinetypes = 0; - int skipnextlf = 0; - int univ_newline = 1; - - if (fobj) { - if (!PyFile_Check(fobj)) { - errno = ENXIO; /* What can you do... */ - return NULL; - } - univ_newline = ((PyFileObject *)fobj)->f_univ_newline; - if ( !univ_newline ) - return fgets(buf, n, stream); - newlinetypes = ((PyFileObject *)fobj)->f_newlinetypes; - skipnextlf = ((PyFileObject *)fobj)->f_skipnextlf; - } - FLOCKFILE(stream); - c = 'x'; /* Shut up gcc warning */ - while (--n > 0 && (c = GETC(stream)) != EOF ) { - if (skipnextlf ) { - skipnextlf = 0; - if (c == '\n') { - /* Seeing a \n here with skipnextlf true - ** means we saw a \r before. - */ - newlinetypes |= NEWLINE_CRLF; - c = GETC(stream); - if (c == EOF) break; - } else { - /* - ** Note that c == EOF also brings us here, - ** so we're okay if the last char in the file - ** is a CR. - */ - newlinetypes |= NEWLINE_CR; - } - } - if (c == '\r') { - /* A \r is translated into a \n, and we skip - ** an adjacent \n, if any. We don't set the - ** newlinetypes flag until we've seen the next char. - */ - skipnextlf = 1; - c = '\n'; - } else if ( c == '\n') { - newlinetypes |= NEWLINE_LF; - } - *p++ = c; - if (c == '\n') break; - } - if ( c == EOF && skipnextlf ) - newlinetypes |= NEWLINE_CR; - FUNLOCKFILE(stream); - *p = '\0'; - if (fobj) { - ((PyFileObject *)fobj)->f_newlinetypes = newlinetypes; - ((PyFileObject *)fobj)->f_skipnextlf = skipnextlf; - } else if ( skipnextlf ) { - /* If we have no file object we cannot save the - ** skipnextlf flag. We have to readahead, which - ** will cause a pause if we're reading from an - ** interactive stream, but that is very unlikely - ** unless we're doing something silly like - ** execfile("/dev/tty"). - */ - c = GETC(stream); - if ( c != '\n' ) - ungetc(c, stream); - } - if (p == buf) - return NULL; - return buf; -} - -/* -** Py_UniversalNewlineFread is an fread variation that understands -** all of \r, \n and \r\n conventions. -** The stream should be opened in binary mode. -** fobj must be a PyFileObject. In this case there -** is no readahead but in stead a flag is used to skip a following -** \n on the next read. Also, if the file is open in binary mode -** the whole conversion is skipped. Finally, the routine keeps track of -** the different types of newlines seen. -*/ -size_t -Py_UniversalNewlineFread(char *buf, size_t n, - FILE *stream, PyObject *fobj) -{ - char *dst = buf; - PyFileObject *f = (PyFileObject *)fobj; - int newlinetypes, skipnextlf; - - assert(buf != NULL); - assert(stream != NULL); - - if (!fobj || !PyFile_Check(fobj)) { - errno = ENXIO; /* What can you do... */ - return 0; - } - if (!f->f_univ_newline) - return fread(buf, 1, n, stream); - newlinetypes = f->f_newlinetypes; - skipnextlf = f->f_skipnextlf; - /* Invariant: n is the number of bytes remaining to be filled - * in the buffer. - */ - while (n) { - size_t nread; - int shortread; - char *src = dst; - - nread = fread(dst, 1, n, stream); - assert(nread <= n); - if (nread == 0) - break; - - n -= nread; /* assuming 1 byte out for each in; will adjust */ - shortread = n != 0; /* true iff EOF or error */ - while (nread--) { - char c = *src++; - if (c == '\r') { - /* Save as LF and set flag to skip next LF. */ - *dst++ = '\n'; - skipnextlf = 1; - } - else if (skipnextlf && c == '\n') { - /* Skip LF, and remember we saw CR LF. */ - skipnextlf = 0; - newlinetypes |= NEWLINE_CRLF; - ++n; - } - else { - /* Normal char to be stored in buffer. Also - * update the newlinetypes flag if either this - * is an LF or the previous char was a CR. - */ - if (c == '\n') - newlinetypes |= NEWLINE_LF; - else if (skipnextlf) - newlinetypes |= NEWLINE_CR; - *dst++ = c; - skipnextlf = 0; - } - } - if (shortread) { - /* If this is EOF, update type flags. */ - if (skipnextlf && feof(stream)) - newlinetypes |= NEWLINE_CR; - break; - } - } - f->f_newlinetypes = newlinetypes; - f->f_skipnextlf = skipnextlf; - return dst - buf; -} - -#ifdef __cplusplus -} -#endif diff --git a/sys/src/cmd/python/Objects/floatobject.c b/sys/src/cmd/python/Objects/floatobject.c deleted file mode 100644 index 2087ceba8..000000000 --- a/sys/src/cmd/python/Objects/floatobject.c +++ /dev/null @@ -1,1748 +0,0 @@ - -/* Float object implementation */ - -/* XXX There should be overflow checks here, but it's hard to check - for any kind of float exception without losing portability. */ - -#include "Python.h" - -#include <ctype.h> - -#if !defined(__STDC__) -extern double fmod(double, double); -extern double pow(double, double); -#endif - -/* Special free list -- see comments for same code in intobject.c. */ -#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ -#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ -#define N_FLOATOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyFloatObject)) - -struct _floatblock { - struct _floatblock *next; - PyFloatObject objects[N_FLOATOBJECTS]; -}; - -typedef struct _floatblock PyFloatBlock; - -static PyFloatBlock *block_list = NULL; -static PyFloatObject *free_list = NULL; - -static PyFloatObject * -fill_free_list(void) -{ - PyFloatObject *p, *q; - /* XXX Float blocks escape the object heap. Use PyObject_MALLOC ??? */ - p = (PyFloatObject *) PyMem_MALLOC(sizeof(PyFloatBlock)); - if (p == NULL) - return (PyFloatObject *) PyErr_NoMemory(); - ((PyFloatBlock *)p)->next = block_list; - block_list = (PyFloatBlock *)p; - p = &((PyFloatBlock *)p)->objects[0]; - q = p + N_FLOATOBJECTS; - while (--q > p) - q->ob_type = (struct _typeobject *)(q-1); - q->ob_type = NULL; - return p + N_FLOATOBJECTS - 1; -} - -PyObject * -PyFloat_FromDouble(double fval) -{ - register PyFloatObject *op; - if (free_list == NULL) { - if ((free_list = fill_free_list()) == NULL) - return NULL; - } - /* Inline PyObject_New */ - op = free_list; - free_list = (PyFloatObject *)op->ob_type; - PyObject_INIT(op, &PyFloat_Type); - op->ob_fval = fval; - return (PyObject *) op; -} - -/************************************************************************** -RED_FLAG 22-Sep-2000 tim -PyFloat_FromString's pend argument is braindead. Prior to this RED_FLAG, - -1. If v was a regular string, *pend was set to point to its terminating - null byte. That's useless (the caller can find that without any - help from this function!). - -2. If v was a Unicode string, or an object convertible to a character - buffer, *pend was set to point into stack trash (the auto temp - vector holding the character buffer). That was downright dangerous. - -Since we can't change the interface of a public API function, pend is -still supported but now *officially* useless: if pend is not NULL, -*pend is set to NULL. -**************************************************************************/ -PyObject * -PyFloat_FromString(PyObject *v, char **pend) -{ - const char *s, *last, *end; - double x; - char buffer[256]; /* for errors */ -#ifdef Py_USING_UNICODE - char s_buffer[256]; /* for objects convertible to a char buffer */ -#endif - Py_ssize_t len; - - if (pend) - *pend = NULL; - if (PyString_Check(v)) { - s = PyString_AS_STRING(v); - len = PyString_GET_SIZE(v); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(v)) { - if (PyUnicode_GET_SIZE(v) >= (Py_ssize_t)sizeof(s_buffer)) { - PyErr_SetString(PyExc_ValueError, - "Unicode float() literal too long to convert"); - return NULL; - } - if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), - PyUnicode_GET_SIZE(v), - s_buffer, - NULL)) - return NULL; - s = s_buffer; - len = strlen(s); - } -#endif - else if (PyObject_AsCharBuffer(v, &s, &len)) { - PyErr_SetString(PyExc_TypeError, - "float() argument must be a string or a number"); - return NULL; - } - - last = s + len; - while (*s && isspace(Py_CHARMASK(*s))) - s++; - if (*s == '\0') { - PyErr_SetString(PyExc_ValueError, "empty string for float()"); - return NULL; - } - /* We don't care about overflow or underflow. If the platform supports - * them, infinities and signed zeroes (on underflow) are fine. - * However, strtod can return 0 for denormalized numbers, where atof - * does not. So (alas!) we special-case a zero result. Note that - * whether strtod sets errno on underflow is not defined, so we can't - * key off errno. - */ - PyFPE_START_PROTECT("strtod", return NULL) - x = PyOS_ascii_strtod(s, (char **)&end); - PyFPE_END_PROTECT(x) - errno = 0; - /* Believe it or not, Solaris 2.6 can move end *beyond* the null - byte at the end of the string, when the input is inf(inity). */ - if (end > last) - end = last; - if (end == s) { - PyOS_snprintf(buffer, sizeof(buffer), - "invalid literal for float(): %.200s", s); - PyErr_SetString(PyExc_ValueError, buffer); - return NULL; - } - /* Since end != s, the platform made *some* kind of sense out - of the input. Trust it. */ - while (*end && isspace(Py_CHARMASK(*end))) - end++; - if (*end != '\0') { - PyOS_snprintf(buffer, sizeof(buffer), - "invalid literal for float(): %.200s", s); - PyErr_SetString(PyExc_ValueError, buffer); - return NULL; - } - else if (end != last) { - PyErr_SetString(PyExc_ValueError, - "null byte in argument for float()"); - return NULL; - } - if (x == 0.0) { - /* See above -- may have been strtod being anal - about denorms. */ - PyFPE_START_PROTECT("atof", return NULL) - x = PyOS_ascii_atof(s); - PyFPE_END_PROTECT(x) - errno = 0; /* whether atof ever set errno is undefined */ - } - return PyFloat_FromDouble(x); -} - -static void -float_dealloc(PyFloatObject *op) -{ - if (PyFloat_CheckExact(op)) { - op->ob_type = (struct _typeobject *)free_list; - free_list = op; - } - else - op->ob_type->tp_free((PyObject *)op); -} - -double -PyFloat_AsDouble(PyObject *op) -{ - PyNumberMethods *nb; - PyFloatObject *fo; - double val; - - if (op && PyFloat_Check(op)) - return PyFloat_AS_DOUBLE((PyFloatObject*) op); - - if (op == NULL) { - PyErr_BadArgument(); - return -1; - } - - if ((nb = op->ob_type->tp_as_number) == NULL || nb->nb_float == NULL) { - PyErr_SetString(PyExc_TypeError, "a float is required"); - return -1; - } - - fo = (PyFloatObject*) (*nb->nb_float) (op); - if (fo == NULL) - return -1; - if (!PyFloat_Check(fo)) { - PyErr_SetString(PyExc_TypeError, - "nb_float should return float object"); - return -1; - } - - val = PyFloat_AS_DOUBLE(fo); - Py_DECREF(fo); - - return val; -} - -/* Methods */ - -static void -format_float(char *buf, size_t buflen, PyFloatObject *v, int precision) -{ - register char *cp; - char format[32]; - /* Subroutine for float_repr and float_print. - We want float numbers to be recognizable as such, - i.e., they should contain a decimal point or an exponent. - However, %g may print the number as an integer; - in such cases, we append ".0" to the string. */ - - assert(PyFloat_Check(v)); - PyOS_snprintf(format, 32, "%%.%ig", precision); - PyOS_ascii_formatd(buf, buflen, format, v->ob_fval); - cp = buf; - if (*cp == '-') - cp++; - for (; *cp != '\0'; cp++) { - /* Any non-digit means it's not an integer; - this takes care of NAN and INF as well. */ - if (!isdigit(Py_CHARMASK(*cp))) - break; - } - if (*cp == '\0') { - *cp++ = '.'; - *cp++ = '0'; - *cp++ = '\0'; - } -} - -/* XXX PyFloat_AsStringEx should not be a public API function (for one - XXX thing, its signature passes a buffer without a length; for another, - XXX it isn't useful outside this file). -*/ -void -PyFloat_AsStringEx(char *buf, PyFloatObject *v, int precision) -{ - format_float(buf, 100, v, precision); -} - -/* Macro and helper that convert PyObject obj to a C double and store - the value in dbl; this replaces the functionality of the coercion - slot function. If conversion to double raises an exception, obj is - set to NULL, and the function invoking this macro returns NULL. If - obj is not of float, int or long type, Py_NotImplemented is incref'ed, - stored in obj, and returned from the function invoking this macro. -*/ -#define CONVERT_TO_DOUBLE(obj, dbl) \ - if (PyFloat_Check(obj)) \ - dbl = PyFloat_AS_DOUBLE(obj); \ - else if (convert_to_double(&(obj), &(dbl)) < 0) \ - return obj; - -static int -convert_to_double(PyObject **v, double *dbl) -{ - register PyObject *obj = *v; - - if (PyInt_Check(obj)) { - *dbl = (double)PyInt_AS_LONG(obj); - } - else if (PyLong_Check(obj)) { - *dbl = PyLong_AsDouble(obj); - if (*dbl == -1.0 && PyErr_Occurred()) { - *v = NULL; - return -1; - } - } - else { - Py_INCREF(Py_NotImplemented); - *v = Py_NotImplemented; - return -1; - } - return 0; -} - -/* Precisions used by repr() and str(), respectively. - - The repr() precision (17 significant decimal digits) is the minimal number - that is guaranteed to have enough precision so that if the number is read - back in the exact same binary value is recreated. This is true for IEEE - floating point by design, and also happens to work for all other modern - hardware. - - The str() precision is chosen so that in most cases, the rounding noise - created by various operations is suppressed, while giving plenty of - precision for practical use. - -*/ - -#define PREC_REPR 17 -#define PREC_STR 12 - -/* XXX PyFloat_AsString and PyFloat_AsReprString should be deprecated: - XXX they pass a char buffer without passing a length. -*/ -void -PyFloat_AsString(char *buf, PyFloatObject *v) -{ - format_float(buf, 100, v, PREC_STR); -} - -void -PyFloat_AsReprString(char *buf, PyFloatObject *v) -{ - format_float(buf, 100, v, PREC_REPR); -} - -/* ARGSUSED */ -static int -float_print(PyFloatObject *v, FILE *fp, int flags) -{ - char buf[100]; - format_float(buf, sizeof(buf), v, - (flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR); - fputs(buf, fp); - return 0; -} - -static PyObject * -float_repr(PyFloatObject *v) -{ - char buf[100]; - format_float(buf, sizeof(buf), v, PREC_REPR); - return PyString_FromString(buf); -} - -static PyObject * -float_str(PyFloatObject *v) -{ - char buf[100]; - format_float(buf, sizeof(buf), v, PREC_STR); - return PyString_FromString(buf); -} - -/* Comparison is pretty much a nightmare. When comparing float to float, - * we do it as straightforwardly (and long-windedly) as conceivable, so - * that, e.g., Python x == y delivers the same result as the platform - * C x == y when x and/or y is a NaN. - * When mixing float with an integer type, there's no good *uniform* approach. - * Converting the double to an integer obviously doesn't work, since we - * may lose info from fractional bits. Converting the integer to a double - * also has two failure modes: (1) a long int may trigger overflow (too - * large to fit in the dynamic range of a C double); (2) even a C long may have - * more bits than fit in a C double (e.g., on a a 64-bit box long may have - * 63 bits of precision, but a C double probably has only 53), and then - * we can falsely claim equality when low-order integer bits are lost by - * coercion to double. So this part is painful too. - */ - -static PyObject* -float_richcompare(PyObject *v, PyObject *w, int op) -{ - double i, j; - int r = 0; - - assert(PyFloat_Check(v)); - i = PyFloat_AS_DOUBLE(v); - - /* Switch on the type of w. Set i and j to doubles to be compared, - * and op to the richcomp to use. - */ - if (PyFloat_Check(w)) - j = PyFloat_AS_DOUBLE(w); - - else if (!Py_IS_FINITE(i)) { - if (PyInt_Check(w) || PyLong_Check(w)) - /* If i is an infinity, its magnitude exceeds any - * finite integer, so it doesn't matter which int we - * compare i with. If i is a NaN, similarly. - */ - j = 0.0; - else - goto Unimplemented; - } - - else if (PyInt_Check(w)) { - long jj = PyInt_AS_LONG(w); - /* In the worst realistic case I can imagine, C double is a - * Cray single with 48 bits of precision, and long has 64 - * bits. - */ -#if SIZEOF_LONG > 6 - unsigned long abs = (unsigned long)(jj < 0 ? -jj : jj); - if (abs >> 48) { - /* Needs more than 48 bits. Make it take the - * PyLong path. - */ - PyObject *result; - PyObject *ww = PyLong_FromLong(jj); - - if (ww == NULL) - return NULL; - result = float_richcompare(v, ww, op); - Py_DECREF(ww); - return result; - } -#endif - j = (double)jj; - assert((long)j == jj); - } - - else if (PyLong_Check(w)) { - int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1; - int wsign = _PyLong_Sign(w); - size_t nbits; - int exponent; - - if (vsign != wsign) { - /* Magnitudes are irrelevant -- the signs alone - * determine the outcome. - */ - i = (double)vsign; - j = (double)wsign; - goto Compare; - } - /* The signs are the same. */ - /* Convert w to a double if it fits. In particular, 0 fits. */ - nbits = _PyLong_NumBits(w); - if (nbits == (size_t)-1 && PyErr_Occurred()) { - /* This long is so large that size_t isn't big enough - * to hold the # of bits. Replace with little doubles - * that give the same outcome -- w is so large that - * its magnitude must exceed the magnitude of any - * finite float. - */ - PyErr_Clear(); - i = (double)vsign; - assert(wsign != 0); - j = wsign * 2.0; - goto Compare; - } - if (nbits <= 48) { - j = PyLong_AsDouble(w); - /* It's impossible that <= 48 bits overflowed. */ - assert(j != -1.0 || ! PyErr_Occurred()); - goto Compare; - } - assert(wsign != 0); /* else nbits was 0 */ - assert(vsign != 0); /* if vsign were 0, then since wsign is - * not 0, we would have taken the - * vsign != wsign branch at the start */ - /* We want to work with non-negative numbers. */ - if (vsign < 0) { - /* "Multiply both sides" by -1; this also swaps the - * comparator. - */ - i = -i; - op = _Py_SwappedOp[op]; - } - assert(i > 0.0); - (void) frexp(i, &exponent); - /* exponent is the # of bits in v before the radix point; - * we know that nbits (the # of bits in w) > 48 at this point - */ - if (exponent < 0 || (size_t)exponent < nbits) { - i = 1.0; - j = 2.0; - goto Compare; - } - if ((size_t)exponent > nbits) { - i = 2.0; - j = 1.0; - goto Compare; - } - /* v and w have the same number of bits before the radix - * point. Construct two longs that have the same comparison - * outcome. - */ - { - double fracpart; - double intpart; - PyObject *result = NULL; - PyObject *one = NULL; - PyObject *vv = NULL; - PyObject *ww = w; - - if (wsign < 0) { - ww = PyNumber_Negative(w); - if (ww == NULL) - goto Error; - } - else - Py_INCREF(ww); - - fracpart = modf(i, &intpart); - vv = PyLong_FromDouble(intpart); - if (vv == NULL) - goto Error; - - if (fracpart != 0.0) { - /* Shift left, and or a 1 bit into vv - * to represent the lost fraction. - */ - PyObject *temp; - - one = PyInt_FromLong(1); - if (one == NULL) - goto Error; - - temp = PyNumber_Lshift(ww, one); - if (temp == NULL) - goto Error; - Py_DECREF(ww); - ww = temp; - - temp = PyNumber_Lshift(vv, one); - if (temp == NULL) - goto Error; - Py_DECREF(vv); - vv = temp; - - temp = PyNumber_Or(vv, one); - if (temp == NULL) - goto Error; - Py_DECREF(vv); - vv = temp; - } - - r = PyObject_RichCompareBool(vv, ww, op); - if (r < 0) - goto Error; - result = PyBool_FromLong(r); - Error: - Py_XDECREF(vv); - Py_XDECREF(ww); - Py_XDECREF(one); - return result; - } - } /* else if (PyLong_Check(w)) */ - - else /* w isn't float, int, or long */ - goto Unimplemented; - - Compare: - PyFPE_START_PROTECT("richcompare", return NULL) - switch (op) { - case Py_EQ: - r = i == j; - break; - case Py_NE: - r = i != j; - break; - case Py_LE: - r = i <= j; - break; - case Py_GE: - r = i >= j; - break; - case Py_LT: - r = i < j; - break; - case Py_GT: - r = i > j; - break; - } - PyFPE_END_PROTECT(r) - return PyBool_FromLong(r); - - Unimplemented: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -static long -float_hash(PyFloatObject *v) -{ - return _Py_HashDouble(v->ob_fval); -} - -static PyObject * -float_add(PyObject *v, PyObject *w) -{ - double a,b; - CONVERT_TO_DOUBLE(v, a); - CONVERT_TO_DOUBLE(w, b); - PyFPE_START_PROTECT("add", return 0) - a = a + b; - PyFPE_END_PROTECT(a) - return PyFloat_FromDouble(a); -} - -static PyObject * -float_sub(PyObject *v, PyObject *w) -{ - double a,b; - CONVERT_TO_DOUBLE(v, a); - CONVERT_TO_DOUBLE(w, b); - PyFPE_START_PROTECT("subtract", return 0) - a = a - b; - PyFPE_END_PROTECT(a) - return PyFloat_FromDouble(a); -} - -static PyObject * -float_mul(PyObject *v, PyObject *w) -{ - double a,b; - CONVERT_TO_DOUBLE(v, a); - CONVERT_TO_DOUBLE(w, b); - PyFPE_START_PROTECT("multiply", return 0) - a = a * b; - PyFPE_END_PROTECT(a) - return PyFloat_FromDouble(a); -} - -static PyObject * -float_div(PyObject *v, PyObject *w) -{ - double a,b; - CONVERT_TO_DOUBLE(v, a); - CONVERT_TO_DOUBLE(w, b); - if (b == 0.0) { - PyErr_SetString(PyExc_ZeroDivisionError, "float division"); - return NULL; - } - PyFPE_START_PROTECT("divide", return 0) - a = a / b; - PyFPE_END_PROTECT(a) - return PyFloat_FromDouble(a); -} - -static PyObject * -float_classic_div(PyObject *v, PyObject *w) -{ - double a,b; - CONVERT_TO_DOUBLE(v, a); - CONVERT_TO_DOUBLE(w, b); - if (Py_DivisionWarningFlag >= 2 && - PyErr_Warn(PyExc_DeprecationWarning, "classic float division") < 0) - return NULL; - if (b == 0.0) { - PyErr_SetString(PyExc_ZeroDivisionError, "float division"); - return NULL; - } - PyFPE_START_PROTECT("divide", return 0) - a = a / b; - PyFPE_END_PROTECT(a) - return PyFloat_FromDouble(a); -} - -static PyObject * -float_rem(PyObject *v, PyObject *w) -{ - double vx, wx; - double mod; - CONVERT_TO_DOUBLE(v, vx); - CONVERT_TO_DOUBLE(w, wx); - if (wx == 0.0) { - PyErr_SetString(PyExc_ZeroDivisionError, "float modulo"); - return NULL; - } - PyFPE_START_PROTECT("modulo", return 0) - mod = fmod(vx, wx); - /* note: checking mod*wx < 0 is incorrect -- underflows to - 0 if wx < sqrt(smallest nonzero double) */ - if (mod && ((wx < 0) != (mod < 0))) { - mod += wx; - } - PyFPE_END_PROTECT(mod) - return PyFloat_FromDouble(mod); -} - -static PyObject * -float_divmod(PyObject *v, PyObject *w) -{ - double vx, wx; - double div, mod, floordiv; - CONVERT_TO_DOUBLE(v, vx); - CONVERT_TO_DOUBLE(w, wx); - if (wx == 0.0) { - PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()"); - return NULL; - } - PyFPE_START_PROTECT("divmod", return 0) - mod = fmod(vx, wx); - /* fmod is typically exact, so vx-mod is *mathematically* an - exact multiple of wx. But this is fp arithmetic, and fp - vx - mod is an approximation; the result is that div may - not be an exact integral value after the division, although - it will always be very close to one. - */ - div = (vx - mod) / wx; - if (mod) { - /* ensure the remainder has the same sign as the denominator */ - if ((wx < 0) != (mod < 0)) { - mod += wx; - div -= 1.0; - } - } - else { - /* the remainder is zero, and in the presence of signed zeroes - fmod returns different results across platforms; ensure - it has the same sign as the denominator; we'd like to do - "mod = wx * 0.0", but that may get optimized away */ - mod *= mod; /* hide "mod = +0" from optimizer */ - if (wx < 0.0) - mod = -mod; - } - /* snap quotient to nearest integral value */ - if (div) { - floordiv = floor(div); - if (div - floordiv > 0.5) - floordiv += 1.0; - } - else { - /* div is zero - get the same sign as the true quotient */ - div *= div; /* hide "div = +0" from optimizers */ - floordiv = div * vx / wx; /* zero w/ sign of vx/wx */ - } - PyFPE_END_PROTECT(floordiv) - return Py_BuildValue("(dd)", floordiv, mod); -} - -static PyObject * -float_floor_div(PyObject *v, PyObject *w) -{ - PyObject *t, *r; - - t = float_divmod(v, w); - if (t == NULL || t == Py_NotImplemented) - return t; - assert(PyTuple_CheckExact(t)); - r = PyTuple_GET_ITEM(t, 0); - Py_INCREF(r); - Py_DECREF(t); - return r; -} - -static PyObject * -float_pow(PyObject *v, PyObject *w, PyObject *z) -{ - double iv, iw, ix; - - if ((PyObject *)z != Py_None) { - PyErr_SetString(PyExc_TypeError, "pow() 3rd argument not " - "allowed unless all arguments are integers"); - return NULL; - } - - CONVERT_TO_DOUBLE(v, iv); - CONVERT_TO_DOUBLE(w, iw); - - /* Sort out special cases here instead of relying on pow() */ - if (iw == 0) { /* v**0 is 1, even 0**0 */ - PyFPE_START_PROTECT("pow", return NULL) - if ((PyObject *)z != Py_None) { - double iz; - CONVERT_TO_DOUBLE(z, iz); - ix = fmod(1.0, iz); - if (ix != 0 && iz < 0) - ix += iz; - } - else - ix = 1.0; - PyFPE_END_PROTECT(ix) - return PyFloat_FromDouble(ix); - } - if (iv == 0.0) { /* 0**w is error if w<0, else 1 */ - if (iw < 0.0) { - PyErr_SetString(PyExc_ZeroDivisionError, - "0.0 cannot be raised to a negative power"); - return NULL; - } - return PyFloat_FromDouble(0.0); - } - if (iv < 0.0) { - /* Whether this is an error is a mess, and bumps into libm - * bugs so we have to figure it out ourselves. - */ - if (iw != floor(iw)) { - PyErr_SetString(PyExc_ValueError, "negative number " - "cannot be raised to a fractional power"); - return NULL; - } - /* iw is an exact integer, albeit perhaps a very large one. - * -1 raised to an exact integer should never be exceptional. - * Alas, some libms (chiefly glibc as of early 2003) return - * NaN and set EDOM on pow(-1, large_int) if the int doesn't - * happen to be representable in a *C* integer. That's a - * bug; we let that slide in math.pow() (which currently - * reflects all platform accidents), but not for Python's **. - */ - if (iv == -1.0 && Py_IS_FINITE(iw)) { - /* Return 1 if iw is even, -1 if iw is odd; there's - * no guarantee that any C integral type is big - * enough to hold iw, so we have to check this - * indirectly. - */ - ix = floor(iw * 0.5) * 2.0; - return PyFloat_FromDouble(ix == iw ? 1.0 : -1.0); - } - /* Else iv != -1.0, and overflow or underflow are possible. - * Unless we're to write pow() ourselves, we have to trust - * the platform to do this correctly. - */ - } - errno = 0; - PyFPE_START_PROTECT("pow", return NULL) - ix = pow(iv, iw); - PyFPE_END_PROTECT(ix) - Py_ADJUST_ERANGE1(ix); - if (errno != 0) { - /* We don't expect any errno value other than ERANGE, but - * the range of libm bugs appears unbounded. - */ - PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError : - PyExc_ValueError); - return NULL; - } - return PyFloat_FromDouble(ix); -} - -static PyObject * -float_neg(PyFloatObject *v) -{ - return PyFloat_FromDouble(-v->ob_fval); -} - -static PyObject * -float_pos(PyFloatObject *v) -{ - if (PyFloat_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return PyFloat_FromDouble(v->ob_fval); -} - -static PyObject * -float_abs(PyFloatObject *v) -{ - return PyFloat_FromDouble(fabs(v->ob_fval)); -} - -static int -float_nonzero(PyFloatObject *v) -{ - return v->ob_fval != 0.0; -} - -static int -float_coerce(PyObject **pv, PyObject **pw) -{ - if (PyInt_Check(*pw)) { - long x = PyInt_AsLong(*pw); - *pw = PyFloat_FromDouble((double)x); - Py_INCREF(*pv); - return 0; - } - else if (PyLong_Check(*pw)) { - double x = PyLong_AsDouble(*pw); - if (x == -1.0 && PyErr_Occurred()) - return -1; - *pw = PyFloat_FromDouble(x); - Py_INCREF(*pv); - return 0; - } - else if (PyFloat_Check(*pw)) { - Py_INCREF(*pv); - Py_INCREF(*pw); - return 0; - } - return 1; /* Can't do it */ -} - -static PyObject * -float_long(PyObject *v) -{ - double x = PyFloat_AsDouble(v); - return PyLong_FromDouble(x); -} - -static PyObject * -float_int(PyObject *v) -{ - double x = PyFloat_AsDouble(v); - double wholepart; /* integral portion of x, rounded toward 0 */ - - (void)modf(x, &wholepart); - /* Try to get out cheap if this fits in a Python int. The attempt - * to cast to long must be protected, as C doesn't define what - * happens if the double is too big to fit in a long. Some rare - * systems raise an exception then (RISCOS was mentioned as one, - * and someone using a non-default option on Sun also bumped into - * that). Note that checking for >= and <= LONG_{MIN,MAX} would - * still be vulnerable: if a long has more bits of precision than - * a double, casting MIN/MAX to double may yield an approximation, - * and if that's rounded up, then, e.g., wholepart=LONG_MAX+1 would - * yield true from the C expression wholepart<=LONG_MAX, despite - * that wholepart is actually greater than LONG_MAX. - */ - if (LONG_MIN < wholepart && wholepart < LONG_MAX) { - const long aslong = (long)wholepart; - return PyInt_FromLong(aslong); - } - return PyLong_FromDouble(wholepart); -} - -static PyObject * -float_float(PyObject *v) -{ - if (PyFloat_CheckExact(v)) - Py_INCREF(v); - else - v = PyFloat_FromDouble(((PyFloatObject *)v)->ob_fval); - return v; -} - - -static PyObject * -float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static PyObject * -float_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *x = Py_False; /* Integer zero */ - static char *kwlist[] = {"x", 0}; - - if (type != &PyFloat_Type) - return float_subtype_new(type, args, kwds); /* Wimp out */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:float", kwlist, &x)) - return NULL; - if (PyString_Check(x)) - return PyFloat_FromString(x, NULL); - return PyNumber_Float(x); -} - -/* Wimpy, slow approach to tp_new calls for subtypes of float: - first create a regular float from whatever arguments we got, - then allocate a subtype instance and initialize its ob_fval - from the regular float. The regular float is then thrown away. -*/ -static PyObject * -float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *tmp, *newobj; - - assert(PyType_IsSubtype(type, &PyFloat_Type)); - tmp = float_new(&PyFloat_Type, args, kwds); - if (tmp == NULL) - return NULL; - assert(PyFloat_CheckExact(tmp)); - newobj = type->tp_alloc(type, 0); - if (newobj == NULL) { - Py_DECREF(tmp); - return NULL; - } - ((PyFloatObject *)newobj)->ob_fval = ((PyFloatObject *)tmp)->ob_fval; - Py_DECREF(tmp); - return newobj; -} - -static PyObject * -float_getnewargs(PyFloatObject *v) -{ - return Py_BuildValue("(d)", v->ob_fval); -} - -/* this is for the benefit of the pack/unpack routines below */ - -typedef enum { - unknown_format, ieee_big_endian_format, ieee_little_endian_format -} float_format_type; - -static float_format_type double_format, float_format; -static float_format_type detected_double_format, detected_float_format; - -static PyObject * -float_getformat(PyTypeObject *v, PyObject* arg) -{ - char* s; - float_format_type r; - - if (!PyString_Check(arg)) { - PyErr_Format(PyExc_TypeError, - "__getformat__() argument must be string, not %.500s", - arg->ob_type->tp_name); - return NULL; - } - s = PyString_AS_STRING(arg); - if (strcmp(s, "double") == 0) { - r = double_format; - } - else if (strcmp(s, "float") == 0) { - r = float_format; - } - else { - PyErr_SetString(PyExc_ValueError, - "__getformat__() argument 1 must be " - "'double' or 'float'"); - return NULL; - } - - switch (r) { - case unknown_format: - return PyString_FromString("unknown"); - case ieee_little_endian_format: - return PyString_FromString("IEEE, little-endian"); - case ieee_big_endian_format: - return PyString_FromString("IEEE, big-endian"); - default: - Py_FatalError("insane float_format or double_format"); - return NULL; - } -} - -PyDoc_STRVAR(float_getformat_doc, -"float.__getformat__(tstr) -> string\n" -"\n" -"You probably don't want to use this function. It exists mainly to be\n" -"used in Python's test suite.\n" -"\n" -"tstr must be 'double' or 'float'. This function returns whichever of\n" -"'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n" -"format of floating point numbers used by the C type named by tstr."); - -static PyObject * -float_setformat(PyTypeObject *v, PyObject* args) -{ - char* tstr; - char* format; - float_format_type f; - float_format_type detected; - float_format_type *p; - - if (!PyArg_ParseTuple(args, "ss:__setformat__", &tstr, &format)) - return NULL; - - if (strcmp(tstr, "double") == 0) { - p = &double_format; - detected = detected_double_format; - } - else if (strcmp(tstr, "float") == 0) { - p = &float_format; - detected = detected_float_format; - } - else { - PyErr_SetString(PyExc_ValueError, - "__setformat__() argument 1 must " - "be 'double' or 'float'"); - return NULL; - } - - if (strcmp(format, "unknown") == 0) { - f = unknown_format; - } - else if (strcmp(format, "IEEE, little-endian") == 0) { - f = ieee_little_endian_format; - } - else if (strcmp(format, "IEEE, big-endian") == 0) { - f = ieee_big_endian_format; - } - else { - PyErr_SetString(PyExc_ValueError, - "__setformat__() argument 2 must be " - "'unknown', 'IEEE, little-endian' or " - "'IEEE, big-endian'"); - return NULL; - - } - - if (f != unknown_format && f != detected) { - PyErr_Format(PyExc_ValueError, - "can only set %s format to 'unknown' or the " - "detected platform value", tstr); - return NULL; - } - - *p = f; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(float_setformat_doc, -"float.__setformat__(tstr, fmt) -> None\n" -"\n" -"You probably don't want to use this function. It exists mainly to be\n" -"used in Python's test suite.\n" -"\n" -"tstr must be 'double' or 'float'. fmt must be one of 'unknown',\n" -"'IEEE, big-endian' or 'IEEE, little-endian', and in addition can only be\n" -"one of the latter two if it appears to match the underlying C reality.\n" -"\n" -"Overrides the automatic determination of C-level floating point type.\n" -"This affects how floats are converted to and from binary strings."); - -static PyMethodDef float_methods[] = { - {"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS}, - {"__getformat__", (PyCFunction)float_getformat, - METH_O|METH_CLASS, float_getformat_doc}, - {"__setformat__", (PyCFunction)float_setformat, - METH_VARARGS|METH_CLASS, float_setformat_doc}, - {NULL, NULL} /* sentinel */ -}; - -PyDoc_STRVAR(float_doc, -"float(x) -> floating point number\n\ -\n\ -Convert a string or number to a floating point number, if possible."); - - -static PyNumberMethods float_as_number = { - float_add, /*nb_add*/ - float_sub, /*nb_subtract*/ - float_mul, /*nb_multiply*/ - float_classic_div, /*nb_divide*/ - float_rem, /*nb_remainder*/ - float_divmod, /*nb_divmod*/ - float_pow, /*nb_power*/ - (unaryfunc)float_neg, /*nb_negative*/ - (unaryfunc)float_pos, /*nb_positive*/ - (unaryfunc)float_abs, /*nb_absolute*/ - (inquiry)float_nonzero, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - float_coerce, /*nb_coerce*/ - float_int, /*nb_int*/ - float_long, /*nb_long*/ - float_float, /*nb_float*/ - 0, /* nb_oct */ - 0, /* nb_hex */ - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ - 0, /* nb_inplace_divide */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - float_floor_div, /* nb_floor_divide */ - float_div, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ -}; - -PyTypeObject PyFloat_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "float", - sizeof(PyFloatObject), - 0, - (destructor)float_dealloc, /* tp_dealloc */ - (printfunc)float_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)float_repr, /* tp_repr */ - &float_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)float_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)float_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - float_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - float_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - float_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - float_new, /* tp_new */ -}; - -void -_PyFloat_Init(void) -{ - /* We attempt to determine if this machine is using IEEE - floating point formats by peering at the bits of some - carefully chosen values. If it looks like we are on an - IEEE platform, the float packing/unpacking routines can - just copy bits, if not they resort to arithmetic & shifts - and masks. The shifts & masks approach works on all finite - values, but what happens to infinities, NaNs and signed - zeroes on packing is an accident, and attempting to unpack - a NaN or an infinity will raise an exception. - - Note that if we're on some whacked-out platform which uses - IEEE formats but isn't strictly little-endian or big- - endian, we will fall back to the portable shifts & masks - method. */ - -#if SIZEOF_DOUBLE == 8 - { - double x = 9006104071832581.0; - if (memcmp(&x, "\x43\x3f\xff\x01\x02\x03\x04\x05", 8) == 0) - detected_double_format = ieee_big_endian_format; - else if (memcmp(&x, "\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0) - detected_double_format = ieee_little_endian_format; - else - detected_double_format = unknown_format; - } -#else - detected_double_format = unknown_format; -#endif - -#if SIZEOF_FLOAT == 4 - { - float y = 16711938.0; - if (memcmp(&y, "\x4b\x7f\x01\x02", 4) == 0) - detected_float_format = ieee_big_endian_format; - else if (memcmp(&y, "\x02\x01\x7f\x4b", 4) == 0) - detected_float_format = ieee_little_endian_format; - else - detected_float_format = unknown_format; - } -#else - detected_float_format = unknown_format; -#endif - - double_format = detected_double_format; - float_format = detected_float_format; -} - -void -PyFloat_Fini(void) -{ - PyFloatObject *p; - PyFloatBlock *list, *next; - unsigned i; - int bc, bf; /* block count, number of freed blocks */ - int frem, fsum; /* remaining unfreed floats per block, total */ - - bc = 0; - bf = 0; - fsum = 0; - list = block_list; - block_list = NULL; - free_list = NULL; - while (list != NULL) { - bc++; - frem = 0; - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (PyFloat_CheckExact(p) && p->ob_refcnt != 0) - frem++; - } - next = list->next; - if (frem) { - list->next = block_list; - block_list = list; - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (!PyFloat_CheckExact(p) || - p->ob_refcnt == 0) { - p->ob_type = (struct _typeobject *) - free_list; - free_list = p; - } - } - } - else { - PyMem_FREE(list); /* XXX PyObject_FREE ??? */ - bf++; - } - fsum += frem; - list = next; - } - if (!Py_VerboseFlag) - return; - fprintf(stderr, "# cleanup floats"); - if (!fsum) { - fprintf(stderr, "\n"); - } - else { - fprintf(stderr, - ": %d unfreed float%s in %d out of %d block%s\n", - fsum, fsum == 1 ? "" : "s", - bc - bf, bc, bc == 1 ? "" : "s"); - } - if (Py_VerboseFlag > 1) { - list = block_list; - while (list != NULL) { - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (PyFloat_CheckExact(p) && - p->ob_refcnt != 0) { - char buf[100]; - PyFloat_AsString(buf, p); - /* XXX(twouters) cast refcount to - long until %zd is universally - available - */ - fprintf(stderr, - "# <float at %p, refcnt=%ld, val=%s>\n", - p, (long)p->ob_refcnt, buf); - } - } - list = list->next; - } - } -} - -/*---------------------------------------------------------------------------- - * _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h. - * - * TODO: On platforms that use the standard IEEE-754 single and double - * formats natively, these routines could simply copy the bytes. - */ -int -_PyFloat_Pack4(double x, unsigned char *p, int le) -{ - if (float_format == unknown_format) { - unsigned char sign; - int e; - double f; - unsigned int fbits; - int incr = 1; - - if (le) { - p += 3; - incr = -1; - } - - if (x < 0) { - sign = 1; - x = -x; - } - else - sign = 0; - - f = frexp(x, &e); - - /* Normalize f to be in the range [1.0, 2.0) */ - if (0.5 <= f && f < 1.0) { - f *= 2.0; - e--; - } - else if (f == 0.0) - e = 0; - else { - PyErr_SetString(PyExc_SystemError, - "frexp() result out of range"); - return -1; - } - - if (e >= 128) - goto Overflow; - else if (e < -126) { - /* Gradual underflow */ - f = ldexp(f, 126 + e); - e = 0; - } - else if (!(e == 0 && f == 0.0)) { - e += 127; - f -= 1.0; /* Get rid of leading 1 */ - } - - f *= 8388608.0; /* 2**23 */ - fbits = (unsigned int)(f + 0.5); /* Round */ - assert(fbits <= 8388608); - if (fbits >> 23) { - /* The carry propagated out of a string of 23 1 bits. */ - fbits = 0; - ++e; - if (e >= 255) - goto Overflow; - } - - /* First byte */ - *p = (sign << 7) | (e >> 1); - p += incr; - - /* Second byte */ - *p = (char) (((e & 1) << 7) | (fbits >> 16)); - p += incr; - - /* Third byte */ - *p = (fbits >> 8) & 0xFF; - p += incr; - - /* Fourth byte */ - *p = fbits & 0xFF; - - /* Done */ - return 0; - - Overflow: - PyErr_SetString(PyExc_OverflowError, - "float too large to pack with f format"); - return -1; - } - else { - float y = (float)x; - const char *s = (char*)&y; - int i, incr = 1; - - if ((float_format == ieee_little_endian_format && !le) - || (float_format == ieee_big_endian_format && le)) { - p += 3; - incr = -1; - } - - for (i = 0; i < 4; i++) { - *p = *s++; - p += incr; - } - return 0; - } -} - -int -_PyFloat_Pack8(double x, unsigned char *p, int le) -{ - if (double_format == unknown_format) { - unsigned char sign; - int e; - double f; - unsigned int fhi, flo; - int incr = 1; - - if (le) { - p += 7; - incr = -1; - } - - if (x < 0) { - sign = 1; - x = -x; - } - else - sign = 0; - - f = frexp(x, &e); - - /* Normalize f to be in the range [1.0, 2.0) */ - if (0.5 <= f && f < 1.0) { - f *= 2.0; - e--; - } - else if (f == 0.0) - e = 0; - else { - PyErr_SetString(PyExc_SystemError, - "frexp() result out of range"); - return -1; - } - - if (e >= 1024) - goto Overflow; - else if (e < -1022) { - /* Gradual underflow */ - f = ldexp(f, 1022 + e); - e = 0; - } - else if (!(e == 0 && f == 0.0)) { - e += 1023; - f -= 1.0; /* Get rid of leading 1 */ - } - - /* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */ - f *= 268435456.0; /* 2**28 */ - fhi = (unsigned int)f; /* Truncate */ - assert(fhi < 268435456); - - f -= (double)fhi; - f *= 16777216.0; /* 2**24 */ - flo = (unsigned int)(f + 0.5); /* Round */ - assert(flo <= 16777216); - if (flo >> 24) { - /* The carry propagated out of a string of 24 1 bits. */ - flo = 0; - ++fhi; - if (fhi >> 28) { - /* And it also progagated out of the next 28 bits. */ - fhi = 0; - ++e; - if (e >= 2047) - goto Overflow; - } - } - - /* First byte */ - *p = (sign << 7) | (e >> 4); - p += incr; - - /* Second byte */ - *p = (unsigned char) (((e & 0xF) << 4) | (fhi >> 24)); - p += incr; - - /* Third byte */ - *p = (fhi >> 16) & 0xFF; - p += incr; - - /* Fourth byte */ - *p = (fhi >> 8) & 0xFF; - p += incr; - - /* Fifth byte */ - *p = fhi & 0xFF; - p += incr; - - /* Sixth byte */ - *p = (flo >> 16) & 0xFF; - p += incr; - - /* Seventh byte */ - *p = (flo >> 8) & 0xFF; - p += incr; - - /* Eighth byte */ - *p = flo & 0xFF; - p += incr; - - /* Done */ - return 0; - - Overflow: - PyErr_SetString(PyExc_OverflowError, - "float too large to pack with d format"); - return -1; - } - else { - const char *s = (char*)&x; - int i, incr = 1; - - if ((double_format == ieee_little_endian_format && !le) - || (double_format == ieee_big_endian_format && le)) { - p += 7; - incr = -1; - } - - for (i = 0; i < 8; i++) { - *p = *s++; - p += incr; - } - return 0; - } -} - -double -_PyFloat_Unpack4(const unsigned char *p, int le) -{ - if (float_format == unknown_format) { - unsigned char sign; - int e; - unsigned int f; - double x; - int incr = 1; - - if (le) { - p += 3; - incr = -1; - } - - /* First byte */ - sign = (*p >> 7) & 1; - e = (*p & 0x7F) << 1; - p += incr; - - /* Second byte */ - e |= (*p >> 7) & 1; - f = (*p & 0x7F) << 16; - p += incr; - - if (e == 255) { - PyErr_SetString( - PyExc_ValueError, - "can't unpack IEEE 754 special value " - "on non-IEEE platform"); - return -1; - } - - /* Third byte */ - f |= *p << 8; - p += incr; - - /* Fourth byte */ - f |= *p; - - x = (double)f / 8388608.0; - - /* XXX This sadly ignores Inf/NaN issues */ - if (e == 0) - e = -126; - else { - x += 1.0; - e -= 127; - } - x = ldexp(x, e); - - if (sign) - x = -x; - - return x; - } - else { - float x; - - if ((float_format == ieee_little_endian_format && !le) - || (float_format == ieee_big_endian_format && le)) { - char buf[4]; - char *d = &buf[3]; - int i; - - for (i = 0; i < 4; i++) { - *d-- = *p++; - } - memcpy(&x, buf, 4); - } - else { - memcpy(&x, p, 4); - } - - return x; - } -} - -double -_PyFloat_Unpack8(const unsigned char *p, int le) -{ - if (double_format == unknown_format) { - unsigned char sign; - int e; - unsigned int fhi, flo; - double x; - int incr = 1; - - if (le) { - p += 7; - incr = -1; - } - - /* First byte */ - sign = (*p >> 7) & 1; - e = (*p & 0x7F) << 4; - - p += incr; - - /* Second byte */ - e |= (*p >> 4) & 0xF; - fhi = (*p & 0xF) << 24; - p += incr; - - if (e == 2047) { - PyErr_SetString( - PyExc_ValueError, - "can't unpack IEEE 754 special value " - "on non-IEEE platform"); - return -1.0; - } - - /* Third byte */ - fhi |= *p << 16; - p += incr; - - /* Fourth byte */ - fhi |= *p << 8; - p += incr; - - /* Fifth byte */ - fhi |= *p; - p += incr; - - /* Sixth byte */ - flo = *p << 16; - p += incr; - - /* Seventh byte */ - flo |= *p << 8; - p += incr; - - /* Eighth byte */ - flo |= *p; - - x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */ - x /= 268435456.0; /* 2**28 */ - - if (e == 0) - e = -1022; - else { - x += 1.0; - e -= 1023; - } - x = ldexp(x, e); - - if (sign) - x = -x; - - return x; - } - else { - double x; - - if ((double_format == ieee_little_endian_format && !le) - || (double_format == ieee_big_endian_format && le)) { - char buf[8]; - char *d = &buf[7]; - int i; - - for (i = 0; i < 8; i++) { - *d-- = *p++; - } - memcpy(&x, buf, 8); - } - else { - memcpy(&x, p, 8); - } - - return x; - } -} diff --git a/sys/src/cmd/python/Objects/frameobject.c b/sys/src/cmd/python/Objects/frameobject.c deleted file mode 100644 index 3a073b6fa..000000000 --- a/sys/src/cmd/python/Objects/frameobject.c +++ /dev/null @@ -1,849 +0,0 @@ -/* Frame object implementation */ - -#include "Python.h" - -#include "code.h" -#include "frameobject.h" -#include "opcode.h" -#include "structmember.h" - -#undef MIN -#undef MAX -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define OFF(x) offsetof(PyFrameObject, x) - -static PyMemberDef frame_memberlist[] = { - {"f_back", T_OBJECT, OFF(f_back), RO}, - {"f_code", T_OBJECT, OFF(f_code), RO}, - {"f_builtins", T_OBJECT, OFF(f_builtins),RO}, - {"f_globals", T_OBJECT, OFF(f_globals), RO}, - {"f_lasti", T_INT, OFF(f_lasti), RO}, - {"f_exc_type", T_OBJECT, OFF(f_exc_type)}, - {"f_exc_value", T_OBJECT, OFF(f_exc_value)}, - {"f_exc_traceback", T_OBJECT, OFF(f_exc_traceback)}, - {NULL} /* Sentinel */ -}; - -static PyObject * -frame_getlocals(PyFrameObject *f, void *closure) -{ - PyFrame_FastToLocals(f); - Py_INCREF(f->f_locals); - return f->f_locals; -} - -static PyObject * -frame_getlineno(PyFrameObject *f, void *closure) -{ - int lineno; - - if (f->f_trace) - lineno = f->f_lineno; - else - lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); - - return PyInt_FromLong(lineno); -} - -/* Setter for f_lineno - you can set f_lineno from within a trace function in - * order to jump to a given line of code, subject to some restrictions. Most - * lines are OK to jump to because they don't make any assumptions about the - * state of the stack (obvious because you could remove the line and the code - * would still work without any stack errors), but there are some constructs - * that limit jumping: - * - * o Lines with an 'except' statement on them can't be jumped to, because - * they expect an exception to be on the top of the stack. - * o Lines that live in a 'finally' block can't be jumped from or to, since - * the END_FINALLY expects to clean up the stack after the 'try' block. - * o 'try'/'for'/'while' blocks can't be jumped into because the blockstack - * needs to be set up before their code runs, and for 'for' loops the - * iterator needs to be on the stack. - */ -static int -frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) -{ - int new_lineno = 0; /* The new value of f_lineno */ - int new_lasti = 0; /* The new value of f_lasti */ - int new_iblock = 0; /* The new value of f_iblock */ - char *code = NULL; /* The bytecode for the frame... */ - Py_ssize_t code_len = 0; /* ...and its length */ - char *lnotab = NULL; /* Iterating over co_lnotab */ - Py_ssize_t lnotab_len = 0; /* (ditto) */ - int offset = 0; /* (ditto) */ - int line = 0; /* (ditto) */ - int addr = 0; /* (ditto) */ - int min_addr = 0; /* Scanning the SETUPs and POPs */ - int max_addr = 0; /* (ditto) */ - int delta_iblock = 0; /* (ditto) */ - int min_delta_iblock = 0; /* (ditto) */ - int min_iblock = 0; /* (ditto) */ - int f_lasti_setup_addr = 0; /* Policing no-jump-into-finally */ - int new_lasti_setup_addr = 0; /* (ditto) */ - int blockstack[CO_MAXBLOCKS]; /* Walking the 'finally' blocks */ - int in_finally[CO_MAXBLOCKS]; /* (ditto) */ - int blockstack_top = 0; /* (ditto) */ - int setup_op = 0; /* (ditto) */ - - /* f_lineno must be an integer. */ - if (!PyInt_Check(p_new_lineno)) { - PyErr_SetString(PyExc_ValueError, - "lineno must be an integer"); - return -1; - } - - /* You can only do this from within a trace function, not via - * _getframe or similar hackery. */ - if (!f->f_trace) - { - PyErr_Format(PyExc_ValueError, - "f_lineno can only be set by a trace function"); - return -1; - } - - /* Fail if the line comes before the start of the code block. */ - new_lineno = (int) PyInt_AsLong(p_new_lineno); - if (new_lineno < f->f_code->co_firstlineno) { - PyErr_Format(PyExc_ValueError, - "line %d comes before the current code block", - new_lineno); - return -1; - } - - /* Find the bytecode offset for the start of the given line, or the - * first code-owning line after it. */ - PyString_AsStringAndSize(f->f_code->co_lnotab, &lnotab, &lnotab_len); - addr = 0; - line = f->f_code->co_firstlineno; - new_lasti = -1; - for (offset = 0; offset < lnotab_len; offset += 2) { - addr += lnotab[offset]; - line += lnotab[offset+1]; - if (line >= new_lineno) { - new_lasti = addr; - new_lineno = line; - break; - } - } - - /* If we didn't reach the requested line, return an error. */ - if (new_lasti == -1) { - PyErr_Format(PyExc_ValueError, - "line %d comes after the current code block", - new_lineno); - return -1; - } - - /* We're now ready to look at the bytecode. */ - PyString_AsStringAndSize(f->f_code->co_code, &code, &code_len); - min_addr = MIN(new_lasti, f->f_lasti); - max_addr = MAX(new_lasti, f->f_lasti); - - /* You can't jump onto a line with an 'except' statement on it - - * they expect to have an exception on the top of the stack, which - * won't be true if you jump to them. They always start with code - * that either pops the exception using POP_TOP (plain 'except:' - * lines do this) or duplicates the exception on the stack using - * DUP_TOP (if there's an exception type specified). See compile.c, - * 'com_try_except' for the full details. There aren't any other - * cases (AFAIK) where a line's code can start with DUP_TOP or - * POP_TOP, but if any ever appear, they'll be subject to the same - * restriction (but with a different error message). */ - if (code[new_lasti] == DUP_TOP || code[new_lasti] == POP_TOP) { - PyErr_SetString(PyExc_ValueError, - "can't jump to 'except' line as there's no exception"); - return -1; - } - - /* You can't jump into or out of a 'finally' block because the 'try' - * block leaves something on the stack for the END_FINALLY to clean - * up. So we walk the bytecode, maintaining a simulated blockstack. - * When we reach the old or new address and it's in a 'finally' block - * we note the address of the corresponding SETUP_FINALLY. The jump - * is only legal if neither address is in a 'finally' block or - * they're both in the same one. 'blockstack' is a stack of the - * bytecode addresses of the SETUP_X opcodes, and 'in_finally' tracks - * whether we're in a 'finally' block at each blockstack level. */ - f_lasti_setup_addr = -1; - new_lasti_setup_addr = -1; - memset(blockstack, '\0', sizeof(blockstack)); - memset(in_finally, '\0', sizeof(in_finally)); - blockstack_top = 0; - for (addr = 0; addr < code_len; addr++) { - unsigned char op = code[addr]; - switch (op) { - case SETUP_LOOP: - case SETUP_EXCEPT: - case SETUP_FINALLY: - blockstack[blockstack_top++] = addr; - in_finally[blockstack_top-1] = 0; - break; - - case POP_BLOCK: - assert(blockstack_top > 0); - setup_op = code[blockstack[blockstack_top-1]]; - if (setup_op == SETUP_FINALLY) { - in_finally[blockstack_top-1] = 1; - } - else { - blockstack_top--; - } - break; - - case END_FINALLY: - /* Ignore END_FINALLYs for SETUP_EXCEPTs - they exist - * in the bytecode but don't correspond to an actual - * 'finally' block. (If blockstack_top is 0, we must - * be seeing such an END_FINALLY.) */ - if (blockstack_top > 0) { - setup_op = code[blockstack[blockstack_top-1]]; - if (setup_op == SETUP_FINALLY) { - blockstack_top--; - } - } - break; - } - - /* For the addresses we're interested in, see whether they're - * within a 'finally' block and if so, remember the address - * of the SETUP_FINALLY. */ - if (addr == new_lasti || addr == f->f_lasti) { - int i = 0; - int setup_addr = -1; - for (i = blockstack_top-1; i >= 0; i--) { - if (in_finally[i]) { - setup_addr = blockstack[i]; - break; - } - } - - if (setup_addr != -1) { - if (addr == new_lasti) { - new_lasti_setup_addr = setup_addr; - } - - if (addr == f->f_lasti) { - f_lasti_setup_addr = setup_addr; - } - } - } - - if (op >= HAVE_ARGUMENT) { - addr += 2; - } - } - - /* Verify that the blockstack tracking code didn't get lost. */ - assert(blockstack_top == 0); - - /* After all that, are we jumping into / out of a 'finally' block? */ - if (new_lasti_setup_addr != f_lasti_setup_addr) { - PyErr_SetString(PyExc_ValueError, - "can't jump into or out of a 'finally' block"); - return -1; - } - - - /* Police block-jumping (you can't jump into the middle of a block) - * and ensure that the blockstack finishes up in a sensible state (by - * popping any blocks we're jumping out of). We look at all the - * blockstack operations between the current position and the new - * one, and keep track of how many blocks we drop out of on the way. - * By also keeping track of the lowest blockstack position we see, we - * can tell whether the jump goes into any blocks without coming out - * again - in that case we raise an exception below. */ - delta_iblock = 0; - for (addr = min_addr; addr < max_addr; addr++) { - unsigned char op = code[addr]; - switch (op) { - case SETUP_LOOP: - case SETUP_EXCEPT: - case SETUP_FINALLY: - delta_iblock++; - break; - - case POP_BLOCK: - delta_iblock--; - break; - } - - min_delta_iblock = MIN(min_delta_iblock, delta_iblock); - - if (op >= HAVE_ARGUMENT) { - addr += 2; - } - } - - /* Derive the absolute iblock values from the deltas. */ - min_iblock = f->f_iblock + min_delta_iblock; - if (new_lasti > f->f_lasti) { - /* Forwards jump. */ - new_iblock = f->f_iblock + delta_iblock; - } - else { - /* Backwards jump. */ - new_iblock = f->f_iblock - delta_iblock; - } - - /* Are we jumping into a block? */ - if (new_iblock > min_iblock) { - PyErr_SetString(PyExc_ValueError, - "can't jump into the middle of a block"); - return -1; - } - - /* Pop any blocks that we're jumping out of. */ - while (f->f_iblock > new_iblock) { - PyTryBlock *b = &f->f_blockstack[--f->f_iblock]; - while ((f->f_stacktop - f->f_valuestack) > b->b_level) { - PyObject *v = (*--f->f_stacktop); - Py_DECREF(v); - } - } - - /* Finally set the new f_lineno and f_lasti and return OK. */ - f->f_lineno = new_lineno; - f->f_lasti = new_lasti; - return 0; -} - -static PyObject * -frame_gettrace(PyFrameObject *f, void *closure) -{ - PyObject* trace = f->f_trace; - - if (trace == NULL) - trace = Py_None; - - Py_INCREF(trace); - - return trace; -} - -static int -frame_settrace(PyFrameObject *f, PyObject* v, void *closure) -{ - /* We rely on f_lineno being accurate when f_trace is set. */ - - PyObject* old_value = f->f_trace; - - Py_XINCREF(v); - f->f_trace = v; - - if (v != NULL) - f->f_lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); - - Py_XDECREF(old_value); - - return 0; -} - -static PyObject * -frame_getrestricted(PyFrameObject *f, void *closure) -{ - return PyBool_FromLong(PyFrame_IsRestricted(f)); -} - -static PyGetSetDef frame_getsetlist[] = { - {"f_locals", (getter)frame_getlocals, NULL, NULL}, - {"f_lineno", (getter)frame_getlineno, - (setter)frame_setlineno, NULL}, - {"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL}, - {"f_restricted",(getter)frame_getrestricted,NULL, NULL}, - {0} -}; - -/* Stack frames are allocated and deallocated at a considerable rate. - In an attempt to improve the speed of function calls, we: - - 1. Hold a single "zombie" frame on each code object. This retains - the allocated and initialised frame object from an invocation of - the code object. The zombie is reanimated the next time we need a - frame object for that code object. Doing this saves the malloc/ - realloc required when using a free_list frame that isn't the - correct size. It also saves some field initialisation. - - In zombie mode, no field of PyFrameObject holds a reference, but - the following fields are still valid: - - * ob_type, ob_size, f_code, f_valuestack; - - * f_locals, f_trace, - f_exc_type, f_exc_value, f_exc_traceback are NULL; - - * f_localsplus does not require re-allocation and - the local variables in f_localsplus are NULL. - - 2. We also maintain a separate free list of stack frames (just like - integers are allocated in a special way -- see intobject.c). When - a stack frame is on the free list, only the following members have - a meaning: - ob_type == &Frametype - f_back next item on free list, or NULL - f_stacksize size of value stack - ob_size size of localsplus - Note that the value and block stacks are preserved -- this can save - another malloc() call or two (and two free() calls as well!). - Also note that, unlike for integers, each frame object is a - malloc'ed object in its own right -- it is only the actual calls to - malloc() that we are trying to save here, not the administration. - After all, while a typical program may make millions of calls, a - call depth of more than 20 or 30 is probably already exceptional - unless the program contains run-away recursion. I hope. - - Later, MAXFREELIST was added to bound the # of frames saved on - free_list. Else programs creating lots of cyclic trash involving - frames could provoke free_list into growing without bound. -*/ - -static PyFrameObject *free_list = NULL; -static int numfree = 0; /* number of frames currently in free_list */ -#define MAXFREELIST 200 /* max value for numfree */ - -static void -frame_dealloc(PyFrameObject *f) -{ - PyObject **p, **valuestack; - PyCodeObject *co; - - PyObject_GC_UnTrack(f); - Py_TRASHCAN_SAFE_BEGIN(f) - /* Kill all local variables */ - valuestack = f->f_valuestack; - for (p = f->f_localsplus; p < valuestack; p++) - Py_CLEAR(*p); - - /* Free stack */ - if (f->f_stacktop != NULL) { - for (p = valuestack; p < f->f_stacktop; p++) - Py_XDECREF(*p); - } - - Py_XDECREF(f->f_back); - Py_DECREF(f->f_builtins); - Py_DECREF(f->f_globals); - Py_CLEAR(f->f_locals); - Py_CLEAR(f->f_trace); - Py_CLEAR(f->f_exc_type); - Py_CLEAR(f->f_exc_value); - Py_CLEAR(f->f_exc_traceback); - - co = f->f_code; - if (co->co_zombieframe == NULL) - co->co_zombieframe = f; - else if (numfree < MAXFREELIST) { - ++numfree; - f->f_back = free_list; - free_list = f; - } - else - PyObject_GC_Del(f); - - Py_DECREF(co); - Py_TRASHCAN_SAFE_END(f) -} - -static int -frame_traverse(PyFrameObject *f, visitproc visit, void *arg) -{ - PyObject **fastlocals, **p; - int i, slots; - - Py_VISIT(f->f_back); - Py_VISIT(f->f_code); - Py_VISIT(f->f_builtins); - Py_VISIT(f->f_globals); - Py_VISIT(f->f_locals); - Py_VISIT(f->f_trace); - Py_VISIT(f->f_exc_type); - Py_VISIT(f->f_exc_value); - Py_VISIT(f->f_exc_traceback); - - /* locals */ - slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars); - fastlocals = f->f_localsplus; - for (i = slots; --i >= 0; ++fastlocals) - Py_VISIT(*fastlocals); - - /* stack */ - if (f->f_stacktop != NULL) { - for (p = f->f_valuestack; p < f->f_stacktop; p++) - Py_VISIT(*p); - } - return 0; -} - -static void -frame_clear(PyFrameObject *f) -{ - PyObject **fastlocals, **p, **oldtop; - int i, slots; - - /* Before anything else, make sure that this frame is clearly marked - * as being defunct! Else, e.g., a generator reachable from this - * frame may also point to this frame, believe itself to still be - * active, and try cleaning up this frame again. - */ - oldtop = f->f_stacktop; - f->f_stacktop = NULL; - - Py_CLEAR(f->f_exc_type); - Py_CLEAR(f->f_exc_value); - Py_CLEAR(f->f_exc_traceback); - Py_CLEAR(f->f_trace); - - /* locals */ - slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars); - fastlocals = f->f_localsplus; - for (i = slots; --i >= 0; ++fastlocals) - Py_CLEAR(*fastlocals); - - /* stack */ - if (oldtop != NULL) { - for (p = f->f_valuestack; p < oldtop; p++) - Py_CLEAR(*p); - } -} - - -PyTypeObject PyFrame_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "frame", - sizeof(PyFrameObject), - sizeof(PyObject *), - (destructor)frame_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)frame_traverse, /* tp_traverse */ - (inquiry)frame_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - frame_memberlist, /* tp_members */ - frame_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ -}; - -static PyObject *builtin_object; - -int _PyFrame_Init() -{ - builtin_object = PyString_InternFromString("__builtins__"); - return (builtin_object != NULL); -} - -PyFrameObject * -PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, - PyObject *locals) -{ - PyFrameObject *back = tstate->frame; - PyFrameObject *f; - PyObject *builtins; - Py_ssize_t i; - -#ifdef Py_DEBUG - if (code == NULL || globals == NULL || !PyDict_Check(globals) || - (locals != NULL && !PyMapping_Check(locals))) { - PyErr_BadInternalCall(); - return NULL; - } -#endif - if (back == NULL || back->f_globals != globals) { - builtins = PyDict_GetItem(globals, builtin_object); - if (builtins) { - if (PyModule_Check(builtins)) { - builtins = PyModule_GetDict(builtins); - assert(!builtins || PyDict_Check(builtins)); - } - else if (!PyDict_Check(builtins)) - builtins = NULL; - } - if (builtins == NULL) { - /* No builtins! Make up a minimal one - Give them 'None', at least. */ - builtins = PyDict_New(); - if (builtins == NULL || - PyDict_SetItemString( - builtins, "None", Py_None) < 0) - return NULL; - } - else - Py_INCREF(builtins); - - } - else { - /* If we share the globals, we share the builtins. - Save a lookup and a call. */ - builtins = back->f_builtins; - assert(builtins != NULL && PyDict_Check(builtins)); - Py_INCREF(builtins); - } - if (code->co_zombieframe != NULL) { - f = code->co_zombieframe; - code->co_zombieframe = NULL; - _Py_NewReference((PyObject *)f); - assert(f->f_code == code); - } - else { - Py_ssize_t extras, ncells, nfrees; - ncells = PyTuple_GET_SIZE(code->co_cellvars); - nfrees = PyTuple_GET_SIZE(code->co_freevars); - extras = code->co_stacksize + code->co_nlocals + ncells + - nfrees; - if (free_list == NULL) { - f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, - extras); - if (f == NULL) { - Py_DECREF(builtins); - return NULL; - } - } - else { - assert(numfree > 0); - --numfree; - f = free_list; - free_list = free_list->f_back; - if (f->ob_size < extras) { - f = PyObject_GC_Resize(PyFrameObject, f, extras); - if (f == NULL) { - Py_DECREF(builtins); - return NULL; - } - } - _Py_NewReference((PyObject *)f); - } - - f->f_code = code; - extras = code->co_nlocals + ncells + nfrees; - f->f_valuestack = f->f_localsplus + extras; - for (i=0; i<extras; i++) - f->f_localsplus[i] = NULL; - f->f_locals = NULL; - f->f_trace = NULL; - f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL; - } - f->f_stacktop = f->f_valuestack; - f->f_builtins = builtins; - Py_XINCREF(back); - f->f_back = back; - Py_INCREF(code); - Py_INCREF(globals); - f->f_globals = globals; - /* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */ - if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) == - (CO_NEWLOCALS | CO_OPTIMIZED)) - ; /* f_locals = NULL; will be set by PyFrame_FastToLocals() */ - else if (code->co_flags & CO_NEWLOCALS) { - locals = PyDict_New(); - if (locals == NULL) { - Py_DECREF(f); - return NULL; - } - f->f_locals = locals; - } - else { - if (locals == NULL) - locals = globals; - Py_INCREF(locals); - f->f_locals = locals; - } - f->f_tstate = tstate; - - f->f_lasti = -1; - f->f_lineno = code->co_firstlineno; - f->f_iblock = 0; - - _PyObject_GC_TRACK(f); - return f; -} - -/* Block management */ - -void -PyFrame_BlockSetup(PyFrameObject *f, int type, int handler, int level) -{ - PyTryBlock *b; - if (f->f_iblock >= CO_MAXBLOCKS) - Py_FatalError("XXX block stack overflow"); - b = &f->f_blockstack[f->f_iblock++]; - b->b_type = type; - b->b_level = level; - b->b_handler = handler; -} - -PyTryBlock * -PyFrame_BlockPop(PyFrameObject *f) -{ - PyTryBlock *b; - if (f->f_iblock <= 0) - Py_FatalError("XXX block stack underflow"); - b = &f->f_blockstack[--f->f_iblock]; - return b; -} - -/* Convert between "fast" version of locals and dictionary version */ - -static void -map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, - Py_ssize_t deref) -{ - Py_ssize_t j; - for (j = nmap; --j >= 0; ) { - PyObject *key = PyTuple_GET_ITEM(map, j); - PyObject *value = values[j]; - if (deref) - value = PyCell_GET(value); - if (value == NULL) { - if (PyObject_DelItem(dict, key) != 0) - PyErr_Clear(); - } - else { - if (PyObject_SetItem(dict, key, value) != 0) - PyErr_Clear(); - } - } -} - -static void -dict_to_map(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, - Py_ssize_t deref, int clear) -{ - Py_ssize_t j; - for (j = nmap; --j >= 0; ) { - PyObject *key = PyTuple_GET_ITEM(map, j); - PyObject *value = PyObject_GetItem(dict, key); - if (value == NULL) - PyErr_Clear(); - if (deref) { - if (value || clear) { - if (PyCell_GET(values[j]) != value) { - if (PyCell_Set(values[j], value) < 0) - PyErr_Clear(); - } - } - } else if (value != NULL || clear) { - if (values[j] != value) { - Py_XINCREF(value); - Py_XDECREF(values[j]); - values[j] = value; - } - } - Py_XDECREF(value); - } -} - -void -PyFrame_FastToLocals(PyFrameObject *f) -{ - /* Merge fast locals into f->f_locals */ - PyObject *locals, *map; - PyObject **fast; - PyObject *error_type, *error_value, *error_traceback; - PyCodeObject *co; - Py_ssize_t j; - int ncells, nfreevars; - if (f == NULL) - return; - locals = f->f_locals; - if (locals == NULL) { - locals = f->f_locals = PyDict_New(); - if (locals == NULL) { - PyErr_Clear(); /* Can't report it :-( */ - return; - } - } - co = f->f_code; - map = co->co_varnames; - if (!PyTuple_Check(map)) - return; - PyErr_Fetch(&error_type, &error_value, &error_traceback); - fast = f->f_localsplus; - j = PyTuple_GET_SIZE(map); - if (j > co->co_nlocals) - j = co->co_nlocals; - if (co->co_nlocals) - map_to_dict(map, j, locals, fast, 0); - ncells = PyTuple_GET_SIZE(co->co_cellvars); - nfreevars = PyTuple_GET_SIZE(co->co_freevars); - if (ncells || nfreevars) { - map_to_dict(co->co_cellvars, ncells, - locals, fast + co->co_nlocals, 1); - map_to_dict(co->co_freevars, nfreevars, - locals, fast + co->co_nlocals + ncells, 1); - } - PyErr_Restore(error_type, error_value, error_traceback); -} - -void -PyFrame_LocalsToFast(PyFrameObject *f, int clear) -{ - /* Merge f->f_locals into fast locals */ - PyObject *locals, *map; - PyObject **fast; - PyObject *error_type, *error_value, *error_traceback; - PyCodeObject *co; - Py_ssize_t j; - int ncells, nfreevars; - if (f == NULL) - return; - locals = f->f_locals; - co = f->f_code; - map = co->co_varnames; - if (locals == NULL) - return; - if (!PyTuple_Check(map)) - return; - PyErr_Fetch(&error_type, &error_value, &error_traceback); - fast = f->f_localsplus; - j = PyTuple_GET_SIZE(map); - if (j > co->co_nlocals) - j = co->co_nlocals; - if (co->co_nlocals) - dict_to_map(co->co_varnames, j, locals, fast, 0, clear); - ncells = PyTuple_GET_SIZE(co->co_cellvars); - nfreevars = PyTuple_GET_SIZE(co->co_freevars); - if (ncells || nfreevars) { - dict_to_map(co->co_cellvars, ncells, - locals, fast + co->co_nlocals, 1, clear); - dict_to_map(co->co_freevars, nfreevars, - locals, fast + co->co_nlocals + ncells, 1, - clear); - } - PyErr_Restore(error_type, error_value, error_traceback); -} - -/* Clear out the free list */ - -void -PyFrame_Fini(void) -{ - while (free_list != NULL) { - PyFrameObject *f = free_list; - free_list = free_list->f_back; - PyObject_GC_Del(f); - --numfree; - } - assert(numfree == 0); - Py_XDECREF(builtin_object); - builtin_object = NULL; -} diff --git a/sys/src/cmd/python/Objects/funcobject.c b/sys/src/cmd/python/Objects/funcobject.c deleted file mode 100644 index 1ba74c5a9..000000000 --- a/sys/src/cmd/python/Objects/funcobject.c +++ /dev/null @@ -1,888 +0,0 @@ - -/* Function object implementation */ - -#include "Python.h" -#include "code.h" -#include "eval.h" -#include "structmember.h" - -PyObject * -PyFunction_New(PyObject *code, PyObject *globals) -{ - PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, - &PyFunction_Type); - static PyObject *__name__ = 0; - if (op != NULL) { - PyObject *doc; - PyObject *consts; - PyObject *module; - op->func_weakreflist = NULL; - Py_INCREF(code); - op->func_code = code; - Py_INCREF(globals); - op->func_globals = globals; - op->func_name = ((PyCodeObject *)code)->co_name; - Py_INCREF(op->func_name); - op->func_defaults = NULL; /* No default arguments */ - op->func_closure = NULL; - consts = ((PyCodeObject *)code)->co_consts; - if (PyTuple_Size(consts) >= 1) { - doc = PyTuple_GetItem(consts, 0); - if (!PyString_Check(doc) && !PyUnicode_Check(doc)) - doc = Py_None; - } - else - doc = Py_None; - Py_INCREF(doc); - op->func_doc = doc; - op->func_dict = NULL; - op->func_module = NULL; - - /* __module__: If module name is in globals, use it. - Otherwise, use None. - */ - if (!__name__) { - __name__ = PyString_InternFromString("__name__"); - if (!__name__) { - Py_DECREF(op); - return NULL; - } - } - module = PyDict_GetItem(globals, __name__); - if (module) { - Py_INCREF(module); - op->func_module = module; - } - } - else - return NULL; - _PyObject_GC_TRACK(op); - return (PyObject *)op; -} - -PyObject * -PyFunction_GetCode(PyObject *op) -{ - if (!PyFunction_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyFunctionObject *) op) -> func_code; -} - -PyObject * -PyFunction_GetGlobals(PyObject *op) -{ - if (!PyFunction_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyFunctionObject *) op) -> func_globals; -} - -PyObject * -PyFunction_GetModule(PyObject *op) -{ - if (!PyFunction_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyFunctionObject *) op) -> func_module; -} - -PyObject * -PyFunction_GetDefaults(PyObject *op) -{ - if (!PyFunction_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyFunctionObject *) op) -> func_defaults; -} - -int -PyFunction_SetDefaults(PyObject *op, PyObject *defaults) -{ - if (!PyFunction_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - if (defaults == Py_None) - defaults = NULL; - else if (defaults && PyTuple_Check(defaults)) { - Py_INCREF(defaults); - } - else { - PyErr_SetString(PyExc_SystemError, "non-tuple default args"); - return -1; - } - Py_XDECREF(((PyFunctionObject *) op) -> func_defaults); - ((PyFunctionObject *) op) -> func_defaults = defaults; - return 0; -} - -PyObject * -PyFunction_GetClosure(PyObject *op) -{ - if (!PyFunction_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyFunctionObject *) op) -> func_closure; -} - -int -PyFunction_SetClosure(PyObject *op, PyObject *closure) -{ - if (!PyFunction_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - if (closure == Py_None) - closure = NULL; - else if (PyTuple_Check(closure)) { - Py_INCREF(closure); - } - else { - PyErr_Format(PyExc_SystemError, - "expected tuple for closure, got '%.100s'", - closure->ob_type->tp_name); - return -1; - } - Py_XDECREF(((PyFunctionObject *) op) -> func_closure); - ((PyFunctionObject *) op) -> func_closure = closure; - return 0; -} - -/* Methods */ - -#define OFF(x) offsetof(PyFunctionObject, x) - -static PyMemberDef func_memberlist[] = { - {"func_closure", T_OBJECT, OFF(func_closure), - RESTRICTED|READONLY}, - {"func_doc", T_OBJECT, OFF(func_doc), WRITE_RESTRICTED}, - {"__doc__", T_OBJECT, OFF(func_doc), WRITE_RESTRICTED}, - {"func_globals", T_OBJECT, OFF(func_globals), - RESTRICTED|READONLY}, - {"__module__", T_OBJECT, OFF(func_module), WRITE_RESTRICTED}, - {NULL} /* Sentinel */ -}; - -static int -restricted(void) -{ - if (!PyEval_GetRestricted()) - return 0; - PyErr_SetString(PyExc_RuntimeError, - "function attributes not accessible in restricted mode"); - return 1; -} - -static PyObject * -func_get_dict(PyFunctionObject *op) -{ - if (restricted()) - return NULL; - if (op->func_dict == NULL) { - op->func_dict = PyDict_New(); - if (op->func_dict == NULL) - return NULL; - } - Py_INCREF(op->func_dict); - return op->func_dict; -} - -static int -func_set_dict(PyFunctionObject *op, PyObject *value) -{ - PyObject *tmp; - - if (restricted()) - return -1; - /* It is illegal to del f.func_dict */ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "function's dictionary may not be deleted"); - return -1; - } - /* Can only set func_dict to a dictionary */ - if (!PyDict_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "setting function's dictionary to a non-dict"); - return -1; - } - tmp = op->func_dict; - Py_INCREF(value); - op->func_dict = value; - Py_XDECREF(tmp); - return 0; -} - -static PyObject * -func_get_code(PyFunctionObject *op) -{ - if (restricted()) - return NULL; - Py_INCREF(op->func_code); - return op->func_code; -} - -static int -func_set_code(PyFunctionObject *op, PyObject *value) -{ - PyObject *tmp; - Py_ssize_t nfree, nclosure; - - if (restricted()) - return -1; - /* Not legal to del f.func_code or to set it to anything - * other than a code object. */ - if (value == NULL || !PyCode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "func_code must be set to a code object"); - return -1; - } - nfree = PyCode_GetNumFree((PyCodeObject *)value); - nclosure = (op->func_closure == NULL ? 0 : - PyTuple_GET_SIZE(op->func_closure)); - if (nclosure != nfree) { - PyErr_Format(PyExc_ValueError, - "%s() requires a code object with %zd free vars," - " not %zd", - PyString_AsString(op->func_name), - nclosure, nfree); - return -1; - } - tmp = op->func_code; - Py_INCREF(value); - op->func_code = value; - Py_DECREF(tmp); - return 0; -} - -static PyObject * -func_get_name(PyFunctionObject *op) -{ - Py_INCREF(op->func_name); - return op->func_name; -} - -static int -func_set_name(PyFunctionObject *op, PyObject *value) -{ - PyObject *tmp; - - if (restricted()) - return -1; - /* Not legal to del f.func_name or to set it to anything - * other than a string object. */ - if (value == NULL || !PyString_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "func_name must be set to a string object"); - return -1; - } - tmp = op->func_name; - Py_INCREF(value); - op->func_name = value; - Py_DECREF(tmp); - return 0; -} - -static PyObject * -func_get_defaults(PyFunctionObject *op) -{ - if (restricted()) - return NULL; - if (op->func_defaults == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - Py_INCREF(op->func_defaults); - return op->func_defaults; -} - -static int -func_set_defaults(PyFunctionObject *op, PyObject *value) -{ - PyObject *tmp; - - if (restricted()) - return -1; - /* Legal to del f.func_defaults. - * Can only set func_defaults to NULL or a tuple. */ - if (value == Py_None) - value = NULL; - if (value != NULL && !PyTuple_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "func_defaults must be set to a tuple object"); - return -1; - } - tmp = op->func_defaults; - Py_XINCREF(value); - op->func_defaults = value; - Py_XDECREF(tmp); - return 0; -} - -static PyGetSetDef func_getsetlist[] = { - {"func_code", (getter)func_get_code, (setter)func_set_code}, - {"func_defaults", (getter)func_get_defaults, - (setter)func_set_defaults}, - {"func_dict", (getter)func_get_dict, (setter)func_set_dict}, - {"__dict__", (getter)func_get_dict, (setter)func_set_dict}, - {"func_name", (getter)func_get_name, (setter)func_set_name}, - {"__name__", (getter)func_get_name, (setter)func_set_name}, - {NULL} /* Sentinel */ -}; - -PyDoc_STRVAR(func_doc, -"function(code, globals[, name[, argdefs[, closure]]])\n\ -\n\ -Create a function object from a code object and a dictionary.\n\ -The optional name string overrides the name from the code object.\n\ -The optional argdefs tuple specifies the default argument values.\n\ -The optional closure tuple supplies the bindings for free variables."); - -/* func_new() maintains the following invariants for closures. The - closure must correspond to the free variables of the code object. - - if len(code.co_freevars) == 0: - closure = NULL - else: - len(closure) == len(code.co_freevars) - for every elt in closure, type(elt) == cell -*/ - -static PyObject * -func_new(PyTypeObject* type, PyObject* args, PyObject* kw) -{ - PyCodeObject *code; - PyObject *globals; - PyObject *name = Py_None; - PyObject *defaults = Py_None; - PyObject *closure = Py_None; - PyFunctionObject *newfunc; - Py_ssize_t nfree, nclosure; - static char *kwlist[] = {"code", "globals", "name", - "argdefs", "closure", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O!|OOO:function", - kwlist, - &PyCode_Type, &code, - &PyDict_Type, &globals, - &name, &defaults, &closure)) - return NULL; - if (name != Py_None && !PyString_Check(name)) { - PyErr_SetString(PyExc_TypeError, - "arg 3 (name) must be None or string"); - return NULL; - } - if (defaults != Py_None && !PyTuple_Check(defaults)) { - PyErr_SetString(PyExc_TypeError, - "arg 4 (defaults) must be None or tuple"); - return NULL; - } - nfree = PyTuple_GET_SIZE(code->co_freevars); - if (!PyTuple_Check(closure)) { - if (nfree && closure == Py_None) { - PyErr_SetString(PyExc_TypeError, - "arg 5 (closure) must be tuple"); - return NULL; - } - else if (closure != Py_None) { - PyErr_SetString(PyExc_TypeError, - "arg 5 (closure) must be None or tuple"); - return NULL; - } - } - - /* check that the closure is well-formed */ - nclosure = closure == Py_None ? 0 : PyTuple_GET_SIZE(closure); - if (nfree != nclosure) - return PyErr_Format(PyExc_ValueError, - "%s requires closure of length %zd, not %zd", - PyString_AS_STRING(code->co_name), - nfree, nclosure); - if (nclosure) { - Py_ssize_t i; - for (i = 0; i < nclosure; i++) { - PyObject *o = PyTuple_GET_ITEM(closure, i); - if (!PyCell_Check(o)) { - return PyErr_Format(PyExc_TypeError, - "arg 5 (closure) expected cell, found %s", - o->ob_type->tp_name); - } - } - } - - newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code, - globals); - if (newfunc == NULL) - return NULL; - - if (name != Py_None) { - Py_INCREF(name); - Py_DECREF(newfunc->func_name); - newfunc->func_name = name; - } - if (defaults != Py_None) { - Py_INCREF(defaults); - newfunc->func_defaults = defaults; - } - if (closure != Py_None) { - Py_INCREF(closure); - newfunc->func_closure = closure; - } - - return (PyObject *)newfunc; -} - -static void -func_dealloc(PyFunctionObject *op) -{ - _PyObject_GC_UNTRACK(op); - if (op->func_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) op); - Py_DECREF(op->func_code); - Py_DECREF(op->func_globals); - Py_XDECREF(op->func_module); - Py_DECREF(op->func_name); - Py_XDECREF(op->func_defaults); - Py_XDECREF(op->func_doc); - Py_XDECREF(op->func_dict); - Py_XDECREF(op->func_closure); - PyObject_GC_Del(op); -} - -static PyObject* -func_repr(PyFunctionObject *op) -{ - return PyString_FromFormat("<function %s at %p>", - PyString_AsString(op->func_name), - op); -} - -static int -func_traverse(PyFunctionObject *f, visitproc visit, void *arg) -{ - Py_VISIT(f->func_code); - Py_VISIT(f->func_globals); - Py_VISIT(f->func_module); - Py_VISIT(f->func_defaults); - Py_VISIT(f->func_doc); - Py_VISIT(f->func_name); - Py_VISIT(f->func_dict); - Py_VISIT(f->func_closure); - return 0; -} - -static PyObject * -function_call(PyObject *func, PyObject *arg, PyObject *kw) -{ - PyObject *result; - PyObject *argdefs; - PyObject **d, **k; - Py_ssize_t nk, nd; - - argdefs = PyFunction_GET_DEFAULTS(func); - if (argdefs != NULL && PyTuple_Check(argdefs)) { - d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0); - nd = PyTuple_Size(argdefs); - } - else { - d = NULL; - nd = 0; - } - - if (kw != NULL && PyDict_Check(kw)) { - Py_ssize_t pos, i; - nk = PyDict_Size(kw); - k = PyMem_NEW(PyObject *, 2*nk); - if (k == NULL) { - PyErr_NoMemory(); - return NULL; - } - pos = i = 0; - while (PyDict_Next(kw, &pos, &k[i], &k[i+1])) - i += 2; - nk = i/2; - /* XXX This is broken if the caller deletes dict items! */ - } - else { - k = NULL; - nk = 0; - } - - result = PyEval_EvalCodeEx( - (PyCodeObject *)PyFunction_GET_CODE(func), - PyFunction_GET_GLOBALS(func), (PyObject *)NULL, - &PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg), - k, nk, d, nd, - PyFunction_GET_CLOSURE(func)); - - if (k != NULL) - PyMem_DEL(k); - - return result; -} - -/* Bind a function to an object */ -static PyObject * -func_descr_get(PyObject *func, PyObject *obj, PyObject *type) -{ - if (obj == Py_None) - obj = NULL; - return PyMethod_New(func, obj, type); -} - -PyTypeObject PyFunction_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "function", - sizeof(PyFunctionObject), - 0, - (destructor)func_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)func_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - function_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - func_doc, /* tp_doc */ - (traverseproc)func_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - func_memberlist, /* tp_members */ - func_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - func_descr_get, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - func_new, /* tp_new */ -}; - - -/* Class method object */ - -/* A class method receives the class as implicit first argument, - just like an instance method receives the instance. - To declare a class method, use this idiom: - - class C: - def f(cls, arg1, arg2, ...): ... - f = classmethod(f) - - It can be called either on the class (e.g. C.f()) or on an instance - (e.g. C().f()); the instance is ignored except for its class. - If a class method is called for a derived class, the derived class - object is passed as the implied first argument. - - Class methods are different than C++ or Java static methods. - If you want those, see static methods below. -*/ - -typedef struct { - PyObject_HEAD - PyObject *cm_callable; -} classmethod; - -static void -cm_dealloc(classmethod *cm) -{ - _PyObject_GC_UNTRACK((PyObject *)cm); - Py_XDECREF(cm->cm_callable); - cm->ob_type->tp_free((PyObject *)cm); -} - -static int -cm_traverse(classmethod *cm, visitproc visit, void *arg) -{ - Py_VISIT(cm->cm_callable); - return 0; -} - -static int -cm_clear(classmethod *cm) -{ - Py_CLEAR(cm->cm_callable); - return 0; -} - - -static PyObject * -cm_descr_get(PyObject *self, PyObject *obj, PyObject *type) -{ - classmethod *cm = (classmethod *)self; - - if (cm->cm_callable == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "uninitialized classmethod object"); - return NULL; - } - if (type == NULL) - type = (PyObject *)(obj->ob_type); - return PyMethod_New(cm->cm_callable, - type, (PyObject *)(type->ob_type)); -} - -static int -cm_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - classmethod *cm = (classmethod *)self; - PyObject *callable; - - if (!PyArg_UnpackTuple(args, "classmethod", 1, 1, &callable)) - return -1; - if (!_PyArg_NoKeywords("classmethod", kwds)) - return -1; - if (!PyCallable_Check(callable)) { - PyErr_Format(PyExc_TypeError, "'%s' object is not callable", - callable->ob_type->tp_name); - return -1; - } - - Py_INCREF(callable); - cm->cm_callable = callable; - return 0; -} - -PyDoc_STRVAR(classmethod_doc, -"classmethod(function) -> method\n\ -\n\ -Convert a function to be a class method.\n\ -\n\ -A class method receives the class as implicit first argument,\n\ -just like an instance method receives the instance.\n\ -To declare a class method, use this idiom:\n\ -\n\ - class C:\n\ - def f(cls, arg1, arg2, ...): ...\n\ - f = classmethod(f)\n\ -\n\ -It can be called either on the class (e.g. C.f()) or on an instance\n\ -(e.g. C().f()). The instance is ignored except for its class.\n\ -If a class method is called for a derived class, the derived class\n\ -object is passed as the implied first argument.\n\ -\n\ -Class methods are different than C++ or Java static methods.\n\ -If you want those, see the staticmethod builtin."); - -PyTypeObject PyClassMethod_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "classmethod", - sizeof(classmethod), - 0, - (destructor)cm_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - classmethod_doc, /* tp_doc */ - (traverseproc)cm_traverse, /* tp_traverse */ - (inquiry)cm_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - cm_descr_get, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - cm_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - -PyObject * -PyClassMethod_New(PyObject *callable) -{ - classmethod *cm = (classmethod *) - PyType_GenericAlloc(&PyClassMethod_Type, 0); - if (cm != NULL) { - Py_INCREF(callable); - cm->cm_callable = callable; - } - return (PyObject *)cm; -} - - -/* Static method object */ - -/* A static method does not receive an implicit first argument. - To declare a static method, use this idiom: - - class C: - def f(arg1, arg2, ...): ... - f = staticmethod(f) - - It can be called either on the class (e.g. C.f()) or on an instance - (e.g. C().f()); the instance is ignored except for its class. - - Static methods in Python are similar to those found in Java or C++. - For a more advanced concept, see class methods above. -*/ - -typedef struct { - PyObject_HEAD - PyObject *sm_callable; -} staticmethod; - -static void -sm_dealloc(staticmethod *sm) -{ - _PyObject_GC_UNTRACK((PyObject *)sm); - Py_XDECREF(sm->sm_callable); - sm->ob_type->tp_free((PyObject *)sm); -} - -static int -sm_traverse(staticmethod *sm, visitproc visit, void *arg) -{ - Py_VISIT(sm->sm_callable); - return 0; -} - -static int -sm_clear(staticmethod *sm) -{ - Py_XDECREF(sm->sm_callable); - sm->sm_callable = NULL; - - return 0; -} - -static PyObject * -sm_descr_get(PyObject *self, PyObject *obj, PyObject *type) -{ - staticmethod *sm = (staticmethod *)self; - - if (sm->sm_callable == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "uninitialized staticmethod object"); - return NULL; - } - Py_INCREF(sm->sm_callable); - return sm->sm_callable; -} - -static int -sm_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - staticmethod *sm = (staticmethod *)self; - PyObject *callable; - - if (!PyArg_UnpackTuple(args, "staticmethod", 1, 1, &callable)) - return -1; - if (!_PyArg_NoKeywords("staticmethod", kwds)) - return -1; - Py_INCREF(callable); - sm->sm_callable = callable; - return 0; -} - -PyDoc_STRVAR(staticmethod_doc, -"staticmethod(function) -> method\n\ -\n\ -Convert a function to be a static method.\n\ -\n\ -A static method does not receive an implicit first argument.\n\ -To declare a static method, use this idiom:\n\ -\n\ - class C:\n\ - def f(arg1, arg2, ...): ...\n\ - f = staticmethod(f)\n\ -\n\ -It can be called either on the class (e.g. C.f()) or on an instance\n\ -(e.g. C().f()). The instance is ignored except for its class.\n\ -\n\ -Static methods in Python are similar to those found in Java or C++.\n\ -For a more advanced concept, see the classmethod builtin."); - -PyTypeObject PyStaticMethod_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "staticmethod", - sizeof(staticmethod), - 0, - (destructor)sm_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - staticmethod_doc, /* tp_doc */ - (traverseproc)sm_traverse, /* tp_traverse */ - (inquiry)sm_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - sm_descr_get, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - sm_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - -PyObject * -PyStaticMethod_New(PyObject *callable) -{ - staticmethod *sm = (staticmethod *) - PyType_GenericAlloc(&PyStaticMethod_Type, 0); - if (sm != NULL) { - Py_INCREF(callable); - sm->sm_callable = callable; - } - return (PyObject *)sm; -} diff --git a/sys/src/cmd/python/Objects/genobject.c b/sys/src/cmd/python/Objects/genobject.c deleted file mode 100644 index 4d0c4f6ee..000000000 --- a/sys/src/cmd/python/Objects/genobject.c +++ /dev/null @@ -1,383 +0,0 @@ -/* Generator object implementation */ - -#include "Python.h" -#include "frameobject.h" -#include "genobject.h" -#include "ceval.h" -#include "structmember.h" -#include "opcode.h" - -static int -gen_traverse(PyGenObject *gen, visitproc visit, void *arg) -{ - Py_VISIT((PyObject *)gen->gi_frame); - return 0; -} - -static void -gen_dealloc(PyGenObject *gen) -{ - PyObject *self = (PyObject *) gen; - - _PyObject_GC_UNTRACK(gen); - - if (gen->gi_weakreflist != NULL) - PyObject_ClearWeakRefs(self); - - _PyObject_GC_TRACK(self); - - if (gen->gi_frame != NULL && gen->gi_frame->f_stacktop != NULL) { - /* Generator is paused, so we need to close */ - gen->ob_type->tp_del(self); - if (self->ob_refcnt > 0) - return; /* resurrected. :( */ - } - - _PyObject_GC_UNTRACK(self); - Py_CLEAR(gen->gi_frame); - PyObject_GC_Del(gen); -} - - -static PyObject * -gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) -{ - PyThreadState *tstate = PyThreadState_GET(); - PyFrameObject *f = gen->gi_frame; - PyObject *result; - - if (gen->gi_running) { - PyErr_SetString(PyExc_ValueError, - "generator already executing"); - return NULL; - } - if (f==NULL || f->f_stacktop == NULL) { - /* Only set exception if called from send() */ - if (arg && !exc) - PyErr_SetNone(PyExc_StopIteration); - return NULL; - } - - if (f->f_lasti == -1) { - if (arg && arg != Py_None) { - PyErr_SetString(PyExc_TypeError, - "can't send non-None value to a " - "just-started generator"); - return NULL; - } - } else { - /* Push arg onto the frame's value stack */ - result = arg ? arg : Py_None; - Py_INCREF(result); - *(f->f_stacktop++) = result; - } - - /* Generators always return to their most recent caller, not - * necessarily their creator. */ - Py_XINCREF(tstate->frame); - assert(f->f_back == NULL); - f->f_back = tstate->frame; - - gen->gi_running = 1; - result = PyEval_EvalFrameEx(f, exc); - gen->gi_running = 0; - - /* Don't keep the reference to f_back any longer than necessary. It - * may keep a chain of frames alive or it could create a reference - * cycle. */ - assert(f->f_back == tstate->frame); - Py_CLEAR(f->f_back); - - /* If the generator just returned (as opposed to yielding), signal - * that the generator is exhausted. */ - if (result == Py_None && f->f_stacktop == NULL) { - Py_DECREF(result); - result = NULL; - /* Set exception if not called by gen_iternext() */ - if (arg) - PyErr_SetNone(PyExc_StopIteration); - } - - if (!result || f->f_stacktop == NULL) { - /* generator can't be rerun, so release the frame */ - Py_DECREF(f); - gen->gi_frame = NULL; - } - - return result; -} - -PyDoc_STRVAR(send_doc, -"send(arg) -> send 'arg' into generator,\n\ -return next yielded value or raise StopIteration."); - -static PyObject * -gen_send(PyGenObject *gen, PyObject *arg) -{ - return gen_send_ex(gen, arg, 0); -} - -PyDoc_STRVAR(close_doc, -"close(arg) -> raise GeneratorExit inside generator."); - -static PyObject * -gen_close(PyGenObject *gen, PyObject *args) -{ - PyObject *retval; - PyErr_SetNone(PyExc_GeneratorExit); - retval = gen_send_ex(gen, Py_None, 1); - if (retval) { - Py_DECREF(retval); - PyErr_SetString(PyExc_RuntimeError, - "generator ignored GeneratorExit"); - return NULL; - } - if (PyErr_ExceptionMatches(PyExc_StopIteration) - || PyErr_ExceptionMatches(PyExc_GeneratorExit)) - { - PyErr_Clear(); /* ignore these errors */ - Py_INCREF(Py_None); - return Py_None; - } - return NULL; -} - -static void -gen_del(PyObject *self) -{ - PyObject *res; - PyObject *error_type, *error_value, *error_traceback; - PyGenObject *gen = (PyGenObject *)self; - - if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) - /* Generator isn't paused, so no need to close */ - return; - - /* Temporarily resurrect the object. */ - assert(self->ob_refcnt == 0); - self->ob_refcnt = 1; - - /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - res = gen_close(gen, NULL); - - if (res == NULL) - PyErr_WriteUnraisable(self); - else - Py_DECREF(res); - - /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); - - /* Undo the temporary resurrection; can't use DECREF here, it would - * cause a recursive call. - */ - assert(self->ob_refcnt > 0); - if (--self->ob_refcnt == 0) - return; /* this is the normal path out */ - - /* close() resurrected it! Make it look like the original Py_DECREF - * never happened. - */ - { - Py_ssize_t refcnt = self->ob_refcnt; - _Py_NewReference(self); - self->ob_refcnt = refcnt; - } - assert(PyType_IS_GC(self->ob_type) && - _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); - - /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so - * we need to undo that. */ - _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --self->ob_type->tp_frees; - --self->ob_type->tp_allocs; -#endif -} - - - -PyDoc_STRVAR(throw_doc, -"throw(typ[,val[,tb]]) -> raise exception in generator,\n\ -return next yielded value or raise StopIteration."); - -static PyObject * -gen_throw(PyGenObject *gen, PyObject *args) -{ - PyObject *typ; - PyObject *tb = NULL; - PyObject *val = NULL; - - if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) - return NULL; - - /* First, check the traceback argument, replacing None with - NULL. */ - if (tb == Py_None) - tb = NULL; - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "throw() third argument must be a traceback object"); - return NULL; - } - - Py_INCREF(typ); - Py_XINCREF(val); - Py_XINCREF(tb); - - if (PyExceptionClass_Check(typ)) { - PyErr_NormalizeException(&typ, &val, &tb); - } - - else if (PyExceptionInstance_Check(typ)) { - /* Raising an instance. The value should be a dummy. */ - if (val && val != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto failed_throw; - } - else { - /* Normalize to raise <class>, <instance> */ - Py_XDECREF(val); - val = typ; - typ = PyExceptionInstance_Class(typ); - Py_INCREF(typ); - } - } - - /* Allow raising builtin string exceptions */ - - else if (!PyString_CheckExact(typ)) { - /* Not something you can raise. throw() fails. */ - PyErr_Format(PyExc_TypeError, - "exceptions must be classes, or instances, not %s", - typ->ob_type->tp_name); - goto failed_throw; - } - - PyErr_Restore(typ, val, tb); - return gen_send_ex(gen, Py_None, 1); - -failed_throw: - /* Didn't use our arguments, so restore their original refcounts */ - Py_DECREF(typ); - Py_XDECREF(val); - Py_XDECREF(tb); - return NULL; -} - - -static PyObject * -gen_iternext(PyGenObject *gen) -{ - return gen_send_ex(gen, NULL, 0); -} - - -static PyMemberDef gen_memberlist[] = { - {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), RO}, - {"gi_running", T_INT, offsetof(PyGenObject, gi_running), RO}, - {NULL} /* Sentinel */ -}; - -static PyMethodDef gen_methods[] = { - {"send",(PyCFunction)gen_send, METH_O, send_doc}, - {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, - {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, - {NULL, NULL} /* Sentinel */ -}; - -PyTypeObject PyGen_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "generator", /* tp_name */ - sizeof(PyGenObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)gen_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)gen_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyGenObject, gi_weakreflist), /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)gen_iternext, /* tp_iternext */ - gen_methods, /* tp_methods */ - gen_memberlist, /* tp_members */ - 0, /* 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 */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - gen_del, /* tp_del */ -}; - -PyObject * -PyGen_New(PyFrameObject *f) -{ - PyGenObject *gen = PyObject_GC_New(PyGenObject, &PyGen_Type); - if (gen == NULL) { - Py_DECREF(f); - return NULL; - } - gen->gi_frame = f; - gen->gi_running = 0; - gen->gi_weakreflist = NULL; - _PyObject_GC_TRACK(gen); - return (PyObject *)gen; -} - -int -PyGen_NeedsFinalizing(PyGenObject *gen) -{ - int i; - PyFrameObject *f = gen->gi_frame; - - if (f == NULL || f->f_stacktop == NULL || f->f_iblock <= 0) - return 0; /* no frame or empty blockstack == no finalization */ - - /* Any block type besides a loop requires cleanup. */ - i = f->f_iblock; - while (--i >= 0) { - if (f->f_blockstack[i].b_type != SETUP_LOOP) - return 1; - } - - /* No blocks except loops, it's safe to skip finalization. */ - return 0; -} diff --git a/sys/src/cmd/python/Objects/intobject.c b/sys/src/cmd/python/Objects/intobject.c deleted file mode 100644 index 8aa8d0b39..000000000 --- a/sys/src/cmd/python/Objects/intobject.c +++ /dev/null @@ -1,1280 +0,0 @@ - -/* Integer object implementation */ - -#include "Python.h" -#include <ctype.h> - -long -PyInt_GetMax(void) -{ - return LONG_MAX; /* To initialize sys.maxint */ -} - -/* Integers are quite normal objects, to make object handling uniform. - (Using odd pointers to represent integers would save much space - but require extra checks for this special case throughout the code.) - Since a typical Python program spends much of its time allocating - and deallocating integers, these operations should be very fast. - Therefore we use a dedicated allocation scheme with a much lower - overhead (in space and time) than straight malloc(): a simple - dedicated free list, filled when necessary with memory from malloc(). - - block_list is a singly-linked list of all PyIntBlocks ever allocated, - linked via their next members. PyIntBlocks are never returned to the - system before shutdown (PyInt_Fini). - - free_list is a singly-linked list of available PyIntObjects, linked - via abuse of their ob_type members. -*/ - -#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ -#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ -#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject)) - -struct _intblock { - struct _intblock *next; - PyIntObject objects[N_INTOBJECTS]; -}; - -typedef struct _intblock PyIntBlock; - -static PyIntBlock *block_list = NULL; -static PyIntObject *free_list = NULL; - -static PyIntObject * -fill_free_list(void) -{ - PyIntObject *p, *q; - /* Python's object allocator isn't appropriate for large blocks. */ - p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock)); - if (p == NULL) - return (PyIntObject *) PyErr_NoMemory(); - ((PyIntBlock *)p)->next = block_list; - block_list = (PyIntBlock *)p; - /* Link the int objects together, from rear to front, then return - the address of the last int object in the block. */ - p = &((PyIntBlock *)p)->objects[0]; - q = p + N_INTOBJECTS; - while (--q > p) - q->ob_type = (struct _typeobject *)(q-1); - q->ob_type = NULL; - return p + N_INTOBJECTS - 1; -} - -#ifndef NSMALLPOSINTS -#define NSMALLPOSINTS 257 -#endif -#ifndef NSMALLNEGINTS -#define NSMALLNEGINTS 5 -#endif -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 -/* References to small integers are saved in this array so that they - can be shared. - The integers that are saved are those in the range - -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). -*/ -static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; -#endif -#ifdef COUNT_ALLOCS -int quick_int_allocs, quick_neg_int_allocs; -#endif - -PyObject * -PyInt_FromLong(long ival) -{ - register PyIntObject *v; -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 - if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { - v = small_ints[ival + NSMALLNEGINTS]; - Py_INCREF(v); -#ifdef COUNT_ALLOCS - if (ival >= 0) - quick_int_allocs++; - else - quick_neg_int_allocs++; -#endif - return (PyObject *) v; - } -#endif - if (free_list == NULL) { - if ((free_list = fill_free_list()) == NULL) - return NULL; - } - /* Inline PyObject_New */ - v = free_list; - free_list = (PyIntObject *)v->ob_type; - PyObject_INIT(v, &PyInt_Type); - v->ob_ival = ival; - return (PyObject *) v; -} - -PyObject * -PyInt_FromSize_t(size_t ival) -{ - if (ival <= LONG_MAX) - return PyInt_FromLong((long)ival); - return _PyLong_FromSize_t(ival); -} - -PyObject * -PyInt_FromSsize_t(Py_ssize_t ival) -{ - if (ival >= LONG_MIN && ival <= LONG_MAX) - return PyInt_FromLong((long)ival); - return _PyLong_FromSsize_t(ival); -} - -static void -int_dealloc(PyIntObject *v) -{ - if (PyInt_CheckExact(v)) { - v->ob_type = (struct _typeobject *)free_list; - free_list = v; - } - else - v->ob_type->tp_free((PyObject *)v); -} - -static void -int_free(PyIntObject *v) -{ - v->ob_type = (struct _typeobject *)free_list; - free_list = v; -} - -long -PyInt_AsLong(register PyObject *op) -{ - PyNumberMethods *nb; - PyIntObject *io; - long val; - - if (op && PyInt_Check(op)) - return PyInt_AS_LONG((PyIntObject*) op); - - if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || - nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return -1; - } - - io = (PyIntObject*) (*nb->nb_int) (op); - if (io == NULL) - return -1; - if (!PyInt_Check(io)) { - if (PyLong_Check(io)) { - /* got a long? => retry int conversion */ - val = PyLong_AsLong((PyObject *)io); - Py_DECREF(io); - if ((val == -1) && PyErr_Occurred()) - return -1; - return val; - } - else - { - Py_DECREF(io); - PyErr_SetString(PyExc_TypeError, - "nb_int should return int object"); - return -1; - } - } - - val = PyInt_AS_LONG(io); - Py_DECREF(io); - - return val; -} - -Py_ssize_t -PyInt_AsSsize_t(register PyObject *op) -{ -#if SIZEOF_SIZE_T != SIZEOF_LONG - PyNumberMethods *nb; - PyIntObject *io; - Py_ssize_t val; -#endif - - if (op == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return -1; - } - - if (PyInt_Check(op)) - return PyInt_AS_LONG((PyIntObject*) op); - if (PyLong_Check(op)) - return _PyLong_AsSsize_t(op); -#if SIZEOF_SIZE_T == SIZEOF_LONG - return PyInt_AsLong(op); -#else - - if ((nb = op->ob_type->tp_as_number) == NULL || - (nb->nb_int == NULL && nb->nb_long == 0)) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return -1; - } - - if (nb->nb_long != 0) { - io = (PyIntObject*) (*nb->nb_long) (op); - } else { - io = (PyIntObject*) (*nb->nb_int) (op); - } - if (io == NULL) - return -1; - if (!PyInt_Check(io)) { - if (PyLong_Check(io)) { - /* got a long? => retry int conversion */ - val = _PyLong_AsSsize_t((PyObject *)io); - Py_DECREF(io); - if ((val == -1) && PyErr_Occurred()) - return -1; - return val; - } - else - { - Py_DECREF(io); - PyErr_SetString(PyExc_TypeError, - "nb_int should return int object"); - return -1; - } - } - - val = PyInt_AS_LONG(io); - Py_DECREF(io); - - return val; -#endif -} - -unsigned long -PyInt_AsUnsignedLongMask(register PyObject *op) -{ - PyNumberMethods *nb; - PyIntObject *io; - unsigned long val; - - if (op && PyInt_Check(op)) - return PyInt_AS_LONG((PyIntObject*) op); - if (op && PyLong_Check(op)) - return PyLong_AsUnsignedLongMask(op); - - if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || - nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return (unsigned long)-1; - } - - io = (PyIntObject*) (*nb->nb_int) (op); - if (io == NULL) - return (unsigned long)-1; - if (!PyInt_Check(io)) { - if (PyLong_Check(io)) { - val = PyLong_AsUnsignedLongMask((PyObject *)io); - Py_DECREF(io); - if (PyErr_Occurred()) - return (unsigned long)-1; - return val; - } - else - { - Py_DECREF(io); - PyErr_SetString(PyExc_TypeError, - "nb_int should return int object"); - return (unsigned long)-1; - } - } - - val = PyInt_AS_LONG(io); - Py_DECREF(io); - - return val; -} - -#ifdef HAVE_LONG_LONG -unsigned PY_LONG_LONG -PyInt_AsUnsignedLongLongMask(register PyObject *op) -{ - PyNumberMethods *nb; - PyIntObject *io; - unsigned PY_LONG_LONG val; - - if (op && PyInt_Check(op)) - return PyInt_AS_LONG((PyIntObject*) op); - if (op && PyLong_Check(op)) - return PyLong_AsUnsignedLongLongMask(op); - - if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || - nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return (unsigned PY_LONG_LONG)-1; - } - - io = (PyIntObject*) (*nb->nb_int) (op); - if (io == NULL) - return (unsigned PY_LONG_LONG)-1; - if (!PyInt_Check(io)) { - if (PyLong_Check(io)) { - val = PyLong_AsUnsignedLongLongMask((PyObject *)io); - Py_DECREF(io); - if (PyErr_Occurred()) - return (unsigned PY_LONG_LONG)-1; - return val; - } - else - { - Py_DECREF(io); - PyErr_SetString(PyExc_TypeError, - "nb_int should return int object"); - return (unsigned PY_LONG_LONG)-1; - } - } - - val = PyInt_AS_LONG(io); - Py_DECREF(io); - - return val; -} -#endif - -PyObject * -PyInt_FromString(char *s, char **pend, int base) -{ - char *end; - long x; - Py_ssize_t slen; - PyObject *sobj, *srepr; - - if ((base != 0 && base < 2) || base > 36) { - PyErr_SetString(PyExc_ValueError, - "int() base must be >= 2 and <= 36"); - return NULL; - } - - while (*s && isspace(Py_CHARMASK(*s))) - s++; - errno = 0; - if (base == 0 && s[0] == '0') { - x = (long) PyOS_strtoul(s, &end, base); - if (x < 0) - return PyLong_FromString(s, pend, base); - } - else - x = PyOS_strtol(s, &end, base); - if (end == s || !isalnum(Py_CHARMASK(end[-1]))) - goto bad; - while (*end && isspace(Py_CHARMASK(*end))) - end++; - if (*end != '\0') { - bad: - slen = strlen(s) < 200 ? strlen(s) : 200; - sobj = PyString_FromStringAndSize(s, slen); - if (sobj == NULL) - return NULL; - srepr = PyObject_Repr(sobj); - Py_DECREF(sobj); - if (srepr == NULL) - return NULL; - PyErr_Format(PyExc_ValueError, - "invalid literal for int() with base %d: %s", - base, PyString_AS_STRING(srepr)); - Py_DECREF(srepr); - return NULL; - } - else if (errno != 0) - return PyLong_FromString(s, pend, base); - if (pend) - *pend = end; - return PyInt_FromLong(x); -} - -#ifdef Py_USING_UNICODE -PyObject * -PyInt_FromUnicode(Py_UNICODE *s, Py_ssize_t length, int base) -{ - PyObject *result; - char *buffer = (char *)PyMem_MALLOC(length+1); - - if (buffer == NULL) - return NULL; - - if (PyUnicode_EncodeDecimal(s, length, buffer, NULL)) { - PyMem_FREE(buffer); - return NULL; - } - result = PyInt_FromString(buffer, NULL, base); - PyMem_FREE(buffer); - return result; -} -#endif - -/* Methods */ - -/* Integers are seen as the "smallest" of all numeric types and thus - don't have any knowledge about conversion of other types to - integers. */ - -#define CONVERT_TO_LONG(obj, lng) \ - if (PyInt_Check(obj)) { \ - lng = PyInt_AS_LONG(obj); \ - } \ - else { \ - Py_INCREF(Py_NotImplemented); \ - return Py_NotImplemented; \ - } - -/* ARGSUSED */ -static int -int_print(PyIntObject *v, FILE *fp, int flags) - /* flags -- not used but required by interface */ -{ - fprintf(fp, "%ld", v->ob_ival); - return 0; -} - -static PyObject * -int_repr(PyIntObject *v) -{ - char buf[64]; - PyOS_snprintf(buf, sizeof(buf), "%ld", v->ob_ival); - return PyString_FromString(buf); -} - -static int -int_compare(PyIntObject *v, PyIntObject *w) -{ - register long i = v->ob_ival; - register long j = w->ob_ival; - return (i < j) ? -1 : (i > j) ? 1 : 0; -} - -static long -int_hash(PyIntObject *v) -{ - /* XXX If this is changed, you also need to change the way - Python's long, float and complex types are hashed. */ - long x = v -> ob_ival; - if (x == -1) - x = -2; - return x; -} - -static PyObject * -int_add(PyIntObject *v, PyIntObject *w) -{ - register long a, b, x; - CONVERT_TO_LONG(v, a); - CONVERT_TO_LONG(w, b); - x = a + b; - if ((x^a) >= 0 || (x^b) >= 0) - return PyInt_FromLong(x); - return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *)w); -} - -static PyObject * -int_sub(PyIntObject *v, PyIntObject *w) -{ - register long a, b, x; - CONVERT_TO_LONG(v, a); - CONVERT_TO_LONG(w, b); - x = a - b; - if ((x^a) >= 0 || (x^~b) >= 0) - return PyInt_FromLong(x); - return PyLong_Type.tp_as_number->nb_subtract((PyObject *)v, - (PyObject *)w); -} - -/* -Integer overflow checking for * is painful: Python tried a couple ways, but -they didn't work on all platforms, or failed in endcases (a product of --sys.maxint-1 has been a particular pain). - -Here's another way: - -The native long product x*y is either exactly right or *way* off, being -just the last n bits of the true product, where n is the number of bits -in a long (the delivered product is the true product plus i*2**n for -some integer i). - -The native double product (double)x * (double)y is subject to three -rounding errors: on a sizeof(long)==8 box, each cast to double can lose -info, and even on a sizeof(long)==4 box, the multiplication can lose info. -But, unlike the native long product, it's not in *range* trouble: even -if sizeof(long)==32 (256-bit longs), the product easily fits in the -dynamic range of a double. So the leading 50 (or so) bits of the double -product are correct. - -We check these two ways against each other, and declare victory if they're -approximately the same. Else, because the native long product is the only -one that can lose catastrophic amounts of information, it's the native long -product that must have overflowed. -*/ - -static PyObject * -int_mul(PyObject *v, PyObject *w) -{ - long a, b; - long longprod; /* a*b in native long arithmetic */ - double doubled_longprod; /* (double)longprod */ - double doubleprod; /* (double)a * (double)b */ - - CONVERT_TO_LONG(v, a); - CONVERT_TO_LONG(w, b); - longprod = a * b; - doubleprod = (double)a * (double)b; - doubled_longprod = (double)longprod; - - /* Fast path for normal case: small multiplicands, and no info - is lost in either method. */ - if (doubled_longprod == doubleprod) - return PyInt_FromLong(longprod); - - /* Somebody somewhere lost info. Close enough, or way off? Note - that a != 0 and b != 0 (else doubled_longprod == doubleprod == 0). - The difference either is or isn't significant compared to the - true value (of which doubleprod is a good approximation). - */ - { - const double diff = doubled_longprod - doubleprod; - const double absdiff = diff >= 0.0 ? diff : -diff; - const double absprod = doubleprod >= 0.0 ? doubleprod : - -doubleprod; - /* absdiff/absprod <= 1/32 iff - 32 * absdiff <= absprod -- 5 good bits is "close enough" */ - if (32.0 * absdiff <= absprod) - return PyInt_FromLong(longprod); - else - return PyLong_Type.tp_as_number->nb_multiply(v, w); - } -} - -/* Integer overflow checking for unary negation: on a 2's-complement - * box, -x overflows iff x is the most negative long. In this case we - * get -x == x. However, -x is undefined (by C) if x /is/ the most - * negative long (it's a signed overflow case), and some compilers care. - * So we cast x to unsigned long first. However, then other compilers - * warn about applying unary minus to an unsigned operand. Hence the - * weird "0-". - */ -#define UNARY_NEG_WOULD_OVERFLOW(x) \ - ((x) < 0 && (unsigned long)(x) == 0-(unsigned long)(x)) - -/* Return type of i_divmod */ -enum divmod_result { - DIVMOD_OK, /* Correct result */ - DIVMOD_OVERFLOW, /* Overflow, try again using longs */ - DIVMOD_ERROR /* Exception raised */ -}; - -static enum divmod_result -i_divmod(register long x, register long y, - long *p_xdivy, long *p_xmody) -{ - long xdivy, xmody; - - if (y == 0) { - PyErr_SetString(PyExc_ZeroDivisionError, - "integer division or modulo by zero"); - return DIVMOD_ERROR; - } - /* (-sys.maxint-1)/-1 is the only overflow case. */ - if (y == -1 && UNARY_NEG_WOULD_OVERFLOW(x)) - return DIVMOD_OVERFLOW; - xdivy = x / y; - xmody = x - xdivy * y; - /* If the signs of x and y differ, and the remainder is non-0, - * C89 doesn't define whether xdivy is now the floor or the - * ceiling of the infinitely precise quotient. We want the floor, - * and we have it iff the remainder's sign matches y's. - */ - if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) { - xmody += y; - --xdivy; - assert(xmody && ((y ^ xmody) >= 0)); - } - *p_xdivy = xdivy; - *p_xmody = xmody; - return DIVMOD_OK; -} - -static PyObject * -int_div(PyIntObject *x, PyIntObject *y) -{ - long xi, yi; - long d, m; - CONVERT_TO_LONG(x, xi); - CONVERT_TO_LONG(y, yi); - switch (i_divmod(xi, yi, &d, &m)) { - case DIVMOD_OK: - return PyInt_FromLong(d); - case DIVMOD_OVERFLOW: - return PyLong_Type.tp_as_number->nb_divide((PyObject *)x, - (PyObject *)y); - default: - return NULL; - } -} - -static PyObject * -int_classic_div(PyIntObject *x, PyIntObject *y) -{ - long xi, yi; - long d, m; - CONVERT_TO_LONG(x, xi); - CONVERT_TO_LONG(y, yi); - if (Py_DivisionWarningFlag && - PyErr_Warn(PyExc_DeprecationWarning, "classic int division") < 0) - return NULL; - switch (i_divmod(xi, yi, &d, &m)) { - case DIVMOD_OK: - return PyInt_FromLong(d); - case DIVMOD_OVERFLOW: - return PyLong_Type.tp_as_number->nb_divide((PyObject *)x, - (PyObject *)y); - default: - return NULL; - } -} - -static PyObject * -int_true_divide(PyObject *v, PyObject *w) -{ - /* If they aren't both ints, give someone else a chance. In - particular, this lets int/long get handled by longs, which - underflows to 0 gracefully if the long is too big to convert - to float. */ - if (PyInt_Check(v) && PyInt_Check(w)) - return PyFloat_Type.tp_as_number->nb_true_divide(v, w); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -static PyObject * -int_mod(PyIntObject *x, PyIntObject *y) -{ - long xi, yi; - long d, m; - CONVERT_TO_LONG(x, xi); - CONVERT_TO_LONG(y, yi); - switch (i_divmod(xi, yi, &d, &m)) { - case DIVMOD_OK: - return PyInt_FromLong(m); - case DIVMOD_OVERFLOW: - return PyLong_Type.tp_as_number->nb_remainder((PyObject *)x, - (PyObject *)y); - default: - return NULL; - } -} - -static PyObject * -int_divmod(PyIntObject *x, PyIntObject *y) -{ - long xi, yi; - long d, m; - CONVERT_TO_LONG(x, xi); - CONVERT_TO_LONG(y, yi); - switch (i_divmod(xi, yi, &d, &m)) { - case DIVMOD_OK: - return Py_BuildValue("(ll)", d, m); - case DIVMOD_OVERFLOW: - return PyLong_Type.tp_as_number->nb_divmod((PyObject *)x, - (PyObject *)y); - default: - return NULL; - } -} - -static PyObject * -int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z) -{ - register long iv, iw, iz=0, ix, temp, prev; - CONVERT_TO_LONG(v, iv); - CONVERT_TO_LONG(w, iw); - if (iw < 0) { - if ((PyObject *)z != Py_None) { - PyErr_SetString(PyExc_TypeError, "pow() 2nd argument " - "cannot be negative when 3rd argument specified"); - return NULL; - } - /* Return a float. This works because we know that - this calls float_pow() which converts its - arguments to double. */ - return PyFloat_Type.tp_as_number->nb_power( - (PyObject *)v, (PyObject *)w, (PyObject *)z); - } - if ((PyObject *)z != Py_None) { - CONVERT_TO_LONG(z, iz); - if (iz == 0) { - PyErr_SetString(PyExc_ValueError, - "pow() 3rd argument cannot be 0"); - return NULL; - } - } - /* - * XXX: The original exponentiation code stopped looping - * when temp hit zero; this code will continue onwards - * unnecessarily, but at least it won't cause any errors. - * Hopefully the speed improvement from the fast exponentiation - * will compensate for the slight inefficiency. - * XXX: Better handling of overflows is desperately needed. - */ - temp = iv; - ix = 1; - while (iw > 0) { - prev = ix; /* Save value for overflow check */ - if (iw & 1) { - ix = ix*temp; - if (temp == 0) - break; /* Avoid ix / 0 */ - if (ix / temp != prev) { - return PyLong_Type.tp_as_number->nb_power( - (PyObject *)v, - (PyObject *)w, - (PyObject *)z); - } - } - iw >>= 1; /* Shift exponent down by 1 bit */ - if (iw==0) break; - prev = temp; - temp *= temp; /* Square the value of temp */ - if (prev != 0 && temp / prev != prev) { - return PyLong_Type.tp_as_number->nb_power( - (PyObject *)v, (PyObject *)w, (PyObject *)z); - } - if (iz) { - /* If we did a multiplication, perform a modulo */ - ix = ix % iz; - temp = temp % iz; - } - } - if (iz) { - long div, mod; - switch (i_divmod(ix, iz, &div, &mod)) { - case DIVMOD_OK: - ix = mod; - break; - case DIVMOD_OVERFLOW: - return PyLong_Type.tp_as_number->nb_power( - (PyObject *)v, (PyObject *)w, (PyObject *)z); - default: - return NULL; - } - } - return PyInt_FromLong(ix); -} - -static PyObject * -int_neg(PyIntObject *v) -{ - register long a; - a = v->ob_ival; - /* check for overflow */ - if (UNARY_NEG_WOULD_OVERFLOW(a)) { - PyObject *o = PyLong_FromLong(a); - if (o != NULL) { - PyObject *result = PyNumber_Negative(o); - Py_DECREF(o); - return result; - } - return NULL; - } - return PyInt_FromLong(-a); -} - -static PyObject * -int_pos(PyIntObject *v) -{ - if (PyInt_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return PyInt_FromLong(v->ob_ival); -} - -static PyObject * -int_abs(PyIntObject *v) -{ - if (v->ob_ival >= 0) - return int_pos(v); - else - return int_neg(v); -} - -static int -int_nonzero(PyIntObject *v) -{ - return v->ob_ival != 0; -} - -static PyObject * -int_invert(PyIntObject *v) -{ - return PyInt_FromLong(~v->ob_ival); -} - -static PyObject * -int_lshift(PyIntObject *v, PyIntObject *w) -{ - long a, b, c; - PyObject *vv, *ww, *result; - - CONVERT_TO_LONG(v, a); - CONVERT_TO_LONG(w, b); - if (b < 0) { - PyErr_SetString(PyExc_ValueError, "negative shift count"); - return NULL; - } - if (a == 0 || b == 0) - return int_pos(v); - if (b >= LONG_BIT) { - vv = PyLong_FromLong(PyInt_AS_LONG(v)); - if (vv == NULL) - return NULL; - ww = PyLong_FromLong(PyInt_AS_LONG(w)); - if (ww == NULL) { - Py_DECREF(vv); - return NULL; - } - result = PyNumber_Lshift(vv, ww); - Py_DECREF(vv); - Py_DECREF(ww); - return result; - } - c = a << b; - if (a != Py_ARITHMETIC_RIGHT_SHIFT(long, c, b)) { - vv = PyLong_FromLong(PyInt_AS_LONG(v)); - if (vv == NULL) - return NULL; - ww = PyLong_FromLong(PyInt_AS_LONG(w)); - if (ww == NULL) { - Py_DECREF(vv); - return NULL; - } - result = PyNumber_Lshift(vv, ww); - Py_DECREF(vv); - Py_DECREF(ww); - return result; - } - return PyInt_FromLong(c); -} - -static PyObject * -int_rshift(PyIntObject *v, PyIntObject *w) -{ - register long a, b; - CONVERT_TO_LONG(v, a); - CONVERT_TO_LONG(w, b); - if (b < 0) { - PyErr_SetString(PyExc_ValueError, "negative shift count"); - return NULL; - } - if (a == 0 || b == 0) - return int_pos(v); - if (b >= LONG_BIT) { - if (a < 0) - a = -1; - else - a = 0; - } - else { - a = Py_ARITHMETIC_RIGHT_SHIFT(long, a, b); - } - return PyInt_FromLong(a); -} - -static PyObject * -int_and(PyIntObject *v, PyIntObject *w) -{ - register long a, b; - CONVERT_TO_LONG(v, a); - CONVERT_TO_LONG(w, b); - return PyInt_FromLong(a & b); -} - -static PyObject * -int_xor(PyIntObject *v, PyIntObject *w) -{ - register long a, b; - CONVERT_TO_LONG(v, a); - CONVERT_TO_LONG(w, b); - return PyInt_FromLong(a ^ b); -} - -static PyObject * -int_or(PyIntObject *v, PyIntObject *w) -{ - register long a, b; - CONVERT_TO_LONG(v, a); - CONVERT_TO_LONG(w, b); - return PyInt_FromLong(a | b); -} - -static int -int_coerce(PyObject **pv, PyObject **pw) -{ - if (PyInt_Check(*pw)) { - Py_INCREF(*pv); - Py_INCREF(*pw); - return 0; - } - return 1; /* Can't do it */ -} - -static PyObject * -int_int(PyIntObject *v) -{ - if (PyInt_CheckExact(v)) - Py_INCREF(v); - else - v = (PyIntObject *)PyInt_FromLong(v->ob_ival); - return (PyObject *)v; -} - -static PyObject * -int_long(PyIntObject *v) -{ - return PyLong_FromLong((v -> ob_ival)); -} - -static PyObject * -int_float(PyIntObject *v) -{ - return PyFloat_FromDouble((double)(v -> ob_ival)); -} - -static PyObject * -int_oct(PyIntObject *v) -{ - char buf[100]; - long x = v -> ob_ival; - if (x < 0) - PyOS_snprintf(buf, sizeof(buf), "-0%lo", -x); - else if (x == 0) - strcpy(buf, "0"); - else - PyOS_snprintf(buf, sizeof(buf), "0%lo", x); - return PyString_FromString(buf); -} - -static PyObject * -int_hex(PyIntObject *v) -{ - char buf[100]; - long x = v -> ob_ival; - if (x < 0) - PyOS_snprintf(buf, sizeof(buf), "-0x%lx", -x); - else - PyOS_snprintf(buf, sizeof(buf), "0x%lx", x); - return PyString_FromString(buf); -} - -static PyObject * -int_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static PyObject * -int_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *x = NULL; - int base = -909; - static char *kwlist[] = {"x", "base", 0}; - - if (type != &PyInt_Type) - return int_subtype_new(type, args, kwds); /* Wimp out */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:int", kwlist, - &x, &base)) - return NULL; - if (x == NULL) - return PyInt_FromLong(0L); - if (base == -909) - return PyNumber_Int(x); - if (PyString_Check(x)) { - /* Since PyInt_FromString doesn't have a length parameter, - * check here for possible NULs in the string. */ - char *string = PyString_AS_STRING(x); - if (strlen(string) != PyString_Size(x)) { - /* create a repr() of the input string, - * just like PyInt_FromString does */ - PyObject *srepr; - srepr = PyObject_Repr(x); - if (srepr == NULL) - return NULL; - PyErr_Format(PyExc_ValueError, - "invalid literal for int() with base %d: %s", - base, PyString_AS_STRING(srepr)); - Py_DECREF(srepr); - return NULL; - } - return PyInt_FromString(string, NULL, base); - } -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(x)) - return PyInt_FromUnicode(PyUnicode_AS_UNICODE(x), - PyUnicode_GET_SIZE(x), - base); -#endif - PyErr_SetString(PyExc_TypeError, - "int() can't convert non-string with explicit base"); - return NULL; -} - -/* Wimpy, slow approach to tp_new calls for subtypes of int: - first create a regular int from whatever arguments we got, - then allocate a subtype instance and initialize its ob_ival - from the regular int. The regular int is then thrown away. -*/ -static PyObject * -int_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *tmp, *newobj; - long ival; - - assert(PyType_IsSubtype(type, &PyInt_Type)); - tmp = int_new(&PyInt_Type, args, kwds); - if (tmp == NULL) - return NULL; - if (!PyInt_Check(tmp)) { - ival = PyLong_AsLong(tmp); - if (ival == -1 && PyErr_Occurred()) { - Py_DECREF(tmp); - return NULL; - } - } else { - ival = ((PyIntObject *)tmp)->ob_ival; - } - - newobj = type->tp_alloc(type, 0); - if (newobj == NULL) { - Py_DECREF(tmp); - return NULL; - } - ((PyIntObject *)newobj)->ob_ival = ival; - Py_DECREF(tmp); - return newobj; -} - -static PyObject * -int_getnewargs(PyIntObject *v) -{ - return Py_BuildValue("(l)", v->ob_ival); -} - -static PyMethodDef int_methods[] = { - {"__getnewargs__", (PyCFunction)int_getnewargs, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -PyDoc_STRVAR(int_doc, -"int(x[, base]) -> integer\n\ -\n\ -Convert a string or number to an integer, if possible. A floating point\n\ -argument will be truncated towards zero (this does not include a string\n\ -representation of a floating point number!) When converting a string, use\n\ -the optional base. It is an error to supply a base when converting a\n\ -non-string. If the argument is outside the integer range a long object\n\ -will be returned instead."); - -static PyNumberMethods int_as_number = { - (binaryfunc)int_add, /*nb_add*/ - (binaryfunc)int_sub, /*nb_subtract*/ - (binaryfunc)int_mul, /*nb_multiply*/ - (binaryfunc)int_classic_div, /*nb_divide*/ - (binaryfunc)int_mod, /*nb_remainder*/ - (binaryfunc)int_divmod, /*nb_divmod*/ - (ternaryfunc)int_pow, /*nb_power*/ - (unaryfunc)int_neg, /*nb_negative*/ - (unaryfunc)int_pos, /*nb_positive*/ - (unaryfunc)int_abs, /*nb_absolute*/ - (inquiry)int_nonzero, /*nb_nonzero*/ - (unaryfunc)int_invert, /*nb_invert*/ - (binaryfunc)int_lshift, /*nb_lshift*/ - (binaryfunc)int_rshift, /*nb_rshift*/ - (binaryfunc)int_and, /*nb_and*/ - (binaryfunc)int_xor, /*nb_xor*/ - (binaryfunc)int_or, /*nb_or*/ - int_coerce, /*nb_coerce*/ - (unaryfunc)int_int, /*nb_int*/ - (unaryfunc)int_long, /*nb_long*/ - (unaryfunc)int_float, /*nb_float*/ - (unaryfunc)int_oct, /*nb_oct*/ - (unaryfunc)int_hex, /*nb_hex*/ - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_divide*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - (binaryfunc)int_div, /* nb_floor_divide */ - int_true_divide, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ - (unaryfunc)int_int, /* nb_index */ -}; - -PyTypeObject PyInt_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "int", - sizeof(PyIntObject), - 0, - (destructor)int_dealloc, /* tp_dealloc */ - (printfunc)int_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)int_compare, /* tp_compare */ - (reprfunc)int_repr, /* tp_repr */ - &int_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)int_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)int_repr, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - int_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - int_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - int_new, /* tp_new */ - (freefunc)int_free, /* tp_free */ -}; - -int -_PyInt_Init(void) -{ - PyIntObject *v; - int ival; -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 - for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) { - if (!free_list && (free_list = fill_free_list()) == NULL) - return 0; - /* PyObject_New is inlined */ - v = free_list; - free_list = (PyIntObject *)v->ob_type; - PyObject_INIT(v, &PyInt_Type); - v->ob_ival = ival; - small_ints[ival + NSMALLNEGINTS] = v; - } -#endif - return 1; -} - -void -PyInt_Fini(void) -{ - PyIntObject *p; - PyIntBlock *list, *next; - int i; - unsigned int ctr; - int bc, bf; /* block count, number of freed blocks */ - int irem, isum; /* remaining unfreed ints per block, total */ - -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 - PyIntObject **q; - - i = NSMALLNEGINTS + NSMALLPOSINTS; - q = small_ints; - while (--i >= 0) { - Py_XDECREF(*q); - *q++ = NULL; - } -#endif - bc = 0; - bf = 0; - isum = 0; - list = block_list; - block_list = NULL; - free_list = NULL; - while (list != NULL) { - bc++; - irem = 0; - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { - if (PyInt_CheckExact(p) && p->ob_refcnt != 0) - irem++; - } - next = list->next; - if (irem) { - list->next = block_list; - block_list = list; - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { - if (!PyInt_CheckExact(p) || - p->ob_refcnt == 0) { - p->ob_type = (struct _typeobject *) - free_list; - free_list = p; - } -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 - else if (-NSMALLNEGINTS <= p->ob_ival && - p->ob_ival < NSMALLPOSINTS && - small_ints[p->ob_ival + - NSMALLNEGINTS] == NULL) { - Py_INCREF(p); - small_ints[p->ob_ival + - NSMALLNEGINTS] = p; - } -#endif - } - } - else { - PyMem_FREE(list); - bf++; - } - isum += irem; - list = next; - } - if (!Py_VerboseFlag) - return; - fprintf(stderr, "# cleanup ints"); - if (!isum) { - fprintf(stderr, "\n"); - } - else { - fprintf(stderr, - ": %d unfreed int%s in %d out of %d block%s\n", - isum, isum == 1 ? "" : "s", - bc - bf, bc, bc == 1 ? "" : "s"); - } - if (Py_VerboseFlag > 1) { - list = block_list; - while (list != NULL) { - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { - if (PyInt_CheckExact(p) && p->ob_refcnt != 0) - /* XXX(twouters) cast refcount to - long until %zd is universally - available - */ - fprintf(stderr, - "# <int at %p, refcnt=%ld, val=%ld>\n", - p, (long)p->ob_refcnt, - p->ob_ival); - } - list = list->next; - } - } -} diff --git a/sys/src/cmd/python/Objects/iterobject.c b/sys/src/cmd/python/Objects/iterobject.c deleted file mode 100644 index cf839f478..000000000 --- a/sys/src/cmd/python/Objects/iterobject.c +++ /dev/null @@ -1,232 +0,0 @@ -/* Iterator objects */ - -#include "Python.h" - -typedef struct { - PyObject_HEAD - long it_index; - PyObject *it_seq; /* Set to NULL when iterator is exhausted */ -} seqiterobject; - -PyObject * -PySeqIter_New(PyObject *seq) -{ - seqiterobject *it; - - if (!PySequence_Check(seq)) { - PyErr_BadInternalCall(); - return NULL; - } - it = PyObject_GC_New(seqiterobject, &PySeqIter_Type); - if (it == NULL) - return NULL; - it->it_index = 0; - Py_INCREF(seq); - it->it_seq = seq; - _PyObject_GC_TRACK(it); - return (PyObject *)it; -} - -static void -iter_dealloc(seqiterobject *it) -{ - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); -} - -static int -iter_traverse(seqiterobject *it, visitproc visit, void *arg) -{ - Py_VISIT(it->it_seq); - return 0; -} - -static PyObject * -iter_iternext(PyObject *iterator) -{ - seqiterobject *it; - PyObject *seq; - PyObject *result; - - assert(PySeqIter_Check(iterator)); - it = (seqiterobject *)iterator; - seq = it->it_seq; - if (seq == NULL) - return NULL; - - result = PySequence_GetItem(seq, it->it_index); - if (result != NULL) { - it->it_index++; - return result; - } - if (PyErr_ExceptionMatches(PyExc_IndexError) || - PyErr_ExceptionMatches(PyExc_StopIteration)) - { - PyErr_Clear(); - Py_DECREF(seq); - it->it_seq = NULL; - } - return NULL; -} - -static PyObject * -iter_len(seqiterobject *it) -{ - Py_ssize_t seqsize, len; - - if (it->it_seq) { - seqsize = PySequence_Size(it->it_seq); - if (seqsize == -1) - return NULL; - len = seqsize - it->it_index; - if (len >= 0) - return PyInt_FromSsize_t(len); - } - return PyInt_FromLong(0); -} - -PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - -static PyMethodDef seqiter_methods[] = { - {"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc}, - {NULL, NULL} /* sentinel */ -}; - -PyTypeObject PySeqIter_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "iterator", /* tp_name */ - sizeof(seqiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)iter_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)iter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - iter_iternext, /* tp_iternext */ - seqiter_methods, /* tp_methods */ - 0, /* tp_members */ -}; - -/* -------------------------------------- */ - -typedef struct { - PyObject_HEAD - PyObject *it_callable; /* Set to NULL when iterator is exhausted */ - PyObject *it_sentinel; /* Set to NULL when iterator is exhausted */ -} calliterobject; - -PyObject * -PyCallIter_New(PyObject *callable, PyObject *sentinel) -{ - calliterobject *it; - it = PyObject_GC_New(calliterobject, &PyCallIter_Type); - if (it == NULL) - return NULL; - Py_INCREF(callable); - it->it_callable = callable; - Py_INCREF(sentinel); - it->it_sentinel = sentinel; - _PyObject_GC_TRACK(it); - return (PyObject *)it; -} -static void -calliter_dealloc(calliterobject *it) -{ - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_callable); - Py_XDECREF(it->it_sentinel); - PyObject_GC_Del(it); -} - -static int -calliter_traverse(calliterobject *it, visitproc visit, void *arg) -{ - Py_VISIT(it->it_callable); - Py_VISIT(it->it_sentinel); - return 0; -} - -static PyObject * -calliter_iternext(calliterobject *it) -{ - if (it->it_callable != NULL) { - PyObject *args = PyTuple_New(0); - PyObject *result; - if (args == NULL) - return NULL; - result = PyObject_Call(it->it_callable, args, NULL); - Py_DECREF(args); - if (result != NULL) { - int ok; - ok = PyObject_RichCompareBool(result, - it->it_sentinel, - Py_EQ); - if (ok == 0) - return result; /* Common case, fast path */ - Py_DECREF(result); - if (ok > 0) { - Py_CLEAR(it->it_callable); - Py_CLEAR(it->it_sentinel); - } - } - else if (PyErr_ExceptionMatches(PyExc_StopIteration)) { - PyErr_Clear(); - Py_CLEAR(it->it_callable); - Py_CLEAR(it->it_sentinel); - } - } - return NULL; -} - -PyTypeObject PyCallIter_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "callable-iterator", /* tp_name */ - sizeof(calliterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)calliter_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)calliter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)calliter_iternext, /* tp_iternext */ - 0, /* tp_methods */ -}; diff --git a/sys/src/cmd/python/Objects/listobject.c b/sys/src/cmd/python/Objects/listobject.c deleted file mode 100644 index 739a571b9..000000000 --- a/sys/src/cmd/python/Objects/listobject.c +++ /dev/null @@ -1,2930 +0,0 @@ -/* List object implementation */ - -#include "Python.h" - -#ifdef STDC_HEADERS -#include <stddef.h> -#else -#include <sys/types.h> /* For size_t */ -#endif - -/* Ensure ob_item has room for at least newsize elements, and set - * ob_size to newsize. If newsize > ob_size on entry, the content - * of the new slots at exit is undefined heap trash; it's the caller's - * responsiblity to overwrite them with sane values. - * The number of allocated elements may grow, shrink, or stay the same. - * Failure is impossible if newsize <= self.allocated on entry, although - * that partly relies on an assumption that the system realloc() never - * fails when passed a number of bytes <= the number of bytes last - * allocated (the C standard doesn't guarantee this, but it's hard to - * imagine a realloc implementation where it wouldn't be true). - * Note that self->ob_item may change, and even if newsize is less - * than ob_size on entry. - */ -static int -list_resize(PyListObject *self, Py_ssize_t newsize) -{ - PyObject **items; - size_t new_allocated; - Py_ssize_t allocated = self->allocated; - - /* Bypass realloc() when a previous overallocation is large enough - to accommodate the newsize. If the newsize falls lower than half - the allocated size, then proceed with the realloc() to shrink the list. - */ - if (allocated >= newsize && newsize >= (allocated >> 1)) { - assert(self->ob_item != NULL || newsize == 0); - self->ob_size = newsize; - return 0; - } - - /* This over-allocates proportional to the list size, making room - * for additional growth. The over-allocation is mild, but is - * enough to give linear-time amortized behavior over a long - * sequence of appends() in the presence of a poorly-performing - * system realloc(). - * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... - */ - new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; - if (newsize == 0) - new_allocated = 0; - items = self->ob_item; - if (new_allocated <= ((~(size_t)0) / sizeof(PyObject *))) - PyMem_RESIZE(items, PyObject *, new_allocated); - else - items = NULL; - if (items == NULL) { - PyErr_NoMemory(); - return -1; - } - self->ob_item = items; - self->ob_size = newsize; - self->allocated = new_allocated; - return 0; -} - -/* Empty list reuse scheme to save calls to malloc and free */ -#define MAXFREELISTS 80 -static PyListObject *free_lists[MAXFREELISTS]; -static int num_free_lists = 0; - -void -PyList_Fini(void) -{ - PyListObject *op; - - while (num_free_lists) { - num_free_lists--; - op = free_lists[num_free_lists]; - assert(PyList_CheckExact(op)); - PyObject_GC_Del(op); - } -} - -PyObject * -PyList_New(Py_ssize_t size) -{ - PyListObject *op; - size_t nbytes; - - if (size < 0) { - PyErr_BadInternalCall(); - return NULL; - } - nbytes = size * sizeof(PyObject *); - /* Check for overflow */ - if (nbytes / sizeof(PyObject *) != (size_t)size) - return PyErr_NoMemory(); - if (num_free_lists) { - num_free_lists--; - op = free_lists[num_free_lists]; - _Py_NewReference((PyObject *)op); - } else { - op = PyObject_GC_New(PyListObject, &PyList_Type); - if (op == NULL) - return NULL; - } - if (size <= 0) - op->ob_item = NULL; - else { - op->ob_item = (PyObject **) PyMem_MALLOC(nbytes); - if (op->ob_item == NULL) { - Py_DECREF(op); - return PyErr_NoMemory(); - } - memset(op->ob_item, 0, nbytes); - } - op->ob_size = size; - op->allocated = size; - _PyObject_GC_TRACK(op); - return (PyObject *) op; -} - -Py_ssize_t -PyList_Size(PyObject *op) -{ - if (!PyList_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - else - return ((PyListObject *)op) -> ob_size; -} - -static PyObject *indexerr = NULL; - -PyObject * -PyList_GetItem(PyObject *op, Py_ssize_t i) -{ - if (!PyList_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - if (i < 0 || i >= ((PyListObject *)op) -> ob_size) { - if (indexerr == NULL) - indexerr = PyString_FromString( - "list index out of range"); - PyErr_SetObject(PyExc_IndexError, indexerr); - return NULL; - } - return ((PyListObject *)op) -> ob_item[i]; -} - -int -PyList_SetItem(register PyObject *op, register Py_ssize_t i, - register PyObject *newitem) -{ - register PyObject *olditem; - register PyObject **p; - if (!PyList_Check(op)) { - Py_XDECREF(newitem); - PyErr_BadInternalCall(); - return -1; - } - if (i < 0 || i >= ((PyListObject *)op) -> ob_size) { - Py_XDECREF(newitem); - PyErr_SetString(PyExc_IndexError, - "list assignment index out of range"); - return -1; - } - p = ((PyListObject *)op) -> ob_item + i; - olditem = *p; - *p = newitem; - Py_XDECREF(olditem); - return 0; -} - -static int -ins1(PyListObject *self, Py_ssize_t where, PyObject *v) -{ - Py_ssize_t i, n = self->ob_size; - PyObject **items; - if (v == NULL) { - PyErr_BadInternalCall(); - return -1; - } - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "cannot add more objects to list"); - return -1; - } - - if (list_resize(self, n+1) == -1) - return -1; - - if (where < 0) { - where += n; - if (where < 0) - where = 0; - } - if (where > n) - where = n; - items = self->ob_item; - for (i = n; --i >= where; ) - items[i+1] = items[i]; - Py_INCREF(v); - items[where] = v; - return 0; -} - -int -PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem) -{ - if (!PyList_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - return ins1((PyListObject *)op, where, newitem); -} - -static int -app1(PyListObject *self, PyObject *v) -{ - Py_ssize_t n = PyList_GET_SIZE(self); - - assert (v != NULL); - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "cannot add more objects to list"); - return -1; - } - - if (list_resize(self, n+1) == -1) - return -1; - - Py_INCREF(v); - PyList_SET_ITEM(self, n, v); - return 0; -} - -int -PyList_Append(PyObject *op, PyObject *newitem) -{ - if (PyList_Check(op) && (newitem != NULL)) - return app1((PyListObject *)op, newitem); - PyErr_BadInternalCall(); - return -1; -} - -/* Methods */ - -static void -list_dealloc(PyListObject *op) -{ - Py_ssize_t i; - PyObject_GC_UnTrack(op); - Py_TRASHCAN_SAFE_BEGIN(op) - if (op->ob_item != NULL) { - /* Do it backwards, for Christian Tismer. - There's a simple test case where somehow this reduces - thrashing when a *very* large list is created and - immediately deleted. */ - i = op->ob_size; - while (--i >= 0) { - Py_XDECREF(op->ob_item[i]); - } - PyMem_FREE(op->ob_item); - } - if (num_free_lists < MAXFREELISTS && PyList_CheckExact(op)) - free_lists[num_free_lists++] = op; - else - op->ob_type->tp_free((PyObject *)op); - Py_TRASHCAN_SAFE_END(op) -} - -static int -list_print(PyListObject *op, FILE *fp, int flags) -{ - int rc; - Py_ssize_t i; - - rc = Py_ReprEnter((PyObject*)op); - if (rc != 0) { - if (rc < 0) - return rc; - fprintf(fp, "[...]"); - return 0; - } - fprintf(fp, "["); - for (i = 0; i < op->ob_size; i++) { - if (i > 0) - fprintf(fp, ", "); - if (PyObject_Print(op->ob_item[i], fp, 0) != 0) { - Py_ReprLeave((PyObject *)op); - return -1; - } - } - fprintf(fp, "]"); - Py_ReprLeave((PyObject *)op); - return 0; -} - -static PyObject * -list_repr(PyListObject *v) -{ - Py_ssize_t i; - PyObject *s, *temp; - PyObject *pieces = NULL, *result = NULL; - - i = Py_ReprEnter((PyObject*)v); - if (i != 0) { - return i > 0 ? PyString_FromString("[...]") : NULL; - } - - if (v->ob_size == 0) { - result = PyString_FromString("[]"); - goto Done; - } - - pieces = PyList_New(0); - if (pieces == NULL) - goto Done; - - /* Do repr() on each element. Note that this may mutate the list, - so must refetch the list size on each iteration. */ - for (i = 0; i < v->ob_size; ++i) { - int status; - s = PyObject_Repr(v->ob_item[i]); - if (s == NULL) - goto Done; - status = PyList_Append(pieces, s); - Py_DECREF(s); /* append created a new ref */ - if (status < 0) - goto Done; - } - - /* Add "[]" decorations to the first and last items. */ - assert(PyList_GET_SIZE(pieces) > 0); - s = PyString_FromString("["); - if (s == NULL) - goto Done; - temp = PyList_GET_ITEM(pieces, 0); - PyString_ConcatAndDel(&s, temp); - PyList_SET_ITEM(pieces, 0, s); - if (s == NULL) - goto Done; - - s = PyString_FromString("]"); - if (s == NULL) - goto Done; - temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1); - PyString_ConcatAndDel(&temp, s); - PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp); - if (temp == NULL) - goto Done; - - /* Paste them all together with ", " between. */ - s = PyString_FromString(", "); - if (s == NULL) - goto Done; - result = _PyString_Join(s, pieces); - Py_DECREF(s); - -Done: - Py_XDECREF(pieces); - Py_ReprLeave((PyObject *)v); - return result; -} - -static Py_ssize_t -list_length(PyListObject *a) -{ - return a->ob_size; -} - -static int -list_contains(PyListObject *a, PyObject *el) -{ - Py_ssize_t i; - int cmp; - - for (i = 0, cmp = 0 ; cmp == 0 && i < a->ob_size; ++i) - cmp = PyObject_RichCompareBool(el, PyList_GET_ITEM(a, i), - Py_EQ); - return cmp; -} - -static PyObject * -list_item(PyListObject *a, Py_ssize_t i) -{ - if (i < 0 || i >= a->ob_size) { - if (indexerr == NULL) - indexerr = PyString_FromString( - "list index out of range"); - PyErr_SetObject(PyExc_IndexError, indexerr); - return NULL; - } - Py_INCREF(a->ob_item[i]); - return a->ob_item[i]; -} - -static PyObject * -list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh) -{ - PyListObject *np; - PyObject **src, **dest; - Py_ssize_t i, len; - if (ilow < 0) - ilow = 0; - else if (ilow > a->ob_size) - ilow = a->ob_size; - if (ihigh < ilow) - ihigh = ilow; - else if (ihigh > a->ob_size) - ihigh = a->ob_size; - len = ihigh - ilow; - np = (PyListObject *) PyList_New(len); - if (np == NULL) - return NULL; - - src = a->ob_item + ilow; - dest = np->ob_item; - for (i = 0; i < len; i++) { - PyObject *v = src[i]; - Py_INCREF(v); - dest[i] = v; - } - return (PyObject *)np; -} - -PyObject * -PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh) -{ - if (!PyList_Check(a)) { - PyErr_BadInternalCall(); - return NULL; - } - return list_slice((PyListObject *)a, ilow, ihigh); -} - -static PyObject * -list_concat(PyListObject *a, PyObject *bb) -{ - Py_ssize_t size; - Py_ssize_t i; - PyObject **src, **dest; - PyListObject *np; - if (!PyList_Check(bb)) { - PyErr_Format(PyExc_TypeError, - "can only concatenate list (not \"%.200s\") to list", - bb->ob_type->tp_name); - return NULL; - } -#define b ((PyListObject *)bb) - size = a->ob_size + b->ob_size; - if (size < 0) - return PyErr_NoMemory(); - np = (PyListObject *) PyList_New(size); - if (np == NULL) { - return NULL; - } - src = a->ob_item; - dest = np->ob_item; - for (i = 0; i < a->ob_size; i++) { - PyObject *v = src[i]; - Py_INCREF(v); - dest[i] = v; - } - src = b->ob_item; - dest = np->ob_item + a->ob_size; - for (i = 0; i < b->ob_size; i++) { - PyObject *v = src[i]; - Py_INCREF(v); - dest[i] = v; - } - return (PyObject *)np; -#undef b -} - -static PyObject * -list_repeat(PyListObject *a, Py_ssize_t n) -{ - Py_ssize_t i, j; - Py_ssize_t size; - PyListObject *np; - PyObject **p, **items; - PyObject *elem; - if (n < 0) - n = 0; - size = a->ob_size * n; - if (size == 0) - return PyList_New(0); - if (n && size/n != a->ob_size) - return PyErr_NoMemory(); - np = (PyListObject *) PyList_New(size); - if (np == NULL) - return NULL; - - items = np->ob_item; - if (a->ob_size == 1) { - elem = a->ob_item[0]; - for (i = 0; i < n; i++) { - items[i] = elem; - Py_INCREF(elem); - } - return (PyObject *) np; - } - p = np->ob_item; - items = a->ob_item; - for (i = 0; i < n; i++) { - for (j = 0; j < a->ob_size; j++) { - *p = items[j]; - Py_INCREF(*p); - p++; - } - } - return (PyObject *) np; -} - -static int -list_clear(PyListObject *a) -{ - Py_ssize_t i; - PyObject **item = a->ob_item; - if (item != NULL) { - /* Because XDECREF can recursively invoke operations on - this list, we make it empty first. */ - i = a->ob_size; - a->ob_size = 0; - a->ob_item = NULL; - a->allocated = 0; - while (--i >= 0) { - Py_XDECREF(item[i]); - } - PyMem_FREE(item); - } - /* Never fails; the return value can be ignored. - Note that there is no guarantee that the list is actually empty - at this point, because XDECREF may have populated it again! */ - return 0; -} - -/* a[ilow:ihigh] = v if v != NULL. - * del a[ilow:ihigh] if v == NULL. - * - * Special speed gimmick: when v is NULL and ihigh - ilow <= 8, it's - * guaranteed the call cannot fail. - */ -static int -list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) -{ - /* Because [X]DECREF can recursively invoke list operations on - this list, we must postpone all [X]DECREF activity until - after the list is back in its canonical shape. Therefore - we must allocate an additional array, 'recycle', into which - we temporarily copy the items that are deleted from the - list. :-( */ - PyObject *recycle_on_stack[8]; - PyObject **recycle = recycle_on_stack; /* will allocate more if needed */ - PyObject **item; - PyObject **vitem = NULL; - PyObject *v_as_SF = NULL; /* PySequence_Fast(v) */ - Py_ssize_t n; /* # of elements in replacement list */ - Py_ssize_t norig; /* # of elements in list getting replaced */ - Py_ssize_t d; /* Change in size */ - Py_ssize_t k; - size_t s; - int result = -1; /* guilty until proved innocent */ -#define b ((PyListObject *)v) - if (v == NULL) - n = 0; - else { - if (a == b) { - /* Special case "a[i:j] = a" -- copy b first */ - v = list_slice(b, 0, b->ob_size); - if (v == NULL) - return result; - result = list_ass_slice(a, ilow, ihigh, v); - Py_DECREF(v); - return result; - } - v_as_SF = PySequence_Fast(v, "can only assign an iterable"); - if(v_as_SF == NULL) - goto Error; - n = PySequence_Fast_GET_SIZE(v_as_SF); - vitem = PySequence_Fast_ITEMS(v_as_SF); - } - if (ilow < 0) - ilow = 0; - else if (ilow > a->ob_size) - ilow = a->ob_size; - - if (ihigh < ilow) - ihigh = ilow; - else if (ihigh > a->ob_size) - ihigh = a->ob_size; - - norig = ihigh - ilow; - assert(norig >= 0); - d = n - norig; - if (a->ob_size + d == 0) { - Py_XDECREF(v_as_SF); - return list_clear(a); - } - item = a->ob_item; - /* recycle the items that we are about to remove */ - s = norig * sizeof(PyObject *); - if (s > sizeof(recycle_on_stack)) { - recycle = (PyObject **)PyMem_MALLOC(s); - if (recycle == NULL) { - PyErr_NoMemory(); - goto Error; - } - } - memcpy(recycle, &item[ilow], s); - - if (d < 0) { /* Delete -d items */ - memmove(&item[ihigh+d], &item[ihigh], - (a->ob_size - ihigh)*sizeof(PyObject *)); - list_resize(a, a->ob_size + d); - item = a->ob_item; - } - else if (d > 0) { /* Insert d items */ - k = a->ob_size; - if (list_resize(a, k+d) < 0) - goto Error; - item = a->ob_item; - memmove(&item[ihigh+d], &item[ihigh], - (k - ihigh)*sizeof(PyObject *)); - } - for (k = 0; k < n; k++, ilow++) { - PyObject *w = vitem[k]; - Py_XINCREF(w); - item[ilow] = w; - } - for (k = norig - 1; k >= 0; --k) - Py_XDECREF(recycle[k]); - result = 0; - Error: - if (recycle != recycle_on_stack) - PyMem_FREE(recycle); - Py_XDECREF(v_as_SF); - return result; -#undef b -} - -int -PyList_SetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) -{ - if (!PyList_Check(a)) { - PyErr_BadInternalCall(); - return -1; - } - return list_ass_slice((PyListObject *)a, ilow, ihigh, v); -} - -static PyObject * -list_inplace_repeat(PyListObject *self, Py_ssize_t n) -{ - PyObject **items; - Py_ssize_t size, i, j, p; - - - size = PyList_GET_SIZE(self); - if (size == 0) { - Py_INCREF(self); - return (PyObject *)self; - } - - if (n < 1) { - (void)list_clear(self); - Py_INCREF(self); - return (PyObject *)self; - } - - if (list_resize(self, size*n) == -1) - return NULL; - - p = size; - items = self->ob_item; - for (i = 1; i < n; i++) { /* Start counting at 1, not 0 */ - for (j = 0; j < size; j++) { - PyObject *o = items[j]; - Py_INCREF(o); - items[p++] = o; - } - } - Py_INCREF(self); - return (PyObject *)self; -} - -static int -list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v) -{ - PyObject *old_value; - if (i < 0 || i >= a->ob_size) { - PyErr_SetString(PyExc_IndexError, - "list assignment index out of range"); - return -1; - } - if (v == NULL) - return list_ass_slice(a, i, i+1, v); - Py_INCREF(v); - old_value = a->ob_item[i]; - a->ob_item[i] = v; - Py_DECREF(old_value); - return 0; -} - -static PyObject * -listinsert(PyListObject *self, PyObject *args) -{ - Py_ssize_t i; - PyObject *v; - if (!PyArg_ParseTuple(args, "nO:insert", &i, &v)) - return NULL; - if (ins1(self, i, v) == 0) - Py_RETURN_NONE; - return NULL; -} - -static PyObject * -listappend(PyListObject *self, PyObject *v) -{ - if (app1(self, v) == 0) - Py_RETURN_NONE; - return NULL; -} - -static PyObject * -listextend(PyListObject *self, PyObject *b) -{ - PyObject *it; /* iter(v) */ - Py_ssize_t m; /* size of self */ - Py_ssize_t n; /* guess for size of b */ - Py_ssize_t mn; /* m + n */ - Py_ssize_t i; - PyObject *(*iternext)(PyObject *); - - /* Special cases: - 1) lists and tuples which can use PySequence_Fast ops - 2) extending self to self requires making a copy first - */ - if (PyList_CheckExact(b) || PyTuple_CheckExact(b) || (PyObject *)self == b) { - PyObject **src, **dest; - b = PySequence_Fast(b, "argument must be iterable"); - if (!b) - return NULL; - n = PySequence_Fast_GET_SIZE(b); - if (n == 0) { - /* short circuit when b is empty */ - Py_DECREF(b); - Py_RETURN_NONE; - } - m = self->ob_size; - if (list_resize(self, m + n) == -1) { - Py_DECREF(b); - return NULL; - } - /* note that we may still have self == b here for the - * situation a.extend(a), but the following code works - * in that case too. Just make sure to resize self - * before calling PySequence_Fast_ITEMS. - */ - /* populate the end of self with b's items */ - src = PySequence_Fast_ITEMS(b); - dest = self->ob_item + m; - for (i = 0; i < n; i++) { - PyObject *o = src[i]; - Py_INCREF(o); - dest[i] = o; - } - Py_DECREF(b); - Py_RETURN_NONE; - } - - it = PyObject_GetIter(b); - if (it == NULL) - return NULL; - iternext = *it->ob_type->tp_iternext; - - /* Guess a result list size. */ - n = _PyObject_LengthHint(b); - if (n < 0) { - if (!PyErr_ExceptionMatches(PyExc_TypeError) && - !PyErr_ExceptionMatches(PyExc_AttributeError)) { - Py_DECREF(it); - return NULL; - } - PyErr_Clear(); - n = 8; /* arbitrary */ - } - m = self->ob_size; - mn = m + n; - if (mn >= m) { - /* Make room. */ - if (list_resize(self, mn) == -1) - goto error; - /* Make the list sane again. */ - self->ob_size = m; - } - /* Else m + n overflowed; on the chance that n lied, and there really - * is enough room, ignore it. If n was telling the truth, we'll - * eventually run out of memory during the loop. - */ - - /* Run iterator to exhaustion. */ - for (;;) { - PyObject *item = iternext(it); - if (item == NULL) { - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); - else - goto error; - } - break; - } - if (self->ob_size < self->allocated) { - /* steals ref */ - PyList_SET_ITEM(self, self->ob_size, item); - ++self->ob_size; - } - else { - int status = app1(self, item); - Py_DECREF(item); /* append creates a new ref */ - if (status < 0) - goto error; - } - } - - /* Cut back result list if initial guess was too large. */ - if (self->ob_size < self->allocated) - list_resize(self, self->ob_size); /* shrinking can't fail */ - - Py_DECREF(it); - Py_RETURN_NONE; - - error: - Py_DECREF(it); - return NULL; -} - -PyObject * -_PyList_Extend(PyListObject *self, PyObject *b) -{ - return listextend(self, b); -} - -static PyObject * -list_inplace_concat(PyListObject *self, PyObject *other) -{ - PyObject *result; - - result = listextend(self, other); - if (result == NULL) - return result; - Py_DECREF(result); - Py_INCREF(self); - return (PyObject *)self; -} - -static PyObject * -listpop(PyListObject *self, PyObject *args) -{ - Py_ssize_t i = -1; - PyObject *v; - int status; - - if (!PyArg_ParseTuple(args, "|n:pop", &i)) - return NULL; - - if (self->ob_size == 0) { - /* Special-case most common failure cause */ - PyErr_SetString(PyExc_IndexError, "pop from empty list"); - return NULL; - } - if (i < 0) - i += self->ob_size; - if (i < 0 || i >= self->ob_size) { - PyErr_SetString(PyExc_IndexError, "pop index out of range"); - return NULL; - } - v = self->ob_item[i]; - if (i == self->ob_size - 1) { - status = list_resize(self, self->ob_size - 1); - assert(status >= 0); - return v; /* and v now owns the reference the list had */ - } - Py_INCREF(v); - status = list_ass_slice(self, i, i+1, (PyObject *)NULL); - assert(status >= 0); - /* Use status, so that in a release build compilers don't - * complain about the unused name. - */ - (void) status; - - return v; -} - -/* Reverse a slice of a list in place, from lo up to (exclusive) hi. */ -static void -reverse_slice(PyObject **lo, PyObject **hi) -{ - assert(lo && hi); - - --hi; - while (lo < hi) { - PyObject *t = *lo; - *lo = *hi; - *hi = t; - ++lo; - --hi; - } -} - -/* Lots of code for an adaptive, stable, natural mergesort. There are many - * pieces to this algorithm; read listsort.txt for overviews and details. - */ - -/* Comparison function. Takes care of calling a user-supplied - * comparison function (any callable Python object), which must not be - * NULL (use the ISLT macro if you don't know, or call PyObject_RichCompareBool - * with Py_LT if you know it's NULL). - * Returns -1 on error, 1 if x < y, 0 if x >= y. - */ -static int -islt(PyObject *x, PyObject *y, PyObject *compare) -{ - PyObject *res; - PyObject *args; - Py_ssize_t i; - - assert(compare != NULL); - /* Call the user's comparison function and translate the 3-way - * result into true or false (or error). - */ - args = PyTuple_New(2); - if (args == NULL) - return -1; - Py_INCREF(x); - Py_INCREF(y); - PyTuple_SET_ITEM(args, 0, x); - PyTuple_SET_ITEM(args, 1, y); - res = PyObject_Call(compare, args, NULL); - Py_DECREF(args); - if (res == NULL) - return -1; - if (!PyInt_Check(res)) { - Py_DECREF(res); - PyErr_SetString(PyExc_TypeError, - "comparison function must return int"); - return -1; - } - i = PyInt_AsLong(res); - Py_DECREF(res); - return i < 0; -} - -/* If COMPARE is NULL, calls PyObject_RichCompareBool with Py_LT, else calls - * islt. This avoids a layer of function call in the usual case, and - * sorting does many comparisons. - * Returns -1 on error, 1 if x < y, 0 if x >= y. - */ -#define ISLT(X, Y, COMPARE) ((COMPARE) == NULL ? \ - PyObject_RichCompareBool(X, Y, Py_LT) : \ - islt(X, Y, COMPARE)) - -/* Compare X to Y via "<". Goto "fail" if the comparison raises an - error. Else "k" is set to true iff X<Y, and an "if (k)" block is - started. It makes more sense in context <wink>. X and Y are PyObject*s. -*/ -#define IFLT(X, Y) if ((k = ISLT(X, Y, compare)) < 0) goto fail; \ - if (k) - -/* binarysort is the best method for sorting small arrays: it does - few compares, but can do data movement quadratic in the number of - elements. - [lo, hi) is a contiguous slice of a list, and is sorted via - binary insertion. This sort is stable. - On entry, must have lo <= start <= hi, and that [lo, start) is already - sorted (pass start == lo if you don't know!). - If islt() complains return -1, else 0. - Even in case of error, the output slice will be some permutation of - the input (nothing is lost or duplicated). -*/ -static int -binarysort(PyObject **lo, PyObject **hi, PyObject **start, PyObject *compare) - /* compare -- comparison function object, or NULL for default */ -{ - register Py_ssize_t k; - register PyObject **l, **p, **r; - register PyObject *pivot; - - assert(lo <= start && start <= hi); - /* assert [lo, start) is sorted */ - if (lo == start) - ++start; - for (; start < hi; ++start) { - /* set l to where *start belongs */ - l = lo; - r = start; - pivot = *r; - /* Invariants: - * pivot >= all in [lo, l). - * pivot < all in [r, start). - * The second is vacuously true at the start. - */ - assert(l < r); - do { - p = l + ((r - l) >> 1); - IFLT(pivot, *p) - r = p; - else - l = p+1; - } while (l < r); - assert(l == r); - /* The invariants still hold, so pivot >= all in [lo, l) and - pivot < all in [l, start), so pivot belongs at l. Note - that if there are elements equal to pivot, l points to the - first slot after them -- that's why this sort is stable. - Slide over to make room. - Caution: using memmove is much slower under MSVC 5; - we're not usually moving many slots. */ - for (p = start; p > l; --p) - *p = *(p-1); - *l = pivot; - } - return 0; - - fail: - return -1; -} - -/* -Return the length of the run beginning at lo, in the slice [lo, hi). lo < hi -is required on entry. "A run" is the longest ascending sequence, with - - lo[0] <= lo[1] <= lo[2] <= ... - -or the longest descending sequence, with - - lo[0] > lo[1] > lo[2] > ... - -Boolean *descending is set to 0 in the former case, or to 1 in the latter. -For its intended use in a stable mergesort, the strictness of the defn of -"descending" is needed so that the caller can safely reverse a descending -sequence without violating stability (strict > ensures there are no equal -elements to get out of order). - -Returns -1 in case of error. -*/ -static Py_ssize_t -count_run(PyObject **lo, PyObject **hi, PyObject *compare, int *descending) -{ - Py_ssize_t k; - Py_ssize_t n; - - assert(lo < hi); - *descending = 0; - ++lo; - if (lo == hi) - return 1; - - n = 2; - IFLT(*lo, *(lo-1)) { - *descending = 1; - for (lo = lo+1; lo < hi; ++lo, ++n) { - IFLT(*lo, *(lo-1)) - ; - else - break; - } - } - else { - for (lo = lo+1; lo < hi; ++lo, ++n) { - IFLT(*lo, *(lo-1)) - break; - } - } - - return n; -fail: - return -1; -} - -/* -Locate the proper position of key in a sorted vector; if the vector contains -an element equal to key, return the position immediately to the left of -the leftmost equal element. [gallop_right() does the same except returns -the position to the right of the rightmost equal element (if any).] - -"a" is a sorted vector with n elements, starting at a[0]. n must be > 0. - -"hint" is an index at which to begin the search, 0 <= hint < n. The closer -hint is to the final result, the faster this runs. - -The return value is the int k in 0..n such that - - a[k-1] < key <= a[k] - -pretending that *(a-1) is minus infinity and a[n] is plus infinity. IOW, -key belongs at index k; or, IOW, the first k elements of a should precede -key, and the last n-k should follow key. - -Returns -1 on error. See listsort.txt for info on the method. -*/ -static Py_ssize_t -gallop_left(PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint, PyObject *compare) -{ - Py_ssize_t ofs; - Py_ssize_t lastofs; - Py_ssize_t k; - - assert(key && a && n > 0 && hint >= 0 && hint < n); - - a += hint; - lastofs = 0; - ofs = 1; - IFLT(*a, key) { - /* a[hint] < key -- gallop right, until - * a[hint + lastofs] < key <= a[hint + ofs] - */ - const Py_ssize_t maxofs = n - hint; /* &a[n-1] is highest */ - while (ofs < maxofs) { - IFLT(a[ofs], key) { - lastofs = ofs; - ofs = (ofs << 1) + 1; - if (ofs <= 0) /* int overflow */ - ofs = maxofs; - } - else /* key <= a[hint + ofs] */ - break; - } - if (ofs > maxofs) - ofs = maxofs; - /* Translate back to offsets relative to &a[0]. */ - lastofs += hint; - ofs += hint; - } - else { - /* key <= a[hint] -- gallop left, until - * a[hint - ofs] < key <= a[hint - lastofs] - */ - const Py_ssize_t maxofs = hint + 1; /* &a[0] is lowest */ - while (ofs < maxofs) { - IFLT(*(a-ofs), key) - break; - /* key <= a[hint - ofs] */ - lastofs = ofs; - ofs = (ofs << 1) + 1; - if (ofs <= 0) /* int overflow */ - ofs = maxofs; - } - if (ofs > maxofs) - ofs = maxofs; - /* Translate back to positive offsets relative to &a[0]. */ - k = lastofs; - lastofs = hint - ofs; - ofs = hint - k; - } - a -= hint; - - assert(-1 <= lastofs && lastofs < ofs && ofs <= n); - /* Now a[lastofs] < key <= a[ofs], so key belongs somewhere to the - * right of lastofs but no farther right than ofs. Do a binary - * search, with invariant a[lastofs-1] < key <= a[ofs]. - */ - ++lastofs; - while (lastofs < ofs) { - Py_ssize_t m = lastofs + ((ofs - lastofs) >> 1); - - IFLT(a[m], key) - lastofs = m+1; /* a[m] < key */ - else - ofs = m; /* key <= a[m] */ - } - assert(lastofs == ofs); /* so a[ofs-1] < key <= a[ofs] */ - return ofs; - -fail: - return -1; -} - -/* -Exactly like gallop_left(), except that if key already exists in a[0:n], -finds the position immediately to the right of the rightmost equal value. - -The return value is the int k in 0..n such that - - a[k-1] <= key < a[k] - -or -1 if error. - -The code duplication is massive, but this is enough different given that -we're sticking to "<" comparisons that it's much harder to follow if -written as one routine with yet another "left or right?" flag. -*/ -static Py_ssize_t -gallop_right(PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint, PyObject *compare) -{ - Py_ssize_t ofs; - Py_ssize_t lastofs; - Py_ssize_t k; - - assert(key && a && n > 0 && hint >= 0 && hint < n); - - a += hint; - lastofs = 0; - ofs = 1; - IFLT(key, *a) { - /* key < a[hint] -- gallop left, until - * a[hint - ofs] <= key < a[hint - lastofs] - */ - const Py_ssize_t maxofs = hint + 1; /* &a[0] is lowest */ - while (ofs < maxofs) { - IFLT(key, *(a-ofs)) { - lastofs = ofs; - ofs = (ofs << 1) + 1; - if (ofs <= 0) /* int overflow */ - ofs = maxofs; - } - else /* a[hint - ofs] <= key */ - break; - } - if (ofs > maxofs) - ofs = maxofs; - /* Translate back to positive offsets relative to &a[0]. */ - k = lastofs; - lastofs = hint - ofs; - ofs = hint - k; - } - else { - /* a[hint] <= key -- gallop right, until - * a[hint + lastofs] <= key < a[hint + ofs] - */ - const Py_ssize_t maxofs = n - hint; /* &a[n-1] is highest */ - while (ofs < maxofs) { - IFLT(key, a[ofs]) - break; - /* a[hint + ofs] <= key */ - lastofs = ofs; - ofs = (ofs << 1) + 1; - if (ofs <= 0) /* int overflow */ - ofs = maxofs; - } - if (ofs > maxofs) - ofs = maxofs; - /* Translate back to offsets relative to &a[0]. */ - lastofs += hint; - ofs += hint; - } - a -= hint; - - assert(-1 <= lastofs && lastofs < ofs && ofs <= n); - /* Now a[lastofs] <= key < a[ofs], so key belongs somewhere to the - * right of lastofs but no farther right than ofs. Do a binary - * search, with invariant a[lastofs-1] <= key < a[ofs]. - */ - ++lastofs; - while (lastofs < ofs) { - Py_ssize_t m = lastofs + ((ofs - lastofs) >> 1); - - IFLT(key, a[m]) - ofs = m; /* key < a[m] */ - else - lastofs = m+1; /* a[m] <= key */ - } - assert(lastofs == ofs); /* so a[ofs-1] <= key < a[ofs] */ - return ofs; - -fail: - return -1; -} - -/* The maximum number of entries in a MergeState's pending-runs stack. - * This is enough to sort arrays of size up to about - * 32 * phi ** MAX_MERGE_PENDING - * where phi ~= 1.618. 85 is ridiculouslylarge enough, good for an array - * with 2**64 elements. - */ -#define MAX_MERGE_PENDING 85 - -/* When we get into galloping mode, we stay there until both runs win less - * often than MIN_GALLOP consecutive times. See listsort.txt for more info. - */ -#define MIN_GALLOP 7 - -/* Avoid malloc for small temp arrays. */ -#define MERGESTATE_TEMP_SIZE 256 - -/* One MergeState exists on the stack per invocation of mergesort. It's just - * a convenient way to pass state around among the helper functions. - */ -struct s_slice { - PyObject **base; - Py_ssize_t len; -}; - -typedef struct s_MergeState { - /* The user-supplied comparison function. or NULL if none given. */ - PyObject *compare; - - /* This controls when we get *into* galloping mode. It's initialized - * to MIN_GALLOP. merge_lo and merge_hi tend to nudge it higher for - * random data, and lower for highly structured data. - */ - Py_ssize_t min_gallop; - - /* 'a' is temp storage to help with merges. It contains room for - * alloced entries. - */ - PyObject **a; /* may point to temparray below */ - Py_ssize_t alloced; - - /* A stack of n pending runs yet to be merged. Run #i starts at - * address base[i] and extends for len[i] elements. It's always - * true (so long as the indices are in bounds) that - * - * pending[i].base + pending[i].len == pending[i+1].base - * - * so we could cut the storage for this, but it's a minor amount, - * and keeping all the info explicit simplifies the code. - */ - int n; - struct s_slice pending[MAX_MERGE_PENDING]; - - /* 'a' points to this when possible, rather than muck with malloc. */ - PyObject *temparray[MERGESTATE_TEMP_SIZE]; -} MergeState; - -/* Conceptually a MergeState's constructor. */ -static void -merge_init(MergeState *ms, PyObject *compare) -{ - assert(ms != NULL); - ms->compare = compare; - ms->a = ms->temparray; - ms->alloced = MERGESTATE_TEMP_SIZE; - ms->n = 0; - ms->min_gallop = MIN_GALLOP; -} - -/* Free all the temp memory owned by the MergeState. This must be called - * when you're done with a MergeState, and may be called before then if - * you want to free the temp memory early. - */ -static void -merge_freemem(MergeState *ms) -{ - assert(ms != NULL); - if (ms->a != ms->temparray) - PyMem_Free(ms->a); - ms->a = ms->temparray; - ms->alloced = MERGESTATE_TEMP_SIZE; -} - -/* Ensure enough temp memory for 'need' array slots is available. - * Returns 0 on success and -1 if the memory can't be gotten. - */ -static int -merge_getmem(MergeState *ms, Py_ssize_t need) -{ - assert(ms != NULL); - if (need <= ms->alloced) - return 0; - /* Don't realloc! That can cost cycles to copy the old data, but - * we don't care what's in the block. - */ - merge_freemem(ms); - ms->a = (PyObject **)PyMem_Malloc(need * sizeof(PyObject*)); - if (ms->a) { - ms->alloced = need; - return 0; - } - PyErr_NoMemory(); - merge_freemem(ms); /* reset to sane state */ - return -1; -} -#define MERGE_GETMEM(MS, NEED) ((NEED) <= (MS)->alloced ? 0 : \ - merge_getmem(MS, NEED)) - -/* Merge the na elements starting at pa with the nb elements starting at pb - * in a stable way, in-place. na and nb must be > 0, and pa + na == pb. - * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the - * merge, and should have na <= nb. See listsort.txt for more info. - * Return 0 if successful, -1 if error. - */ -static Py_ssize_t -merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, - PyObject **pb, Py_ssize_t nb) -{ - Py_ssize_t k; - PyObject *compare; - PyObject **dest; - int result = -1; /* guilty until proved innocent */ - Py_ssize_t min_gallop = ms->min_gallop; - - assert(ms && pa && pb && na > 0 && nb > 0 && pa + na == pb); - if (MERGE_GETMEM(ms, na) < 0) - return -1; - memcpy(ms->a, pa, na * sizeof(PyObject*)); - dest = pa; - pa = ms->a; - - *dest++ = *pb++; - --nb; - if (nb == 0) - goto Succeed; - if (na == 1) - goto CopyB; - - compare = ms->compare; - for (;;) { - Py_ssize_t acount = 0; /* # of times A won in a row */ - Py_ssize_t bcount = 0; /* # of times B won in a row */ - - /* Do the straightforward thing until (if ever) one run - * appears to win consistently. - */ - for (;;) { - assert(na > 1 && nb > 0); - k = ISLT(*pb, *pa, compare); - if (k) { - if (k < 0) - goto Fail; - *dest++ = *pb++; - ++bcount; - acount = 0; - --nb; - if (nb == 0) - goto Succeed; - if (bcount >= min_gallop) - break; - } - else { - *dest++ = *pa++; - ++acount; - bcount = 0; - --na; - if (na == 1) - goto CopyB; - if (acount >= min_gallop) - break; - } - } - - /* One run is winning so consistently that galloping may - * be a huge win. So try that, and continue galloping until - * (if ever) neither run appears to be winning consistently - * anymore. - */ - ++min_gallop; - do { - assert(na > 1 && nb > 0); - min_gallop -= min_gallop > 1; - ms->min_gallop = min_gallop; - k = gallop_right(*pb, pa, na, 0, compare); - acount = k; - if (k) { - if (k < 0) - goto Fail; - memcpy(dest, pa, k * sizeof(PyObject *)); - dest += k; - pa += k; - na -= k; - if (na == 1) - goto CopyB; - /* na==0 is impossible now if the comparison - * function is consistent, but we can't assume - * that it is. - */ - if (na == 0) - goto Succeed; - } - *dest++ = *pb++; - --nb; - if (nb == 0) - goto Succeed; - - k = gallop_left(*pa, pb, nb, 0, compare); - bcount = k; - if (k) { - if (k < 0) - goto Fail; - memmove(dest, pb, k * sizeof(PyObject *)); - dest += k; - pb += k; - nb -= k; - if (nb == 0) - goto Succeed; - } - *dest++ = *pa++; - --na; - if (na == 1) - goto CopyB; - } while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP); - ++min_gallop; /* penalize it for leaving galloping mode */ - ms->min_gallop = min_gallop; - } -Succeed: - result = 0; -Fail: - if (na) - memcpy(dest, pa, na * sizeof(PyObject*)); - return result; -CopyB: - assert(na == 1 && nb > 0); - /* The last element of pa belongs at the end of the merge. */ - memmove(dest, pb, nb * sizeof(PyObject *)); - dest[nb] = *pa; - return 0; -} - -/* Merge the na elements starting at pa with the nb elements starting at pb - * in a stable way, in-place. na and nb must be > 0, and pa + na == pb. - * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the - * merge, and should have na >= nb. See listsort.txt for more info. - * Return 0 if successful, -1 if error. - */ -static Py_ssize_t -merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t nb) -{ - Py_ssize_t k; - PyObject *compare; - PyObject **dest; - int result = -1; /* guilty until proved innocent */ - PyObject **basea; - PyObject **baseb; - Py_ssize_t min_gallop = ms->min_gallop; - - assert(ms && pa && pb && na > 0 && nb > 0 && pa + na == pb); - if (MERGE_GETMEM(ms, nb) < 0) - return -1; - dest = pb + nb - 1; - memcpy(ms->a, pb, nb * sizeof(PyObject*)); - basea = pa; - baseb = ms->a; - pb = ms->a + nb - 1; - pa += na - 1; - - *dest-- = *pa--; - --na; - if (na == 0) - goto Succeed; - if (nb == 1) - goto CopyA; - - compare = ms->compare; - for (;;) { - Py_ssize_t acount = 0; /* # of times A won in a row */ - Py_ssize_t bcount = 0; /* # of times B won in a row */ - - /* Do the straightforward thing until (if ever) one run - * appears to win consistently. - */ - for (;;) { - assert(na > 0 && nb > 1); - k = ISLT(*pb, *pa, compare); - if (k) { - if (k < 0) - goto Fail; - *dest-- = *pa--; - ++acount; - bcount = 0; - --na; - if (na == 0) - goto Succeed; - if (acount >= min_gallop) - break; - } - else { - *dest-- = *pb--; - ++bcount; - acount = 0; - --nb; - if (nb == 1) - goto CopyA; - if (bcount >= min_gallop) - break; - } - } - - /* One run is winning so consistently that galloping may - * be a huge win. So try that, and continue galloping until - * (if ever) neither run appears to be winning consistently - * anymore. - */ - ++min_gallop; - do { - assert(na > 0 && nb > 1); - min_gallop -= min_gallop > 1; - ms->min_gallop = min_gallop; - k = gallop_right(*pb, basea, na, na-1, compare); - if (k < 0) - goto Fail; - k = na - k; - acount = k; - if (k) { - dest -= k; - pa -= k; - memmove(dest+1, pa+1, k * sizeof(PyObject *)); - na -= k; - if (na == 0) - goto Succeed; - } - *dest-- = *pb--; - --nb; - if (nb == 1) - goto CopyA; - - k = gallop_left(*pa, baseb, nb, nb-1, compare); - if (k < 0) - goto Fail; - k = nb - k; - bcount = k; - if (k) { - dest -= k; - pb -= k; - memcpy(dest+1, pb+1, k * sizeof(PyObject *)); - nb -= k; - if (nb == 1) - goto CopyA; - /* nb==0 is impossible now if the comparison - * function is consistent, but we can't assume - * that it is. - */ - if (nb == 0) - goto Succeed; - } - *dest-- = *pa--; - --na; - if (na == 0) - goto Succeed; - } while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP); - ++min_gallop; /* penalize it for leaving galloping mode */ - ms->min_gallop = min_gallop; - } -Succeed: - result = 0; -Fail: - if (nb) - memcpy(dest-(nb-1), baseb, nb * sizeof(PyObject*)); - return result; -CopyA: - assert(nb == 1 && na > 0); - /* The first element of pb belongs at the front of the merge. */ - dest -= na; - pa -= na; - memmove(dest+1, pa+1, na * sizeof(PyObject *)); - *dest = *pb; - return 0; -} - -/* Merge the two runs at stack indices i and i+1. - * Returns 0 on success, -1 on error. - */ -static Py_ssize_t -merge_at(MergeState *ms, Py_ssize_t i) -{ - PyObject **pa, **pb; - Py_ssize_t na, nb; - Py_ssize_t k; - PyObject *compare; - - assert(ms != NULL); - assert(ms->n >= 2); - assert(i >= 0); - assert(i == ms->n - 2 || i == ms->n - 3); - - pa = ms->pending[i].base; - na = ms->pending[i].len; - pb = ms->pending[i+1].base; - nb = ms->pending[i+1].len; - assert(na > 0 && nb > 0); - assert(pa + na == pb); - - /* Record the length of the combined runs; if i is the 3rd-last - * run now, also slide over the last run (which isn't involved - * in this merge). The current run i+1 goes away in any case. - */ - ms->pending[i].len = na + nb; - if (i == ms->n - 3) - ms->pending[i+1] = ms->pending[i+2]; - --ms->n; - - /* Where does b start in a? Elements in a before that can be - * ignored (already in place). - */ - compare = ms->compare; - k = gallop_right(*pb, pa, na, 0, compare); - if (k < 0) - return -1; - pa += k; - na -= k; - if (na == 0) - return 0; - - /* Where does a end in b? Elements in b after that can be - * ignored (already in place). - */ - nb = gallop_left(pa[na-1], pb, nb, nb-1, compare); - if (nb <= 0) - return nb; - - /* Merge what remains of the runs, using a temp array with - * min(na, nb) elements. - */ - if (na <= nb) - return merge_lo(ms, pa, na, pb, nb); - else - return merge_hi(ms, pa, na, pb, nb); -} - -/* Examine the stack of runs waiting to be merged, merging adjacent runs - * until the stack invariants are re-established: - * - * 1. len[-3] > len[-2] + len[-1] - * 2. len[-2] > len[-1] - * - * See listsort.txt for more info. - * - * Returns 0 on success, -1 on error. - */ -static int -merge_collapse(MergeState *ms) -{ - struct s_slice *p = ms->pending; - - assert(ms); - while (ms->n > 1) { - Py_ssize_t n = ms->n - 2; - if (n > 0 && p[n-1].len <= p[n].len + p[n+1].len) { - if (p[n-1].len < p[n+1].len) - --n; - if (merge_at(ms, n) < 0) - return -1; - } - else if (p[n].len <= p[n+1].len) { - if (merge_at(ms, n) < 0) - return -1; - } - else - break; - } - return 0; -} - -/* Regardless of invariants, merge all runs on the stack until only one - * remains. This is used at the end of the mergesort. - * - * Returns 0 on success, -1 on error. - */ -static int -merge_force_collapse(MergeState *ms) -{ - struct s_slice *p = ms->pending; - - assert(ms); - while (ms->n > 1) { - Py_ssize_t n = ms->n - 2; - if (n > 0 && p[n-1].len < p[n+1].len) - --n; - if (merge_at(ms, n) < 0) - return -1; - } - return 0; -} - -/* Compute a good value for the minimum run length; natural runs shorter - * than this are boosted artificially via binary insertion. - * - * If n < 64, return n (it's too small to bother with fancy stuff). - * Else if n is an exact power of 2, return 32. - * Else return an int k, 32 <= k <= 64, such that n/k is close to, but - * strictly less than, an exact power of 2. - * - * See listsort.txt for more info. - */ -static Py_ssize_t -merge_compute_minrun(Py_ssize_t n) -{ - Py_ssize_t r = 0; /* becomes 1 if any 1 bits are shifted off */ - - assert(n >= 0); - while (n >= 64) { - r |= n & 1; - n >>= 1; - } - return n + r; -} - -/* Special wrapper to support stable sorting using the decorate-sort-undecorate - pattern. Holds a key which is used for comparisons and the original record - which is returned during the undecorate phase. By exposing only the key - during comparisons, the underlying sort stability characteristics are left - unchanged. Also, if a custom comparison function is used, it will only see - the key instead of a full record. */ - -typedef struct { - PyObject_HEAD - PyObject *key; - PyObject *value; -} sortwrapperobject; - -PyDoc_STRVAR(sortwrapper_doc, "Object wrapper with a custom sort key."); -static PyObject * -sortwrapper_richcompare(sortwrapperobject *, sortwrapperobject *, int); -static void -sortwrapper_dealloc(sortwrapperobject *); - -static PyTypeObject sortwrapper_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "sortwrapper", /* tp_name */ - sizeof(sortwrapperobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)sortwrapper_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_HAVE_RICHCOMPARE, /* tp_flags */ - sortwrapper_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)sortwrapper_richcompare, /* tp_richcompare */ -}; - - -static PyObject * -sortwrapper_richcompare(sortwrapperobject *a, sortwrapperobject *b, int op) -{ - if (!PyObject_TypeCheck(b, &sortwrapper_type)) { - PyErr_SetString(PyExc_TypeError, - "expected a sortwrapperobject"); - return NULL; - } - return PyObject_RichCompare(a->key, b->key, op); -} - -static void -sortwrapper_dealloc(sortwrapperobject *so) -{ - Py_XDECREF(so->key); - Py_XDECREF(so->value); - PyObject_Del(so); -} - -/* Returns a new reference to a sortwrapper. - Consumes the references to the two underlying objects. */ - -static PyObject * -build_sortwrapper(PyObject *key, PyObject *value) -{ - sortwrapperobject *so; - - so = PyObject_New(sortwrapperobject, &sortwrapper_type); - if (so == NULL) - return NULL; - so->key = key; - so->value = value; - return (PyObject *)so; -} - -/* Returns a new reference to the value underlying the wrapper. */ -static PyObject * -sortwrapper_getvalue(PyObject *so) -{ - PyObject *value; - - if (!PyObject_TypeCheck(so, &sortwrapper_type)) { - PyErr_SetString(PyExc_TypeError, - "expected a sortwrapperobject"); - return NULL; - } - value = ((sortwrapperobject *)so)->value; - Py_INCREF(value); - return value; -} - -/* Wrapper for user specified cmp functions in combination with a - specified key function. Makes sure the cmp function is presented - with the actual key instead of the sortwrapper */ - -typedef struct { - PyObject_HEAD - PyObject *func; -} cmpwrapperobject; - -static void -cmpwrapper_dealloc(cmpwrapperobject *co) -{ - Py_XDECREF(co->func); - PyObject_Del(co); -} - -static PyObject * -cmpwrapper_call(cmpwrapperobject *co, PyObject *args, PyObject *kwds) -{ - PyObject *x, *y, *xx, *yy; - - if (!PyArg_UnpackTuple(args, "", 2, 2, &x, &y)) - return NULL; - if (!PyObject_TypeCheck(x, &sortwrapper_type) || - !PyObject_TypeCheck(y, &sortwrapper_type)) { - PyErr_SetString(PyExc_TypeError, - "expected a sortwrapperobject"); - return NULL; - } - xx = ((sortwrapperobject *)x)->key; - yy = ((sortwrapperobject *)y)->key; - return PyObject_CallFunctionObjArgs(co->func, xx, yy, NULL); -} - -PyDoc_STRVAR(cmpwrapper_doc, "cmp() wrapper for sort with custom keys."); - -static PyTypeObject cmpwrapper_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "cmpwrapper", /* tp_name */ - sizeof(cmpwrapperobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)cmpwrapper_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 */ - (ternaryfunc)cmpwrapper_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - cmpwrapper_doc, /* tp_doc */ -}; - -static PyObject * -build_cmpwrapper(PyObject *cmpfunc) -{ - cmpwrapperobject *co; - - co = PyObject_New(cmpwrapperobject, &cmpwrapper_type); - if (co == NULL) - return NULL; - Py_INCREF(cmpfunc); - co->func = cmpfunc; - return (PyObject *)co; -} - -/* An adaptive, stable, natural mergesort. See listsort.txt. - * Returns Py_None on success, NULL on error. Even in case of error, the - * list will be some permutation of its input state (nothing is lost or - * duplicated). - */ -static PyObject * -listsort(PyListObject *self, PyObject *args, PyObject *kwds) -{ - MergeState ms; - PyObject **lo, **hi; - Py_ssize_t nremaining; - Py_ssize_t minrun; - Py_ssize_t saved_ob_size, saved_allocated; - PyObject **saved_ob_item; - PyObject **final_ob_item; - PyObject *compare = NULL; - PyObject *result = NULL; /* guilty until proved innocent */ - int reverse = 0; - PyObject *keyfunc = NULL; - Py_ssize_t i; - PyObject *key, *value, *kvpair; - static char *kwlist[] = {"cmp", "key", "reverse", 0}; - - assert(self != NULL); - assert (PyList_Check(self)); - if (args != NULL) { - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:sort", - kwlist, &compare, &keyfunc, &reverse)) - return NULL; - } - if (compare == Py_None) - compare = NULL; - if (keyfunc == Py_None) - keyfunc = NULL; - if (compare != NULL && keyfunc != NULL) { - compare = build_cmpwrapper(compare); - if (compare == NULL) - return NULL; - } else - Py_XINCREF(compare); - - /* The list is temporarily made empty, so that mutations performed - * by comparison functions can't affect the slice of memory we're - * sorting (allowing mutations during sorting is a core-dump - * factory, since ob_item may change). - */ - saved_ob_size = self->ob_size; - saved_ob_item = self->ob_item; - saved_allocated = self->allocated; - self->ob_size = 0; - self->ob_item = NULL; - self->allocated = -1; /* any operation will reset it to >= 0 */ - - if (keyfunc != NULL) { - for (i=0 ; i < saved_ob_size ; i++) { - value = saved_ob_item[i]; - key = PyObject_CallFunctionObjArgs(keyfunc, value, - NULL); - if (key == NULL) { - for (i=i-1 ; i>=0 ; i--) { - kvpair = saved_ob_item[i]; - value = sortwrapper_getvalue(kvpair); - saved_ob_item[i] = value; - Py_DECREF(kvpair); - } - goto dsu_fail; - } - kvpair = build_sortwrapper(key, value); - if (kvpair == NULL) - goto dsu_fail; - saved_ob_item[i] = kvpair; - } - } - - /* Reverse sort stability achieved by initially reversing the list, - applying a stable forward sort, then reversing the final result. */ - if (reverse && saved_ob_size > 1) - reverse_slice(saved_ob_item, saved_ob_item + saved_ob_size); - - merge_init(&ms, compare); - - nremaining = saved_ob_size; - if (nremaining < 2) - goto succeed; - - /* March over the array once, left to right, finding natural runs, - * and extending short natural runs to minrun elements. - */ - lo = saved_ob_item; - hi = lo + nremaining; - minrun = merge_compute_minrun(nremaining); - do { - int descending; - Py_ssize_t n; - - /* Identify next run. */ - n = count_run(lo, hi, compare, &descending); - if (n < 0) - goto fail; - if (descending) - reverse_slice(lo, lo + n); - /* If short, extend to min(minrun, nremaining). */ - if (n < minrun) { - const Py_ssize_t force = nremaining <= minrun ? - nremaining : minrun; - if (binarysort(lo, lo + force, lo + n, compare) < 0) - goto fail; - n = force; - } - /* Push run onto pending-runs stack, and maybe merge. */ - assert(ms.n < MAX_MERGE_PENDING); - ms.pending[ms.n].base = lo; - ms.pending[ms.n].len = n; - ++ms.n; - if (merge_collapse(&ms) < 0) - goto fail; - /* Advance to find next run. */ - lo += n; - nremaining -= n; - } while (nremaining); - assert(lo == hi); - - if (merge_force_collapse(&ms) < 0) - goto fail; - assert(ms.n == 1); - assert(ms.pending[0].base == saved_ob_item); - assert(ms.pending[0].len == saved_ob_size); - -succeed: - result = Py_None; -fail: - if (keyfunc != NULL) { - for (i=0 ; i < saved_ob_size ; i++) { - kvpair = saved_ob_item[i]; - value = sortwrapper_getvalue(kvpair); - saved_ob_item[i] = value; - Py_DECREF(kvpair); - } - } - - if (self->allocated != -1 && result != NULL) { - /* The user mucked with the list during the sort, - * and we don't already have another error to report. - */ - PyErr_SetString(PyExc_ValueError, "list modified during sort"); - result = NULL; - } - - if (reverse && saved_ob_size > 1) - reverse_slice(saved_ob_item, saved_ob_item + saved_ob_size); - - merge_freemem(&ms); - -dsu_fail: - final_ob_item = self->ob_item; - i = self->ob_size; - self->ob_size = saved_ob_size; - self->ob_item = saved_ob_item; - self->allocated = saved_allocated; - if (final_ob_item != NULL) { - /* we cannot use list_clear() for this because it does not - guarantee that the list is really empty when it returns */ - while (--i >= 0) { - Py_XDECREF(final_ob_item[i]); - } - PyMem_FREE(final_ob_item); - } - Py_XDECREF(compare); - Py_XINCREF(result); - return result; -} -#undef IFLT -#undef ISLT - -int -PyList_Sort(PyObject *v) -{ - if (v == NULL || !PyList_Check(v)) { - PyErr_BadInternalCall(); - return -1; - } - v = listsort((PyListObject *)v, (PyObject *)NULL, (PyObject *)NULL); - if (v == NULL) - return -1; - Py_DECREF(v); - return 0; -} - -static PyObject * -listreverse(PyListObject *self) -{ - if (self->ob_size > 1) - reverse_slice(self->ob_item, self->ob_item + self->ob_size); - Py_RETURN_NONE; -} - -int -PyList_Reverse(PyObject *v) -{ - PyListObject *self = (PyListObject *)v; - - if (v == NULL || !PyList_Check(v)) { - PyErr_BadInternalCall(); - return -1; - } - if (self->ob_size > 1) - reverse_slice(self->ob_item, self->ob_item + self->ob_size); - return 0; -} - -PyObject * -PyList_AsTuple(PyObject *v) -{ - PyObject *w; - PyObject **p; - Py_ssize_t n; - if (v == NULL || !PyList_Check(v)) { - PyErr_BadInternalCall(); - return NULL; - } - n = ((PyListObject *)v)->ob_size; - w = PyTuple_New(n); - if (w == NULL) - return NULL; - p = ((PyTupleObject *)w)->ob_item; - memcpy((void *)p, - (void *)((PyListObject *)v)->ob_item, - n*sizeof(PyObject *)); - while (--n >= 0) { - Py_INCREF(*p); - p++; - } - return w; -} - -static PyObject * -listindex(PyListObject *self, PyObject *args) -{ - Py_ssize_t i, start=0, stop=self->ob_size; - PyObject *v; - - if (!PyArg_ParseTuple(args, "O|O&O&:index", &v, - _PyEval_SliceIndex, &start, - _PyEval_SliceIndex, &stop)) - return NULL; - if (start < 0) { - start += self->ob_size; - if (start < 0) - start = 0; - } - if (stop < 0) { - stop += self->ob_size; - if (stop < 0) - stop = 0; - } - for (i = start; i < stop && i < self->ob_size; i++) { - int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ); - if (cmp > 0) - return PyInt_FromSsize_t(i); - else if (cmp < 0) - return NULL; - } - PyErr_SetString(PyExc_ValueError, "list.index(x): x not in list"); - return NULL; -} - -static PyObject * -listcount(PyListObject *self, PyObject *v) -{ - Py_ssize_t count = 0; - Py_ssize_t i; - - for (i = 0; i < self->ob_size; i++) { - int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ); - if (cmp > 0) - count++; - else if (cmp < 0) - return NULL; - } - return PyInt_FromSsize_t(count); -} - -static PyObject * -listremove(PyListObject *self, PyObject *v) -{ - Py_ssize_t i; - - for (i = 0; i < self->ob_size; i++) { - int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ); - if (cmp > 0) { - if (list_ass_slice(self, i, i+1, - (PyObject *)NULL) == 0) - Py_RETURN_NONE; - return NULL; - } - else if (cmp < 0) - return NULL; - } - PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list"); - return NULL; -} - -static int -list_traverse(PyListObject *o, visitproc visit, void *arg) -{ - Py_ssize_t i; - - for (i = o->ob_size; --i >= 0; ) - Py_VISIT(o->ob_item[i]); - return 0; -} - -static PyObject * -list_richcompare(PyObject *v, PyObject *w, int op) -{ - PyListObject *vl, *wl; - Py_ssize_t i; - - if (!PyList_Check(v) || !PyList_Check(w)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - vl = (PyListObject *)v; - wl = (PyListObject *)w; - - if (vl->ob_size != wl->ob_size && (op == Py_EQ || op == Py_NE)) { - /* Shortcut: if the lengths differ, the lists differ */ - PyObject *res; - if (op == Py_EQ) - res = Py_False; - else - res = Py_True; - Py_INCREF(res); - return res; - } - - /* Search for the first index where items are different */ - for (i = 0; i < vl->ob_size && i < wl->ob_size; i++) { - int k = PyObject_RichCompareBool(vl->ob_item[i], - wl->ob_item[i], Py_EQ); - if (k < 0) - return NULL; - if (!k) - break; - } - - if (i >= vl->ob_size || i >= wl->ob_size) { - /* No more items to compare -- compare sizes */ - Py_ssize_t vs = vl->ob_size; - Py_ssize_t ws = wl->ob_size; - int cmp; - PyObject *res; - switch (op) { - case Py_LT: cmp = vs < ws; break; - case Py_LE: cmp = vs <= ws; break; - case Py_EQ: cmp = vs == ws; break; - case Py_NE: cmp = vs != ws; break; - case Py_GT: cmp = vs > ws; break; - case Py_GE: cmp = vs >= ws; break; - default: return NULL; /* cannot happen */ - } - if (cmp) - res = Py_True; - else - res = Py_False; - Py_INCREF(res); - return res; - } - - /* We have an item that differs -- shortcuts for EQ/NE */ - if (op == Py_EQ) { - Py_INCREF(Py_False); - return Py_False; - } - if (op == Py_NE) { - Py_INCREF(Py_True); - return Py_True; - } - - /* Compare the final item again using the proper operator */ - return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op); -} - -static int -list_init(PyListObject *self, PyObject *args, PyObject *kw) -{ - PyObject *arg = NULL; - static char *kwlist[] = {"sequence", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:list", kwlist, &arg)) - return -1; - - /* Verify list invariants established by PyType_GenericAlloc() */ - assert(0 <= self->ob_size); - assert(self->ob_size <= self->allocated || self->allocated == -1); - assert(self->ob_item != NULL || - self->allocated == 0 || self->allocated == -1); - - /* Empty previous contents */ - if (self->ob_item != NULL) { - (void)list_clear(self); - } - if (arg != NULL) { - PyObject *rv = listextend(self, arg); - if (rv == NULL) - return -1; - Py_DECREF(rv); - } - return 0; -} - -static long -list_nohash(PyObject *self) -{ - PyErr_SetString(PyExc_TypeError, "list objects are unhashable"); - return -1; -} - -static PyObject *list_iter(PyObject *seq); -static PyObject *list_reversed(PyListObject* seq, PyObject* unused); - -PyDoc_STRVAR(getitem_doc, -"x.__getitem__(y) <==> x[y]"); -PyDoc_STRVAR(reversed_doc, -"L.__reversed__() -- return a reverse iterator over the list"); -PyDoc_STRVAR(append_doc, -"L.append(object) -- append object to end"); -PyDoc_STRVAR(extend_doc, -"L.extend(iterable) -- extend list by appending elements from the iterable"); -PyDoc_STRVAR(insert_doc, -"L.insert(index, object) -- insert object before index"); -PyDoc_STRVAR(pop_doc, -"L.pop([index]) -> item -- remove and return item at index (default last)"); -PyDoc_STRVAR(remove_doc, -"L.remove(value) -- remove first occurrence of value"); -PyDoc_STRVAR(index_doc, -"L.index(value, [start, [stop]]) -> integer -- return first index of value"); -PyDoc_STRVAR(count_doc, -"L.count(value) -> integer -- return number of occurrences of value"); -PyDoc_STRVAR(reverse_doc, -"L.reverse() -- reverse *IN PLACE*"); -PyDoc_STRVAR(sort_doc, -"L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;\n\ -cmp(x, y) -> -1, 0, 1"); - -static PyObject *list_subscript(PyListObject*, PyObject*); - -static PyMethodDef list_methods[] = { - {"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST, getitem_doc}, - {"__reversed__",(PyCFunction)list_reversed, METH_NOARGS, reversed_doc}, - {"append", (PyCFunction)listappend, METH_O, append_doc}, - {"insert", (PyCFunction)listinsert, METH_VARARGS, insert_doc}, - {"extend", (PyCFunction)listextend, METH_O, extend_doc}, - {"pop", (PyCFunction)listpop, METH_VARARGS, pop_doc}, - {"remove", (PyCFunction)listremove, METH_O, remove_doc}, - {"index", (PyCFunction)listindex, METH_VARARGS, index_doc}, - {"count", (PyCFunction)listcount, METH_O, count_doc}, - {"reverse", (PyCFunction)listreverse, METH_NOARGS, reverse_doc}, - {"sort", (PyCFunction)listsort, METH_VARARGS | METH_KEYWORDS, sort_doc}, - {NULL, NULL} /* sentinel */ -}; - -static PySequenceMethods list_as_sequence = { - (lenfunc)list_length, /* sq_length */ - (binaryfunc)list_concat, /* sq_concat */ - (ssizeargfunc)list_repeat, /* sq_repeat */ - (ssizeargfunc)list_item, /* sq_item */ - (ssizessizeargfunc)list_slice, /* sq_slice */ - (ssizeobjargproc)list_ass_item, /* sq_ass_item */ - (ssizessizeobjargproc)list_ass_slice, /* sq_ass_slice */ - (objobjproc)list_contains, /* sq_contains */ - (binaryfunc)list_inplace_concat, /* sq_inplace_concat */ - (ssizeargfunc)list_inplace_repeat, /* sq_inplace_repeat */ -}; - -PyDoc_STRVAR(list_doc, -"list() -> new list\n" -"list(sequence) -> new list initialized from sequence's items"); - - -static PyObject * -list_subscript(PyListObject* self, PyObject* item) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i; - i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += PyList_GET_SIZE(self); - return list_item(self, i); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength, cur, i; - PyObject* result; - PyObject* it; - PyObject **src, **dest; - - if (PySlice_GetIndicesEx((PySliceObject*)item, self->ob_size, - &start, &stop, &step, &slicelength) < 0) { - return NULL; - } - - if (slicelength <= 0) { - return PyList_New(0); - } - else { - result = PyList_New(slicelength); - if (!result) return NULL; - - src = self->ob_item; - dest = ((PyListObject *)result)->ob_item; - for (cur = start, i = 0; i < slicelength; - cur += step, i++) { - it = src[cur]; - Py_INCREF(it); - dest[i] = it; - } - - return result; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "list indices must be integers"); - return NULL; - } -} - -static int -list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return -1; - if (i < 0) - i += PyList_GET_SIZE(self); - return list_ass_item(self, i, value); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)item, self->ob_size, - &start, &stop, &step, &slicelength) < 0) { - return -1; - } - - /* treat L[slice(a,b)] = v _exactly_ like L[a:b] = v */ - if (step == 1 && ((PySliceObject*)item)->step == Py_None) - return list_ass_slice(self, start, stop, value); - - if (value == NULL) { - /* delete slice */ - PyObject **garbage; - Py_ssize_t cur, i; - - if (slicelength <= 0) - return 0; - - if (step < 0) { - stop = start + 1; - start = stop + step*(slicelength - 1) - 1; - step = -step; - } - - garbage = (PyObject**) - PyMem_MALLOC(slicelength*sizeof(PyObject*)); - if (!garbage) { - PyErr_NoMemory(); - return -1; - } - - /* drawing pictures might help - understand these for loops */ - for (cur = start, i = 0; - cur < stop; - cur += step, i++) { - Py_ssize_t lim = step; - - garbage[i] = PyList_GET_ITEM(self, cur); - - if (cur + step >= self->ob_size) { - lim = self->ob_size - cur - 1; - } - - memmove(self->ob_item + cur - i, - self->ob_item + cur + 1, - lim * sizeof(PyObject *)); - } - - for (cur = start + slicelength*step + 1; - cur < self->ob_size; cur++) { - PyList_SET_ITEM(self, cur - slicelength, - PyList_GET_ITEM(self, cur)); - } - - self->ob_size -= slicelength; - list_resize(self, self->ob_size); - - for (i = 0; i < slicelength; i++) { - Py_DECREF(garbage[i]); - } - PyMem_FREE(garbage); - - return 0; - } - else { - /* assign slice */ - PyObject **garbage, *ins, *seq, **seqitems, **selfitems; - Py_ssize_t cur, i; - - /* protect against a[::-1] = a */ - if (self == (PyListObject*)value) { - seq = list_slice((PyListObject*)value, 0, - PyList_GET_SIZE(value)); - } - else { - seq = PySequence_Fast(value, - "must assign iterable to extended slice"); - } - if (!seq) - return -1; - - if (PySequence_Fast_GET_SIZE(seq) != slicelength) { - PyErr_Format(PyExc_ValueError, - "attempt to assign sequence of size %zd to extended slice of size %zd", - PySequence_Fast_GET_SIZE(seq), - slicelength); - Py_DECREF(seq); - return -1; - } - - if (!slicelength) { - Py_DECREF(seq); - return 0; - } - - garbage = (PyObject**) - PyMem_MALLOC(slicelength*sizeof(PyObject*)); - if (!garbage) { - Py_DECREF(seq); - PyErr_NoMemory(); - return -1; - } - - selfitems = self->ob_item; - seqitems = PySequence_Fast_ITEMS(seq); - for (cur = start, i = 0; i < slicelength; - cur += step, i++) { - garbage[i] = selfitems[cur]; - ins = seqitems[i]; - Py_INCREF(ins); - selfitems[cur] = ins; - } - - for (i = 0; i < slicelength; i++) { - Py_DECREF(garbage[i]); - } - - PyMem_FREE(garbage); - Py_DECREF(seq); - - return 0; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "list indices must be integers"); - return -1; - } -} - -static PyMappingMethods list_as_mapping = { - (lenfunc)list_length, - (binaryfunc)list_subscript, - (objobjargproc)list_ass_subscript -}; - -PyTypeObject PyList_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "list", - sizeof(PyListObject), - 0, - (destructor)list_dealloc, /* tp_dealloc */ - (printfunc)list_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)list_repr, /* tp_repr */ - 0, /* tp_as_number */ - &list_as_sequence, /* tp_as_sequence */ - &list_as_mapping, /* tp_as_mapping */ - list_nohash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - list_doc, /* tp_doc */ - (traverseproc)list_traverse, /* tp_traverse */ - (inquiry)list_clear, /* tp_clear */ - list_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - list_iter, /* tp_iter */ - 0, /* tp_iternext */ - list_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)list_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - - -/*********************** List Iterator **************************/ - -typedef struct { - PyObject_HEAD - long it_index; - PyListObject *it_seq; /* Set to NULL when iterator is exhausted */ -} listiterobject; - -static PyObject *list_iter(PyObject *); -static void listiter_dealloc(listiterobject *); -static int listiter_traverse(listiterobject *, visitproc, void *); -static PyObject *listiter_next(listiterobject *); -static PyObject *listiter_len(listiterobject *); - -PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - -static PyMethodDef listiter_methods[] = { - {"__length_hint__", (PyCFunction)listiter_len, METH_NOARGS, length_hint_doc}, - {NULL, NULL} /* sentinel */ -}; - -PyTypeObject PyListIter_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "listiterator", /* tp_name */ - sizeof(listiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)listiter_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)listiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)listiter_next, /* tp_iternext */ - listiter_methods, /* tp_methods */ - 0, /* tp_members */ -}; - - -static PyObject * -list_iter(PyObject *seq) -{ - listiterobject *it; - - if (!PyList_Check(seq)) { - PyErr_BadInternalCall(); - return NULL; - } - it = PyObject_GC_New(listiterobject, &PyListIter_Type); - if (it == NULL) - return NULL; - it->it_index = 0; - Py_INCREF(seq); - it->it_seq = (PyListObject *)seq; - _PyObject_GC_TRACK(it); - return (PyObject *)it; -} - -static void -listiter_dealloc(listiterobject *it) -{ - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); -} - -static int -listiter_traverse(listiterobject *it, visitproc visit, void *arg) -{ - Py_VISIT(it->it_seq); - return 0; -} - -static PyObject * -listiter_next(listiterobject *it) -{ - PyListObject *seq; - PyObject *item; - - assert(it != NULL); - seq = it->it_seq; - if (seq == NULL) - return NULL; - assert(PyList_Check(seq)); - - if (it->it_index < PyList_GET_SIZE(seq)) { - item = PyList_GET_ITEM(seq, it->it_index); - ++it->it_index; - Py_INCREF(item); - return item; - } - - Py_DECREF(seq); - it->it_seq = NULL; - return NULL; -} - -static PyObject * -listiter_len(listiterobject *it) -{ - Py_ssize_t len; - if (it->it_seq) { - len = PyList_GET_SIZE(it->it_seq) - it->it_index; - if (len >= 0) - return PyInt_FromSsize_t(len); - } - return PyInt_FromLong(0); -} -/*********************** List Reverse Iterator **************************/ - -typedef struct { - PyObject_HEAD - Py_ssize_t it_index; - PyListObject *it_seq; /* Set to NULL when iterator is exhausted */ -} listreviterobject; - -static PyObject *list_reversed(PyListObject *, PyObject *); -static void listreviter_dealloc(listreviterobject *); -static int listreviter_traverse(listreviterobject *, visitproc, void *); -static PyObject *listreviter_next(listreviterobject *); -static Py_ssize_t listreviter_len(listreviterobject *); - -static PySequenceMethods listreviter_as_sequence = { - (lenfunc)listreviter_len, /* sq_length */ - 0, /* sq_concat */ -}; - -PyTypeObject PyListRevIter_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "listreverseiterator", /* tp_name */ - sizeof(listreviterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)listreviter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &listreviter_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)listreviter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)listreviter_next, /* tp_iternext */ - 0, -}; - -static PyObject * -list_reversed(PyListObject *seq, PyObject *unused) -{ - listreviterobject *it; - - it = PyObject_GC_New(listreviterobject, &PyListRevIter_Type); - if (it == NULL) - return NULL; - assert(PyList_Check(seq)); - it->it_index = PyList_GET_SIZE(seq) - 1; - Py_INCREF(seq); - it->it_seq = seq; - PyObject_GC_Track(it); - return (PyObject *)it; -} - -static void -listreviter_dealloc(listreviterobject *it) -{ - PyObject_GC_UnTrack(it); - Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); -} - -static int -listreviter_traverse(listreviterobject *it, visitproc visit, void *arg) -{ - Py_VISIT(it->it_seq); - return 0; -} - -static PyObject * -listreviter_next(listreviterobject *it) -{ - PyObject *item; - Py_ssize_t index = it->it_index; - PyListObject *seq = it->it_seq; - - if (index>=0 && index < PyList_GET_SIZE(seq)) { - item = PyList_GET_ITEM(seq, index); - it->it_index--; - Py_INCREF(item); - return item; - } - it->it_index = -1; - if (seq != NULL) { - it->it_seq = NULL; - Py_DECREF(seq); - } - return NULL; -} - -static Py_ssize_t -listreviter_len(listreviterobject *it) -{ - Py_ssize_t len = it->it_index + 1; - if (it->it_seq == NULL || PyList_GET_SIZE(it->it_seq) < len) - return 0; - return len; -} - diff --git a/sys/src/cmd/python/Objects/listsort.txt b/sys/src/cmd/python/Objects/listsort.txt deleted file mode 100644 index 92269840e..000000000 --- a/sys/src/cmd/python/Objects/listsort.txt +++ /dev/null @@ -1,677 +0,0 @@ -Intro ------ -This describes an adaptive, stable, natural mergesort, modestly called -timsort (hey, I earned it <wink>). It has supernatural performance on many -kinds of partially ordered arrays (less than lg(N!) comparisons needed, and -as few as N-1), yet as fast as Python's previous highly tuned samplesort -hybrid on random arrays. - -In a nutshell, the main routine marches over the array once, left to right, -alternately identifying the next run, then merging it into the previous -runs "intelligently". Everything else is complication for speed, and some -hard-won measure of memory efficiency. - - -Comparison with Python's Samplesort Hybrid ------------------------------------------- -+ timsort can require a temp array containing as many as N//2 pointers, - which means as many as 2*N extra bytes on 32-bit boxes. It can be - expected to require a temp array this large when sorting random data; on - data with significant structure, it may get away without using any extra - heap memory. This appears to be the strongest argument against it, but - compared to the size of an object, 2 temp bytes worst-case (also expected- - case for random data) doesn't scare me much. - - It turns out that Perl is moving to a stable mergesort, and the code for - that appears always to require a temp array with room for at least N - pointers. (Note that I wouldn't want to do that even if space weren't an - issue; I believe its efforts at memory frugality also save timsort - significant pointer-copying costs, and allow it to have a smaller working - set.) - -+ Across about four hours of generating random arrays, and sorting them - under both methods, samplesort required about 1.5% more comparisons - (the program is at the end of this file). - -+ In real life, this may be faster or slower on random arrays than - samplesort was, depending on platform quirks. Since it does fewer - comparisons on average, it can be expected to do better the more - expensive a comparison function is. OTOH, it does more data movement - (pointer copying) than samplesort, and that may negate its small - comparison advantage (depending on platform quirks) unless comparison - is very expensive. - -+ On arrays with many kinds of pre-existing order, this blows samplesort out - of the water. It's significantly faster than samplesort even on some - cases samplesort was special-casing the snot out of. I believe that lists - very often do have exploitable partial order in real life, and this is the - strongest argument in favor of timsort (indeed, samplesort's special cases - for extreme partial order are appreciated by real users, and timsort goes - much deeper than those, in particular naturally covering every case where - someone has suggested "and it would be cool if list.sort() had a special - case for this too ... and for that ..."). - -+ Here are exact comparison counts across all the tests in sortperf.py, - when run with arguments "15 20 1". - - Column Key: - *sort: random data - \sort: descending data - /sort: ascending data - 3sort: ascending, then 3 random exchanges - +sort: ascending, then 10 random at the end - ~sort: many duplicates - =sort: all equal - !sort: worst case scenario - - First the trivial cases, trivial for samplesort because it special-cased - them, and trivial for timsort because it naturally works on runs. Within - an "n" block, the first line gives the # of compares done by samplesort, - the second line by timsort, and the third line is the percentage by - which the samplesort count exceeds the timsort count: - - n \sort /sort =sort -------- ------ ------ ------ - 32768 32768 32767 32767 samplesort - 32767 32767 32767 timsort - 0.00% 0.00% 0.00% (samplesort - timsort) / timsort - - 65536 65536 65535 65535 - 65535 65535 65535 - 0.00% 0.00% 0.00% - - 131072 131072 131071 131071 - 131071 131071 131071 - 0.00% 0.00% 0.00% - - 262144 262144 262143 262143 - 262143 262143 262143 - 0.00% 0.00% 0.00% - - 524288 524288 524287 524287 - 524287 524287 524287 - 0.00% 0.00% 0.00% - -1048576 1048576 1048575 1048575 - 1048575 1048575 1048575 - 0.00% 0.00% 0.00% - - The algorithms are effectively identical in these cases, except that - timsort does one less compare in \sort. - - Now for the more interesting cases. lg(n!) is the information-theoretic - limit for the best any comparison-based sorting algorithm can do on - average (across all permutations). When a method gets significantly - below that, it's either astronomically lucky, or is finding exploitable - structure in the data. - - n lg(n!) *sort 3sort +sort %sort ~sort !sort -------- ------- ------ ------- ------- ------ ------- -------- - 32768 444255 453096 453614 32908 452871 130491 469141 old - 448885 33016 33007 50426 182083 65534 new - 0.94% 1273.92% -0.30% 798.09% -28.33% 615.87% %ch from new - - 65536 954037 972699 981940 65686 973104 260029 1004607 - 962991 65821 65808 101667 364341 131070 - 1.01% 1391.83% -0.19% 857.15% -28.63% 666.47% - - 131072 2039137 2101881 2091491 131232 2092894 554790 2161379 - 2057533 131410 131361 206193 728871 262142 - 2.16% 1491.58% -0.10% 915.02% -23.88% 724.51% - - 262144 4340409 4464460 4403233 262314 4445884 1107842 4584560 - 4377402 262437 262459 416347 1457945 524286 - 1.99% 1577.82% -0.06% 967.83% -24.01% 774.44% - - 524288 9205096 9453356 9408463 524468 9441930 2218577 9692015 - 9278734 524580 524633 837947 2916107 1048574 - 1.88% 1693.52% -0.03% 1026.79% -23.92% 824.30% - -1048576 19458756 19950272 19838588 1048766 19912134 4430649 20434212 - 19606028 1048958 1048941 1694896 5832445 2097150 - 1.76% 1791.27% -0.02% 1074.83% -24.03% 874.38% - - Discussion of cases: - - *sort: There's no structure in random data to exploit, so the theoretical - limit is lg(n!). Both methods get close to that, and timsort is hugging - it (indeed, in a *marginal* sense, it's a spectacular improvement -- - there's only about 1% left before hitting the wall, and timsort knows - darned well it's doing compares that won't pay on random data -- but so - does the samplesort hybrid). For contrast, Hoare's original random-pivot - quicksort does about 39% more compares than the limit, and the median-of-3 - variant about 19% more. - - 3sort, %sort, and !sort: No contest; there's structure in this data, but - not of the specific kinds samplesort special-cases. Note that structure - in !sort wasn't put there on purpose -- it was crafted as a worst case for - a previous quicksort implementation. That timsort nails it came as a - surprise to me (although it's obvious in retrospect). - - +sort: samplesort special-cases this data, and does a few less compares - than timsort. However, timsort runs this case significantly faster on all - boxes we have timings for, because timsort is in the business of merging - runs efficiently, while samplesort does much more data movement in this - (for it) special case. - - ~sort: samplesort's special cases for large masses of equal elements are - extremely effective on ~sort's specific data pattern, and timsort just - isn't going to get close to that, despite that it's clearly getting a - great deal of benefit out of the duplicates (the # of compares is much less - than lg(n!)). ~sort has a perfectly uniform distribution of just 4 - distinct values, and as the distribution gets more skewed, samplesort's - equal-element gimmicks become less effective, while timsort's adaptive - strategies find more to exploit; in a database supplied by Kevin Altis, a - sort on its highly skewed "on which stock exchange does this company's - stock trade?" field ran over twice as fast under timsort. - - However, despite that timsort does many more comparisons on ~sort, and - that on several platforms ~sort runs highly significantly slower under - timsort, on other platforms ~sort runs highly significantly faster under - timsort. No other kind of data has shown this wild x-platform behavior, - and we don't have an explanation for it. The only thing I can think of - that could transform what "should be" highly significant slowdowns into - highly significant speedups on some boxes are catastrophic cache effects - in samplesort. - - But timsort "should be" slower than samplesort on ~sort, so it's hard - to count that it isn't on some boxes as a strike against it <wink>. - -+ Here's the highwater mark for the number of heap-based temp slots (4 - bytes each on this box) needed by each test, again with arguments - "15 20 1": - - 2**i *sort \sort /sort 3sort +sort %sort ~sort =sort !sort - 32768 16384 0 0 6256 0 10821 12288 0 16383 - 65536 32766 0 0 21652 0 31276 24576 0 32767 - 131072 65534 0 0 17258 0 58112 49152 0 65535 - 262144 131072 0 0 35660 0 123561 98304 0 131071 - 524288 262142 0 0 31302 0 212057 196608 0 262143 -1048576 524286 0 0 312438 0 484942 393216 0 524287 - - Discussion: The tests that end up doing (close to) perfectly balanced - merges (*sort, !sort) need all N//2 temp slots (or almost all). ~sort - also ends up doing balanced merges, but systematically benefits a lot from - the preliminary pre-merge searches described under "Merge Memory" later. - %sort approaches having a balanced merge at the end because the random - selection of elements to replace is expected to produce an out-of-order - element near the midpoint. \sort, /sort, =sort are the trivial one-run - cases, needing no merging at all. +sort ends up having one very long run - and one very short, and so gets all the temp space it needs from the small - temparray member of the MergeState struct (note that the same would be - true if the new random elements were prefixed to the sorted list instead, - but not if they appeared "in the middle"). 3sort approaches N//3 temp - slots twice, but the run lengths that remain after 3 random exchanges - clearly has very high variance. - - -A detailed description of timsort follows. - -Runs ----- -count_run() returns the # of elements in the next run. A run is either -"ascending", which means non-decreasing: - - a0 <= a1 <= a2 <= ... - -or "descending", which means strictly decreasing: - - a0 > a1 > a2 > ... - -Note that a run is always at least 2 long, unless we start at the array's -last element. - -The definition of descending is strict, because the main routine reverses -a descending run in-place, transforming a descending run into an ascending -run. Reversal is done via the obvious fast "swap elements starting at each -end, and converge at the middle" method, and that can violate stability if -the slice contains any equal elements. Using a strict definition of -descending ensures that a descending run contains distinct elements. - -If an array is random, it's very unlikely we'll see long runs. If a natural -run contains less than minrun elements (see next section), the main loop -artificially boosts it to minrun elements, via a stable binary insertion sort -applied to the right number of array elements following the short natural -run. In a random array, *all* runs are likely to be minrun long as a -result. This has two primary good effects: - -1. Random data strongly tends then toward perfectly balanced (both runs have - the same length) merges, which is the most efficient way to proceed when - data is random. - -2. Because runs are never very short, the rest of the code doesn't make - heroic efforts to shave a few cycles off per-merge overheads. For - example, reasonable use of function calls is made, rather than trying to - inline everything. Since there are no more than N/minrun runs to begin - with, a few "extra" function calls per merge is barely measurable. - - -Computing minrun ----------------- -If N < 64, minrun is N. IOW, binary insertion sort is used for the whole -array then; it's hard to beat that given the overheads of trying something -fancier. - -When N is a power of 2, testing on random data showed that minrun values of -16, 32, 64 and 128 worked about equally well. At 256 the data-movement cost -in binary insertion sort clearly hurt, and at 8 the increase in the number -of function calls clearly hurt. Picking *some* power of 2 is important -here, so that the merges end up perfectly balanced (see next section). We -pick 32 as a good value in the sweet range; picking a value at the low end -allows the adaptive gimmicks more opportunity to exploit shorter natural -runs. - -Because sortperf.py only tries powers of 2, it took a long time to notice -that 32 isn't a good choice for the general case! Consider N=2112: - ->>> divmod(2112, 32) -(66, 0) ->>> - -If the data is randomly ordered, we're very likely to end up with 66 runs -each of length 32. The first 64 of these trigger a sequence of perfectly -balanced merges (see next section), leaving runs of lengths 2048 and 64 to -merge at the end. The adaptive gimmicks can do that with fewer than 2048+64 -compares, but it's still more compares than necessary, and-- mergesort's -bugaboo relative to samplesort --a lot more data movement (O(N) copies just -to get 64 elements into place). - -If we take minrun=33 in this case, then we're very likely to end up with 64 -runs each of length 33, and then all merges are perfectly balanced. Better! - -What we want to avoid is picking minrun such that in - - q, r = divmod(N, minrun) - -q is a power of 2 and r>0 (then the last merge only gets r elements into -place, and r < minrun is small compared to N), or q a little larger than a -power of 2 regardless of r (then we've got a case similar to "2112", again -leaving too little work for the last merge to do). - -Instead we pick a minrun in range(32, 65) such that N/minrun is exactly a -power of 2, or if that isn't possible, is close to, but strictly less than, -a power of 2. This is easier to do than it may sound: take the first 6 -bits of N, and add 1 if any of the remaining bits are set. In fact, that -rule covers every case in this section, including small N and exact powers -of 2; merge_compute_minrun() is a deceptively simple function. - - -The Merge Pattern ------------------ -In order to exploit regularities in the data, we're merging on natural -run lengths, and they can become wildly unbalanced. That's a Good Thing -for this sort! It means we have to find a way to manage an assortment of -potentially very different run lengths, though. - -Stability constrains permissible merging patterns. For example, if we have -3 consecutive runs of lengths - - A:10000 B:20000 C:10000 - -we dare not merge A with C first, because if A, B and C happen to contain -a common element, it would get out of order wrt its occurence(s) in B. The -merging must be done as (A+B)+C or A+(B+C) instead. - -So merging is always done on two consecutive runs at a time, and in-place, -although this may require some temp memory (more on that later). - -When a run is identified, its base address and length are pushed on a stack -in the MergeState struct. merge_collapse() is then called to see whether it -should merge it with preceding run(s). We would like to delay merging as -long as possible in order to exploit patterns that may come up later, but we -like even more to do merging as soon as possible to exploit that the run just -found is still high in the memory hierarchy. We also can't delay merging -"too long" because it consumes memory to remember the runs that are still -unmerged, and the stack has a fixed size. - -What turned out to be a good compromise maintains two invariants on the -stack entries, where A, B and C are the lengths of the three righmost not-yet -merged slices: - -1. A > B+C -2. B > C - -Note that, by induction, #2 implies the lengths of pending runs form a -decreasing sequence. #1 implies that, reading the lengths right to left, -the pending-run lengths grow at least as fast as the Fibonacci numbers. -Therefore the stack can never grow larger than about log_base_phi(N) entries, -where phi = (1+sqrt(5))/2 ~= 1.618. Thus a small # of stack slots suffice -for very large arrays. - -If A <= B+C, the smaller of A and C is merged with B (ties favor C, for the -freshness-in-cache reason), and the new run replaces the A,B or B,C entries; -e.g., if the last 3 entries are - - A:30 B:20 C:10 - -then B is merged with C, leaving - - A:30 BC:30 - -on the stack. Or if they were - - A:500 B:400: C:1000 - -then A is merged with B, leaving - - AB:900 C:1000 - -on the stack. - -In both examples, the stack configuration after the merge still violates -invariant #2, and merge_collapse() goes on to continue merging runs until -both invariants are satisfied. As an extreme case, suppose we didn't do the -minrun gimmick, and natural runs were of lengths 128, 64, 32, 16, 8, 4, 2, -and 2. Nothing would get merged until the final 2 was seen, and that would -trigger 7 perfectly balanced merges. - -The thrust of these rules when they trigger merging is to balance the run -lengths as closely as possible, while keeping a low bound on the number of -runs we have to remember. This is maximally effective for random data, -where all runs are likely to be of (artificially forced) length minrun, and -then we get a sequence of perfectly balanced merges (with, perhaps, some -oddballs at the end). - -OTOH, one reason this sort is so good for partly ordered data has to do -with wildly unbalanced run lengths. - - -Merge Memory ------------- -Merging adjacent runs of lengths A and B in-place is very difficult. -Theoretical constructions are known that can do it, but they're too difficult -and slow for practical use. But if we have temp memory equal to min(A, B), -it's easy. - -If A is smaller (function merge_lo), copy A to a temp array, leave B alone, -and then we can do the obvious merge algorithm left to right, from the temp -area and B, starting the stores into where A used to live. There's always a -free area in the original area comprising a number of elements equal to the -number not yet merged from the temp array (trivially true at the start; -proceed by induction). The only tricky bit is that if a comparison raises an -exception, we have to remember to copy the remaining elements back in from -the temp area, lest the array end up with duplicate entries from B. But -that's exactly the same thing we need to do if we reach the end of B first, -so the exit code is pleasantly common to both the normal and error cases. - -If B is smaller (function merge_hi, which is merge_lo's "mirror image"), -much the same, except that we need to merge right to left, copying B into a -temp array and starting the stores at the right end of where B used to live. - -A refinement: When we're about to merge adjacent runs A and B, we first do -a form of binary search (more on that later) to see where B[0] should end up -in A. Elements in A preceding that point are already in their final -positions, effectively shrinking the size of A. Likewise we also search to -see where A[-1] should end up in B, and elements of B after that point can -also be ignored. This cuts the amount of temp memory needed by the same -amount. - -These preliminary searches may not pay off, and can be expected *not* to -repay their cost if the data is random. But they can win huge in all of -time, copying, and memory savings when they do pay, so this is one of the -"per-merge overheads" mentioned above that we're happy to endure because -there is at most one very short run. It's generally true in this algorithm -that we're willing to gamble a little to win a lot, even though the net -expectation is negative for random data. - - -Merge Algorithms ----------------- -merge_lo() and merge_hi() are where the bulk of the time is spent. merge_lo -deals with runs where A <= B, and merge_hi where A > B. They don't know -whether the data is clustered or uniform, but a lovely thing about merging -is that many kinds of clustering "reveal themselves" by how many times in a -row the winning merge element comes from the same run. We'll only discuss -merge_lo here; merge_hi is exactly analogous. - -Merging begins in the usual, obvious way, comparing the first element of A -to the first of B, and moving B[0] to the merge area if it's less than A[0], -else moving A[0] to the merge area. Call that the "one pair at a time" -mode. The only twist here is keeping track of how many times in a row "the -winner" comes from the same run. - -If that count reaches MIN_GALLOP, we switch to "galloping mode". Here -we *search* B for where A[0] belongs, and move over all the B's before -that point in one chunk to the merge area, then move A[0] to the merge -area. Then we search A for where B[0] belongs, and similarly move a -slice of A in one chunk. Then back to searching B for where A[0] belongs, -etc. We stay in galloping mode until both searches find slices to copy -less than MIN_GALLOP elements long, at which point we go back to one-pair- -at-a-time mode. - -A refinement: The MergeState struct contains the value of min_gallop that -controls when we enter galloping mode, initialized to MIN_GALLOP. -merge_lo() and merge_hi() adjust this higher when galloping isn't paying -off, and lower when it is. - - -Galloping ---------- -Still without loss of generality, assume A is the shorter run. In galloping -mode, we first look for A[0] in B. We do this via "galloping", comparing -A[0] in turn to B[0], B[1], B[3], B[7], ..., B[2**j - 1], ..., until finding -the k such that B[2**(k-1) - 1] < A[0] <= B[2**k - 1]. This takes at most -roughly lg(B) comparisons, and, unlike a straight binary search, favors -finding the right spot early in B (more on that later). - -After finding such a k, the region of uncertainty is reduced to 2**(k-1) - 1 -consecutive elements, and a straight binary search requires exactly k-1 -additional comparisons to nail it. Then we copy all the B's up to that -point in one chunk, and then copy A[0]. Note that no matter where A[0] -belongs in B, the combination of galloping + binary search finds it in no -more than about 2*lg(B) comparisons. - -If we did a straight binary search, we could find it in no more than -ceiling(lg(B+1)) comparisons -- but straight binary search takes that many -comparisons no matter where A[0] belongs. Straight binary search thus loses -to galloping unless the run is quite long, and we simply can't guess -whether it is in advance. - -If data is random and runs have the same length, A[0] belongs at B[0] half -the time, at B[1] a quarter of the time, and so on: a consecutive winning -sub-run in B of length k occurs with probability 1/2**(k+1). So long -winning sub-runs are extremely unlikely in random data, and guessing that a -winning sub-run is going to be long is a dangerous game. - -OTOH, if data is lopsided or lumpy or contains many duplicates, long -stretches of winning sub-runs are very likely, and cutting the number of -comparisons needed to find one from O(B) to O(log B) is a huge win. - -Galloping compromises by getting out fast if there isn't a long winning -sub-run, yet finding such very efficiently when they exist. - -I first learned about the galloping strategy in a related context; see: - - "Adaptive Set Intersections, Unions, and Differences" (2000) - Erik D. Demaine, Alejandro López-Ortiz, J. Ian Munro - -and its followup(s). An earlier paper called the same strategy -"exponential search": - - "Optimistic Sorting and Information Theoretic Complexity" - Peter McIlroy - SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), pp - 467-474, Austin, Texas, 25-27 January 1993. - -and it probably dates back to an earlier paper by Bentley and Yao. The -McIlroy paper in particular has good analysis of a mergesort that's -probably strongly related to this one in its galloping strategy. - - -Galloping with a Broken Leg ---------------------------- -So why don't we always gallop? Because it can lose, on two counts: - -1. While we're willing to endure small per-merge overheads, per-comparison - overheads are a different story. Calling Yet Another Function per - comparison is expensive, and gallop_left() and gallop_right() are - too long-winded for sane inlining. - -2. Galloping can-- alas --require more comparisons than linear one-at-time - search, depending on the data. - -#2 requires details. If A[0] belongs before B[0], galloping requires 1 -compare to determine that, same as linear search, except it costs more -to call the gallop function. If A[0] belongs right before B[1], galloping -requires 2 compares, again same as linear search. On the third compare, -galloping checks A[0] against B[3], and if it's <=, requires one more -compare to determine whether A[0] belongs at B[2] or B[3]. That's a total -of 4 compares, but if A[0] does belong at B[2], linear search would have -discovered that in only 3 compares, and that's a huge loss! Really. It's -an increase of 33% in the number of compares needed, and comparisons are -expensive in Python. - -index in B where # compares linear # gallop # binary gallop -A[0] belongs search needs compares compares total ----------------- ----------------- -------- -------- ------ - 0 1 1 0 1 - - 1 2 2 0 2 - - 2 3 3 1 4 - 3 4 3 1 4 - - 4 5 4 2 6 - 5 6 4 2 6 - 6 7 4 2 6 - 7 8 4 2 6 - - 8 9 5 3 8 - 9 10 5 3 8 - 10 11 5 3 8 - 11 12 5 3 8 - ... - -In general, if A[0] belongs at B[i], linear search requires i+1 comparisons -to determine that, and galloping a total of 2*floor(lg(i))+2 comparisons. -The advantage of galloping is unbounded as i grows, but it doesn't win at -all until i=6. Before then, it loses twice (at i=2 and i=4), and ties -at the other values. At and after i=6, galloping always wins. - -We can't guess in advance when it's going to win, though, so we do one pair -at a time until the evidence seems strong that galloping may pay. MIN_GALLOP -is 7, and that's pretty strong evidence. However, if the data is random, it -simply will trigger galloping mode purely by luck every now and again, and -it's quite likely to hit one of the losing cases next. On the other hand, -in cases like ~sort, galloping always pays, and MIN_GALLOP is larger than it -"should be" then. So the MergeState struct keeps a min_gallop variable -that merge_lo and merge_hi adjust: the longer we stay in galloping mode, -the smaller min_gallop gets, making it easier to transition back to -galloping mode (if we ever leave it in the current merge, and at the -start of the next merge). But whenever the gallop loop doesn't pay, -min_gallop is increased by one, making it harder to transition back -to galloping mode (and again both within a merge and across merges). For -random data, this all but eliminates the gallop penalty: min_gallop grows -large enough that we almost never get into galloping mode. And for cases -like ~sort, min_gallop can fall to as low as 1. This seems to work well, -but in all it's a minor improvement over using a fixed MIN_GALLOP value. - - -Galloping Complication ----------------------- -The description above was for merge_lo. merge_hi has to merge "from the -other end", and really needs to gallop starting at the last element in a run -instead of the first. Galloping from the first still works, but does more -comparisons than it should (this is significant -- I timed it both ways). -For this reason, the gallop_left() and gallop_right() functions have a -"hint" argument, which is the index at which galloping should begin. So -galloping can actually start at any index, and proceed at offsets of 1, 3, -7, 15, ... or -1, -3, -7, -15, ... from the starting index. - -In the code as I type it's always called with either 0 or n-1 (where n is -the # of elements in a run). It's tempting to try to do something fancier, -melding galloping with some form of interpolation search; for example, if -we're merging a run of length 1 with a run of length 10000, index 5000 is -probably a better guess at the final result than either 0 or 9999. But -it's unclear how to generalize that intuition usefully, and merging of -wildly unbalanced runs already enjoys excellent performance. - -~sort is a good example of when balanced runs could benefit from a better -hint value: to the extent possible, this would like to use a starting -offset equal to the previous value of acount/bcount. Doing so saves about -10% of the compares in ~sort. However, doing so is also a mixed bag, -hurting other cases. - - -Comparing Average # of Compares on Random Arrays ------------------------------------------------- -[NOTE: This was done when the new algorithm used about 0.1% more compares - on random data than does its current incarnation.] - -Here list.sort() is samplesort, and list.msort() this sort: - -""" -import random -from time import clock as now - -def fill(n): - from random import random - return [random() for i in xrange(n)] - -def mycmp(x, y): - global ncmp - ncmp += 1 - return cmp(x, y) - -def timeit(values, method): - global ncmp - X = values[:] - bound = getattr(X, method) - ncmp = 0 - t1 = now() - bound(mycmp) - t2 = now() - return t2-t1, ncmp - -format = "%5s %9.2f %11d" -f2 = "%5s %9.2f %11.2f" - -def drive(): - count = sst = sscmp = mst = mscmp = nelts = 0 - while True: - n = random.randrange(100000) - nelts += n - x = fill(n) - - t, c = timeit(x, 'sort') - sst += t - sscmp += c - - t, c = timeit(x, 'msort') - mst += t - mscmp += c - - count += 1 - if count % 10: - continue - - print "count", count, "nelts", nelts - print format % ("sort", sst, sscmp) - print format % ("msort", mst, mscmp) - print f2 % ("", (sst-mst)*1e2/mst, (sscmp-mscmp)*1e2/mscmp) - -drive() -""" - -I ran this on Windows and kept using the computer lightly while it was -running. time.clock() is wall-clock time on Windows, with better than -microsecond resolution. samplesort started with a 1.52% #-of-comparisons -disadvantage, fell quickly to 1.48%, and then fluctuated within that small -range. Here's the last chunk of output before I killed the job: - -count 2630 nelts 130906543 - sort 6110.80 1937887573 -msort 6002.78 1909389381 - 1.80 1.49 - -We've done nearly 2 billion comparisons apiece at Python speed there, and -that's enough <wink>. - -For random arrays of size 2 (yes, there are only 2 interesting ones), -samplesort has a 50%(!) comparison disadvantage. This is a consequence of -samplesort special-casing at most one ascending run at the start, then -falling back to the general case if it doesn't find an ascending run -immediately. The consequence is that it ends up using two compares to sort -[2, 1]. Gratifyingly, timsort doesn't do any special-casing, so had to be -taught how to deal with mixtures of ascending and descending runs -efficiently in all cases. diff --git a/sys/src/cmd/python/Objects/longobject.c b/sys/src/cmd/python/Objects/longobject.c deleted file mode 100644 index cb4900d9d..000000000 --- a/sys/src/cmd/python/Objects/longobject.c +++ /dev/null @@ -1,3458 +0,0 @@ - - -/* Long (arbitrary precision) integer object implementation */ - -/* XXX The functional organization of this file is terrible */ - -#include "Python.h" -#include "longintrepr.h" - -#include <ctype.h> - -/* For long multiplication, use the O(N**2) school algorithm unless - * both operands contain more than KARATSUBA_CUTOFF digits (this - * being an internal Python long digit, in base BASE). - */ -#define KARATSUBA_CUTOFF 70 -#define KARATSUBA_SQUARE_CUTOFF (2 * KARATSUBA_CUTOFF) - -/* For exponentiation, use the binary left-to-right algorithm - * unless the exponent contains more than FIVEARY_CUTOFF digits. - * In that case, do 5 bits at a time. The potential drawback is that - * a table of 2**5 intermediate results is computed. - */ -#define FIVEARY_CUTOFF 8 - -#define ABS(x) ((x) < 0 ? -(x) : (x)) - -#undef MIN -#undef MAX -#define MAX(x, y) ((x) < (y) ? (y) : (x)) -#define MIN(x, y) ((x) > (y) ? (y) : (x)) - -/* Forward */ -static PyLongObject *long_normalize(PyLongObject *); -static PyLongObject *mul1(PyLongObject *, wdigit); -static PyLongObject *muladd1(PyLongObject *, wdigit, wdigit); -static PyLongObject *divrem1(PyLongObject *, digit, digit *); -static PyObject *long_format(PyObject *aa, int base, int addL); - -#define SIGCHECK(PyTryBlock) \ - if (--_Py_Ticker < 0) { \ - _Py_Ticker = _Py_CheckInterval; \ - if (PyErr_CheckSignals()) PyTryBlock \ - } - -/* Normalize (remove leading zeros from) a long int object. - Doesn't attempt to free the storage--in most cases, due to the nature - of the algorithms used, this could save at most be one word anyway. */ - -static PyLongObject * -long_normalize(register PyLongObject *v) -{ - Py_ssize_t j = ABS(v->ob_size); - Py_ssize_t i = j; - - while (i > 0 && v->ob_digit[i-1] == 0) - --i; - if (i != j) - v->ob_size = (v->ob_size < 0) ? -(i) : i; - return v; -} - -/* Allocate a new long int object with size digits. - Return NULL and set exception if we run out of memory. */ - -PyLongObject * -_PyLong_New(Py_ssize_t size) -{ - if (size > PY_SSIZE_T_MAX) { - PyErr_NoMemory(); - return NULL; - } - return PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size); -} - -PyObject * -_PyLong_Copy(PyLongObject *src) -{ - PyLongObject *result; - Py_ssize_t i; - - assert(src != NULL); - i = src->ob_size; - if (i < 0) - i = -(i); - result = _PyLong_New(i); - if (result != NULL) { - result->ob_size = src->ob_size; - while (--i >= 0) - result->ob_digit[i] = src->ob_digit[i]; - } - return (PyObject *)result; -} - -/* Create a new long int object from a C long int */ - -PyObject * -PyLong_FromLong(long ival) -{ - PyLongObject *v; - unsigned long t; /* unsigned so >> doesn't propagate sign bit */ - int ndigits = 0; - int negative = 0; - - if (ival < 0) { - ival = -ival; - negative = 1; - } - - /* Count the number of Python digits. - We used to pick 5 ("big enough for anything"), but that's a - waste of time and space given that 5*15 = 75 bits are rarely - needed. */ - t = (unsigned long)ival; - while (t) { - ++ndigits; - t >>= SHIFT; - } - v = _PyLong_New(ndigits); - if (v != NULL) { - digit *p = v->ob_digit; - v->ob_size = negative ? -ndigits : ndigits; - t = (unsigned long)ival; - while (t) { - *p++ = (digit)(t & MASK); - t >>= SHIFT; - } - } - return (PyObject *)v; -} - -/* Create a new long int object from a C unsigned long int */ - -PyObject * -PyLong_FromUnsignedLong(unsigned long ival) -{ - PyLongObject *v; - unsigned long t; - int ndigits = 0; - - /* Count the number of Python digits. */ - t = (unsigned long)ival; - while (t) { - ++ndigits; - t >>= SHIFT; - } - v = _PyLong_New(ndigits); - if (v != NULL) { - digit *p = v->ob_digit; - v->ob_size = ndigits; - while (ival) { - *p++ = (digit)(ival & MASK); - ival >>= SHIFT; - } - } - return (PyObject *)v; -} - -/* Create a new long int object from a C double */ - -PyObject * -PyLong_FromDouble(double dval) -{ - PyLongObject *v; - double frac; - int i, ndig, expo, neg; - neg = 0; - if (Py_IS_INFINITY(dval)) { - PyErr_SetString(PyExc_OverflowError, - "cannot convert float infinity to long"); - return NULL; - } - if (dval < 0.0) { - neg = 1; - dval = -dval; - } - frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */ - if (expo <= 0) - return PyLong_FromLong(0L); - ndig = (expo-1) / SHIFT + 1; /* Number of 'digits' in result */ - v = _PyLong_New(ndig); - if (v == NULL) - return NULL; - frac = ldexp(frac, (expo-1) % SHIFT + 1); - for (i = ndig; --i >= 0; ) { - long bits = (long)frac; - v->ob_digit[i] = (digit) bits; - frac = frac - (double)bits; - frac = ldexp(frac, SHIFT); - } - if (neg) - v->ob_size = -(v->ob_size); - return (PyObject *)v; -} - -/* Checking for overflow in PyLong_AsLong is a PITA since C doesn't define - * anything about what happens when a signed integer operation overflows, - * and some compilers think they're doing you a favor by being "clever" - * then. The bit pattern for the largest postive signed long is - * (unsigned long)LONG_MAX, and for the smallest negative signed long - * it is abs(LONG_MIN), which we could write -(unsigned long)LONG_MIN. - * However, some other compilers warn about applying unary minus to an - * unsigned operand. Hence the weird "0-". - */ -#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN) -#define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN) - -/* Get a C long int from a long int object. - Returns -1 and sets an error condition if overflow occurs. */ - -long -PyLong_AsLong(PyObject *vv) -{ - /* This version by Tim Peters */ - register PyLongObject *v; - unsigned long x, prev; - Py_ssize_t i; - int sign; - - if (vv == NULL || !PyLong_Check(vv)) { - if (vv != NULL && PyInt_Check(vv)) - return PyInt_AsLong(vv); - PyErr_BadInternalCall(); - return -1; - } - v = (PyLongObject *)vv; - i = v->ob_size; - sign = 1; - x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } - while (--i >= 0) { - prev = x; - x = (x << SHIFT) + v->ob_digit[i]; - if ((x >> SHIFT) != prev) - goto overflow; - } - /* Haven't lost any bits, but casting to long requires extra care - * (see comment above). - */ - if (x <= (unsigned long)LONG_MAX) { - return (long)x * sign; - } - else if (sign < 0 && x == PY_ABS_LONG_MIN) { - return LONG_MIN; - } - /* else overflow */ - - overflow: - PyErr_SetString(PyExc_OverflowError, - "long int too large to convert to int"); - return -1; -} - -/* Get a Py_ssize_t from a long int object. - Returns -1 and sets an error condition if overflow occurs. */ - -Py_ssize_t -_PyLong_AsSsize_t(PyObject *vv) { - register PyLongObject *v; - size_t x, prev; - Py_ssize_t i; - int sign; - - if (vv == NULL || !PyLong_Check(vv)) { - PyErr_BadInternalCall(); - return -1; - } - v = (PyLongObject *)vv; - i = v->ob_size; - sign = 1; - x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } - while (--i >= 0) { - prev = x; - x = (x << SHIFT) + v->ob_digit[i]; - if ((x >> SHIFT) != prev) - goto overflow; - } - /* Haven't lost any bits, but casting to a signed type requires - * extra care (see comment above). - */ - if (x <= (size_t)PY_SSIZE_T_MAX) { - return (Py_ssize_t)x * sign; - } - else if (sign < 0 && x == PY_ABS_SSIZE_T_MIN) { - return PY_SSIZE_T_MIN; - } - /* else overflow */ - - overflow: - PyErr_SetString(PyExc_OverflowError, - "long int too large to convert to int"); - return -1; -} - -/* Get a C unsigned long int from a long int object. - Returns -1 and sets an error condition if overflow occurs. */ - -unsigned long -PyLong_AsUnsignedLong(PyObject *vv) -{ - register PyLongObject *v; - unsigned long x, prev; - Py_ssize_t i; - - if (vv == NULL || !PyLong_Check(vv)) { - if (vv != NULL && PyInt_Check(vv)) { - long val = PyInt_AsLong(vv); - if (val < 0) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned long"); - return (unsigned long) -1; - } - return val; - } - PyErr_BadInternalCall(); - return (unsigned long) -1; - } - v = (PyLongObject *)vv; - i = v->ob_size; - x = 0; - if (i < 0) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned long"); - return (unsigned long) -1; - } - while (--i >= 0) { - prev = x; - x = (x << SHIFT) + v->ob_digit[i]; - if ((x >> SHIFT) != prev) { - PyErr_SetString(PyExc_OverflowError, - "long int too large to convert"); - return (unsigned long) -1; - } - } - return x; -} - -/* Get a C unsigned long int from a long int object, ignoring the high bits. - Returns -1 and sets an error condition if an error occurs. */ - -unsigned long -PyLong_AsUnsignedLongMask(PyObject *vv) -{ - register PyLongObject *v; - unsigned long x; - Py_ssize_t i; - int sign; - - if (vv == NULL || !PyLong_Check(vv)) { - if (vv != NULL && PyInt_Check(vv)) - return PyInt_AsUnsignedLongMask(vv); - PyErr_BadInternalCall(); - return (unsigned long) -1; - } - v = (PyLongObject *)vv; - i = v->ob_size; - sign = 1; - x = 0; - if (i < 0) { - sign = -1; - i = -i; - } - while (--i >= 0) { - x = (x << SHIFT) + v->ob_digit[i]; - } - return x * sign; -} - -int -_PyLong_Sign(PyObject *vv) -{ - PyLongObject *v = (PyLongObject *)vv; - - assert(v != NULL); - assert(PyLong_Check(v)); - - return v->ob_size == 0 ? 0 : (v->ob_size < 0 ? -1 : 1); -} - -size_t -_PyLong_NumBits(PyObject *vv) -{ - PyLongObject *v = (PyLongObject *)vv; - size_t result = 0; - Py_ssize_t ndigits; - - assert(v != NULL); - assert(PyLong_Check(v)); - ndigits = ABS(v->ob_size); - assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); - if (ndigits > 0) { - digit msd = v->ob_digit[ndigits - 1]; - - result = (ndigits - 1) * SHIFT; - if (result / SHIFT != (size_t)(ndigits - 1)) - goto Overflow; - do { - ++result; - if (result == 0) - goto Overflow; - msd >>= 1; - } while (msd); - } - return result; - -Overflow: - PyErr_SetString(PyExc_OverflowError, "long has too many bits " - "to express in a platform size_t"); - return (size_t)-1; -} - -PyObject * -_PyLong_FromByteArray(const unsigned char* bytes, size_t n, - int little_endian, int is_signed) -{ - const unsigned char* pstartbyte;/* LSB of bytes */ - int incr; /* direction to move pstartbyte */ - const unsigned char* pendbyte; /* MSB of bytes */ - size_t numsignificantbytes; /* number of bytes that matter */ - size_t ndigits; /* number of Python long digits */ - PyLongObject* v; /* result */ - int idigit = 0; /* next free index in v->ob_digit */ - - if (n == 0) - return PyLong_FromLong(0L); - - if (little_endian) { - pstartbyte = bytes; - pendbyte = bytes + n - 1; - incr = 1; - } - else { - pstartbyte = bytes + n - 1; - pendbyte = bytes; - incr = -1; - } - - if (is_signed) - is_signed = *pendbyte >= 0x80; - - /* Compute numsignificantbytes. This consists of finding the most - significant byte. Leading 0 bytes are insignficant if the number - is positive, and leading 0xff bytes if negative. */ - { - size_t i; - const unsigned char* p = pendbyte; - const int pincr = -incr; /* search MSB to LSB */ - const unsigned char insignficant = is_signed ? 0xff : 0x00; - - for (i = 0; i < n; ++i, p += pincr) { - if (*p != insignficant) - break; - } - numsignificantbytes = n - i; - /* 2's-comp is a bit tricky here, e.g. 0xff00 == -0x0100, so - actually has 2 significant bytes. OTOH, 0xff0001 == - -0x00ffff, so we wouldn't *need* to bump it there; but we - do for 0xffff = -0x0001. To be safe without bothering to - check every case, bump it regardless. */ - if (is_signed && numsignificantbytes < n) - ++numsignificantbytes; - } - - /* How many Python long digits do we need? We have - 8*numsignificantbytes bits, and each Python long digit has SHIFT - bits, so it's the ceiling of the quotient. */ - ndigits = (numsignificantbytes * 8 + SHIFT - 1) / SHIFT; - if (ndigits > (size_t)INT_MAX) - return PyErr_NoMemory(); - v = _PyLong_New((int)ndigits); - if (v == NULL) - return NULL; - - /* Copy the bits over. The tricky parts are computing 2's-comp on - the fly for signed numbers, and dealing with the mismatch between - 8-bit bytes and (probably) 15-bit Python digits.*/ - { - size_t i; - twodigits carry = 1; /* for 2's-comp calculation */ - twodigits accum = 0; /* sliding register */ - unsigned int accumbits = 0; /* number of bits in accum */ - const unsigned char* p = pstartbyte; - - for (i = 0; i < numsignificantbytes; ++i, p += incr) { - twodigits thisbyte = *p; - /* Compute correction for 2's comp, if needed. */ - if (is_signed) { - thisbyte = (0xff ^ thisbyte) + carry; - carry = thisbyte >> 8; - thisbyte &= 0xff; - } - /* Because we're going LSB to MSB, thisbyte is - more significant than what's already in accum, - so needs to be prepended to accum. */ - accum |= thisbyte << accumbits; - accumbits += 8; - if (accumbits >= SHIFT) { - /* There's enough to fill a Python digit. */ - assert(idigit < (int)ndigits); - v->ob_digit[idigit] = (digit)(accum & MASK); - ++idigit; - accum >>= SHIFT; - accumbits -= SHIFT; - assert(accumbits < SHIFT); - } - } - assert(accumbits < SHIFT); - if (accumbits) { - assert(idigit < (int)ndigits); - v->ob_digit[idigit] = (digit)accum; - ++idigit; - } - } - - v->ob_size = is_signed ? -idigit : idigit; - return (PyObject *)long_normalize(v); -} - -int -_PyLong_AsByteArray(PyLongObject* v, - unsigned char* bytes, size_t n, - int little_endian, int is_signed) -{ - int i; /* index into v->ob_digit */ - Py_ssize_t ndigits; /* |v->ob_size| */ - twodigits accum; /* sliding register */ - unsigned int accumbits; /* # bits in accum */ - int do_twos_comp; /* store 2's-comp? is_signed and v < 0 */ - twodigits carry; /* for computing 2's-comp */ - size_t j; /* # bytes filled */ - unsigned char* p; /* pointer to next byte in bytes */ - int pincr; /* direction to move p */ - - assert(v != NULL && PyLong_Check(v)); - - if (v->ob_size < 0) { - ndigits = -(v->ob_size); - if (!is_signed) { - PyErr_SetString(PyExc_TypeError, - "can't convert negative long to unsigned"); - return -1; - } - do_twos_comp = 1; - } - else { - ndigits = v->ob_size; - do_twos_comp = 0; - } - - if (little_endian) { - p = bytes; - pincr = 1; - } - else { - p = bytes + n - 1; - pincr = -1; - } - - /* Copy over all the Python digits. - It's crucial that every Python digit except for the MSD contribute - exactly SHIFT bits to the total, so first assert that the long is - normalized. */ - assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); - j = 0; - accum = 0; - accumbits = 0; - carry = do_twos_comp ? 1 : 0; - for (i = 0; i < ndigits; ++i) { - twodigits thisdigit = v->ob_digit[i]; - if (do_twos_comp) { - thisdigit = (thisdigit ^ MASK) + carry; - carry = thisdigit >> SHIFT; - thisdigit &= MASK; - } - /* Because we're going LSB to MSB, thisdigit is more - significant than what's already in accum, so needs to be - prepended to accum. */ - accum |= thisdigit << accumbits; - accumbits += SHIFT; - - /* The most-significant digit may be (probably is) at least - partly empty. */ - if (i == ndigits - 1) { - /* Count # of sign bits -- they needn't be stored, - * although for signed conversion we need later to - * make sure at least one sign bit gets stored. - * First shift conceptual sign bit to real sign bit. - */ - stwodigits s = (stwodigits)(thisdigit << - (8*sizeof(stwodigits) - SHIFT)); - unsigned int nsignbits = 0; - while ((s < 0) == do_twos_comp && nsignbits < SHIFT) { - ++nsignbits; - s <<= 1; - } - accumbits -= nsignbits; - } - - /* Store as many bytes as possible. */ - while (accumbits >= 8) { - if (j >= n) - goto Overflow; - ++j; - *p = (unsigned char)(accum & 0xff); - p += pincr; - accumbits -= 8; - accum >>= 8; - } - } - - /* Store the straggler (if any). */ - assert(accumbits < 8); - assert(carry == 0); /* else do_twos_comp and *every* digit was 0 */ - if (accumbits > 0) { - if (j >= n) - goto Overflow; - ++j; - if (do_twos_comp) { - /* Fill leading bits of the byte with sign bits - (appropriately pretending that the long had an - infinite supply of sign bits). */ - accum |= (~(twodigits)0) << accumbits; - } - *p = (unsigned char)(accum & 0xff); - p += pincr; - } - else if (j == n && n > 0 && is_signed) { - /* The main loop filled the byte array exactly, so the code - just above didn't get to ensure there's a sign bit, and the - loop below wouldn't add one either. Make sure a sign bit - exists. */ - unsigned char msb = *(p - pincr); - int sign_bit_set = msb >= 0x80; - assert(accumbits == 0); - if (sign_bit_set == do_twos_comp) - return 0; - else - goto Overflow; - } - - /* Fill remaining bytes with copies of the sign bit. */ - { - unsigned char signbyte = do_twos_comp ? 0xffU : 0U; - for ( ; j < n; ++j, p += pincr) - *p = signbyte; - } - - return 0; - -Overflow: - PyErr_SetString(PyExc_OverflowError, "long too big to convert"); - return -1; - -} - -double -_PyLong_AsScaledDouble(PyObject *vv, int *exponent) -{ -/* NBITS_WANTED should be > the number of bits in a double's precision, - but small enough so that 2**NBITS_WANTED is within the normal double - range. nbitsneeded is set to 1 less than that because the most-significant - Python digit contains at least 1 significant bit, but we don't want to - bother counting them (catering to the worst case cheaply). - - 57 is one more than VAX-D double precision; I (Tim) don't know of a double - format with more precision than that; it's 1 larger so that we add in at - least one round bit to stand in for the ignored least-significant bits. -*/ -#define NBITS_WANTED 57 - PyLongObject *v; - double x; - const double multiplier = (double)(1L << SHIFT); - Py_ssize_t i; - int sign; - int nbitsneeded; - - if (vv == NULL || !PyLong_Check(vv)) { - PyErr_BadInternalCall(); - return -1; - } - v = (PyLongObject *)vv; - i = v->ob_size; - sign = 1; - if (i < 0) { - sign = -1; - i = -(i); - } - else if (i == 0) { - *exponent = 0; - return 0.0; - } - --i; - x = (double)v->ob_digit[i]; - nbitsneeded = NBITS_WANTED - 1; - /* Invariant: i Python digits remain unaccounted for. */ - while (i > 0 && nbitsneeded > 0) { - --i; - x = x * multiplier + (double)v->ob_digit[i]; - nbitsneeded -= SHIFT; - } - /* There are i digits we didn't shift in. Pretending they're all - zeroes, the true value is x * 2**(i*SHIFT). */ - *exponent = i; - assert(x > 0.0); - return x * sign; -#undef NBITS_WANTED -} - -/* Get a C double from a long int object. */ - -double -PyLong_AsDouble(PyObject *vv) -{ - int e = -1; - double x; - - if (vv == NULL || !PyLong_Check(vv)) { - PyErr_BadInternalCall(); - return -1; - } - x = _PyLong_AsScaledDouble(vv, &e); - if (x == -1.0 && PyErr_Occurred()) - return -1.0; - /* 'e' initialized to -1 to silence gcc-4.0.x, but it should be - set correctly after a successful _PyLong_AsScaledDouble() call */ - assert(e >= 0); - if (e > INT_MAX / SHIFT) - goto overflow; - errno = 0; - x = ldexp(x, e * SHIFT); - if (Py_OVERFLOWED(x)) - goto overflow; - return x; - -overflow: - PyErr_SetString(PyExc_OverflowError, - "long int too large to convert to float"); - return -1.0; -} - -/* Create a new long (or int) object from a C pointer */ - -PyObject * -PyLong_FromVoidPtr(void *p) -{ -#if SIZEOF_VOID_P <= SIZEOF_LONG - if ((long)p < 0) - return PyLong_FromUnsignedLong((unsigned long)p); - return PyInt_FromLong((long)p); -#else - -#ifndef HAVE_LONG_LONG -# error "PyLong_FromVoidPtr: sizeof(void*) > sizeof(long), but no long long" -#endif -#if SIZEOF_LONG_LONG < SIZEOF_VOID_P -# error "PyLong_FromVoidPtr: sizeof(PY_LONG_LONG) < sizeof(void*)" -#endif - /* optimize null pointers */ - if (p == NULL) - return PyInt_FromLong(0); - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)p); - -#endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ -} - -/* Get a C pointer from a long object (or an int object in some cases) */ - -void * -PyLong_AsVoidPtr(PyObject *vv) -{ - /* This function will allow int or long objects. If vv is neither, - then the PyLong_AsLong*() functions will raise the exception: - PyExc_SystemError, "bad argument to internal function" - */ -#if SIZEOF_VOID_P <= SIZEOF_LONG - long x; - - if (PyInt_Check(vv)) - x = PyInt_AS_LONG(vv); - else if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) - x = PyLong_AsLong(vv); - else - x = PyLong_AsUnsignedLong(vv); -#else - -#ifndef HAVE_LONG_LONG -# error "PyLong_AsVoidPtr: sizeof(void*) > sizeof(long), but no long long" -#endif -#if SIZEOF_LONG_LONG < SIZEOF_VOID_P -# error "PyLong_AsVoidPtr: sizeof(PY_LONG_LONG) < sizeof(void*)" -#endif - PY_LONG_LONG x; - - if (PyInt_Check(vv)) - x = PyInt_AS_LONG(vv); - else if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) - x = PyLong_AsLongLong(vv); - else - x = PyLong_AsUnsignedLongLong(vv); - -#endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ - - if (x == -1 && PyErr_Occurred()) - return NULL; - return (void *)x; -} - -#ifdef HAVE_LONG_LONG - -/* Initial PY_LONG_LONG support by Chris Herborth (chrish@qnx.com), later - * rewritten to use the newer PyLong_{As,From}ByteArray API. - */ - -#define IS_LITTLE_ENDIAN (int)*(unsigned char*)&one - -/* Create a new long int object from a C PY_LONG_LONG int. */ - -PyObject * -PyLong_FromLongLong(PY_LONG_LONG ival) -{ - PyLongObject *v; - unsigned PY_LONG_LONG t; /* unsigned so >> doesn't propagate sign bit */ - int ndigits = 0; - int negative = 0; - - if (ival < 0) { - ival = -ival; - negative = 1; - } - - /* Count the number of Python digits. - We used to pick 5 ("big enough for anything"), but that's a - waste of time and space given that 5*15 = 75 bits are rarely - needed. */ - t = (unsigned PY_LONG_LONG)ival; - while (t) { - ++ndigits; - t >>= SHIFT; - } - v = _PyLong_New(ndigits); - if (v != NULL) { - digit *p = v->ob_digit; - v->ob_size = negative ? -ndigits : ndigits; - t = (unsigned PY_LONG_LONG)ival; - while (t) { - *p++ = (digit)(t & MASK); - t >>= SHIFT; - } - } - return (PyObject *)v; -} - -/* Create a new long int object from a C unsigned PY_LONG_LONG int. */ - -PyObject * -PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG ival) -{ - PyLongObject *v; - unsigned PY_LONG_LONG t; - int ndigits = 0; - - /* Count the number of Python digits. */ - t = (unsigned PY_LONG_LONG)ival; - while (t) { - ++ndigits; - t >>= SHIFT; - } - v = _PyLong_New(ndigits); - if (v != NULL) { - digit *p = v->ob_digit; - v->ob_size = ndigits; - while (ival) { - *p++ = (digit)(ival & MASK); - ival >>= SHIFT; - } - } - return (PyObject *)v; -} - -/* Create a new long int object from a C Py_ssize_t. */ - -PyObject * -_PyLong_FromSsize_t(Py_ssize_t ival) -{ - Py_ssize_t bytes = ival; - int one = 1; - return _PyLong_FromByteArray( - (unsigned char *)&bytes, - SIZEOF_SIZE_T, IS_LITTLE_ENDIAN, 0); -} - -/* Create a new long int object from a C size_t. */ - -PyObject * -_PyLong_FromSize_t(size_t ival) -{ - size_t bytes = ival; - int one = 1; - return _PyLong_FromByteArray( - (unsigned char *)&bytes, - SIZEOF_SIZE_T, IS_LITTLE_ENDIAN, 0); -} - -/* Get a C PY_LONG_LONG int from a long int object. - Return -1 and set an error if overflow occurs. */ - -PY_LONG_LONG -PyLong_AsLongLong(PyObject *vv) -{ - PY_LONG_LONG bytes; - int one = 1; - int res; - - if (vv == NULL) { - PyErr_BadInternalCall(); - return -1; - } - if (!PyLong_Check(vv)) { - PyNumberMethods *nb; - PyObject *io; - if (PyInt_Check(vv)) - return (PY_LONG_LONG)PyInt_AsLong(vv); - if ((nb = vv->ob_type->tp_as_number) == NULL || - nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return -1; - } - io = (*nb->nb_int) (vv); - if (io == NULL) - return -1; - if (PyInt_Check(io)) { - bytes = PyInt_AsLong(io); - Py_DECREF(io); - return bytes; - } - if (PyLong_Check(io)) { - bytes = PyLong_AsLongLong(io); - Py_DECREF(io); - return bytes; - } - Py_DECREF(io); - PyErr_SetString(PyExc_TypeError, "integer conversion failed"); - return -1; - } - - res = _PyLong_AsByteArray( - (PyLongObject *)vv, (unsigned char *)&bytes, - SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 1); - - /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */ - if (res < 0) - return (PY_LONG_LONG)-1; - else - return bytes; -} - -/* Get a C unsigned PY_LONG_LONG int from a long int object. - Return -1 and set an error if overflow occurs. */ - -unsigned PY_LONG_LONG -PyLong_AsUnsignedLongLong(PyObject *vv) -{ - unsigned PY_LONG_LONG bytes; - int one = 1; - int res; - - if (vv == NULL || !PyLong_Check(vv)) { - PyErr_BadInternalCall(); - return (unsigned PY_LONG_LONG)-1; - } - - res = _PyLong_AsByteArray( - (PyLongObject *)vv, (unsigned char *)&bytes, - SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 0); - - /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */ - if (res < 0) - return (unsigned PY_LONG_LONG)res; - else - return bytes; -} - -/* Get a C unsigned long int from a long int object, ignoring the high bits. - Returns -1 and sets an error condition if an error occurs. */ - -unsigned PY_LONG_LONG -PyLong_AsUnsignedLongLongMask(PyObject *vv) -{ - register PyLongObject *v; - unsigned PY_LONG_LONG x; - Py_ssize_t i; - int sign; - - if (vv == NULL || !PyLong_Check(vv)) { - PyErr_BadInternalCall(); - return (unsigned long) -1; - } - v = (PyLongObject *)vv; - i = v->ob_size; - sign = 1; - x = 0; - if (i < 0) { - sign = -1; - i = -i; - } - while (--i >= 0) { - x = (x << SHIFT) + v->ob_digit[i]; - } - return x * sign; -} -#undef IS_LITTLE_ENDIAN - -#endif /* HAVE_LONG_LONG */ - - -static int -convert_binop(PyObject *v, PyObject *w, PyLongObject **a, PyLongObject **b) { - if (PyLong_Check(v)) { - *a = (PyLongObject *) v; - Py_INCREF(v); - } - else if (PyInt_Check(v)) { - *a = (PyLongObject *) PyLong_FromLong(PyInt_AS_LONG(v)); - } - else { - return 0; - } - if (PyLong_Check(w)) { - *b = (PyLongObject *) w; - Py_INCREF(w); - } - else if (PyInt_Check(w)) { - *b = (PyLongObject *) PyLong_FromLong(PyInt_AS_LONG(w)); - } - else { - Py_DECREF(*a); - return 0; - } - return 1; -} - -#define CONVERT_BINOP(v, w, a, b) \ - if (!convert_binop(v, w, a, b)) { \ - Py_INCREF(Py_NotImplemented); \ - return Py_NotImplemented; \ - } - -/* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n] - * is modified in place, by adding y to it. Carries are propagated as far as - * x[m-1], and the remaining carry (0 or 1) is returned. - */ -static digit -v_iadd(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n) -{ - int i; - digit carry = 0; - - assert(m >= n); - for (i = 0; i < n; ++i) { - carry += x[i] + y[i]; - x[i] = carry & MASK; - carry >>= SHIFT; - assert((carry & 1) == carry); - } - for (; carry && i < m; ++i) { - carry += x[i]; - x[i] = carry & MASK; - carry >>= SHIFT; - assert((carry & 1) == carry); - } - return carry; -} - -/* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n] - * is modified in place, by subtracting y from it. Borrows are propagated as - * far as x[m-1], and the remaining borrow (0 or 1) is returned. - */ -static digit -v_isub(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n) -{ - int i; - digit borrow = 0; - - assert(m >= n); - for (i = 0; i < n; ++i) { - borrow = x[i] - y[i] - borrow; - x[i] = borrow & MASK; - borrow >>= SHIFT; - borrow &= 1; /* keep only 1 sign bit */ - } - for (; borrow && i < m; ++i) { - borrow = x[i] - borrow; - x[i] = borrow & MASK; - borrow >>= SHIFT; - borrow &= 1; - } - return borrow; -} - -/* Multiply by a single digit, ignoring the sign. */ - -static PyLongObject * -mul1(PyLongObject *a, wdigit n) -{ - return muladd1(a, n, (digit)0); -} - -/* Multiply by a single digit and add a single digit, ignoring the sign. */ - -static PyLongObject * -muladd1(PyLongObject *a, wdigit n, wdigit extra) -{ - Py_ssize_t size_a = ABS(a->ob_size); - PyLongObject *z = _PyLong_New(size_a+1); - twodigits carry = extra; - Py_ssize_t i; - - if (z == NULL) - return NULL; - for (i = 0; i < size_a; ++i) { - carry += (twodigits)a->ob_digit[i] * n; - z->ob_digit[i] = (digit) (carry & MASK); - carry >>= SHIFT; - } - z->ob_digit[i] = (digit) carry; - return long_normalize(z); -} - -/* Divide long pin, w/ size digits, by non-zero digit n, storing quotient - in pout, and returning the remainder. pin and pout point at the LSD. - It's OK for pin == pout on entry, which saves oodles of mallocs/frees in - long_format, but that should be done with great care since longs are - immutable. */ - -static digit -inplace_divrem1(digit *pout, digit *pin, Py_ssize_t size, digit n) -{ - twodigits rem = 0; - - assert(n > 0 && n <= MASK); - pin += size; - pout += size; - while (--size >= 0) { - digit hi; - rem = (rem << SHIFT) + *--pin; - *--pout = hi = (digit)(rem / n); - rem -= hi * n; - } - return (digit)rem; -} - -/* Divide a long integer by a digit, returning both the quotient - (as function result) and the remainder (through *prem). - The sign of a is ignored; n should not be zero. */ - -static PyLongObject * -divrem1(PyLongObject *a, digit n, digit *prem) -{ - const Py_ssize_t size = ABS(a->ob_size); - PyLongObject *z; - - assert(n > 0 && n <= MASK); - z = _PyLong_New(size); - if (z == NULL) - return NULL; - *prem = inplace_divrem1(z->ob_digit, a->ob_digit, size, n); - return long_normalize(z); -} - -/* Convert a long int object to a string, using a given conversion base. - Return a string object. - If base is 8 or 16, add the proper prefix '0' or '0x'. */ - -static PyObject * -long_format(PyObject *aa, int base, int addL) -{ - register PyLongObject *a = (PyLongObject *)aa; - PyStringObject *str; - Py_ssize_t i, j, sz; - Py_ssize_t size_a; - char *p; - int bits; - char sign = '\0'; - - if (a == NULL || !PyLong_Check(a)) { - PyErr_BadInternalCall(); - return NULL; - } - assert(base >= 2 && base <= 36); - size_a = ABS(a->ob_size); - - /* Compute a rough upper bound for the length of the string */ - i = base; - bits = 0; - while (i > 1) { - ++bits; - i >>= 1; - } - i = 5 + (addL ? 1 : 0); - j = size_a*SHIFT + bits-1; - sz = i + j / bits; - if (j / SHIFT < size_a || sz < i) { - PyErr_SetString(PyExc_OverflowError, - "long is too large to format"); - return NULL; - } - str = (PyStringObject *) PyString_FromStringAndSize((char *)0, sz); - if (str == NULL) - return NULL; - p = PyString_AS_STRING(str) + sz; - *p = '\0'; - if (addL) - *--p = 'L'; - if (a->ob_size < 0) - sign = '-'; - - if (a->ob_size == 0) { - *--p = '0'; - } - else if ((base & (base - 1)) == 0) { - /* JRH: special case for power-of-2 bases */ - twodigits accum = 0; - int accumbits = 0; /* # of bits in accum */ - int basebits = 1; /* # of bits in base-1 */ - i = base; - while ((i >>= 1) > 1) - ++basebits; - - for (i = 0; i < size_a; ++i) { - accum |= (twodigits)a->ob_digit[i] << accumbits; - accumbits += SHIFT; - assert(accumbits >= basebits); - do { - char cdigit = (char)(accum & (base - 1)); - cdigit += (cdigit < 10) ? '0' : 'a'-10; - assert(p > PyString_AS_STRING(str)); - *--p = cdigit; - accumbits -= basebits; - accum >>= basebits; - } while (i < size_a-1 ? accumbits >= basebits : - accum > 0); - } - } - else { - /* Not 0, and base not a power of 2. Divide repeatedly by - base, but for speed use the highest power of base that - fits in a digit. */ - Py_ssize_t size = size_a; - digit *pin = a->ob_digit; - PyLongObject *scratch; - /* powbasw <- largest power of base that fits in a digit. */ - digit powbase = base; /* powbase == base ** power */ - int power = 1; - for (;;) { - unsigned long newpow = powbase * (unsigned long)base; - if (newpow >> SHIFT) /* doesn't fit in a digit */ - break; - powbase = (digit)newpow; - ++power; - } - - /* Get a scratch area for repeated division. */ - scratch = _PyLong_New(size); - if (scratch == NULL) { - Py_DECREF(str); - return NULL; - } - - /* Repeatedly divide by powbase. */ - do { - int ntostore = power; - digit rem = inplace_divrem1(scratch->ob_digit, - pin, size, powbase); - pin = scratch->ob_digit; /* no need to use a again */ - if (pin[size - 1] == 0) - --size; - SIGCHECK({ - Py_DECREF(scratch); - Py_DECREF(str); - return NULL; - }) - - /* Break rem into digits. */ - assert(ntostore > 0); - do { - digit nextrem = (digit)(rem / base); - char c = (char)(rem - nextrem * base); - assert(p > PyString_AS_STRING(str)); - c += (c < 10) ? '0' : 'a'-10; - *--p = c; - rem = nextrem; - --ntostore; - /* Termination is a bit delicate: must not - store leading zeroes, so must get out if - remaining quotient and rem are both 0. */ - } while (ntostore && (size || rem)); - } while (size != 0); - Py_DECREF(scratch); - } - - if (base == 8) { - if (size_a != 0) - *--p = '0'; - } - else if (base == 16) { - *--p = 'x'; - *--p = '0'; - } - else if (base != 10) { - *--p = '#'; - *--p = '0' + base%10; - if (base > 10) - *--p = '0' + base/10; - } - if (sign) - *--p = sign; - if (p != PyString_AS_STRING(str)) { - char *q = PyString_AS_STRING(str); - assert(p > q); - do { - } while ((*q++ = *p++) != '\0'); - q--; - _PyString_Resize((PyObject **)&str, - (Py_ssize_t) (q - PyString_AS_STRING(str))); - } - return (PyObject *)str; -} - -/* Table of digit values for 8-bit string -> integer conversion. - * '0' maps to 0, ..., '9' maps to 9. - * 'a' and 'A' map to 10, ..., 'z' and 'Z' map to 35. - * All other indices map to 37. - * Note that when converting a base B string, a char c is a legitimate - * base B digit iff _PyLong_DigitValue[Py_CHARMASK(c)] < B. - */ -int _PyLong_DigitValue[256] = { - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 37, 37, 37, 37, 37, 37, - 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37, - 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, -}; - -/* *str points to the first digit in a string of base `base` digits. base - * is a power of 2 (2, 4, 8, 16, or 32). *str is set to point to the first - * non-digit (which may be *str!). A normalized long is returned. - * The point to this routine is that it takes time linear in the number of - * string characters. - */ -static PyLongObject * -long_from_binary_base(char **str, int base) -{ - char *p = *str; - char *start = p; - int bits_per_char; - Py_ssize_t n; - PyLongObject *z; - twodigits accum; - int bits_in_accum; - digit *pdigit; - - assert(base >= 2 && base <= 32 && (base & (base - 1)) == 0); - n = base; - for (bits_per_char = -1; n; ++bits_per_char) - n >>= 1; - /* n <- total # of bits needed, while setting p to end-of-string */ - n = 0; - while (_PyLong_DigitValue[Py_CHARMASK(*p)] < base) - ++p; - *str = p; - /* n <- # of Python digits needed, = ceiling(n/SHIFT). */ - n = (p - start) * bits_per_char + SHIFT - 1; - if (n / bits_per_char < p - start) { - PyErr_SetString(PyExc_ValueError, - "long string too large to convert"); - return NULL; - } - n = n / SHIFT; - z = _PyLong_New(n); - if (z == NULL) - return NULL; - /* Read string from right, and fill in long from left; i.e., - * from least to most significant in both. - */ - accum = 0; - bits_in_accum = 0; - pdigit = z->ob_digit; - while (--p >= start) { - int k = _PyLong_DigitValue[Py_CHARMASK(*p)]; - assert(k >= 0 && k < base); - accum |= (twodigits)(k << bits_in_accum); - bits_in_accum += bits_per_char; - if (bits_in_accum >= SHIFT) { - *pdigit++ = (digit)(accum & MASK); - assert(pdigit - z->ob_digit <= (int)n); - accum >>= SHIFT; - bits_in_accum -= SHIFT; - assert(bits_in_accum < SHIFT); - } - } - if (bits_in_accum) { - assert(bits_in_accum <= SHIFT); - *pdigit++ = (digit)accum; - assert(pdigit - z->ob_digit <= (int)n); - } - while (pdigit - z->ob_digit < n) - *pdigit++ = 0; - return long_normalize(z); -} - -PyObject * -PyLong_FromString(char *str, char **pend, int base) -{ - int sign = 1; - char *start, *orig_str = str; - PyLongObject *z; - PyObject *strobj, *strrepr; - Py_ssize_t slen; - - if ((base != 0 && base < 2) || base > 36) { - PyErr_SetString(PyExc_ValueError, - "long() arg 2 must be >= 2 and <= 36"); - return NULL; - } - while (*str != '\0' && isspace(Py_CHARMASK(*str))) - str++; - if (*str == '+') - ++str; - else if (*str == '-') { - ++str; - sign = -1; - } - while (*str != '\0' && isspace(Py_CHARMASK(*str))) - str++; - if (base == 0) { - if (str[0] != '0') - base = 10; - else if (str[1] == 'x' || str[1] == 'X') - base = 16; - else - base = 8; - } - if (base == 16 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) - str += 2; - - start = str; - if ((base & (base - 1)) == 0) - z = long_from_binary_base(&str, base); - else { -/*** -Binary bases can be converted in time linear in the number of digits, because -Python's representation base is binary. Other bases (including decimal!) use -the simple quadratic-time algorithm below, complicated by some speed tricks. - -First some math: the largest integer that can be expressed in N base-B digits -is B**N-1. Consequently, if we have an N-digit input in base B, the worst- -case number of Python digits needed to hold it is the smallest integer n s.t. - - BASE**n-1 >= B**N-1 [or, adding 1 to both sides] - BASE**n >= B**N [taking logs to base BASE] - n >= log(B**N)/log(BASE) = N * log(B)/log(BASE) - -The static array log_base_BASE[base] == log(base)/log(BASE) so we can compute -this quickly. A Python long with that much space is reserved near the start, -and the result is computed into it. - -The input string is actually treated as being in base base**i (i.e., i digits -are processed at a time), where two more static arrays hold: - - convwidth_base[base] = the largest integer i such that base**i <= BASE - convmultmax_base[base] = base ** convwidth_base[base] - -The first of these is the largest i such that i consecutive input digits -must fit in a single Python digit. The second is effectively the input -base we're really using. - -Viewing the input as a sequence <c0, c1, ..., c_n-1> of digits in base -convmultmax_base[base], the result is "simply" - - (((c0*B + c1)*B + c2)*B + c3)*B + ... ))) + c_n-1 - -where B = convmultmax_base[base]. - -Error analysis: as above, the number of Python digits `n` needed is worst- -case - - n >= N * log(B)/log(BASE) - -where `N` is the number of input digits in base `B`. This is computed via - - size_z = (Py_ssize_t)((scan - str) * log_base_BASE[base]) + 1; - -below. Two numeric concerns are how much space this can waste, and whether -the computed result can be too small. To be concrete, assume BASE = 2**15, -which is the default (and it's unlikely anyone changes that). - -Waste isn't a problem: provided the first input digit isn't 0, the difference -between the worst-case input with N digits and the smallest input with N -digits is about a factor of B, but B is small compared to BASE so at most -one allocated Python digit can remain unused on that count. If -N*log(B)/log(BASE) is mathematically an exact integer, then truncating that -and adding 1 returns a result 1 larger than necessary. However, that can't -happen: whenever B is a power of 2, long_from_binary_base() is called -instead, and it's impossible for B**i to be an integer power of 2**15 when -B is not a power of 2 (i.e., it's impossible for N*log(B)/log(BASE) to be -an exact integer when B is not a power of 2, since B**i has a prime factor -other than 2 in that case, but (2**15)**j's only prime factor is 2). - -The computed result can be too small if the true value of N*log(B)/log(BASE) -is a little bit larger than an exact integer, but due to roundoff errors (in -computing log(B), log(BASE), their quotient, and/or multiplying that by N) -yields a numeric result a little less than that integer. Unfortunately, "how -close can a transcendental function get to an integer over some range?" -questions are generally theoretically intractable. Computer analysis via -continued fractions is practical: expand log(B)/log(BASE) via continued -fractions, giving a sequence i/j of "the best" rational approximations. Then -j*log(B)/log(BASE) is approximately equal to (the integer) i. This shows that -we can get very close to being in trouble, but very rarely. For example, -76573 is a denominator in one of the continued-fraction approximations to -log(10)/log(2**15), and indeed: - - >>> log(10)/log(2**15)*76573 - 16958.000000654003 - -is very close to an integer. If we were working with IEEE single-precision, -rounding errors could kill us. Finding worst cases in IEEE double-precision -requires better-than-double-precision log() functions, and Tim didn't bother. -Instead the code checks to see whether the allocated space is enough as each -new Python digit is added, and copies the whole thing to a larger long if not. -This should happen extremely rarely, and in fact I don't have a test case -that triggers it(!). Instead the code was tested by artificially allocating -just 1 digit at the start, so that the copying code was exercised for every -digit beyond the first. -***/ - register twodigits c; /* current input character */ - Py_ssize_t size_z; - int i; - int convwidth; - twodigits convmultmax, convmult; - digit *pz, *pzstop; - char* scan; - - static double log_base_BASE[37] = {0.0e0,}; - static int convwidth_base[37] = {0,}; - static twodigits convmultmax_base[37] = {0,}; - - if (log_base_BASE[base] == 0.0) { - twodigits convmax = base; - int i = 1; - - log_base_BASE[base] = log((double)base) / - log((double)BASE); - for (;;) { - twodigits next = convmax * base; - if (next > BASE) - break; - convmax = next; - ++i; - } - convmultmax_base[base] = convmax; - assert(i > 0); - convwidth_base[base] = i; - } - - /* Find length of the string of numeric characters. */ - scan = str; - while (_PyLong_DigitValue[Py_CHARMASK(*scan)] < base) - ++scan; - - /* Create a long object that can contain the largest possible - * integer with this base and length. Note that there's no - * need to initialize z->ob_digit -- no slot is read up before - * being stored into. - */ - size_z = (Py_ssize_t)((scan - str) * log_base_BASE[base]) + 1; - /* Uncomment next line to test exceedingly rare copy code */ - /* size_z = 1; */ - assert(size_z > 0); - z = _PyLong_New(size_z); - if (z == NULL) - return NULL; - z->ob_size = 0; - - /* `convwidth` consecutive input digits are treated as a single - * digit in base `convmultmax`. - */ - convwidth = convwidth_base[base]; - convmultmax = convmultmax_base[base]; - - /* Work ;-) */ - while (str < scan) { - /* grab up to convwidth digits from the input string */ - c = (digit)_PyLong_DigitValue[Py_CHARMASK(*str++)]; - for (i = 1; i < convwidth && str != scan; ++i, ++str) { - c = (twodigits)(c * base + - _PyLong_DigitValue[Py_CHARMASK(*str)]); - assert(c < BASE); - } - - convmult = convmultmax; - /* Calculate the shift only if we couldn't get - * convwidth digits. - */ - if (i != convwidth) { - convmult = base; - for ( ; i > 1; --i) - convmult *= base; - } - - /* Multiply z by convmult, and add c. */ - pz = z->ob_digit; - pzstop = pz + z->ob_size; - for (; pz < pzstop; ++pz) { - c += (twodigits)*pz * convmult; - *pz = (digit)(c & MASK); - c >>= SHIFT; - } - /* carry off the current end? */ - if (c) { - assert(c < BASE); - if (z->ob_size < size_z) { - *pz = (digit)c; - ++z->ob_size; - } - else { - PyLongObject *tmp; - /* Extremely rare. Get more space. */ - assert(z->ob_size == size_z); - tmp = _PyLong_New(size_z + 1); - if (tmp == NULL) { - Py_DECREF(z); - return NULL; - } - memcpy(tmp->ob_digit, - z->ob_digit, - sizeof(digit) * size_z); - Py_DECREF(z); - z = tmp; - z->ob_digit[size_z] = (digit)c; - ++size_z; - } - } - } - } - if (z == NULL) - return NULL; - if (str == start) - goto onError; - if (sign < 0) - z->ob_size = -(z->ob_size); - if (*str == 'L' || *str == 'l') - str++; - while (*str && isspace(Py_CHARMASK(*str))) - str++; - if (*str != '\0') - goto onError; - if (pend) - *pend = str; - return (PyObject *) z; - - onError: - Py_XDECREF(z); - slen = strlen(orig_str) < 200 ? strlen(orig_str) : 200; - strobj = PyString_FromStringAndSize(orig_str, slen); - if (strobj == NULL) - return NULL; - strrepr = PyObject_Repr(strobj); - Py_DECREF(strobj); - if (strrepr == NULL) - return NULL; - PyErr_Format(PyExc_ValueError, - "invalid literal for long() with base %d: %s", - base, PyString_AS_STRING(strrepr)); - Py_DECREF(strrepr); - return NULL; -} - -#ifdef Py_USING_UNICODE -PyObject * -PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) -{ - PyObject *result; - char *buffer = (char *)PyMem_MALLOC(length+1); - - if (buffer == NULL) - return NULL; - - if (PyUnicode_EncodeDecimal(u, length, buffer, NULL)) { - PyMem_FREE(buffer); - return NULL; - } - result = PyLong_FromString(buffer, NULL, base); - PyMem_FREE(buffer); - return result; -} -#endif - -/* forward */ -static PyLongObject *x_divrem - (PyLongObject *, PyLongObject *, PyLongObject **); -static PyObject *long_pos(PyLongObject *); -static int long_divrem(PyLongObject *, PyLongObject *, - PyLongObject **, PyLongObject **); - -/* Long division with remainder, top-level routine */ - -static int -long_divrem(PyLongObject *a, PyLongObject *b, - PyLongObject **pdiv, PyLongObject **prem) -{ - Py_ssize_t size_a = ABS(a->ob_size), size_b = ABS(b->ob_size); - PyLongObject *z; - - if (size_b == 0) { - PyErr_SetString(PyExc_ZeroDivisionError, - "long division or modulo by zero"); - return -1; - } - if (size_a < size_b || - (size_a == size_b && - a->ob_digit[size_a-1] < b->ob_digit[size_b-1])) { - /* |a| < |b|. */ - *pdiv = _PyLong_New(0); - Py_INCREF(a); - *prem = (PyLongObject *) a; - return 0; - } - if (size_b == 1) { - digit rem = 0; - z = divrem1(a, b->ob_digit[0], &rem); - if (z == NULL) - return -1; - *prem = (PyLongObject *) PyLong_FromLong((long)rem); - } - else { - z = x_divrem(a, b, prem); - if (z == NULL) - return -1; - } - /* Set the signs. - The quotient z has the sign of a*b; - the remainder r has the sign of a, - so a = b*z + r. */ - if ((a->ob_size < 0) != (b->ob_size < 0)) - z->ob_size = -(z->ob_size); - if (a->ob_size < 0 && (*prem)->ob_size != 0) - (*prem)->ob_size = -((*prem)->ob_size); - *pdiv = z; - return 0; -} - -/* Unsigned long division with remainder -- the algorithm */ - -static PyLongObject * -x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) -{ - Py_ssize_t size_v = ABS(v1->ob_size), size_w = ABS(w1->ob_size); - digit d = (digit) ((twodigits)BASE / (w1->ob_digit[size_w-1] + 1)); - PyLongObject *v = mul1(v1, d); - PyLongObject *w = mul1(w1, d); - PyLongObject *a; - Py_ssize_t j, k; - - if (v == NULL || w == NULL) { - Py_XDECREF(v); - Py_XDECREF(w); - return NULL; - } - - assert(size_v >= size_w && size_w > 1); /* Assert checks by div() */ - assert(v->ob_refcnt == 1); /* Since v will be used as accumulator! */ - assert(size_w == ABS(w->ob_size)); /* That's how d was calculated */ - - size_v = ABS(v->ob_size); - k = size_v - size_w; - a = _PyLong_New(k + 1); - - for (j = size_v; a != NULL && k >= 0; --j, --k) { - digit vj = (j >= size_v) ? 0 : v->ob_digit[j]; - twodigits q; - stwodigits carry = 0; - int i; - - SIGCHECK({ - Py_DECREF(a); - a = NULL; - break; - }) - if (vj == w->ob_digit[size_w-1]) - q = MASK; - else - q = (((twodigits)vj << SHIFT) + v->ob_digit[j-1]) / - w->ob_digit[size_w-1]; - - while (w->ob_digit[size_w-2]*q > - (( - ((twodigits)vj << SHIFT) - + v->ob_digit[j-1] - - q*w->ob_digit[size_w-1] - ) << SHIFT) - + v->ob_digit[j-2]) - --q; - - for (i = 0; i < size_w && i+k < size_v; ++i) { - twodigits z = w->ob_digit[i] * q; - digit zz = (digit) (z >> SHIFT); - carry += v->ob_digit[i+k] - z - + ((twodigits)zz << SHIFT); - v->ob_digit[i+k] = (digit)(carry & MASK); - carry = Py_ARITHMETIC_RIGHT_SHIFT(BASE_TWODIGITS_TYPE, - carry, SHIFT); - carry -= zz; - } - - if (i+k < size_v) { - carry += v->ob_digit[i+k]; - v->ob_digit[i+k] = 0; - } - - if (carry == 0) - a->ob_digit[k] = (digit) q; - else { - assert(carry == -1); - a->ob_digit[k] = (digit) q-1; - carry = 0; - for (i = 0; i < size_w && i+k < size_v; ++i) { - carry += v->ob_digit[i+k] + w->ob_digit[i]; - v->ob_digit[i+k] = (digit)(carry & MASK); - carry = Py_ARITHMETIC_RIGHT_SHIFT( - BASE_TWODIGITS_TYPE, - carry, SHIFT); - } - } - } /* for j, k */ - - if (a == NULL) - *prem = NULL; - else { - a = long_normalize(a); - *prem = divrem1(v, d, &d); - /* d receives the (unused) remainder */ - if (*prem == NULL) { - Py_DECREF(a); - a = NULL; - } - } - Py_DECREF(v); - Py_DECREF(w); - return a; -} - -/* Methods */ - -static void -long_dealloc(PyObject *v) -{ - v->ob_type->tp_free(v); -} - -static PyObject * -long_repr(PyObject *v) -{ - return long_format(v, 10, 1); -} - -static PyObject * -long_str(PyObject *v) -{ - return long_format(v, 10, 0); -} - -static int -long_compare(PyLongObject *a, PyLongObject *b) -{ - Py_ssize_t sign; - - if (a->ob_size != b->ob_size) { - if (ABS(a->ob_size) == 0 && ABS(b->ob_size) == 0) - sign = 0; - else - sign = a->ob_size - b->ob_size; - } - else { - Py_ssize_t i = ABS(a->ob_size); - while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i]) - ; - if (i < 0) - sign = 0; - else { - sign = (int)a->ob_digit[i] - (int)b->ob_digit[i]; - if (a->ob_size < 0) - sign = -sign; - } - } - return sign < 0 ? -1 : sign > 0 ? 1 : 0; -} - -static long -long_hash(PyLongObject *v) -{ - long x; - Py_ssize_t i; - int sign; - - /* This is designed so that Python ints and longs with the - same value hash to the same value, otherwise comparisons - of mapping keys will turn out weird */ - i = v->ob_size; - sign = 1; - x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } -#define LONG_BIT_SHIFT (8*sizeof(long) - SHIFT) - while (--i >= 0) { - /* Force a native long #-bits (32 or 64) circular shift */ - x = ((x << SHIFT) & ~MASK) | ((x >> LONG_BIT_SHIFT) & MASK); - x += v->ob_digit[i]; - } -#undef LONG_BIT_SHIFT - x = x * sign; - if (x == -1) - x = -2; - return x; -} - - -/* Add the absolute values of two long integers. */ - -static PyLongObject * -x_add(PyLongObject *a, PyLongObject *b) -{ - Py_ssize_t size_a = ABS(a->ob_size), size_b = ABS(b->ob_size); - PyLongObject *z; - int i; - digit carry = 0; - - /* Ensure a is the larger of the two: */ - if (size_a < size_b) { - { PyLongObject *temp = a; a = b; b = temp; } - { Py_ssize_t size_temp = size_a; - size_a = size_b; - size_b = size_temp; } - } - z = _PyLong_New(size_a+1); - if (z == NULL) - return NULL; - for (i = 0; i < size_b; ++i) { - carry += a->ob_digit[i] + b->ob_digit[i]; - z->ob_digit[i] = carry & MASK; - carry >>= SHIFT; - } - for (; i < size_a; ++i) { - carry += a->ob_digit[i]; - z->ob_digit[i] = carry & MASK; - carry >>= SHIFT; - } - z->ob_digit[i] = carry; - return long_normalize(z); -} - -/* Subtract the absolute values of two integers. */ - -static PyLongObject * -x_sub(PyLongObject *a, PyLongObject *b) -{ - Py_ssize_t size_a = ABS(a->ob_size), size_b = ABS(b->ob_size); - PyLongObject *z; - Py_ssize_t i; - int sign = 1; - digit borrow = 0; - - /* Ensure a is the larger of the two: */ - if (size_a < size_b) { - sign = -1; - { PyLongObject *temp = a; a = b; b = temp; } - { Py_ssize_t size_temp = size_a; - size_a = size_b; - size_b = size_temp; } - } - else if (size_a == size_b) { - /* Find highest digit where a and b differ: */ - i = size_a; - while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i]) - ; - if (i < 0) - return _PyLong_New(0); - if (a->ob_digit[i] < b->ob_digit[i]) { - sign = -1; - { PyLongObject *temp = a; a = b; b = temp; } - } - size_a = size_b = i+1; - } - z = _PyLong_New(size_a); - if (z == NULL) - return NULL; - for (i = 0; i < size_b; ++i) { - /* The following assumes unsigned arithmetic - works module 2**N for some N>SHIFT. */ - borrow = a->ob_digit[i] - b->ob_digit[i] - borrow; - z->ob_digit[i] = borrow & MASK; - borrow >>= SHIFT; - borrow &= 1; /* Keep only one sign bit */ - } - for (; i < size_a; ++i) { - borrow = a->ob_digit[i] - borrow; - z->ob_digit[i] = borrow & MASK; - borrow >>= SHIFT; - borrow &= 1; /* Keep only one sign bit */ - } - assert(borrow == 0); - if (sign < 0) - z->ob_size = -(z->ob_size); - return long_normalize(z); -} - -static PyObject * -long_add(PyLongObject *v, PyLongObject *w) -{ - PyLongObject *a, *b, *z; - - CONVERT_BINOP((PyObject *)v, (PyObject *)w, &a, &b); - - if (a->ob_size < 0) { - if (b->ob_size < 0) { - z = x_add(a, b); - if (z != NULL && z->ob_size != 0) - z->ob_size = -(z->ob_size); - } - else - z = x_sub(b, a); - } - else { - if (b->ob_size < 0) - z = x_sub(a, b); - else - z = x_add(a, b); - } - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *)z; -} - -static PyObject * -long_sub(PyLongObject *v, PyLongObject *w) -{ - PyLongObject *a, *b, *z; - - CONVERT_BINOP((PyObject *)v, (PyObject *)w, &a, &b); - - if (a->ob_size < 0) { - if (b->ob_size < 0) - z = x_sub(a, b); - else - z = x_add(a, b); - if (z != NULL && z->ob_size != 0) - z->ob_size = -(z->ob_size); - } - else { - if (b->ob_size < 0) - z = x_add(a, b); - else - z = x_sub(a, b); - } - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *)z; -} - -/* Grade school multiplication, ignoring the signs. - * Returns the absolute value of the product, or NULL if error. - */ -static PyLongObject * -x_mul(PyLongObject *a, PyLongObject *b) -{ - PyLongObject *z; - Py_ssize_t size_a = ABS(a->ob_size); - Py_ssize_t size_b = ABS(b->ob_size); - Py_ssize_t i; - - z = _PyLong_New(size_a + size_b); - if (z == NULL) - return NULL; - - memset(z->ob_digit, 0, z->ob_size * sizeof(digit)); - if (a == b) { - /* Efficient squaring per HAC, Algorithm 14.16: - * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf - * Gives slightly less than a 2x speedup when a == b, - * via exploiting that each entry in the multiplication - * pyramid appears twice (except for the size_a squares). - */ - for (i = 0; i < size_a; ++i) { - twodigits carry; - twodigits f = a->ob_digit[i]; - digit *pz = z->ob_digit + (i << 1); - digit *pa = a->ob_digit + i + 1; - digit *paend = a->ob_digit + size_a; - - SIGCHECK({ - Py_DECREF(z); - return NULL; - }) - - carry = *pz + f * f; - *pz++ = (digit)(carry & MASK); - carry >>= SHIFT; - assert(carry <= MASK); - - /* Now f is added in twice in each column of the - * pyramid it appears. Same as adding f<<1 once. - */ - f <<= 1; - while (pa < paend) { - carry += *pz + *pa++ * f; - *pz++ = (digit)(carry & MASK); - carry >>= SHIFT; - assert(carry <= (MASK << 1)); - } - if (carry) { - carry += *pz; - *pz++ = (digit)(carry & MASK); - carry >>= SHIFT; - } - if (carry) - *pz += (digit)(carry & MASK); - assert((carry >> SHIFT) == 0); - } - } - else { /* a is not the same as b -- gradeschool long mult */ - for (i = 0; i < size_a; ++i) { - twodigits carry = 0; - twodigits f = a->ob_digit[i]; - digit *pz = z->ob_digit + i; - digit *pb = b->ob_digit; - digit *pbend = b->ob_digit + size_b; - - SIGCHECK({ - Py_DECREF(z); - return NULL; - }) - - while (pb < pbend) { - carry += *pz + *pb++ * f; - *pz++ = (digit)(carry & MASK); - carry >>= SHIFT; - assert(carry <= MASK); - } - if (carry) - *pz += (digit)(carry & MASK); - assert((carry >> SHIFT) == 0); - } - } - return long_normalize(z); -} - -/* A helper for Karatsuba multiplication (k_mul). - Takes a long "n" and an integer "size" representing the place to - split, and sets low and high such that abs(n) == (high << size) + low, - viewing the shift as being by digits. The sign bit is ignored, and - the return values are >= 0. - Returns 0 on success, -1 on failure. -*/ -static int -kmul_split(PyLongObject *n, Py_ssize_t size, PyLongObject **high, PyLongObject **low) -{ - PyLongObject *hi, *lo; - Py_ssize_t size_lo, size_hi; - const Py_ssize_t size_n = ABS(n->ob_size); - - size_lo = MIN(size_n, size); - size_hi = size_n - size_lo; - - if ((hi = _PyLong_New(size_hi)) == NULL) - return -1; - if ((lo = _PyLong_New(size_lo)) == NULL) { - Py_DECREF(hi); - return -1; - } - - memcpy(lo->ob_digit, n->ob_digit, size_lo * sizeof(digit)); - memcpy(hi->ob_digit, n->ob_digit + size_lo, size_hi * sizeof(digit)); - - *high = long_normalize(hi); - *low = long_normalize(lo); - return 0; -} - -static PyLongObject *k_lopsided_mul(PyLongObject *a, PyLongObject *b); - -/* Karatsuba multiplication. Ignores the input signs, and returns the - * absolute value of the product (or NULL if error). - * See Knuth Vol. 2 Chapter 4.3.3 (Pp. 294-295). - */ -static PyLongObject * -k_mul(PyLongObject *a, PyLongObject *b) -{ - Py_ssize_t asize = ABS(a->ob_size); - Py_ssize_t bsize = ABS(b->ob_size); - PyLongObject *ah = NULL; - PyLongObject *al = NULL; - PyLongObject *bh = NULL; - PyLongObject *bl = NULL; - PyLongObject *ret = NULL; - PyLongObject *t1, *t2, *t3; - Py_ssize_t shift; /* the number of digits we split off */ - Py_ssize_t i; - - /* (ah*X+al)(bh*X+bl) = ah*bh*X*X + (ah*bl + al*bh)*X + al*bl - * Let k = (ah+al)*(bh+bl) = ah*bl + al*bh + ah*bh + al*bl - * Then the original product is - * ah*bh*X*X + (k - ah*bh - al*bl)*X + al*bl - * By picking X to be a power of 2, "*X" is just shifting, and it's - * been reduced to 3 multiplies on numbers half the size. - */ - - /* We want to split based on the larger number; fiddle so that b - * is largest. - */ - if (asize > bsize) { - t1 = a; - a = b; - b = t1; - - i = asize; - asize = bsize; - bsize = i; - } - - /* Use gradeschool math when either number is too small. */ - i = a == b ? KARATSUBA_SQUARE_CUTOFF : KARATSUBA_CUTOFF; - if (asize <= i) { - if (asize == 0) - return _PyLong_New(0); - else - return x_mul(a, b); - } - - /* If a is small compared to b, splitting on b gives a degenerate - * case with ah==0, and Karatsuba may be (even much) less efficient - * than "grade school" then. However, we can still win, by viewing - * b as a string of "big digits", each of width a->ob_size. That - * leads to a sequence of balanced calls to k_mul. - */ - if (2 * asize <= bsize) - return k_lopsided_mul(a, b); - - /* Split a & b into hi & lo pieces. */ - shift = bsize >> 1; - if (kmul_split(a, shift, &ah, &al) < 0) goto fail; - assert(ah->ob_size > 0); /* the split isn't degenerate */ - - if (a == b) { - bh = ah; - bl = al; - Py_INCREF(bh); - Py_INCREF(bl); - } - else if (kmul_split(b, shift, &bh, &bl) < 0) goto fail; - - /* The plan: - * 1. Allocate result space (asize + bsize digits: that's always - * enough). - * 2. Compute ah*bh, and copy into result at 2*shift. - * 3. Compute al*bl, and copy into result at 0. Note that this - * can't overlap with #2. - * 4. Subtract al*bl from the result, starting at shift. This may - * underflow (borrow out of the high digit), but we don't care: - * we're effectively doing unsigned arithmetic mod - * BASE**(sizea + sizeb), and so long as the *final* result fits, - * borrows and carries out of the high digit can be ignored. - * 5. Subtract ah*bh from the result, starting at shift. - * 6. Compute (ah+al)*(bh+bl), and add it into the result starting - * at shift. - */ - - /* 1. Allocate result space. */ - ret = _PyLong_New(asize + bsize); - if (ret == NULL) goto fail; -#ifdef Py_DEBUG - /* Fill with trash, to catch reference to uninitialized digits. */ - memset(ret->ob_digit, 0xDF, ret->ob_size * sizeof(digit)); -#endif - - /* 2. t1 <- ah*bh, and copy into high digits of result. */ - if ((t1 = k_mul(ah, bh)) == NULL) goto fail; - assert(t1->ob_size >= 0); - assert(2*shift + t1->ob_size <= ret->ob_size); - memcpy(ret->ob_digit + 2*shift, t1->ob_digit, - t1->ob_size * sizeof(digit)); - - /* Zero-out the digits higher than the ah*bh copy. */ - i = ret->ob_size - 2*shift - t1->ob_size; - if (i) - memset(ret->ob_digit + 2*shift + t1->ob_size, 0, - i * sizeof(digit)); - - /* 3. t2 <- al*bl, and copy into the low digits. */ - if ((t2 = k_mul(al, bl)) == NULL) { - Py_DECREF(t1); - goto fail; - } - assert(t2->ob_size >= 0); - assert(t2->ob_size <= 2*shift); /* no overlap with high digits */ - memcpy(ret->ob_digit, t2->ob_digit, t2->ob_size * sizeof(digit)); - - /* Zero out remaining digits. */ - i = 2*shift - t2->ob_size; /* number of uninitialized digits */ - if (i) - memset(ret->ob_digit + t2->ob_size, 0, i * sizeof(digit)); - - /* 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first - * because it's fresher in cache. - */ - i = ret->ob_size - shift; /* # digits after shift */ - (void)v_isub(ret->ob_digit + shift, i, t2->ob_digit, t2->ob_size); - Py_DECREF(t2); - - (void)v_isub(ret->ob_digit + shift, i, t1->ob_digit, t1->ob_size); - Py_DECREF(t1); - - /* 6. t3 <- (ah+al)(bh+bl), and add into result. */ - if ((t1 = x_add(ah, al)) == NULL) goto fail; - Py_DECREF(ah); - Py_DECREF(al); - ah = al = NULL; - - if (a == b) { - t2 = t1; - Py_INCREF(t2); - } - else if ((t2 = x_add(bh, bl)) == NULL) { - Py_DECREF(t1); - goto fail; - } - Py_DECREF(bh); - Py_DECREF(bl); - bh = bl = NULL; - - t3 = k_mul(t1, t2); - Py_DECREF(t1); - Py_DECREF(t2); - if (t3 == NULL) goto fail; - assert(t3->ob_size >= 0); - - /* Add t3. It's not obvious why we can't run out of room here. - * See the (*) comment after this function. - */ - (void)v_iadd(ret->ob_digit + shift, i, t3->ob_digit, t3->ob_size); - Py_DECREF(t3); - - return long_normalize(ret); - - fail: - Py_XDECREF(ret); - Py_XDECREF(ah); - Py_XDECREF(al); - Py_XDECREF(bh); - Py_XDECREF(bl); - return NULL; -} - -/* (*) Why adding t3 can't "run out of room" above. - -Let f(x) mean the floor of x and c(x) mean the ceiling of x. Some facts -to start with: - -1. For any integer i, i = c(i/2) + f(i/2). In particular, - bsize = c(bsize/2) + f(bsize/2). -2. shift = f(bsize/2) -3. asize <= bsize -4. Since we call k_lopsided_mul if asize*2 <= bsize, asize*2 > bsize in this - routine, so asize > bsize/2 >= f(bsize/2) in this routine. - -We allocated asize + bsize result digits, and add t3 into them at an offset -of shift. This leaves asize+bsize-shift allocated digit positions for t3 -to fit into, = (by #1 and #2) asize + f(bsize/2) + c(bsize/2) - f(bsize/2) = -asize + c(bsize/2) available digit positions. - -bh has c(bsize/2) digits, and bl at most f(size/2) digits. So bh+hl has -at most c(bsize/2) digits + 1 bit. - -If asize == bsize, ah has c(bsize/2) digits, else ah has at most f(bsize/2) -digits, and al has at most f(bsize/2) digits in any case. So ah+al has at -most (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 1 bit. - -The product (ah+al)*(bh+bl) therefore has at most - - c(bsize/2) + (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits - -and we have asize + c(bsize/2) available digit positions. We need to show -this is always enough. An instance of c(bsize/2) cancels out in both, so -the question reduces to whether asize digits is enough to hold -(asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits. If asize < bsize, -then we're asking whether asize digits >= f(bsize/2) digits + 2 bits. By #4, -asize is at least f(bsize/2)+1 digits, so this in turn reduces to whether 1 -digit is enough to hold 2 bits. This is so since SHIFT=15 >= 2. If -asize == bsize, then we're asking whether bsize digits is enough to hold -c(bsize/2) digits + 2 bits, or equivalently (by #1) whether f(bsize/2) digits -is enough to hold 2 bits. This is so if bsize >= 2, which holds because -bsize >= KARATSUBA_CUTOFF >= 2. - -Note that since there's always enough room for (ah+al)*(bh+bl), and that's -clearly >= each of ah*bh and al*bl, there's always enough room to subtract -ah*bh and al*bl too. -*/ - -/* b has at least twice the digits of a, and a is big enough that Karatsuba - * would pay off *if* the inputs had balanced sizes. View b as a sequence - * of slices, each with a->ob_size digits, and multiply the slices by a, - * one at a time. This gives k_mul balanced inputs to work with, and is - * also cache-friendly (we compute one double-width slice of the result - * at a time, then move on, never bactracking except for the helpful - * single-width slice overlap between successive partial sums). - */ -static PyLongObject * -k_lopsided_mul(PyLongObject *a, PyLongObject *b) -{ - const Py_ssize_t asize = ABS(a->ob_size); - Py_ssize_t bsize = ABS(b->ob_size); - Py_ssize_t nbdone; /* # of b digits already multiplied */ - PyLongObject *ret; - PyLongObject *bslice = NULL; - - assert(asize > KARATSUBA_CUTOFF); - assert(2 * asize <= bsize); - - /* Allocate result space, and zero it out. */ - ret = _PyLong_New(asize + bsize); - if (ret == NULL) - return NULL; - memset(ret->ob_digit, 0, ret->ob_size * sizeof(digit)); - - /* Successive slices of b are copied into bslice. */ - bslice = _PyLong_New(asize); - if (bslice == NULL) - goto fail; - - nbdone = 0; - while (bsize > 0) { - PyLongObject *product; - const Py_ssize_t nbtouse = MIN(bsize, asize); - - /* Multiply the next slice of b by a. */ - memcpy(bslice->ob_digit, b->ob_digit + nbdone, - nbtouse * sizeof(digit)); - bslice->ob_size = nbtouse; - product = k_mul(a, bslice); - if (product == NULL) - goto fail; - - /* Add into result. */ - (void)v_iadd(ret->ob_digit + nbdone, ret->ob_size - nbdone, - product->ob_digit, product->ob_size); - Py_DECREF(product); - - bsize -= nbtouse; - nbdone += nbtouse; - } - - Py_DECREF(bslice); - return long_normalize(ret); - - fail: - Py_DECREF(ret); - Py_XDECREF(bslice); - return NULL; -} - -static PyObject * -long_mul(PyLongObject *v, PyLongObject *w) -{ - PyLongObject *a, *b, *z; - - if (!convert_binop((PyObject *)v, (PyObject *)w, &a, &b)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - z = k_mul(a, b); - /* Negate if exactly one of the inputs is negative. */ - if (((a->ob_size ^ b->ob_size) < 0) && z) - z->ob_size = -(z->ob_size); - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *)z; -} - -/* The / and % operators are now defined in terms of divmod(). - The expression a mod b has the value a - b*floor(a/b). - The long_divrem function gives the remainder after division of - |a| by |b|, with the sign of a. This is also expressed - as a - b*trunc(a/b), if trunc truncates towards zero. - Some examples: - a b a rem b a mod b - 13 10 3 3 - -13 10 -3 7 - 13 -10 3 -7 - -13 -10 -3 -3 - So, to get from rem to mod, we have to add b if a and b - have different signs. We then subtract one from the 'div' - part of the outcome to keep the invariant intact. */ - -/* Compute - * *pdiv, *pmod = divmod(v, w) - * NULL can be passed for pdiv or pmod, in which case that part of - * the result is simply thrown away. The caller owns a reference to - * each of these it requests (does not pass NULL for). - */ -static int -l_divmod(PyLongObject *v, PyLongObject *w, - PyLongObject **pdiv, PyLongObject **pmod) -{ - PyLongObject *div, *mod; - - if (long_divrem(v, w, &div, &mod) < 0) - return -1; - if ((mod->ob_size < 0 && w->ob_size > 0) || - (mod->ob_size > 0 && w->ob_size < 0)) { - PyLongObject *temp; - PyLongObject *one; - temp = (PyLongObject *) long_add(mod, w); - Py_DECREF(mod); - mod = temp; - if (mod == NULL) { - Py_DECREF(div); - return -1; - } - one = (PyLongObject *) PyLong_FromLong(1L); - if (one == NULL || - (temp = (PyLongObject *) long_sub(div, one)) == NULL) { - Py_DECREF(mod); - Py_DECREF(div); - Py_XDECREF(one); - return -1; - } - Py_DECREF(one); - Py_DECREF(div); - div = temp; - } - if (pdiv != NULL) - *pdiv = div; - else - Py_DECREF(div); - - if (pmod != NULL) - *pmod = mod; - else - Py_DECREF(mod); - - return 0; -} - -static PyObject * -long_div(PyObject *v, PyObject *w) -{ - PyLongObject *a, *b, *div; - - CONVERT_BINOP(v, w, &a, &b); - if (l_divmod(a, b, &div, NULL) < 0) - div = NULL; - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *)div; -} - -static PyObject * -long_classic_div(PyObject *v, PyObject *w) -{ - PyLongObject *a, *b, *div; - - CONVERT_BINOP(v, w, &a, &b); - if (Py_DivisionWarningFlag && - PyErr_Warn(PyExc_DeprecationWarning, "classic long division") < 0) - div = NULL; - else if (l_divmod(a, b, &div, NULL) < 0) - div = NULL; - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *)div; -} - -static PyObject * -long_true_divide(PyObject *v, PyObject *w) -{ - PyLongObject *a, *b; - double ad, bd; - int failed, aexp = -1, bexp = -1; - - CONVERT_BINOP(v, w, &a, &b); - ad = _PyLong_AsScaledDouble((PyObject *)a, &aexp); - bd = _PyLong_AsScaledDouble((PyObject *)b, &bexp); - failed = (ad == -1.0 || bd == -1.0) && PyErr_Occurred(); - Py_DECREF(a); - Py_DECREF(b); - if (failed) - return NULL; - /* 'aexp' and 'bexp' were initialized to -1 to silence gcc-4.0.x, - but should really be set correctly after sucessful calls to - _PyLong_AsScaledDouble() */ - assert(aexp >= 0 && bexp >= 0); - - if (bd == 0.0) { - PyErr_SetString(PyExc_ZeroDivisionError, - "long division or modulo by zero"); - return NULL; - } - - /* True value is very close to ad/bd * 2**(SHIFT*(aexp-bexp)) */ - ad /= bd; /* overflow/underflow impossible here */ - aexp -= bexp; - if (aexp > INT_MAX / SHIFT) - goto overflow; - else if (aexp < -(INT_MAX / SHIFT)) - return PyFloat_FromDouble(0.0); /* underflow to 0 */ - errno = 0; - ad = ldexp(ad, aexp * SHIFT); - if (Py_OVERFLOWED(ad)) /* ignore underflow to 0.0 */ - goto overflow; - return PyFloat_FromDouble(ad); - -overflow: - PyErr_SetString(PyExc_OverflowError, - "long/long too large for a float"); - return NULL; - -} - -static PyObject * -long_mod(PyObject *v, PyObject *w) -{ - PyLongObject *a, *b, *mod; - - CONVERT_BINOP(v, w, &a, &b); - - if (l_divmod(a, b, NULL, &mod) < 0) - mod = NULL; - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *)mod; -} - -static PyObject * -long_divmod(PyObject *v, PyObject *w) -{ - PyLongObject *a, *b, *div, *mod; - PyObject *z; - - CONVERT_BINOP(v, w, &a, &b); - - if (l_divmod(a, b, &div, &mod) < 0) { - Py_DECREF(a); - Py_DECREF(b); - return NULL; - } - z = PyTuple_New(2); - if (z != NULL) { - PyTuple_SetItem(z, 0, (PyObject *) div); - PyTuple_SetItem(z, 1, (PyObject *) mod); - } - else { - Py_DECREF(div); - Py_DECREF(mod); - } - Py_DECREF(a); - Py_DECREF(b); - return z; -} - -/* pow(v, w, x) */ -static PyObject * -long_pow(PyObject *v, PyObject *w, PyObject *x) -{ - PyLongObject *a, *b, *c; /* a,b,c = v,w,x */ - int negativeOutput = 0; /* if x<0 return negative output */ - - PyLongObject *z = NULL; /* accumulated result */ - Py_ssize_t i, j, k; /* counters */ - PyLongObject *temp = NULL; - - /* 5-ary values. If the exponent is large enough, table is - * precomputed so that table[i] == a**i % c for i in range(32). - */ - PyLongObject *table[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - /* a, b, c = v, w, x */ - CONVERT_BINOP(v, w, &a, &b); - if (PyLong_Check(x)) { - c = (PyLongObject *)x; - Py_INCREF(x); - } - else if (PyInt_Check(x)) { - c = (PyLongObject *)PyLong_FromLong(PyInt_AS_LONG(x)); - if (c == NULL) - goto Error; - } - else if (x == Py_None) - c = NULL; - else { - Py_DECREF(a); - Py_DECREF(b); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (b->ob_size < 0) { /* if exponent is negative */ - if (c) { - PyErr_SetString(PyExc_TypeError, "pow() 2nd argument " - "cannot be negative when 3rd argument specified"); - goto Error; - } - else { - /* else return a float. This works because we know - that this calls float_pow() which converts its - arguments to double. */ - Py_DECREF(a); - Py_DECREF(b); - return PyFloat_Type.tp_as_number->nb_power(v, w, x); - } - } - - if (c) { - /* if modulus == 0: - raise ValueError() */ - if (c->ob_size == 0) { - PyErr_SetString(PyExc_ValueError, - "pow() 3rd argument cannot be 0"); - goto Error; - } - - /* if modulus < 0: - negativeOutput = True - modulus = -modulus */ - if (c->ob_size < 0) { - negativeOutput = 1; - temp = (PyLongObject *)_PyLong_Copy(c); - if (temp == NULL) - goto Error; - Py_DECREF(c); - c = temp; - temp = NULL; - c->ob_size = - c->ob_size; - } - - /* if modulus == 1: - return 0 */ - if ((c->ob_size == 1) && (c->ob_digit[0] == 1)) { - z = (PyLongObject *)PyLong_FromLong(0L); - goto Done; - } - - /* if base < 0: - base = base % modulus - Having the base positive just makes things easier. */ - if (a->ob_size < 0) { - if (l_divmod(a, c, NULL, &temp) < 0) - goto Error; - Py_DECREF(a); - a = temp; - temp = NULL; - } - } - - /* At this point a, b, and c are guaranteed non-negative UNLESS - c is NULL, in which case a may be negative. */ - - z = (PyLongObject *)PyLong_FromLong(1L); - if (z == NULL) - goto Error; - - /* Perform a modular reduction, X = X % c, but leave X alone if c - * is NULL. - */ -#define REDUCE(X) \ - if (c != NULL) { \ - if (l_divmod(X, c, NULL, &temp) < 0) \ - goto Error; \ - Py_XDECREF(X); \ - X = temp; \ - temp = NULL; \ - } - - /* Multiply two values, then reduce the result: - result = X*Y % c. If c is NULL, skip the mod. */ -#define MULT(X, Y, result) \ -{ \ - temp = (PyLongObject *)long_mul(X, Y); \ - if (temp == NULL) \ - goto Error; \ - Py_XDECREF(result); \ - result = temp; \ - temp = NULL; \ - REDUCE(result) \ -} - - if (b->ob_size <= FIVEARY_CUTOFF) { - /* Left-to-right binary exponentiation (HAC Algorithm 14.79) */ - /* http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf */ - for (i = b->ob_size - 1; i >= 0; --i) { - digit bi = b->ob_digit[i]; - - for (j = 1 << (SHIFT-1); j != 0; j >>= 1) { - MULT(z, z, z) - if (bi & j) - MULT(z, a, z) - } - } - } - else { - /* Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) */ - Py_INCREF(z); /* still holds 1L */ - table[0] = z; - for (i = 1; i < 32; ++i) - MULT(table[i-1], a, table[i]) - - for (i = b->ob_size - 1; i >= 0; --i) { - const digit bi = b->ob_digit[i]; - - for (j = SHIFT - 5; j >= 0; j -= 5) { - const int index = (bi >> j) & 0x1f; - for (k = 0; k < 5; ++k) - MULT(z, z, z) - if (index) - MULT(z, table[index], z) - } - } - } - - if (negativeOutput && (z->ob_size != 0)) { - temp = (PyLongObject *)long_sub(z, c); - if (temp == NULL) - goto Error; - Py_DECREF(z); - z = temp; - temp = NULL; - } - goto Done; - - Error: - if (z != NULL) { - Py_DECREF(z); - z = NULL; - } - /* fall through */ - Done: - if (b->ob_size > FIVEARY_CUTOFF) { - for (i = 0; i < 32; ++i) - Py_XDECREF(table[i]); - } - Py_DECREF(a); - Py_DECREF(b); - Py_XDECREF(c); - Py_XDECREF(temp); - return (PyObject *)z; -} - -static PyObject * -long_invert(PyLongObject *v) -{ - /* Implement ~x as -(x+1) */ - PyLongObject *x; - PyLongObject *w; - w = (PyLongObject *)PyLong_FromLong(1L); - if (w == NULL) - return NULL; - x = (PyLongObject *) long_add(v, w); - Py_DECREF(w); - if (x == NULL) - return NULL; - x->ob_size = -(x->ob_size); - return (PyObject *)x; -} - -static PyObject * -long_pos(PyLongObject *v) -{ - if (PyLong_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return _PyLong_Copy(v); -} - -static PyObject * -long_neg(PyLongObject *v) -{ - PyLongObject *z; - if (v->ob_size == 0 && PyLong_CheckExact(v)) { - /* -0 == 0 */ - Py_INCREF(v); - return (PyObject *) v; - } - z = (PyLongObject *)_PyLong_Copy(v); - if (z != NULL) - z->ob_size = -(v->ob_size); - return (PyObject *)z; -} - -static PyObject * -long_abs(PyLongObject *v) -{ - if (v->ob_size < 0) - return long_neg(v); - else - return long_pos(v); -} - -static int -long_nonzero(PyLongObject *v) -{ - return ABS(v->ob_size) != 0; -} - -static PyObject * -long_rshift(PyLongObject *v, PyLongObject *w) -{ - PyLongObject *a, *b; - PyLongObject *z = NULL; - long shiftby; - Py_ssize_t newsize, wordshift, loshift, hishift, i, j; - digit lomask, himask; - - CONVERT_BINOP((PyObject *)v, (PyObject *)w, &a, &b); - - if (a->ob_size < 0) { - /* Right shifting negative numbers is harder */ - PyLongObject *a1, *a2; - a1 = (PyLongObject *) long_invert(a); - if (a1 == NULL) - goto rshift_error; - a2 = (PyLongObject *) long_rshift(a1, b); - Py_DECREF(a1); - if (a2 == NULL) - goto rshift_error; - z = (PyLongObject *) long_invert(a2); - Py_DECREF(a2); - } - else { - - shiftby = PyLong_AsLong((PyObject *)b); - if (shiftby == -1L && PyErr_Occurred()) - goto rshift_error; - if (shiftby < 0) { - PyErr_SetString(PyExc_ValueError, - "negative shift count"); - goto rshift_error; - } - wordshift = shiftby / SHIFT; - newsize = ABS(a->ob_size) - wordshift; - if (newsize <= 0) { - z = _PyLong_New(0); - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *)z; - } - loshift = shiftby % SHIFT; - hishift = SHIFT - loshift; - lomask = ((digit)1 << hishift) - 1; - himask = MASK ^ lomask; - z = _PyLong_New(newsize); - if (z == NULL) - goto rshift_error; - if (a->ob_size < 0) - z->ob_size = -(z->ob_size); - for (i = 0, j = wordshift; i < newsize; i++, j++) { - z->ob_digit[i] = (a->ob_digit[j] >> loshift) & lomask; - if (i+1 < newsize) - z->ob_digit[i] |= - (a->ob_digit[j+1] << hishift) & himask; - } - z = long_normalize(z); - } -rshift_error: - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *) z; - -} - -static PyObject * -long_lshift(PyObject *v, PyObject *w) -{ - /* This version due to Tim Peters */ - PyLongObject *a, *b; - PyLongObject *z = NULL; - long shiftby; - Py_ssize_t oldsize, newsize, wordshift, remshift, i, j; - twodigits accum; - - CONVERT_BINOP(v, w, &a, &b); - - shiftby = PyLong_AsLong((PyObject *)b); - if (shiftby == -1L && PyErr_Occurred()) - goto lshift_error; - if (shiftby < 0) { - PyErr_SetString(PyExc_ValueError, "negative shift count"); - goto lshift_error; - } - if ((long)(int)shiftby != shiftby) { - PyErr_SetString(PyExc_ValueError, - "outrageous left shift count"); - goto lshift_error; - } - /* wordshift, remshift = divmod(shiftby, SHIFT) */ - wordshift = (int)shiftby / SHIFT; - remshift = (int)shiftby - wordshift * SHIFT; - - oldsize = ABS(a->ob_size); - newsize = oldsize + wordshift; - if (remshift) - ++newsize; - z = _PyLong_New(newsize); - if (z == NULL) - goto lshift_error; - if (a->ob_size < 0) - z->ob_size = -(z->ob_size); - for (i = 0; i < wordshift; i++) - z->ob_digit[i] = 0; - accum = 0; - for (i = wordshift, j = 0; j < oldsize; i++, j++) { - accum |= (twodigits)a->ob_digit[j] << remshift; - z->ob_digit[i] = (digit)(accum & MASK); - accum >>= SHIFT; - } - if (remshift) - z->ob_digit[newsize-1] = (digit)accum; - else - assert(!accum); - z = long_normalize(z); -lshift_error: - Py_DECREF(a); - Py_DECREF(b); - return (PyObject *) z; -} - - -/* Bitwise and/xor/or operations */ - -static PyObject * -long_bitwise(PyLongObject *a, - int op, /* '&', '|', '^' */ - PyLongObject *b) -{ - digit maska, maskb; /* 0 or MASK */ - int negz; - Py_ssize_t size_a, size_b, size_z; - PyLongObject *z; - int i; - digit diga, digb; - PyObject *v; - - if (a->ob_size < 0) { - a = (PyLongObject *) long_invert(a); - if (a == NULL) - return NULL; - maska = MASK; - } - else { - Py_INCREF(a); - maska = 0; - } - if (b->ob_size < 0) { - b = (PyLongObject *) long_invert(b); - if (b == NULL) { - Py_DECREF(a); - return NULL; - } - maskb = MASK; - } - else { - Py_INCREF(b); - maskb = 0; - } - - negz = 0; - switch (op) { - case '^': - if (maska != maskb) { - maska ^= MASK; - negz = -1; - } - break; - case '&': - if (maska && maskb) { - op = '|'; - maska ^= MASK; - maskb ^= MASK; - negz = -1; - } - break; - case '|': - if (maska || maskb) { - op = '&'; - maska ^= MASK; - maskb ^= MASK; - negz = -1; - } - break; - } - - /* JRH: The original logic here was to allocate the result value (z) - as the longer of the two operands. However, there are some cases - where the result is guaranteed to be shorter than that: AND of two - positives, OR of two negatives: use the shorter number. AND with - mixed signs: use the positive number. OR with mixed signs: use the - negative number. After the transformations above, op will be '&' - iff one of these cases applies, and mask will be non-0 for operands - whose length should be ignored. - */ - - size_a = a->ob_size; - size_b = b->ob_size; - size_z = op == '&' - ? (maska - ? size_b - : (maskb ? size_a : MIN(size_a, size_b))) - : MAX(size_a, size_b); - z = _PyLong_New(size_z); - if (z == NULL) { - Py_DECREF(a); - Py_DECREF(b); - return NULL; - } - - for (i = 0; i < size_z; ++i) { - diga = (i < size_a ? a->ob_digit[i] : 0) ^ maska; - digb = (i < size_b ? b->ob_digit[i] : 0) ^ maskb; - switch (op) { - case '&': z->ob_digit[i] = diga & digb; break; - case '|': z->ob_digit[i] = diga | digb; break; - case '^': z->ob_digit[i] = diga ^ digb; break; - } - } - - Py_DECREF(a); - Py_DECREF(b); - z = long_normalize(z); - if (negz == 0) - return (PyObject *) z; - v = long_invert(z); - Py_DECREF(z); - return v; -} - -static PyObject * -long_and(PyObject *v, PyObject *w) -{ - PyLongObject *a, *b; - PyObject *c; - CONVERT_BINOP(v, w, &a, &b); - c = long_bitwise(a, '&', b); - Py_DECREF(a); - Py_DECREF(b); - return c; -} - -static PyObject * -long_xor(PyObject *v, PyObject *w) -{ - PyLongObject *a, *b; - PyObject *c; - CONVERT_BINOP(v, w, &a, &b); - c = long_bitwise(a, '^', b); - Py_DECREF(a); - Py_DECREF(b); - return c; -} - -static PyObject * -long_or(PyObject *v, PyObject *w) -{ - PyLongObject *a, *b; - PyObject *c; - CONVERT_BINOP(v, w, &a, &b); - c = long_bitwise(a, '|', b); - Py_DECREF(a); - Py_DECREF(b); - return c; -} - -static int -long_coerce(PyObject **pv, PyObject **pw) -{ - if (PyInt_Check(*pw)) { - *pw = PyLong_FromLong(PyInt_AS_LONG(*pw)); - Py_INCREF(*pv); - return 0; - } - else if (PyLong_Check(*pw)) { - Py_INCREF(*pv); - Py_INCREF(*pw); - return 0; - } - return 1; /* Can't do it */ -} - -static PyObject * -long_long(PyObject *v) -{ - if (PyLong_CheckExact(v)) - Py_INCREF(v); - else - v = _PyLong_Copy((PyLongObject *)v); - return v; -} - -static PyObject * -long_int(PyObject *v) -{ - long x; - x = PyLong_AsLong(v); - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - PyErr_Clear(); - if (PyLong_CheckExact(v)) { - Py_INCREF(v); - return v; - } - else - return _PyLong_Copy((PyLongObject *)v); - } - else - return NULL; - } - return PyInt_FromLong(x); -} - -static PyObject * -long_float(PyObject *v) -{ - double result; - result = PyLong_AsDouble(v); - if (result == -1.0 && PyErr_Occurred()) - return NULL; - return PyFloat_FromDouble(result); -} - -static PyObject * -long_oct(PyObject *v) -{ - return long_format(v, 8, 1); -} - -static PyObject * -long_hex(PyObject *v) -{ - return long_format(v, 16, 1); -} - -static PyObject * -long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static PyObject * -long_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *x = NULL; - int base = -909; /* unlikely! */ - static char *kwlist[] = {"x", "base", 0}; - - if (type != &PyLong_Type) - return long_subtype_new(type, args, kwds); /* Wimp out */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:long", kwlist, - &x, &base)) - return NULL; - if (x == NULL) - return PyLong_FromLong(0L); - if (base == -909) - return PyNumber_Long(x); - else if (PyString_Check(x)) { - /* Since PyLong_FromString doesn't have a length parameter, - * check here for possible NULs in the string. */ - char *string = PyString_AS_STRING(x); - if (strlen(string) != PyString_Size(x)) { - /* create a repr() of the input string, - * just like PyLong_FromString does. */ - PyObject *srepr; - srepr = PyObject_Repr(x); - if (srepr == NULL) - return NULL; - PyErr_Format(PyExc_ValueError, - "invalid literal for long() with base %d: %s", - base, PyString_AS_STRING(srepr)); - Py_DECREF(srepr); - return NULL; - } - return PyLong_FromString(PyString_AS_STRING(x), NULL, base); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(x)) - return PyLong_FromUnicode(PyUnicode_AS_UNICODE(x), - PyUnicode_GET_SIZE(x), - base); -#endif - else { - PyErr_SetString(PyExc_TypeError, - "long() can't convert non-string with explicit base"); - return NULL; - } -} - -/* Wimpy, slow approach to tp_new calls for subtypes of long: - first create a regular long from whatever arguments we got, - then allocate a subtype instance and initialize it from - the regular long. The regular long is then thrown away. -*/ -static PyObject * -long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyLongObject *tmp, *newobj; - Py_ssize_t i, n; - - assert(PyType_IsSubtype(type, &PyLong_Type)); - tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds); - if (tmp == NULL) - return NULL; - assert(PyLong_CheckExact(tmp)); - n = tmp->ob_size; - if (n < 0) - n = -n; - newobj = (PyLongObject *)type->tp_alloc(type, n); - if (newobj == NULL) { - Py_DECREF(tmp); - return NULL; - } - assert(PyLong_Check(newobj)); - newobj->ob_size = tmp->ob_size; - for (i = 0; i < n; i++) - newobj->ob_digit[i] = tmp->ob_digit[i]; - Py_DECREF(tmp); - return (PyObject *)newobj; -} - -static PyObject * -long_getnewargs(PyLongObject *v) -{ - return Py_BuildValue("(N)", _PyLong_Copy(v)); -} - -static PyMethodDef long_methods[] = { - {"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -PyDoc_STRVAR(long_doc, -"long(x[, base]) -> integer\n\ -\n\ -Convert a string or number to a long integer, if possible. A floating\n\ -point argument will be truncated towards zero (this does not include a\n\ -string representation of a floating point number!) When converting a\n\ -string, use the optional base. It is an error to supply a base when\n\ -converting a non-string."); - -static PyNumberMethods long_as_number = { - (binaryfunc) long_add, /*nb_add*/ - (binaryfunc) long_sub, /*nb_subtract*/ - (binaryfunc) long_mul, /*nb_multiply*/ - long_classic_div, /*nb_divide*/ - long_mod, /*nb_remainder*/ - long_divmod, /*nb_divmod*/ - long_pow, /*nb_power*/ - (unaryfunc) long_neg, /*nb_negative*/ - (unaryfunc) long_pos, /*tp_positive*/ - (unaryfunc) long_abs, /*tp_absolute*/ - (inquiry) long_nonzero, /*tp_nonzero*/ - (unaryfunc) long_invert, /*nb_invert*/ - long_lshift, /*nb_lshift*/ - (binaryfunc) long_rshift, /*nb_rshift*/ - long_and, /*nb_and*/ - long_xor, /*nb_xor*/ - long_or, /*nb_or*/ - long_coerce, /*nb_coerce*/ - long_int, /*nb_int*/ - long_long, /*nb_long*/ - long_float, /*nb_float*/ - long_oct, /*nb_oct*/ - long_hex, /*nb_hex*/ - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ - 0, /* nb_inplace_divide */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - long_div, /* nb_floor_divide */ - long_true_divide, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ - long_long, /* nb_index */ -}; - -PyTypeObject PyLong_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "long", /* tp_name */ - sizeof(PyLongObject) - sizeof(digit), /* tp_basicsize */ - sizeof(digit), /* tp_itemsize */ - long_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)long_compare, /* tp_compare */ - long_repr, /* tp_repr */ - &long_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)long_hash, /* tp_hash */ - 0, /* tp_call */ - long_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - long_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - long_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - long_new, /* tp_new */ - PyObject_Del, /* tp_free */ -}; diff --git a/sys/src/cmd/python/Objects/methodobject.c b/sys/src/cmd/python/Objects/methodobject.c deleted file mode 100644 index ecc9a0ab5..000000000 --- a/sys/src/cmd/python/Objects/methodobject.c +++ /dev/null @@ -1,365 +0,0 @@ - -/* Method object implementation */ - -#include "Python.h" -#include "structmember.h" - -static PyCFunctionObject *free_list = NULL; - -PyObject * -PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) -{ - PyCFunctionObject *op; - op = free_list; - if (op != NULL) { - free_list = (PyCFunctionObject *)(op->m_self); - PyObject_INIT(op, &PyCFunction_Type); - } - else { - op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); - if (op == NULL) - return NULL; - } - op->m_ml = ml; - Py_XINCREF(self); - op->m_self = self; - Py_XINCREF(module); - op->m_module = module; - _PyObject_GC_TRACK(op); - return (PyObject *)op; -} - -PyCFunction -PyCFunction_GetFunction(PyObject *op) -{ - if (!PyCFunction_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyCFunctionObject *)op) -> m_ml -> ml_meth; -} - -PyObject * -PyCFunction_GetSelf(PyObject *op) -{ - if (!PyCFunction_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyCFunctionObject *)op) -> m_self; -} - -int -PyCFunction_GetFlags(PyObject *op) -{ - if (!PyCFunction_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - return ((PyCFunctionObject *)op) -> m_ml -> ml_flags; -} - -PyObject * -PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) -{ - PyCFunctionObject* f = (PyCFunctionObject*)func; - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); - Py_ssize_t size; - - switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) { - case METH_VARARGS: - if (kw == NULL || PyDict_Size(kw) == 0) - return (*meth)(self, arg); - break; - case METH_VARARGS | METH_KEYWORDS: - case METH_OLDARGS | METH_KEYWORDS: - return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); - case METH_NOARGS: - if (kw == NULL || PyDict_Size(kw) == 0) { - size = PyTuple_GET_SIZE(arg); - if (size == 0) - return (*meth)(self, NULL); - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - f->m_ml->ml_name, size); - return NULL; - } - break; - case METH_O: - if (kw == NULL || PyDict_Size(kw) == 0) { - size = PyTuple_GET_SIZE(arg); - if (size == 1) - return (*meth)(self, PyTuple_GET_ITEM(arg, 0)); - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%zd given)", - f->m_ml->ml_name, size); - return NULL; - } - break; - case METH_OLDARGS: - /* the really old style */ - if (kw == NULL || PyDict_Size(kw) == 0) { - size = PyTuple_GET_SIZE(arg); - if (size == 1) - arg = PyTuple_GET_ITEM(arg, 0); - else if (size == 0) - arg = NULL; - return (*meth)(self, arg); - } - break; - default: - PyErr_BadInternalCall(); - return NULL; - } - PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - f->m_ml->ml_name); - return NULL; -} - -/* Methods (the standard built-in methods, that is) */ - -static void -meth_dealloc(PyCFunctionObject *m) -{ - _PyObject_GC_UNTRACK(m); - Py_XDECREF(m->m_self); - Py_XDECREF(m->m_module); - m->m_self = (PyObject *)free_list; - free_list = m; -} - -static PyObject * -meth_get__doc__(PyCFunctionObject *m, void *closure) -{ - const char *doc = m->m_ml->ml_doc; - - if (doc != NULL) - return PyString_FromString(doc); - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -meth_get__name__(PyCFunctionObject *m, void *closure) -{ - return PyString_FromString(m->m_ml->ml_name); -} - -static int -meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg) -{ - Py_VISIT(m->m_self); - Py_VISIT(m->m_module); - return 0; -} - -static PyObject * -meth_get__self__(PyCFunctionObject *m, void *closure) -{ - PyObject *self; - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_RuntimeError, - "method.__self__ not accessible in restricted mode"); - return NULL; - } - self = m->m_self; - if (self == NULL) - self = Py_None; - Py_INCREF(self); - return self; -} - -static PyGetSetDef meth_getsets [] = { - {"__doc__", (getter)meth_get__doc__, NULL, NULL}, - {"__name__", (getter)meth_get__name__, NULL, NULL}, - {"__self__", (getter)meth_get__self__, NULL, NULL}, - {0} -}; - -#define OFF(x) offsetof(PyCFunctionObject, x) - -static PyMemberDef meth_members[] = { - {"__module__", T_OBJECT, OFF(m_module), WRITE_RESTRICTED}, - {NULL} -}; - -static PyObject * -meth_repr(PyCFunctionObject *m) -{ - if (m->m_self == NULL) - return PyString_FromFormat("<built-in function %s>", - m->m_ml->ml_name); - return PyString_FromFormat("<built-in method %s of %s object at %p>", - m->m_ml->ml_name, - m->m_self->ob_type->tp_name, - m->m_self); -} - -static int -meth_compare(PyCFunctionObject *a, PyCFunctionObject *b) -{ - if (a->m_self != b->m_self) - return (a->m_self < b->m_self) ? -1 : 1; - if (a->m_ml->ml_meth == b->m_ml->ml_meth) - return 0; - if (strcmp(a->m_ml->ml_name, b->m_ml->ml_name) < 0) - return -1; - else - return 1; -} - -static long -meth_hash(PyCFunctionObject *a) -{ - long x,y; - if (a->m_self == NULL) - x = 0; - else { - x = PyObject_Hash(a->m_self); - if (x == -1) - return -1; - } - y = _Py_HashPointer((void*)(a->m_ml->ml_meth)); - if (y == -1) - return -1; - x ^= y; - if (x == -1) - x = -2; - return x; -} - - -PyTypeObject PyCFunction_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "builtin_function_or_method", - sizeof(PyCFunctionObject), - 0, - (destructor)meth_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)meth_compare, /* tp_compare */ - (reprfunc)meth_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)meth_hash, /* tp_hash */ - PyCFunction_Call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)meth_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - meth_members, /* tp_members */ - meth_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ -}; - -/* List all methods in a chain -- helper for findmethodinchain */ - -static PyObject * -listmethodchain(PyMethodChain *chain) -{ - PyMethodChain *c; - PyMethodDef *ml; - int i, n; - PyObject *v; - - n = 0; - for (c = chain; c != NULL; c = c->link) { - for (ml = c->methods; ml->ml_name != NULL; ml++) - n++; - } - v = PyList_New(n); - if (v == NULL) - return NULL; - i = 0; - for (c = chain; c != NULL; c = c->link) { - for (ml = c->methods; ml->ml_name != NULL; ml++) { - PyList_SetItem(v, i, PyString_FromString(ml->ml_name)); - i++; - } - } - if (PyErr_Occurred()) { - Py_DECREF(v); - return NULL; - } - PyList_Sort(v); - return v; -} - -/* Find a method in a method chain */ - -PyObject * -Py_FindMethodInChain(PyMethodChain *chain, PyObject *self, const char *name) -{ - if (name[0] == '_' && name[1] == '_') { - if (strcmp(name, "__methods__") == 0) - return listmethodchain(chain); - if (strcmp(name, "__doc__") == 0) { - const char *doc = self->ob_type->tp_doc; - if (doc != NULL) - return PyString_FromString(doc); - } - } - while (chain != NULL) { - PyMethodDef *ml = chain->methods; - for (; ml->ml_name != NULL; ml++) { - if (name[0] == ml->ml_name[0] && - strcmp(name+1, ml->ml_name+1) == 0) - /* XXX */ - return PyCFunction_New(ml, self); - } - chain = chain->link; - } - PyErr_SetString(PyExc_AttributeError, name); - return NULL; -} - -/* Find a method in a single method list */ - -PyObject * -Py_FindMethod(PyMethodDef *methods, PyObject *self, const char *name) -{ - PyMethodChain chain; - chain.methods = methods; - chain.link = NULL; - return Py_FindMethodInChain(&chain, self, name); -} - -/* Clear out the free list */ - -void -PyCFunction_Fini(void) -{ - while (free_list) { - PyCFunctionObject *v = free_list; - free_list = (PyCFunctionObject *)(v->m_self); - PyObject_GC_Del(v); - } -} - -/* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(), - but it's part of the API so we need to keep a function around that - existing C extensions can call. -*/ - -#undef PyCFunction_New -PyAPI_FUNC(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *); - -PyObject * -PyCFunction_New(PyMethodDef *ml, PyObject *self) -{ - return PyCFunction_NewEx(ml, self, NULL); -} diff --git a/sys/src/cmd/python/Objects/mkfile b/sys/src/cmd/python/Objects/mkfile deleted file mode 100644 index 9771b2639..000000000 --- a/sys/src/cmd/python/Objects/mkfile +++ /dev/null @@ -1,46 +0,0 @@ -APE=/sys/src/ape -<$APE/config - -LIB=../libpython.a$O - -OFILES=\ - abstract.$O\ - boolobject.$O\ - bufferobject.$O\ - cellobject.$O\ - classobject.$O\ - cobject.$O\ - codeobject.$O\ - complexobject.$O\ - descrobject.$O\ - dictobject.$O\ - enumobject.$O\ - exceptions.$O\ - fileobject.$O\ - floatobject.$O\ - frameobject.$O\ - funcobject.$O\ - genobject.$O\ - intobject.$O\ - iterobject.$O\ - listobject.$O\ - longobject.$O\ - methodobject.$O\ - moduleobject.$O\ - object.$O\ - obmalloc.$O\ - rangeobject.$O\ - setobject.$O\ - sliceobject.$O\ - stringobject.$O\ - structseq.$O\ - tupleobject.$O\ - typeobject.$O\ - unicodectype.$O\ - unicodeobject.$O\ - weakrefobject.$O\ - -</sys/src/cmd/mklib - -CFLAGS=-c -I.. -I../Include -DT$objtype -DPy_BUILD_CORE -DNDEBUG - diff --git a/sys/src/cmd/python/Objects/moduleobject.c b/sys/src/cmd/python/Objects/moduleobject.c deleted file mode 100644 index e454fcf32..000000000 --- a/sys/src/cmd/python/Objects/moduleobject.c +++ /dev/null @@ -1,259 +0,0 @@ - -/* Module object implementation */ - -#include "Python.h" -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *md_dict; -} PyModuleObject; - -static PyMemberDef module_members[] = { - {"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY}, - {0} -}; - -PyObject * -PyModule_New(const char *name) -{ - PyModuleObject *m; - PyObject *nameobj; - m = PyObject_GC_New(PyModuleObject, &PyModule_Type); - if (m == NULL) - return NULL; - nameobj = PyString_FromString(name); - m->md_dict = PyDict_New(); - if (m->md_dict == NULL || nameobj == NULL) - goto fail; - if (PyDict_SetItemString(m->md_dict, "__name__", nameobj) != 0) - goto fail; - if (PyDict_SetItemString(m->md_dict, "__doc__", Py_None) != 0) - goto fail; - Py_DECREF(nameobj); - PyObject_GC_Track(m); - return (PyObject *)m; - - fail: - Py_XDECREF(nameobj); - Py_DECREF(m); - return NULL; -} - -PyObject * -PyModule_GetDict(PyObject *m) -{ - PyObject *d; - if (!PyModule_Check(m)) { - PyErr_BadInternalCall(); - return NULL; - } - d = ((PyModuleObject *)m) -> md_dict; - if (d == NULL) - ((PyModuleObject *)m) -> md_dict = d = PyDict_New(); - return d; -} - -char * -PyModule_GetName(PyObject *m) -{ - PyObject *d; - PyObject *nameobj; - if (!PyModule_Check(m)) { - PyErr_BadArgument(); - return NULL; - } - d = ((PyModuleObject *)m)->md_dict; - if (d == NULL || - (nameobj = PyDict_GetItemString(d, "__name__")) == NULL || - !PyString_Check(nameobj)) - { - PyErr_SetString(PyExc_SystemError, "nameless module"); - return NULL; - } - return PyString_AsString(nameobj); -} - -char * -PyModule_GetFilename(PyObject *m) -{ - PyObject *d; - PyObject *fileobj; - if (!PyModule_Check(m)) { - PyErr_BadArgument(); - return NULL; - } - d = ((PyModuleObject *)m)->md_dict; - if (d == NULL || - (fileobj = PyDict_GetItemString(d, "__file__")) == NULL || - !PyString_Check(fileobj)) - { - PyErr_SetString(PyExc_SystemError, "module filename missing"); - return NULL; - } - return PyString_AsString(fileobj); -} - -void -_PyModule_Clear(PyObject *m) -{ - /* To make the execution order of destructors for global - objects a bit more predictable, we first zap all objects - whose name starts with a single underscore, before we clear - the entire dictionary. We zap them by replacing them with - None, rather than deleting them from the dictionary, to - avoid rehashing the dictionary (to some extent). */ - - Py_ssize_t pos; - PyObject *key, *value; - PyObject *d; - - d = ((PyModuleObject *)m)->md_dict; - if (d == NULL) - return; - - /* First, clear only names starting with a single underscore */ - pos = 0; - while (PyDict_Next(d, &pos, &key, &value)) { - if (value != Py_None && PyString_Check(key)) { - char *s = PyString_AsString(key); - if (s[0] == '_' && s[1] != '_') { - if (Py_VerboseFlag > 1) - PySys_WriteStderr("# clear[1] %s\n", s); - PyDict_SetItem(d, key, Py_None); - } - } - } - - /* Next, clear all names except for __builtins__ */ - pos = 0; - while (PyDict_Next(d, &pos, &key, &value)) { - if (value != Py_None && PyString_Check(key)) { - char *s = PyString_AsString(key); - if (s[0] != '_' || strcmp(s, "__builtins__") != 0) { - if (Py_VerboseFlag > 1) - PySys_WriteStderr("# clear[2] %s\n", s); - PyDict_SetItem(d, key, Py_None); - } - } - } - - /* Note: we leave __builtins__ in place, so that destructors - of non-global objects defined in this module can still use - builtins, in particularly 'None'. */ - -} - -/* Methods */ - -static int -module_init(PyModuleObject *m, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"name", "doc", NULL}; - PyObject *dict, *name = Py_None, *doc = Py_None; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|O:module.__init__", - kwlist, &name, &doc)) - return -1; - dict = m->md_dict; - if (dict == NULL) { - dict = PyDict_New(); - if (dict == NULL) - return -1; - m->md_dict = dict; - } - if (PyDict_SetItemString(dict, "__name__", name) < 0) - return -1; - if (PyDict_SetItemString(dict, "__doc__", doc) < 0) - return -1; - return 0; -} - -static void -module_dealloc(PyModuleObject *m) -{ - PyObject_GC_UnTrack(m); - if (m->md_dict != NULL) { - _PyModule_Clear((PyObject *)m); - Py_DECREF(m->md_dict); - } - m->ob_type->tp_free((PyObject *)m); -} - -static PyObject * -module_repr(PyModuleObject *m) -{ - char *name; - char *filename; - - name = PyModule_GetName((PyObject *)m); - if (name == NULL) { - PyErr_Clear(); - name = "?"; - } - filename = PyModule_GetFilename((PyObject *)m); - if (filename == NULL) { - PyErr_Clear(); - return PyString_FromFormat("<module '%s' (built-in)>", name); - } - return PyString_FromFormat("<module '%s' from '%s'>", name, filename); -} - -/* We only need a traverse function, no clear function: If the module - is in a cycle, md_dict will be cleared as well, which will break - the cycle. */ -static int -module_traverse(PyModuleObject *m, visitproc visit, void *arg) -{ - Py_VISIT(m->md_dict); - return 0; -} - -PyDoc_STRVAR(module_doc, -"module(name[, doc])\n\ -\n\ -Create a module object.\n\ -The name must be a string; the optional doc argument can have any type."); - -PyTypeObject PyModule_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "module", /* tp_name */ - sizeof(PyModuleObject), /* tp_size */ - 0, /* tp_itemsize */ - (destructor)module_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)module_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - module_doc, /* tp_doc */ - (traverseproc)module_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - module_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(PyModuleObject, md_dict), /* tp_dictoffset */ - (initproc)module_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; diff --git a/sys/src/cmd/python/Objects/object.c b/sys/src/cmd/python/Objects/object.c deleted file mode 100644 index b0672f30e..000000000 --- a/sys/src/cmd/python/Objects/object.c +++ /dev/null @@ -1,2139 +0,0 @@ - -/* Generic object operations; and implementation of None (NoObject) */ - -#include "Python.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef Py_REF_DEBUG -Py_ssize_t _Py_RefTotal; - -Py_ssize_t -_Py_GetRefTotal(void) -{ - PyObject *o; - Py_ssize_t total = _Py_RefTotal; - /* ignore the references to the dummy object of the dicts and sets - because they are not reliable and not useful (now that the - hash table code is well-tested) */ - o = _PyDict_Dummy(); - if (o != NULL) - total -= o->ob_refcnt; - o = _PySet_Dummy(); - if (o != NULL) - total -= o->ob_refcnt; - return total; -} -#endif /* Py_REF_DEBUG */ - -int Py_DivisionWarningFlag; - -/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. - These are used by the individual routines for object creation. - Do not call them otherwise, they do not initialize the object! */ - -#ifdef Py_TRACE_REFS -/* Head of circular doubly-linked list of all objects. These are linked - * together via the _ob_prev and _ob_next members of a PyObject, which - * exist only in a Py_TRACE_REFS build. - */ -static PyObject refchain = {&refchain, &refchain}; - -/* Insert op at the front of the list of all objects. If force is true, - * op is added even if _ob_prev and _ob_next are non-NULL already. If - * force is false amd _ob_prev or _ob_next are non-NULL, do nothing. - * force should be true if and only if op points to freshly allocated, - * uninitialized memory, or you've unlinked op from the list and are - * relinking it into the front. - * Note that objects are normally added to the list via _Py_NewReference, - * which is called by PyObject_Init. Not all objects are initialized that - * way, though; exceptions include statically allocated type objects, and - * statically allocated singletons (like Py_True and Py_None). - */ -void -_Py_AddToAllObjects(PyObject *op, int force) -{ -#ifdef Py_DEBUG - if (!force) { - /* If it's initialized memory, op must be in or out of - * the list unambiguously. - */ - assert((op->_ob_prev == NULL) == (op->_ob_next == NULL)); - } -#endif - if (force || op->_ob_prev == NULL) { - op->_ob_next = refchain._ob_next; - op->_ob_prev = &refchain; - refchain._ob_next->_ob_prev = op; - refchain._ob_next = op; - } -} -#endif /* Py_TRACE_REFS */ - -#ifdef COUNT_ALLOCS -static PyTypeObject *type_list; -/* All types are added to type_list, at least when - they get one object created. That makes them - immortal, which unfortunately contributes to - garbage itself. If unlist_types_without_objects - is set, they will be removed from the type_list - once the last object is deallocated. */ -int unlist_types_without_objects; -extern int tuple_zero_allocs, fast_tuple_allocs; -extern int quick_int_allocs, quick_neg_int_allocs; -extern int null_strings, one_strings; -void -dump_counts(FILE* f) -{ - PyTypeObject *tp; - - for (tp = type_list; tp; tp = tp->tp_next) - fprintf(f, "%s alloc'd: %d, freed: %d, max in use: %d\n", - tp->tp_name, tp->tp_allocs, tp->tp_frees, - tp->tp_maxalloc); - fprintf(f, "fast tuple allocs: %d, empty: %d\n", - fast_tuple_allocs, tuple_zero_allocs); - fprintf(f, "fast int allocs: pos: %d, neg: %d\n", - quick_int_allocs, quick_neg_int_allocs); - fprintf(f, "null strings: %d, 1-strings: %d\n", - null_strings, one_strings); -} - -PyObject * -get_counts(void) -{ - PyTypeObject *tp; - PyObject *result; - PyObject *v; - - result = PyList_New(0); - if (result == NULL) - return NULL; - for (tp = type_list; tp; tp = tp->tp_next) { - v = Py_BuildValue("(snnn)", tp->tp_name, tp->tp_allocs, - tp->tp_frees, tp->tp_maxalloc); - if (v == NULL) { - Py_DECREF(result); - return NULL; - } - if (PyList_Append(result, v) < 0) { - Py_DECREF(v); - Py_DECREF(result); - return NULL; - } - Py_DECREF(v); - } - return result; -} - -void -inc_count(PyTypeObject *tp) -{ - if (tp->tp_next == NULL && tp->tp_prev == NULL) { - /* first time; insert in linked list */ - if (tp->tp_next != NULL) /* sanity check */ - Py_FatalError("XXX inc_count sanity check"); - if (type_list) - type_list->tp_prev = tp; - tp->tp_next = type_list; - /* Note that as of Python 2.2, heap-allocated type objects - * can go away, but this code requires that they stay alive - * until program exit. That's why we're careful with - * refcounts here. type_list gets a new reference to tp, - * while ownership of the reference type_list used to hold - * (if any) was transferred to tp->tp_next in the line above. - * tp is thus effectively immortal after this. - */ - Py_INCREF(tp); - type_list = tp; -#ifdef Py_TRACE_REFS - /* Also insert in the doubly-linked list of all objects, - * if not already there. - */ - _Py_AddToAllObjects((PyObject *)tp, 0); -#endif - } - tp->tp_allocs++; - if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc) - tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees; -} - -void dec_count(PyTypeObject *tp) -{ - tp->tp_frees++; - if (unlist_types_without_objects && - tp->tp_allocs == tp->tp_frees) { - /* unlink the type from type_list */ - if (tp->tp_prev) - tp->tp_prev->tp_next = tp->tp_next; - else - type_list = tp->tp_next; - if (tp->tp_next) - tp->tp_next->tp_prev = tp->tp_prev; - tp->tp_next = tp->tp_prev = NULL; - Py_DECREF(tp); - } -} - -#endif - -#ifdef Py_REF_DEBUG -/* Log a fatal error; doesn't return. */ -void -_Py_NegativeRefcount(const char *fname, int lineno, PyObject *op) -{ - char buf[300]; - - PyOS_snprintf(buf, sizeof(buf), - "%s:%i object at %p has negative ref count " - "%" PY_FORMAT_SIZE_T "d", - fname, lineno, op, op->ob_refcnt); - Py_FatalError(buf); -} - -#endif /* Py_REF_DEBUG */ - -void -Py_IncRef(PyObject *o) -{ - Py_XINCREF(o); -} - -void -Py_DecRef(PyObject *o) -{ - Py_XDECREF(o); -} - -PyObject * -PyObject_Init(PyObject *op, PyTypeObject *tp) -{ - if (op == NULL) - return PyErr_NoMemory(); - /* Any changes should be reflected in PyObject_INIT (objimpl.h) */ - op->ob_type = tp; - _Py_NewReference(op); - return op; -} - -PyVarObject * -PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size) -{ - if (op == NULL) - return (PyVarObject *) PyErr_NoMemory(); - /* Any changes should be reflected in PyObject_INIT_VAR */ - op->ob_size = size; - op->ob_type = tp; - _Py_NewReference((PyObject *)op); - return op; -} - -PyObject * -_PyObject_New(PyTypeObject *tp) -{ - PyObject *op; - op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); - if (op == NULL) - return PyErr_NoMemory(); - return PyObject_INIT(op, tp); -} - -PyVarObject * -_PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems) -{ - PyVarObject *op; - const size_t size = _PyObject_VAR_SIZE(tp, nitems); - op = (PyVarObject *) PyObject_MALLOC(size); - if (op == NULL) - return (PyVarObject *)PyErr_NoMemory(); - return PyObject_INIT_VAR(op, tp, nitems); -} - -/* for binary compatibility with 2.2 */ -#undef _PyObject_Del -void -_PyObject_Del(PyObject *op) -{ - PyObject_FREE(op); -} - -/* Implementation of PyObject_Print with recursion checking */ -static int -internal_print(PyObject *op, FILE *fp, int flags, int nesting) -{ - int ret = 0; - if (nesting > 10) { - PyErr_SetString(PyExc_RuntimeError, "print recursion"); - return -1; - } - if (PyErr_CheckSignals()) - return -1; -#ifdef USE_STACKCHECK - if (PyOS_CheckStack()) { - PyErr_SetString(PyExc_MemoryError, "stack overflow"); - return -1; - } -#endif - clearerr(fp); /* Clear any previous error condition */ - if (op == NULL) { - fprintf(fp, "<nil>"); - } - else { - if (op->ob_refcnt <= 0) - /* XXX(twouters) cast refcount to long until %zd is - universally available */ - fprintf(fp, "<refcnt %ld at %p>", - (long)op->ob_refcnt, op); - else if (op->ob_type->tp_print == NULL) { - PyObject *s; - if (flags & Py_PRINT_RAW) - s = PyObject_Str(op); - else - s = PyObject_Repr(op); - if (s == NULL) - ret = -1; - else { - ret = internal_print(s, fp, Py_PRINT_RAW, - nesting+1); - } - Py_XDECREF(s); - } - else - ret = (*op->ob_type->tp_print)(op, fp, flags); - } - if (ret == 0) { - if (ferror(fp)) { - PyErr_SetFromErrno(PyExc_IOError); - clearerr(fp); - ret = -1; - } - } - return ret; -} - -int -PyObject_Print(PyObject *op, FILE *fp, int flags) -{ - return internal_print(op, fp, flags, 0); -} - - -/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */ -void _PyObject_Dump(PyObject* op) -{ - if (op == NULL) - fprintf(stderr, "NULL\n"); - else { - fprintf(stderr, "object : "); - (void)PyObject_Print(op, stderr, 0); - /* XXX(twouters) cast refcount to long until %zd is - universally available */ - fprintf(stderr, "\n" - "type : %s\n" - "refcount: %ld\n" - "address : %p\n", - op->ob_type==NULL ? "NULL" : op->ob_type->tp_name, - (long)op->ob_refcnt, - op); - } -} - -PyObject * -PyObject_Repr(PyObject *v) -{ - if (PyErr_CheckSignals()) - return NULL; -#ifdef USE_STACKCHECK - if (PyOS_CheckStack()) { - PyErr_SetString(PyExc_MemoryError, "stack overflow"); - return NULL; - } -#endif - if (v == NULL) - return PyString_FromString("<NULL>"); - else if (v->ob_type->tp_repr == NULL) - return PyString_FromFormat("<%s object at %p>", - v->ob_type->tp_name, v); - else { - PyObject *res; - res = (*v->ob_type->tp_repr)(v); - if (res == NULL) - return NULL; -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(res)) { - PyObject* str; - str = PyUnicode_AsEncodedString(res, NULL, NULL); - Py_DECREF(res); - if (str) - res = str; - else - return NULL; - } -#endif - if (!PyString_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__repr__ returned non-string (type %.200s)", - res->ob_type->tp_name); - Py_DECREF(res); - return NULL; - } - return res; - } -} - -PyObject * -_PyObject_Str(PyObject *v) -{ - PyObject *res; - int type_ok; - if (v == NULL) - return PyString_FromString("<NULL>"); - if (PyString_CheckExact(v)) { - Py_INCREF(v); - return v; - } -#ifdef Py_USING_UNICODE - if (PyUnicode_CheckExact(v)) { - Py_INCREF(v); - return v; - } -#endif - if (v->ob_type->tp_str == NULL) - return PyObject_Repr(v); - - res = (*v->ob_type->tp_str)(v); - if (res == NULL) - return NULL; - type_ok = PyString_Check(res); -#ifdef Py_USING_UNICODE - type_ok = type_ok || PyUnicode_Check(res); -#endif - if (!type_ok) { - PyErr_Format(PyExc_TypeError, - "__str__ returned non-string (type %.200s)", - res->ob_type->tp_name); - Py_DECREF(res); - return NULL; - } - return res; -} - -PyObject * -PyObject_Str(PyObject *v) -{ - PyObject *res = _PyObject_Str(v); - if (res == NULL) - return NULL; -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(res)) { - PyObject* str; - str = PyUnicode_AsEncodedString(res, NULL, NULL); - Py_DECREF(res); - if (str) - res = str; - else - return NULL; - } -#endif - assert(PyString_Check(res)); - return res; -} - -#ifdef Py_USING_UNICODE -PyObject * -PyObject_Unicode(PyObject *v) -{ - PyObject *res; - PyObject *func; - PyObject *str; - static PyObject *unicodestr; - - if (v == NULL) { - res = PyString_FromString("<NULL>"); - if (res == NULL) - return NULL; - str = PyUnicode_FromEncodedObject(res, NULL, "strict"); - Py_DECREF(res); - return str; - } else if (PyUnicode_CheckExact(v)) { - Py_INCREF(v); - return v; - } - /* XXX As soon as we have a tp_unicode slot, we should - check this before trying the __unicode__ - method. */ - if (unicodestr == NULL) { - unicodestr= PyString_InternFromString("__unicode__"); - if (unicodestr == NULL) - return NULL; - } - func = PyObject_GetAttr(v, unicodestr); - if (func != NULL) { - res = PyEval_CallObject(func, (PyObject *)NULL); - Py_DECREF(func); - } - else { - PyErr_Clear(); - if (PyUnicode_Check(v)) { - /* For a Unicode subtype that's didn't overwrite __unicode__, - return a true Unicode object with the same data. */ - return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(v), - PyUnicode_GET_SIZE(v)); - } - if (PyString_CheckExact(v)) { - Py_INCREF(v); - res = v; - } - else { - if (v->ob_type->tp_str != NULL) - res = (*v->ob_type->tp_str)(v); - else - res = PyObject_Repr(v); - } - } - if (res == NULL) - return NULL; - if (!PyUnicode_Check(res)) { - str = PyUnicode_FromEncodedObject(res, NULL, "strict"); - Py_DECREF(res); - res = str; - } - return res; -} -#endif - - -/* Helper to warn about deprecated tp_compare return values. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w. - (This function cannot return 2.) -*/ -static int -adjust_tp_compare(int c) -{ - if (PyErr_Occurred()) { - if (c != -1 && c != -2) { - PyObject *t, *v, *tb; - PyErr_Fetch(&t, &v, &tb); - if (PyErr_Warn(PyExc_RuntimeWarning, - "tp_compare didn't return -1 or -2 " - "for exception") < 0) { - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(tb); - } - else - PyErr_Restore(t, v, tb); - } - return -2; - } - else if (c < -1 || c > 1) { - if (PyErr_Warn(PyExc_RuntimeWarning, - "tp_compare didn't return -1, 0 or 1") < 0) - return -2; - else - return c < -1 ? -1 : 1; - } - else { - assert(c >= -1 && c <= 1); - return c; - } -} - - -/* Macro to get the tp_richcompare field of a type if defined */ -#define RICHCOMPARE(t) (PyType_HasFeature((t), Py_TPFLAGS_HAVE_RICHCOMPARE) \ - ? (t)->tp_richcompare : NULL) - -/* Map rich comparison operators to their swapped version, e.g. LT --> GT */ -int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE}; - -/* Try a genuine rich comparison, returning an object. Return: - NULL for exception; - NotImplemented if this particular rich comparison is not implemented or - undefined; - some object not equal to NotImplemented if it is implemented - (this latter object may not be a Boolean). -*/ -static PyObject * -try_rich_compare(PyObject *v, PyObject *w, int op) -{ - richcmpfunc f; - PyObject *res; - - if (v->ob_type != w->ob_type && - PyType_IsSubtype(w->ob_type, v->ob_type) && - (f = RICHCOMPARE(w->ob_type)) != NULL) { - res = (*f)(w, v, _Py_SwappedOp[op]); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } - if ((f = RICHCOMPARE(v->ob_type)) != NULL) { - res = (*f)(v, w, op); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } - if ((f = RICHCOMPARE(w->ob_type)) != NULL) { - return (*f)(w, v, _Py_SwappedOp[op]); - } - res = Py_NotImplemented; - Py_INCREF(res); - return res; -} - -/* Try a genuine rich comparison, returning an int. Return: - -1 for exception (including the case where try_rich_compare() returns an - object that's not a Boolean); - 0 if the outcome is false; - 1 if the outcome is true; - 2 if this particular rich comparison is not implemented or undefined. -*/ -static int -try_rich_compare_bool(PyObject *v, PyObject *w, int op) -{ - PyObject *res; - int ok; - - if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL) - return 2; /* Shortcut, avoid INCREF+DECREF */ - res = try_rich_compare(v, w, op); - if (res == NULL) - return -1; - if (res == Py_NotImplemented) { - Py_DECREF(res); - return 2; - } - ok = PyObject_IsTrue(res); - Py_DECREF(res); - return ok; -} - -/* Try rich comparisons to determine a 3-way comparison. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w; - 2 if this particular rich comparison is not implemented or undefined. -*/ -static int -try_rich_to_3way_compare(PyObject *v, PyObject *w) -{ - static struct { int op; int outcome; } tries[3] = { - /* Try this operator, and if it is true, use this outcome: */ - {Py_EQ, 0}, - {Py_LT, -1}, - {Py_GT, 1}, - }; - int i; - - if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL) - return 2; /* Shortcut */ - - for (i = 0; i < 3; i++) { - switch (try_rich_compare_bool(v, w, tries[i].op)) { - case -1: - return -2; - case 1: - return tries[i].outcome; - } - } - - return 2; -} - -/* Try a 3-way comparison, returning an int. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w; - 2 if this particular 3-way comparison is not implemented or undefined. -*/ -static int -try_3way_compare(PyObject *v, PyObject *w) -{ - int c; - cmpfunc f; - - /* Comparisons involving instances are given to instance_compare, - which has the same return conventions as this function. */ - - f = v->ob_type->tp_compare; - if (PyInstance_Check(v)) - return (*f)(v, w); - if (PyInstance_Check(w)) - return (*w->ob_type->tp_compare)(v, w); - - /* If both have the same (non-NULL) tp_compare, use it. */ - if (f != NULL && f == w->ob_type->tp_compare) { - c = (*f)(v, w); - return adjust_tp_compare(c); - } - - /* If either tp_compare is _PyObject_SlotCompare, that's safe. */ - if (f == _PyObject_SlotCompare || - w->ob_type->tp_compare == _PyObject_SlotCompare) - return _PyObject_SlotCompare(v, w); - - /* If we're here, v and w, - a) are not instances; - b) have different types or a type without tp_compare; and - c) don't have a user-defined tp_compare. - tp_compare implementations in C assume that both arguments - have their type, so we give up if the coercion fails or if - it yields types which are still incompatible (which can - happen with a user-defined nb_coerce). - */ - c = PyNumber_CoerceEx(&v, &w); - if (c < 0) - return -2; - if (c > 0) - return 2; - f = v->ob_type->tp_compare; - if (f != NULL && f == w->ob_type->tp_compare) { - c = (*f)(v, w); - Py_DECREF(v); - Py_DECREF(w); - return adjust_tp_compare(c); - } - - /* No comparison defined */ - Py_DECREF(v); - Py_DECREF(w); - return 2; -} - -/* Final fallback 3-way comparison, returning an int. Return: - -2 if an error occurred; - -1 if v < w; - 0 if v == w; - 1 if v > w. -*/ -static int -default_3way_compare(PyObject *v, PyObject *w) -{ - int c; - const char *vname, *wname; - - if (v->ob_type == w->ob_type) { - /* When comparing these pointers, they must be cast to - * integer types (i.e. Py_uintptr_t, our spelling of C9X's - * uintptr_t). ANSI specifies that pointer compares other - * than == and != to non-related structures are undefined. - */ - Py_uintptr_t vv = (Py_uintptr_t)v; - Py_uintptr_t ww = (Py_uintptr_t)w; - return (vv < ww) ? -1 : (vv > ww) ? 1 : 0; - } - - /* None is smaller than anything */ - if (v == Py_None) - return -1; - if (w == Py_None) - return 1; - - /* different type: compare type names; numbers are smaller */ - if (PyNumber_Check(v)) - vname = ""; - else - vname = v->ob_type->tp_name; - if (PyNumber_Check(w)) - wname = ""; - else - wname = w->ob_type->tp_name; - c = strcmp(vname, wname); - if (c < 0) - return -1; - if (c > 0) - return 1; - /* Same type name, or (more likely) incomparable numeric types */ - return ((Py_uintptr_t)(v->ob_type) < ( - Py_uintptr_t)(w->ob_type)) ? -1 : 1; -} - -/* Do a 3-way comparison, by hook or by crook. Return: - -2 for an exception (but see below); - -1 if v < w; - 0 if v == w; - 1 if v > w; - BUT: if the object implements a tp_compare function, it returns - whatever this function returns (whether with an exception or not). -*/ -static int -do_cmp(PyObject *v, PyObject *w) -{ - int c; - cmpfunc f; - - if (v->ob_type == w->ob_type - && (f = v->ob_type->tp_compare) != NULL) { - c = (*f)(v, w); - if (PyInstance_Check(v)) { - /* Instance tp_compare has a different signature. - But if it returns undefined we fall through. */ - if (c != 2) - return c; - /* Else fall through to try_rich_to_3way_compare() */ - } - else - return adjust_tp_compare(c); - } - /* We only get here if one of the following is true: - a) v and w have different types - b) v and w have the same type, which doesn't have tp_compare - c) v and w are instances, and either __cmp__ is not defined or - __cmp__ returns NotImplemented - */ - c = try_rich_to_3way_compare(v, w); - if (c < 2) - return c; - c = try_3way_compare(v, w); - if (c < 2) - return c; - return default_3way_compare(v, w); -} - -/* Compare v to w. Return - -1 if v < w or exception (PyErr_Occurred() true in latter case). - 0 if v == w. - 1 if v > w. - XXX The docs (C API manual) say the return value is undefined in case - XXX of error. -*/ -int -PyObject_Compare(PyObject *v, PyObject *w) -{ - int result; - - if (v == NULL || w == NULL) { - PyErr_BadInternalCall(); - return -1; - } - if (v == w) - return 0; - if (Py_EnterRecursiveCall(" in cmp")) - return -1; - result = do_cmp(v, w); - Py_LeaveRecursiveCall(); - return result < 0 ? -1 : result; -} - -/* Return (new reference to) Py_True or Py_False. */ -static PyObject * -convert_3way_to_object(int op, int c) -{ - PyObject *result; - switch (op) { - case Py_LT: c = c < 0; break; - case Py_LE: c = c <= 0; break; - case Py_EQ: c = c == 0; break; - case Py_NE: c = c != 0; break; - case Py_GT: c = c > 0; break; - case Py_GE: c = c >= 0; break; - } - result = c ? Py_True : Py_False; - Py_INCREF(result); - return result; -} - -/* We want a rich comparison but don't have one. Try a 3-way cmp instead. - Return - NULL if error - Py_True if v op w - Py_False if not (v op w) -*/ -static PyObject * -try_3way_to_rich_compare(PyObject *v, PyObject *w, int op) -{ - int c; - - c = try_3way_compare(v, w); - if (c >= 2) - c = default_3way_compare(v, w); - if (c <= -2) - return NULL; - return convert_3way_to_object(op, c); -} - -/* Do rich comparison on v and w. Return - NULL if error - Else a new reference to an object other than Py_NotImplemented, usually(?): - Py_True if v op w - Py_False if not (v op w) -*/ -static PyObject * -do_richcmp(PyObject *v, PyObject *w, int op) -{ - PyObject *res; - - res = try_rich_compare(v, w, op); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - - return try_3way_to_rich_compare(v, w, op); -} - -/* Return: - NULL for exception; - some object not equal to NotImplemented if it is implemented - (this latter object may not be a Boolean). -*/ -PyObject * -PyObject_RichCompare(PyObject *v, PyObject *w, int op) -{ - PyObject *res; - - assert(Py_LT <= op && op <= Py_GE); - if (Py_EnterRecursiveCall(" in cmp")) - return NULL; - - /* If the types are equal, and not old-style instances, try to - get out cheap (don't bother with coercions etc.). */ - if (v->ob_type == w->ob_type && !PyInstance_Check(v)) { - cmpfunc fcmp; - richcmpfunc frich = RICHCOMPARE(v->ob_type); - /* If the type has richcmp, try it first. try_rich_compare - tries it two-sided, which is not needed since we've a - single type only. */ - if (frich != NULL) { - res = (*frich)(v, w, op); - if (res != Py_NotImplemented) - goto Done; - Py_DECREF(res); - } - /* No richcmp, or this particular richmp not implemented. - Try 3-way cmp. */ - fcmp = v->ob_type->tp_compare; - if (fcmp != NULL) { - int c = (*fcmp)(v, w); - c = adjust_tp_compare(c); - if (c == -2) { - res = NULL; - goto Done; - } - res = convert_3way_to_object(op, c); - goto Done; - } - } - - /* Fast path not taken, or couldn't deliver a useful result. */ - res = do_richcmp(v, w, op); -Done: - Py_LeaveRecursiveCall(); - return res; -} - -/* Return -1 if error; 1 if v op w; 0 if not (v op w). */ -int -PyObject_RichCompareBool(PyObject *v, PyObject *w, int op) -{ - PyObject *res; - int ok; - - /* Quick result when objects are the same. - Guarantees that identity implies equality. */ - if (v == w) { - if (op == Py_EQ) - return 1; - else if (op == Py_NE) - return 0; - } - - res = PyObject_RichCompare(v, w, op); - if (res == NULL) - return -1; - if (PyBool_Check(res)) - ok = (res == Py_True); - else - ok = PyObject_IsTrue(res); - Py_DECREF(res); - return ok; -} - -/* Set of hash utility functions to help maintaining the invariant that - if a==b then hash(a)==hash(b) - - All the utility functions (_Py_Hash*()) return "-1" to signify an error. -*/ - -long -_Py_HashDouble(double v) -{ - double intpart, fractpart; - int expo; - long hipart; - long x; /* the final hash value */ - /* This is designed so that Python numbers of different types - * that compare equal hash to the same value; otherwise comparisons - * of mapping keys will turn out weird. - */ - - fractpart = modf(v, &intpart); - if (fractpart == 0.0) { - /* This must return the same hash as an equal int or long. */ - if (intpart > LONG_MAX || -intpart > LONG_MAX) { - /* Convert to long and use its hash. */ - PyObject *plong; /* converted to Python long */ - if (Py_IS_INFINITY(intpart)) - /* can't convert to long int -- arbitrary */ - v = v < 0 ? -271828.0 : 314159.0; - plong = PyLong_FromDouble(v); - if (plong == NULL) - return -1; - x = PyObject_Hash(plong); - Py_DECREF(plong); - return x; - } - /* Fits in a C long == a Python int, so is its own hash. */ - x = (long)intpart; - if (x == -1) - x = -2; - return x; - } - /* The fractional part is non-zero, so we don't have to worry about - * making this match the hash of some other type. - * Use frexp to get at the bits in the double. - * Since the VAX D double format has 56 mantissa bits, which is the - * most of any double format in use, each of these parts may have as - * many as (but no more than) 56 significant bits. - * So, assuming sizeof(long) >= 4, each part can be broken into two - * longs; frexp and multiplication are used to do that. - * Also, since the Cray double format has 15 exponent bits, which is - * the most of any double format in use, shifting the exponent field - * left by 15 won't overflow a long (again assuming sizeof(long) >= 4). - */ - v = frexp(v, &expo); - v *= 2147483648.0; /* 2**31 */ - hipart = (long)v; /* take the top 32 bits */ - v = (v - (double)hipart) * 2147483648.0; /* get the next 32 bits */ - x = hipart + (long)v + (expo << 15); - if (x == -1) - x = -2; - return x; -} - -long -_Py_HashPointer(void *p) -{ -#if SIZEOF_LONG >= SIZEOF_VOID_P - return (long)p; -#else - /* convert to a Python long and hash that */ - PyObject* longobj; - long x; - - if ((longobj = PyLong_FromVoidPtr(p)) == NULL) { - x = -1; - goto finally; - } - x = PyObject_Hash(longobj); - -finally: - Py_XDECREF(longobj); - return x; -#endif -} - - -long -PyObject_Hash(PyObject *v) -{ - PyTypeObject *tp = v->ob_type; - if (tp->tp_hash != NULL) - return (*tp->tp_hash)(v); - if (tp->tp_compare == NULL && RICHCOMPARE(tp) == NULL) { - return _Py_HashPointer(v); /* Use address as hash value */ - } - /* If there's a cmp but no hash defined, the object can't be hashed */ - PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", - v->ob_type->tp_name); - return -1; -} - -PyObject * -PyObject_GetAttrString(PyObject *v, const char *name) -{ - PyObject *w, *res; - - if (v->ob_type->tp_getattr != NULL) - return (*v->ob_type->tp_getattr)(v, (char*)name); - w = PyString_InternFromString(name); - if (w == NULL) - return NULL; - res = PyObject_GetAttr(v, w); - Py_XDECREF(w); - return res; -} - -int -PyObject_HasAttrString(PyObject *v, const char *name) -{ - PyObject *res = PyObject_GetAttrString(v, name); - if (res != NULL) { - Py_DECREF(res); - return 1; - } - PyErr_Clear(); - return 0; -} - -int -PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w) -{ - PyObject *s; - int res; - - if (v->ob_type->tp_setattr != NULL) - return (*v->ob_type->tp_setattr)(v, (char*)name, w); - s = PyString_InternFromString(name); - if (s == NULL) - return -1; - res = PyObject_SetAttr(v, s, w); - Py_XDECREF(s); - return res; -} - -PyObject * -PyObject_GetAttr(PyObject *v, PyObject *name) -{ - PyTypeObject *tp = v->ob_type; - - if (!PyString_Check(name)) { -#ifdef Py_USING_UNICODE - /* The Unicode to string conversion is done here because the - existing tp_getattro slots expect a string object as name - and we wouldn't want to break those. */ - if (PyUnicode_Check(name)) { - name = _PyUnicode_AsDefaultEncodedString(name, NULL); - if (name == NULL) - return NULL; - } - else -#endif - { - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", - name->ob_type->tp_name); - return NULL; - } - } - if (tp->tp_getattro != NULL) - return (*tp->tp_getattro)(v, name); - if (tp->tp_getattr != NULL) - return (*tp->tp_getattr)(v, PyString_AS_STRING(name)); - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%.400s'", - tp->tp_name, PyString_AS_STRING(name)); - return NULL; -} - -int -PyObject_HasAttr(PyObject *v, PyObject *name) -{ - PyObject *res = PyObject_GetAttr(v, name); - if (res != NULL) { - Py_DECREF(res); - return 1; - } - PyErr_Clear(); - return 0; -} - -int -PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) -{ - PyTypeObject *tp = v->ob_type; - int err; - - if (!PyString_Check(name)){ -#ifdef Py_USING_UNICODE - /* The Unicode to string conversion is done here because the - existing tp_setattro slots expect a string object as name - and we wouldn't want to break those. */ - if (PyUnicode_Check(name)) { - name = PyUnicode_AsEncodedString(name, NULL, NULL); - if (name == NULL) - return -1; - } - else -#endif - { - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", - name->ob_type->tp_name); - return -1; - } - } - else - Py_INCREF(name); - - PyString_InternInPlace(&name); - if (tp->tp_setattro != NULL) { - err = (*tp->tp_setattro)(v, name, value); - Py_DECREF(name); - return err; - } - if (tp->tp_setattr != NULL) { - err = (*tp->tp_setattr)(v, PyString_AS_STRING(name), value); - Py_DECREF(name); - return err; - } - Py_DECREF(name); - if (tp->tp_getattr == NULL && tp->tp_getattro == NULL) - PyErr_Format(PyExc_TypeError, - "'%.100s' object has no attributes " - "(%s .%.100s)", - tp->tp_name, - value==NULL ? "del" : "assign to", - PyString_AS_STRING(name)); - else - PyErr_Format(PyExc_TypeError, - "'%.100s' object has only read-only attributes " - "(%s .%.100s)", - tp->tp_name, - value==NULL ? "del" : "assign to", - PyString_AS_STRING(name)); - return -1; -} - -/* Helper to get a pointer to an object's __dict__ slot, if any */ - -PyObject ** -_PyObject_GetDictPtr(PyObject *obj) -{ - Py_ssize_t dictoffset; - PyTypeObject *tp = obj->ob_type; - - if (!(tp->tp_flags & Py_TPFLAGS_HAVE_CLASS)) - return NULL; - dictoffset = tp->tp_dictoffset; - if (dictoffset == 0) - return NULL; - if (dictoffset < 0) { - Py_ssize_t tsize; - size_t size; - - tsize = ((PyVarObject *)obj)->ob_size; - if (tsize < 0) - tsize = -tsize; - size = _PyObject_VAR_SIZE(tp, tsize); - - dictoffset += (long)size; - assert(dictoffset > 0); - assert(dictoffset % SIZEOF_VOID_P == 0); - } - return (PyObject **) ((char *)obj + dictoffset); -} - -PyObject * -PyObject_SelfIter(PyObject *obj) -{ - Py_INCREF(obj); - return obj; -} - -/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */ - -PyObject * -PyObject_GenericGetAttr(PyObject *obj, PyObject *name) -{ - PyTypeObject *tp = obj->ob_type; - PyObject *descr = NULL; - PyObject *res = NULL; - descrgetfunc f; - Py_ssize_t dictoffset; - PyObject **dictptr; - - if (!PyString_Check(name)){ -#ifdef Py_USING_UNICODE - /* The Unicode to string conversion is done here because the - existing tp_setattro slots expect a string object as name - and we wouldn't want to break those. */ - if (PyUnicode_Check(name)) { - name = PyUnicode_AsEncodedString(name, NULL, NULL); - if (name == NULL) - return NULL; - } - else -#endif - { - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", - name->ob_type->tp_name); - return NULL; - } - } - else - Py_INCREF(name); - - if (tp->tp_dict == NULL) { - if (PyType_Ready(tp) < 0) - goto done; - } - - /* Inline _PyType_Lookup */ - { - Py_ssize_t i, n; - PyObject *mro, *base, *dict; - - /* Look in tp_dict of types in MRO */ - mro = tp->tp_mro; - assert(mro != NULL); - assert(PyTuple_Check(mro)); - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - base = PyTuple_GET_ITEM(mro, i); - if (PyClass_Check(base)) - dict = ((PyClassObject *)base)->cl_dict; - else { - assert(PyType_Check(base)); - dict = ((PyTypeObject *)base)->tp_dict; - } - assert(dict && PyDict_Check(dict)); - descr = PyDict_GetItem(dict, name); - if (descr != NULL) - break; - } - } - - Py_XINCREF(descr); - - f = NULL; - if (descr != NULL && - PyType_HasFeature(descr->ob_type, Py_TPFLAGS_HAVE_CLASS)) { - f = descr->ob_type->tp_descr_get; - if (f != NULL && PyDescr_IsData(descr)) { - res = f(descr, obj, (PyObject *)obj->ob_type); - Py_DECREF(descr); - goto done; - } - } - - /* Inline _PyObject_GetDictPtr */ - dictoffset = tp->tp_dictoffset; - if (dictoffset != 0) { - PyObject *dict; - if (dictoffset < 0) { - Py_ssize_t tsize; - size_t size; - - tsize = ((PyVarObject *)obj)->ob_size; - if (tsize < 0) - tsize = -tsize; - size = _PyObject_VAR_SIZE(tp, tsize); - - dictoffset += (long)size; - assert(dictoffset > 0); - assert(dictoffset % SIZEOF_VOID_P == 0); - } - dictptr = (PyObject **) ((char *)obj + dictoffset); - dict = *dictptr; - if (dict != NULL) { - res = PyDict_GetItem(dict, name); - if (res != NULL) { - Py_INCREF(res); - Py_XDECREF(descr); - goto done; - } - } - } - - if (f != NULL) { - res = f(descr, obj, (PyObject *)obj->ob_type); - Py_DECREF(descr); - goto done; - } - - if (descr != NULL) { - res = descr; - /* descr was already increfed above */ - goto done; - } - - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%.400s'", - tp->tp_name, PyString_AS_STRING(name)); - done: - Py_DECREF(name); - return res; -} - -int -PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value) -{ - PyTypeObject *tp = obj->ob_type; - PyObject *descr; - descrsetfunc f; - PyObject **dictptr; - int res = -1; - - if (!PyString_Check(name)){ -#ifdef Py_USING_UNICODE - /* The Unicode to string conversion is done here because the - existing tp_setattro slots expect a string object as name - and we wouldn't want to break those. */ - if (PyUnicode_Check(name)) { - name = PyUnicode_AsEncodedString(name, NULL, NULL); - if (name == NULL) - return -1; - } - else -#endif - { - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", - name->ob_type->tp_name); - return -1; - } - } - else - Py_INCREF(name); - - if (tp->tp_dict == NULL) { - if (PyType_Ready(tp) < 0) - goto done; - } - - descr = _PyType_Lookup(tp, name); - f = NULL; - if (descr != NULL && - PyType_HasFeature(descr->ob_type, Py_TPFLAGS_HAVE_CLASS)) { - f = descr->ob_type->tp_descr_set; - if (f != NULL && PyDescr_IsData(descr)) { - res = f(descr, obj, value); - goto done; - } - } - - dictptr = _PyObject_GetDictPtr(obj); - if (dictptr != NULL) { - PyObject *dict = *dictptr; - if (dict == NULL && value != NULL) { - dict = PyDict_New(); - if (dict == NULL) - goto done; - *dictptr = dict; - } - if (dict != NULL) { - if (value == NULL) - res = PyDict_DelItem(dict, name); - else - res = PyDict_SetItem(dict, name, value); - if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) - PyErr_SetObject(PyExc_AttributeError, name); - goto done; - } - } - - if (f != NULL) { - res = f(descr, obj, value); - goto done; - } - - if (descr == NULL) { - PyErr_Format(PyExc_AttributeError, - "'%.100s' object has no attribute '%.200s'", - tp->tp_name, PyString_AS_STRING(name)); - goto done; - } - - PyErr_Format(PyExc_AttributeError, - "'%.50s' object attribute '%.400s' is read-only", - tp->tp_name, PyString_AS_STRING(name)); - done: - Py_DECREF(name); - return res; -} - -/* Test a value used as condition, e.g., in a for or if statement. - Return -1 if an error occurred */ - -int -PyObject_IsTrue(PyObject *v) -{ - Py_ssize_t res; - if (v == Py_True) - return 1; - if (v == Py_False) - return 0; - if (v == Py_None) - return 0; - else if (v->ob_type->tp_as_number != NULL && - v->ob_type->tp_as_number->nb_nonzero != NULL) - res = (*v->ob_type->tp_as_number->nb_nonzero)(v); - else if (v->ob_type->tp_as_mapping != NULL && - v->ob_type->tp_as_mapping->mp_length != NULL) - res = (*v->ob_type->tp_as_mapping->mp_length)(v); - else if (v->ob_type->tp_as_sequence != NULL && - v->ob_type->tp_as_sequence->sq_length != NULL) - res = (*v->ob_type->tp_as_sequence->sq_length)(v); - else - return 1; - /* if it is negative, it should be either -1 or -2 */ - return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int); -} - -/* equivalent of 'not v' - Return -1 if an error occurred */ - -int -PyObject_Not(PyObject *v) -{ - int res; - res = PyObject_IsTrue(v); - if (res < 0) - return res; - return res == 0; -} - -/* Coerce two numeric types to the "larger" one. - Increment the reference count on each argument. - Return value: - -1 if an error occurred; - 0 if the coercion succeeded (and then the reference counts are increased); - 1 if no coercion is possible (and no error is raised). -*/ -int -PyNumber_CoerceEx(PyObject **pv, PyObject **pw) -{ - register PyObject *v = *pv; - register PyObject *w = *pw; - int res; - - /* Shortcut only for old-style types */ - if (v->ob_type == w->ob_type && - !PyType_HasFeature(v->ob_type, Py_TPFLAGS_CHECKTYPES)) - { - Py_INCREF(v); - Py_INCREF(w); - return 0; - } - if (v->ob_type->tp_as_number && v->ob_type->tp_as_number->nb_coerce) { - res = (*v->ob_type->tp_as_number->nb_coerce)(pv, pw); - if (res <= 0) - return res; - } - if (w->ob_type->tp_as_number && w->ob_type->tp_as_number->nb_coerce) { - res = (*w->ob_type->tp_as_number->nb_coerce)(pw, pv); - if (res <= 0) - return res; - } - return 1; -} - -/* Coerce two numeric types to the "larger" one. - Increment the reference count on each argument. - Return -1 and raise an exception if no coercion is possible - (and then no reference count is incremented). -*/ -int -PyNumber_Coerce(PyObject **pv, PyObject **pw) -{ - int err = PyNumber_CoerceEx(pv, pw); - if (err <= 0) - return err; - PyErr_SetString(PyExc_TypeError, "number coercion failed"); - return -1; -} - - -/* Test whether an object can be called */ - -int -PyCallable_Check(PyObject *x) -{ - if (x == NULL) - return 0; - if (PyInstance_Check(x)) { - PyObject *call = PyObject_GetAttrString(x, "__call__"); - if (call == NULL) { - PyErr_Clear(); - return 0; - } - /* Could test recursively but don't, for fear of endless - recursion if some joker sets self.__call__ = self */ - Py_DECREF(call); - return 1; - } - else { - return x->ob_type->tp_call != NULL; - } -} - -/* Helper for PyObject_Dir. - Merge the __dict__ of aclass into dict, and recursively also all - the __dict__s of aclass's base classes. The order of merging isn't - defined, as it's expected that only the final set of dict keys is - interesting. - Return 0 on success, -1 on error. -*/ - -static int -merge_class_dict(PyObject* dict, PyObject* aclass) -{ - PyObject *classdict; - PyObject *bases; - - assert(PyDict_Check(dict)); - assert(aclass); - - /* Merge in the type's dict (if any). */ - classdict = PyObject_GetAttrString(aclass, "__dict__"); - if (classdict == NULL) - PyErr_Clear(); - else { - int status = PyDict_Update(dict, classdict); - Py_DECREF(classdict); - if (status < 0) - return -1; - } - - /* Recursively merge in the base types' (if any) dicts. */ - bases = PyObject_GetAttrString(aclass, "__bases__"); - if (bases == NULL) - PyErr_Clear(); - else { - /* We have no guarantee that bases is a real tuple */ - Py_ssize_t i, n; - n = PySequence_Size(bases); /* This better be right */ - if (n < 0) - PyErr_Clear(); - else { - for (i = 0; i < n; i++) { - int status; - PyObject *base = PySequence_GetItem(bases, i); - if (base == NULL) { - Py_DECREF(bases); - return -1; - } - status = merge_class_dict(dict, base); - Py_DECREF(base); - if (status < 0) { - Py_DECREF(bases); - return -1; - } - } - } - Py_DECREF(bases); - } - return 0; -} - -/* Helper for PyObject_Dir. - If obj has an attr named attrname that's a list, merge its string - elements into keys of dict. - Return 0 on success, -1 on error. Errors due to not finding the attr, - or the attr not being a list, are suppressed. -*/ - -static int -merge_list_attr(PyObject* dict, PyObject* obj, const char *attrname) -{ - PyObject *list; - int result = 0; - - assert(PyDict_Check(dict)); - assert(obj); - assert(attrname); - - list = PyObject_GetAttrString(obj, attrname); - if (list == NULL) - PyErr_Clear(); - - else if (PyList_Check(list)) { - int i; - for (i = 0; i < PyList_GET_SIZE(list); ++i) { - PyObject *item = PyList_GET_ITEM(list, i); - if (PyString_Check(item)) { - result = PyDict_SetItem(dict, item, Py_None); - if (result < 0) - break; - } - } - } - - Py_XDECREF(list); - return result; -} - -/* Like __builtin__.dir(arg). See bltinmodule.c's builtin_dir for the - docstring, which should be kept in synch with this implementation. */ - -PyObject * -PyObject_Dir(PyObject *arg) -{ - /* Set exactly one of these non-NULL before the end. */ - PyObject *result = NULL; /* result list */ - PyObject *masterdict = NULL; /* result is masterdict.keys() */ - - /* If NULL arg, return the locals. */ - if (arg == NULL) { - PyObject *locals = PyEval_GetLocals(); - if (locals == NULL) - goto error; - result = PyMapping_Keys(locals); - if (result == NULL) - goto error; - } - - /* Elif this is some form of module, we only want its dict. */ - else if (PyModule_Check(arg)) { - masterdict = PyObject_GetAttrString(arg, "__dict__"); - if (masterdict == NULL) - goto error; - if (!PyDict_Check(masterdict)) { - PyErr_SetString(PyExc_TypeError, - "module.__dict__ is not a dictionary"); - goto error; - } - } - - /* Elif some form of type or class, grab its dict and its bases. - We deliberately don't suck up its __class__, as methods belonging - to the metaclass would probably be more confusing than helpful. */ - else if (PyType_Check(arg) || PyClass_Check(arg)) { - masterdict = PyDict_New(); - if (masterdict == NULL) - goto error; - if (merge_class_dict(masterdict, arg) < 0) - goto error; - } - - /* Else look at its dict, and the attrs reachable from its class. */ - else { - PyObject *itsclass; - /* Create a dict to start with. CAUTION: Not everything - responding to __dict__ returns a dict! */ - masterdict = PyObject_GetAttrString(arg, "__dict__"); - if (masterdict == NULL) { - PyErr_Clear(); - masterdict = PyDict_New(); - } - else if (!PyDict_Check(masterdict)) { - Py_DECREF(masterdict); - masterdict = PyDict_New(); - } - else { - /* The object may have returned a reference to its - dict, so copy it to avoid mutating it. */ - PyObject *temp = PyDict_Copy(masterdict); - Py_DECREF(masterdict); - masterdict = temp; - } - if (masterdict == NULL) - goto error; - - /* Merge in __members__ and __methods__ (if any). - XXX Would like this to go away someday; for now, it's - XXX needed to get at im_self etc of method objects. */ - if (merge_list_attr(masterdict, arg, "__members__") < 0) - goto error; - if (merge_list_attr(masterdict, arg, "__methods__") < 0) - goto error; - - /* Merge in attrs reachable from its class. - CAUTION: Not all objects have a __class__ attr. */ - itsclass = PyObject_GetAttrString(arg, "__class__"); - if (itsclass == NULL) - PyErr_Clear(); - else { - int status = merge_class_dict(masterdict, itsclass); - Py_DECREF(itsclass); - if (status < 0) - goto error; - } - } - - assert((result == NULL) ^ (masterdict == NULL)); - if (masterdict != NULL) { - /* The result comes from its keys. */ - assert(result == NULL); - result = PyDict_Keys(masterdict); - if (result == NULL) - goto error; - } - - assert(result); - if (!PyList_Check(result)) { - PyErr_Format(PyExc_TypeError, - "Expected keys() to be a list, not '%.200s'", - result->ob_type->tp_name); - goto error; - } - if (PyList_Sort(result) != 0) - goto error; - else - goto normal_return; - - error: - Py_XDECREF(result); - result = NULL; - /* fall through */ - normal_return: - Py_XDECREF(masterdict); - return result; -} - -/* -NoObject is usable as a non-NULL undefined value, used by the macro None. -There is (and should be!) no way to create other objects of this type, -so there is exactly one (which is indestructible, by the way). -(XXX This type and the type of NotImplemented below should be unified.) -*/ - -/* ARGSUSED */ -static PyObject * -none_repr(PyObject *op) -{ - return PyString_FromString("None"); -} - -/* ARGUSED */ -static void -none_dealloc(PyObject* ignore) -{ - /* This should never get called, but we also don't want to SEGV if - * we accidently decref None out of existance. - */ - Py_FatalError("deallocating None"); -} - - -static PyTypeObject PyNone_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "NoneType", - 0, - 0, - none_dealloc, /*tp_dealloc*/ /*never called*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - none_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ -}; - -PyObject _Py_NoneStruct = { - PyObject_HEAD_INIT(&PyNone_Type) -}; - -/* NotImplemented is an object that can be used to signal that an - operation is not implemented for the given type combination. */ - -static PyObject * -NotImplemented_repr(PyObject *op) -{ - return PyString_FromString("NotImplemented"); -} - -static PyTypeObject PyNotImplemented_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "NotImplementedType", - 0, - 0, - none_dealloc, /*tp_dealloc*/ /*never called*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - NotImplemented_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ -}; - -PyObject _Py_NotImplementedStruct = { - PyObject_HEAD_INIT(&PyNotImplemented_Type) -}; - -void -_Py_ReadyTypes(void) -{ - if (PyType_Ready(&PyType_Type) < 0) - Py_FatalError("Can't initialize 'type'"); - - if (PyType_Ready(&_PyWeakref_RefType) < 0) - Py_FatalError("Can't initialize 'weakref'"); - - if (PyType_Ready(&PyBool_Type) < 0) - Py_FatalError("Can't initialize 'bool'"); - - if (PyType_Ready(&PyString_Type) < 0) - Py_FatalError("Can't initialize 'str'"); - - if (PyType_Ready(&PyList_Type) < 0) - Py_FatalError("Can't initialize 'list'"); - - if (PyType_Ready(&PyNone_Type) < 0) - Py_FatalError("Can't initialize type(None)"); - - if (PyType_Ready(&PyNotImplemented_Type) < 0) - Py_FatalError("Can't initialize type(NotImplemented)"); -} - - -#ifdef Py_TRACE_REFS - -void -_Py_NewReference(PyObject *op) -{ - _Py_INC_REFTOTAL; - op->ob_refcnt = 1; - _Py_AddToAllObjects(op, 1); - _Py_INC_TPALLOCS(op); -} - -void -_Py_ForgetReference(register PyObject *op) -{ -#ifdef SLOW_UNREF_CHECK - register PyObject *p; -#endif - if (op->ob_refcnt < 0) - Py_FatalError("UNREF negative refcnt"); - if (op == &refchain || - op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) - Py_FatalError("UNREF invalid object"); -#ifdef SLOW_UNREF_CHECK - for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { - if (p == op) - break; - } - if (p == &refchain) /* Not found */ - Py_FatalError("UNREF unknown object"); -#endif - op->_ob_next->_ob_prev = op->_ob_prev; - op->_ob_prev->_ob_next = op->_ob_next; - op->_ob_next = op->_ob_prev = NULL; - _Py_INC_TPFREES(op); -} - -void -_Py_Dealloc(PyObject *op) -{ - destructor dealloc = op->ob_type->tp_dealloc; - _Py_ForgetReference(op); - (*dealloc)(op); -} - -/* Print all live objects. Because PyObject_Print is called, the - * interpreter must be in a healthy state. - */ -void -_Py_PrintReferences(FILE *fp) -{ - PyObject *op; - fprintf(fp, "Remaining objects:\n"); - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { - fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] ", op, op->ob_refcnt); - if (PyObject_Print(op, fp, 0) != 0) - PyErr_Clear(); - putc('\n', fp); - } -} - -/* Print the addresses of all live objects. Unlike _Py_PrintReferences, this - * doesn't make any calls to the Python C API, so is always safe to call. - */ -void -_Py_PrintReferenceAddresses(FILE *fp) -{ - PyObject *op; - fprintf(fp, "Remaining object addresses:\n"); - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) - fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] %s\n", op, - op->ob_refcnt, op->ob_type->tp_name); -} - -PyObject * -_Py_GetObjects(PyObject *self, PyObject *args) -{ - int i, n; - PyObject *t = NULL; - PyObject *res, *op; - - if (!PyArg_ParseTuple(args, "i|O", &n, &t)) - return NULL; - op = refchain._ob_next; - res = PyList_New(0); - if (res == NULL) - return NULL; - for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { - while (op == self || op == args || op == res || op == t || - (t != NULL && op->ob_type != (PyTypeObject *) t)) { - op = op->_ob_next; - if (op == &refchain) - return res; - } - if (PyList_Append(res, op) < 0) { - Py_DECREF(res); - return NULL; - } - op = op->_ob_next; - } - return res; -} - -#endif - - -/* Hack to force loading of cobject.o */ -PyTypeObject *_Py_cobject_hack = &PyCObject_Type; - - -/* Hack to force loading of abstract.o */ -Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size; - - -/* Python's malloc wrappers (see pymem.h) */ - -void * -PyMem_Malloc(size_t nbytes) -{ - return PyMem_MALLOC(nbytes); -} - -void * -PyMem_Realloc(void *p, size_t nbytes) -{ - return PyMem_REALLOC(p, nbytes); -} - -void -PyMem_Free(void *p) -{ - PyMem_FREE(p); -} - - -/* These methods are used to control infinite recursion in repr, str, print, - etc. Container objects that may recursively contain themselves, - e.g. builtin dictionaries and lists, should used Py_ReprEnter() and - Py_ReprLeave() to avoid infinite recursion. - - Py_ReprEnter() returns 0 the first time it is called for a particular - object and 1 every time thereafter. It returns -1 if an exception - occurred. Py_ReprLeave() has no return value. - - See dictobject.c and listobject.c for examples of use. -*/ - -#define KEY "Py_Repr" - -int -Py_ReprEnter(PyObject *obj) -{ - PyObject *dict; - PyObject *list; - Py_ssize_t i; - - dict = PyThreadState_GetDict(); - if (dict == NULL) - return 0; - list = PyDict_GetItemString(dict, KEY); - if (list == NULL) { - list = PyList_New(0); - if (list == NULL) - return -1; - if (PyDict_SetItemString(dict, KEY, list) < 0) - return -1; - Py_DECREF(list); - } - i = PyList_GET_SIZE(list); - while (--i >= 0) { - if (PyList_GET_ITEM(list, i) == obj) - return 1; - } - PyList_Append(list, obj); - return 0; -} - -void -Py_ReprLeave(PyObject *obj) -{ - PyObject *dict; - PyObject *list; - Py_ssize_t i; - - dict = PyThreadState_GetDict(); - if (dict == NULL) - return; - list = PyDict_GetItemString(dict, KEY); - if (list == NULL || !PyList_Check(list)) - return; - i = PyList_GET_SIZE(list); - /* Count backwards because we always expect obj to be list[-1] */ - while (--i >= 0) { - if (PyList_GET_ITEM(list, i) == obj) { - PyList_SetSlice(list, i, i + 1, NULL); - break; - } - } -} - -/* Trashcan support. */ - -/* Current call-stack depth of tp_dealloc calls. */ -int _PyTrash_delete_nesting = 0; - -/* List of objects that still need to be cleaned up, singly linked via their - * gc headers' gc_prev pointers. - */ -PyObject *_PyTrash_delete_later = NULL; - -/* Add op to the _PyTrash_delete_later list. Called when the current - * call-stack depth gets large. op must be a currently untracked gc'ed - * object, with refcount 0. Py_DECREF must already have been called on it. - */ -void -_PyTrash_deposit_object(PyObject *op) -{ - assert(PyObject_IS_GC(op)); - assert(_Py_AS_GC(op)->gc.gc_refs == _PyGC_REFS_UNTRACKED); - assert(op->ob_refcnt == 0); - _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *)_PyTrash_delete_later; - _PyTrash_delete_later = op; -} - -/* Dealloccate all the objects in the _PyTrash_delete_later list. Called when - * the call-stack unwinds again. - */ -void -_PyTrash_destroy_chain(void) -{ - while (_PyTrash_delete_later) { - PyObject *op = _PyTrash_delete_later; - destructor dealloc = op->ob_type->tp_dealloc; - - _PyTrash_delete_later = - (PyObject*) _Py_AS_GC(op)->gc.gc_prev; - - /* Call the deallocator directly. This used to try to - * fool Py_DECREF into calling it indirectly, but - * Py_DECREF was already called on this object, and in - * assorted non-release builds calling Py_DECREF again ends - * up distorting allocation statistics. - */ - assert(op->ob_refcnt == 0); - ++_PyTrash_delete_nesting; - (*dealloc)(op); - --_PyTrash_delete_nesting; - } -} - -#ifdef __cplusplus -} -#endif - diff --git a/sys/src/cmd/python/Objects/obmalloc.c b/sys/src/cmd/python/Objects/obmalloc.c deleted file mode 100644 index 840570e06..000000000 --- a/sys/src/cmd/python/Objects/obmalloc.c +++ /dev/null @@ -1,1745 +0,0 @@ -#include "Python.h" - -#ifdef WITH_PYMALLOC - -/* An object allocator for Python. - - Here is an introduction to the layers of the Python memory architecture, - showing where the object allocator is actually used (layer +2), It is - called for every object allocation and deallocation (PyObject_New/Del), - unless the object-specific allocators implement a proprietary allocation - scheme (ex.: ints use a simple free list). This is also the place where - the cyclic garbage collector operates selectively on container objects. - - - Object-specific allocators - _____ ______ ______ ________ - [ int ] [ dict ] [ list ] ... [ string ] Python core | -+3 | <----- Object-specific memory -----> | <-- Non-object memory --> | - _______________________________ | | - [ Python's object allocator ] | | -+2 | ####### Object memory ####### | <------ Internal buffers ------> | - ______________________________________________________________ | - [ Python's raw memory allocator (PyMem_ API) ] | -+1 | <----- Python memory (under PyMem manager's control) ------> | | - __________________________________________________________________ - [ Underlying general-purpose allocator (ex: C library malloc) ] - 0 | <------ Virtual memory allocated for the python process -------> | - - ========================================================================= - _______________________________________________________________________ - [ OS-specific Virtual Memory Manager (VMM) ] --1 | <--- Kernel dynamic storage allocation & management (page-based) ---> | - __________________________________ __________________________________ - [ ] [ ] --2 | <-- Physical memory: ROM/RAM --> | | <-- Secondary storage (swap) --> | - -*/ -/*==========================================================================*/ - -/* A fast, special-purpose memory allocator for small blocks, to be used - on top of a general-purpose malloc -- heavily based on previous art. */ - -/* Vladimir Marangozov -- August 2000 */ - -/* - * "Memory management is where the rubber meets the road -- if we do the wrong - * thing at any level, the results will not be good. And if we don't make the - * levels work well together, we are in serious trouble." (1) - * - * (1) Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles, - * "Dynamic Storage Allocation: A Survey and Critical Review", - * in Proc. 1995 Int'l. Workshop on Memory Management, September 1995. - */ - -/* #undef WITH_MEMORY_LIMITS */ /* disable mem limit checks */ - -/*==========================================================================*/ - -/* - * Allocation strategy abstract: - * - * For small requests, the allocator sub-allocates <Big> blocks of memory. - * Requests greater than 256 bytes are routed to the system's allocator. - * - * Small requests are grouped in size classes spaced 8 bytes apart, due - * to the required valid alignment of the returned address. Requests of - * a particular size are serviced from memory pools of 4K (one VMM page). - * Pools are fragmented on demand and contain free lists of blocks of one - * particular size class. In other words, there is a fixed-size allocator - * for each size class. Free pools are shared by the different allocators - * thus minimizing the space reserved for a particular size class. - * - * This allocation strategy is a variant of what is known as "simple - * segregated storage based on array of free lists". The main drawback of - * simple segregated storage is that we might end up with lot of reserved - * memory for the different free lists, which degenerate in time. To avoid - * this, we partition each free list in pools and we share dynamically the - * reserved space between all free lists. This technique is quite efficient - * for memory intensive programs which allocate mainly small-sized blocks. - * - * For small requests we have the following table: - * - * Request in bytes Size of allocated block Size class idx - * ---------------------------------------------------------------- - * 1-8 8 0 - * 9-16 16 1 - * 17-24 24 2 - * 25-32 32 3 - * 33-40 40 4 - * 41-48 48 5 - * 49-56 56 6 - * 57-64 64 7 - * 65-72 72 8 - * ... ... ... - * 241-248 248 30 - * 249-256 256 31 - * - * 0, 257 and up: routed to the underlying allocator. - */ - -/*==========================================================================*/ - -/* - * -- Main tunable settings section -- - */ - -/* - * Alignment of addresses returned to the user. 8-bytes alignment works - * on most current architectures (with 32-bit or 64-bit address busses). - * The alignment value is also used for grouping small requests in size - * classes spaced ALIGNMENT bytes apart. - * - * You shouldn't change this unless you know what you are doing. - */ -#define ALIGNMENT 8 /* must be 2^N */ -#define ALIGNMENT_SHIFT 3 -#define ALIGNMENT_MASK (ALIGNMENT - 1) - -/* Return the number of bytes in size class I, as a uint. */ -#define INDEX2SIZE(I) (((uint)(I) + 1) << ALIGNMENT_SHIFT) - -/* - * Max size threshold below which malloc requests are considered to be - * small enough in order to use preallocated memory pools. You can tune - * this value according to your application behaviour and memory needs. - * - * The following invariants must hold: - * 1) ALIGNMENT <= SMALL_REQUEST_THRESHOLD <= 256 - * 2) SMALL_REQUEST_THRESHOLD is evenly divisible by ALIGNMENT - * - * Although not required, for better performance and space efficiency, - * it is recommended that SMALL_REQUEST_THRESHOLD is set to a power of 2. - */ -#define SMALL_REQUEST_THRESHOLD 256 -#define NB_SMALL_SIZE_CLASSES (SMALL_REQUEST_THRESHOLD / ALIGNMENT) - -/* - * The system's VMM page size can be obtained on most unices with a - * getpagesize() call or deduced from various header files. To make - * things simpler, we assume that it is 4K, which is OK for most systems. - * It is probably better if this is the native page size, but it doesn't - * have to be. In theory, if SYSTEM_PAGE_SIZE is larger than the native page - * size, then `POOL_ADDR(p)->arenaindex' could rarely cause a segmentation - * violation fault. 4K is apparently OK for all the platforms that python - * currently targets. - */ -#define SYSTEM_PAGE_SIZE (4 * 1024) -#define SYSTEM_PAGE_SIZE_MASK (SYSTEM_PAGE_SIZE - 1) - -/* - * Maximum amount of memory managed by the allocator for small requests. - */ -#ifdef WITH_MEMORY_LIMITS -#ifndef SMALL_MEMORY_LIMIT -#define SMALL_MEMORY_LIMIT (64 * 1024 * 1024) /* 64 MB -- more? */ -#endif -#endif - -/* - * The allocator sub-allocates <Big> blocks of memory (called arenas) aligned - * on a page boundary. This is a reserved virtual address space for the - * current process (obtained through a malloc call). In no way this means - * that the memory arenas will be used entirely. A malloc(<Big>) is usually - * an address range reservation for <Big> bytes, unless all pages within this - * space are referenced subsequently. So malloc'ing big blocks and not using - * them does not mean "wasting memory". It's an addressable range wastage... - * - * Therefore, allocating arenas with malloc is not optimal, because there is - * some address space wastage, but this is the most portable way to request - * memory from the system across various platforms. - */ -#define ARENA_SIZE (256 << 10) /* 256KB */ - -#ifdef WITH_MEMORY_LIMITS -#define MAX_ARENAS (SMALL_MEMORY_LIMIT / ARENA_SIZE) -#endif - -/* - * Size of the pools used for small blocks. Should be a power of 2, - * between 1K and SYSTEM_PAGE_SIZE, that is: 1k, 2k, 4k. - */ -#define POOL_SIZE SYSTEM_PAGE_SIZE /* must be 2^N */ -#define POOL_SIZE_MASK SYSTEM_PAGE_SIZE_MASK - -/* - * -- End of tunable settings section -- - */ - -/*==========================================================================*/ - -/* - * Locking - * - * To reduce lock contention, it would probably be better to refine the - * crude function locking with per size class locking. I'm not positive - * however, whether it's worth switching to such locking policy because - * of the performance penalty it might introduce. - * - * The following macros describe the simplest (should also be the fastest) - * lock object on a particular platform and the init/fini/lock/unlock - * operations on it. The locks defined here are not expected to be recursive - * because it is assumed that they will always be called in the order: - * INIT, [LOCK, UNLOCK]*, FINI. - */ - -/* - * Python's threads are serialized, so object malloc locking is disabled. - */ -#define SIMPLELOCK_DECL(lock) /* simple lock declaration */ -#define SIMPLELOCK_INIT(lock) /* allocate (if needed) and initialize */ -#define SIMPLELOCK_FINI(lock) /* free/destroy an existing lock */ -#define SIMPLELOCK_LOCK(lock) /* acquire released lock */ -#define SIMPLELOCK_UNLOCK(lock) /* release acquired lock */ - -/* - * Basic types - * I don't care if these are defined in <sys/types.h> or elsewhere. Axiom. - */ -#undef uchar -#define uchar unsigned char /* assuming == 8 bits */ - -#undef uint -#define uint unsigned int /* assuming >= 16 bits */ - -#undef ulong -#define ulong unsigned long /* assuming >= 32 bits */ - -#undef uptr -#define uptr Py_uintptr_t - -/* When you say memory, my mind reasons in terms of (pointers to) blocks */ -typedef uchar block; - -/* Pool for small blocks. */ -struct pool_header { - union { block *_padding; - uint count; } ref; /* number of allocated blocks */ - block *freeblock; /* pool's free list head */ - struct pool_header *nextpool; /* next pool of this size class */ - struct pool_header *prevpool; /* previous pool "" */ - uint arenaindex; /* index into arenas of base adr */ - uint szidx; /* block size class index */ - uint nextoffset; /* bytes to virgin block */ - uint maxnextoffset; /* largest valid nextoffset */ -}; - -typedef struct pool_header *poolp; - -/* Record keeping for arenas. */ -struct arena_object { - /* The address of the arena, as returned by malloc. Note that 0 - * will never be returned by a successful malloc, and is used - * here to mark an arena_object that doesn't correspond to an - * allocated arena. - */ - uptr address; - - /* Pool-aligned pointer to the next pool to be carved off. */ - block* pool_address; - - /* The number of available pools in the arena: free pools + never- - * allocated pools. - */ - uint nfreepools; - - /* The total number of pools in the arena, whether or not available. */ - uint ntotalpools; - - /* Singly-linked list of available pools. */ - struct pool_header* freepools; - - /* Whenever this arena_object is not associated with an allocated - * arena, the nextarena member is used to link all unassociated - * arena_objects in the singly-linked `unused_arena_objects` list. - * The prevarena member is unused in this case. - * - * When this arena_object is associated with an allocated arena - * with at least one available pool, both members are used in the - * doubly-linked `usable_arenas` list, which is maintained in - * increasing order of `nfreepools` values. - * - * Else this arena_object is associated with an allocated arena - * all of whose pools are in use. `nextarena` and `prevarena` - * are both meaningless in this case. - */ - struct arena_object* nextarena; - struct arena_object* prevarena; -}; - -#undef ROUNDUP -#define ROUNDUP(x) (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK) -#define POOL_OVERHEAD ROUNDUP(sizeof(struct pool_header)) - -#define DUMMY_SIZE_IDX 0xffff /* size class of newly cached pools */ - -/* Round pointer P down to the closest pool-aligned address <= P, as a poolp */ -#define POOL_ADDR(P) ((poolp)((uptr)(P) & ~(uptr)POOL_SIZE_MASK)) - -/* Return total number of blocks in pool of size index I, as a uint. */ -#define NUMBLOCKS(I) ((uint)(POOL_SIZE - POOL_OVERHEAD) / INDEX2SIZE(I)) - -/*==========================================================================*/ - -/* - * This malloc lock - */ -SIMPLELOCK_DECL(_malloc_lock) -#define LOCK() SIMPLELOCK_LOCK(_malloc_lock) -#define UNLOCK() SIMPLELOCK_UNLOCK(_malloc_lock) -#define LOCK_INIT() SIMPLELOCK_INIT(_malloc_lock) -#define LOCK_FINI() SIMPLELOCK_FINI(_malloc_lock) - -/* - * Pool table -- headed, circular, doubly-linked lists of partially used pools. - -This is involved. For an index i, usedpools[i+i] is the header for a list of -all partially used pools holding small blocks with "size class idx" i. So -usedpools[0] corresponds to blocks of size 8, usedpools[2] to blocks of size -16, and so on: index 2*i <-> blocks of size (i+1)<<ALIGNMENT_SHIFT. - -Pools are carved off an arena's highwater mark (an arena_object's pool_address -member) as needed. Once carved off, a pool is in one of three states forever -after: - -used == partially used, neither empty nor full - At least one block in the pool is currently allocated, and at least one - block in the pool is not currently allocated (note this implies a pool - has room for at least two blocks). - This is a pool's initial state, as a pool is created only when malloc - needs space. - The pool holds blocks of a fixed size, and is in the circular list headed - at usedpools[i] (see above). It's linked to the other used pools of the - same size class via the pool_header's nextpool and prevpool members. - If all but one block is currently allocated, a malloc can cause a - transition to the full state. If all but one block is not currently - allocated, a free can cause a transition to the empty state. - -full == all the pool's blocks are currently allocated - On transition to full, a pool is unlinked from its usedpools[] list. - It's not linked to from anything then anymore, and its nextpool and - prevpool members are meaningless until it transitions back to used. - A free of a block in a full pool puts the pool back in the used state. - Then it's linked in at the front of the appropriate usedpools[] list, so - that the next allocation for its size class will reuse the freed block. - -empty == all the pool's blocks are currently available for allocation - On transition to empty, a pool is unlinked from its usedpools[] list, - and linked to the front of its arena_object's singly-linked freepools list, - via its nextpool member. The prevpool member has no meaning in this case. - Empty pools have no inherent size class: the next time a malloc finds - an empty list in usedpools[], it takes the first pool off of freepools. - If the size class needed happens to be the same as the size class the pool - last had, some pool initialization can be skipped. - - -Block Management - -Blocks within pools are again carved out as needed. pool->freeblock points to -the start of a singly-linked list of free blocks within the pool. When a -block is freed, it's inserted at the front of its pool's freeblock list. Note -that the available blocks in a pool are *not* linked all together when a pool -is initialized. Instead only "the first two" (lowest addresses) blocks are -set up, returning the first such block, and setting pool->freeblock to a -one-block list holding the second such block. This is consistent with that -pymalloc strives at all levels (arena, pool, and block) never to touch a piece -of memory until it's actually needed. - -So long as a pool is in the used state, we're certain there *is* a block -available for allocating, and pool->freeblock is not NULL. If pool->freeblock -points to the end of the free list before we've carved the entire pool into -blocks, that means we simply haven't yet gotten to one of the higher-address -blocks. The offset from the pool_header to the start of "the next" virgin -block is stored in the pool_header nextoffset member, and the largest value -of nextoffset that makes sense is stored in the maxnextoffset member when a -pool is initialized. All the blocks in a pool have been passed out at least -once when and only when nextoffset > maxnextoffset. - - -Major obscurity: While the usedpools vector is declared to have poolp -entries, it doesn't really. It really contains two pointers per (conceptual) -poolp entry, the nextpool and prevpool members of a pool_header. The -excruciating initialization code below fools C so that - - usedpool[i+i] - -"acts like" a genuine poolp, but only so long as you only reference its -nextpool and prevpool members. The "- 2*sizeof(block *)" gibberish is -compensating for that a pool_header's nextpool and prevpool members -immediately follow a pool_header's first two members: - - union { block *_padding; - uint count; } ref; - block *freeblock; - -each of which consume sizeof(block *) bytes. So what usedpools[i+i] really -contains is a fudged-up pointer p such that *if* C believes it's a poolp -pointer, then p->nextpool and p->prevpool are both p (meaning that the headed -circular list is empty). - -It's unclear why the usedpools setup is so convoluted. It could be to -minimize the amount of cache required to hold this heavily-referenced table -(which only *needs* the two interpool pointer members of a pool_header). OTOH, -referencing code has to remember to "double the index" and doing so isn't -free, usedpools[0] isn't a strictly legal pointer, and we're crucially relying -on that C doesn't insert any padding anywhere in a pool_header at or before -the prevpool member. -**************************************************************************** */ - -#define PTA(x) ((poolp )((uchar *)&(usedpools[2*(x)]) - 2*sizeof(block *))) -#define PT(x) PTA(x), PTA(x) - -static poolp usedpools[2 * ((NB_SMALL_SIZE_CLASSES + 7) / 8) * 8] = { - PT(0), PT(1), PT(2), PT(3), PT(4), PT(5), PT(6), PT(7) -#if NB_SMALL_SIZE_CLASSES > 8 - , PT(8), PT(9), PT(10), PT(11), PT(12), PT(13), PT(14), PT(15) -#if NB_SMALL_SIZE_CLASSES > 16 - , PT(16), PT(17), PT(18), PT(19), PT(20), PT(21), PT(22), PT(23) -#if NB_SMALL_SIZE_CLASSES > 24 - , PT(24), PT(25), PT(26), PT(27), PT(28), PT(29), PT(30), PT(31) -#if NB_SMALL_SIZE_CLASSES > 32 - , PT(32), PT(33), PT(34), PT(35), PT(36), PT(37), PT(38), PT(39) -#if NB_SMALL_SIZE_CLASSES > 40 - , PT(40), PT(41), PT(42), PT(43), PT(44), PT(45), PT(46), PT(47) -#if NB_SMALL_SIZE_CLASSES > 48 - , PT(48), PT(49), PT(50), PT(51), PT(52), PT(53), PT(54), PT(55) -#if NB_SMALL_SIZE_CLASSES > 56 - , PT(56), PT(57), PT(58), PT(59), PT(60), PT(61), PT(62), PT(63) -#endif /* NB_SMALL_SIZE_CLASSES > 56 */ -#endif /* NB_SMALL_SIZE_CLASSES > 48 */ -#endif /* NB_SMALL_SIZE_CLASSES > 40 */ -#endif /* NB_SMALL_SIZE_CLASSES > 32 */ -#endif /* NB_SMALL_SIZE_CLASSES > 24 */ -#endif /* NB_SMALL_SIZE_CLASSES > 16 */ -#endif /* NB_SMALL_SIZE_CLASSES > 8 */ -}; - -/*========================================================================== -Arena management. - -`arenas` is a vector of arena_objects. It contains maxarenas entries, some of -which may not be currently used (== they're arena_objects that aren't -currently associated with an allocated arena). Note that arenas proper are -separately malloc'ed. - -Prior to Python 2.5, arenas were never free()'ed. Starting with Python 2.5, -we do try to free() arenas, and use some mild heuristic strategies to increase -the likelihood that arenas eventually can be freed. - -unused_arena_objects - - This is a singly-linked list of the arena_objects that are currently not - being used (no arena is associated with them). Objects are taken off the - head of the list in new_arena(), and are pushed on the head of the list in - PyObject_Free() when the arena is empty. Key invariant: an arena_object - is on this list if and only if its .address member is 0. - -usable_arenas - - This is a doubly-linked list of the arena_objects associated with arenas - that have pools available. These pools are either waiting to be reused, - or have not been used before. The list is sorted to have the most- - allocated arenas first (ascending order based on the nfreepools member). - This means that the next allocation will come from a heavily used arena, - which gives the nearly empty arenas a chance to be returned to the system. - In my unscientific tests this dramatically improved the number of arenas - that could be freed. - -Note that an arena_object associated with an arena all of whose pools are -currently in use isn't on either list. -*/ - -/* Array of objects used to track chunks of memory (arenas). */ -static struct arena_object* arenas = NULL; -/* Number of slots currently allocated in the `arenas` vector. */ -static uint maxarenas = 0; - -/* The head of the singly-linked, NULL-terminated list of available - * arena_objects. - */ -static struct arena_object* unused_arena_objects = NULL; - -/* The head of the doubly-linked, NULL-terminated at each end, list of - * arena_objects associated with arenas that have pools available. - */ -static struct arena_object* usable_arenas = NULL; - -/* How many arena_objects do we initially allocate? - * 16 = can allocate 16 arenas = 16 * ARENA_SIZE = 4MB before growing the - * `arenas` vector. - */ -#define INITIAL_ARENA_OBJECTS 16 - -/* Number of arenas allocated that haven't been free()'d. */ -static size_t narenas_currently_allocated = 0; - -#ifdef PYMALLOC_DEBUG -/* Total number of times malloc() called to allocate an arena. */ -static size_t ntimes_arena_allocated = 0; -/* High water mark (max value ever seen) for narenas_currently_allocated. */ -static size_t narenas_highwater = 0; -#endif - -/* Allocate a new arena. If we run out of memory, return NULL. Else - * allocate a new arena, and return the address of an arena_object - * describing the new arena. It's expected that the caller will set - * `usable_arenas` to the return value. - */ -static struct arena_object* -new_arena(void) -{ - struct arena_object* arenaobj; - uint excess; /* number of bytes above pool alignment */ - -#ifdef PYMALLOC_DEBUG - if (Py_GETENV("PYTHONMALLOCSTATS")) - _PyObject_DebugMallocStats(); -#endif - if (unused_arena_objects == NULL) { - uint i; - uint numarenas; - size_t nbytes; - - /* Double the number of arena objects on each allocation. - * Note that it's possible for `numarenas` to overflow. - */ - numarenas = maxarenas ? maxarenas << 1 : INITIAL_ARENA_OBJECTS; - if (numarenas <= maxarenas) - return NULL; /* overflow */ - nbytes = numarenas * sizeof(*arenas); - if (nbytes / sizeof(*arenas) != numarenas) - return NULL; /* overflow */ - arenaobj = (struct arena_object *)realloc(arenas, nbytes); - if (arenaobj == NULL) - return NULL; - arenas = arenaobj; - - /* We might need to fix pointers that were copied. However, - * new_arena only gets called when all the pages in the - * previous arenas are full. Thus, there are *no* pointers - * into the old array. Thus, we don't have to worry about - * invalid pointers. Just to be sure, some asserts: - */ - assert(usable_arenas == NULL); - assert(unused_arena_objects == NULL); - - /* Put the new arenas on the unused_arena_objects list. */ - for (i = maxarenas; i < numarenas; ++i) { - arenas[i].address = 0; /* mark as unassociated */ - arenas[i].nextarena = i < numarenas - 1 ? - &arenas[i+1] : NULL; - } - - /* Update globals. */ - unused_arena_objects = &arenas[maxarenas]; - maxarenas = numarenas; - } - - /* Take the next available arena object off the head of the list. */ - assert(unused_arena_objects != NULL); - arenaobj = unused_arena_objects; - unused_arena_objects = arenaobj->nextarena; - assert(arenaobj->address == 0); - arenaobj->address = (uptr)malloc(ARENA_SIZE); - if (arenaobj->address == 0) { - /* The allocation failed: return NULL after putting the - * arenaobj back. - */ - arenaobj->nextarena = unused_arena_objects; - unused_arena_objects = arenaobj; - return NULL; - } - - ++narenas_currently_allocated; -#ifdef PYMALLOC_DEBUG - ++ntimes_arena_allocated; - if (narenas_currently_allocated > narenas_highwater) - narenas_highwater = narenas_currently_allocated; -#endif - arenaobj->freepools = NULL; - /* pool_address <- first pool-aligned address in the arena - nfreepools <- number of whole pools that fit after alignment */ - arenaobj->pool_address = (block*)arenaobj->address; - arenaobj->nfreepools = ARENA_SIZE / POOL_SIZE; - assert(POOL_SIZE * arenaobj->nfreepools == ARENA_SIZE); - excess = (uint)(arenaobj->address & POOL_SIZE_MASK); - if (excess != 0) { - --arenaobj->nfreepools; - arenaobj->pool_address += POOL_SIZE - excess; - } - arenaobj->ntotalpools = arenaobj->nfreepools; - - return arenaobj; -} - -/* -Py_ADDRESS_IN_RANGE(P, POOL) - -Return true if and only if P is an address that was allocated by pymalloc. -POOL must be the pool address associated with P, i.e., POOL = POOL_ADDR(P) -(the caller is asked to compute this because the macro expands POOL more than -once, and for efficiency it's best for the caller to assign POOL_ADDR(P) to a -variable and pass the latter to the macro; because Py_ADDRESS_IN_RANGE is -called on every alloc/realloc/free, micro-efficiency is important here). - -Tricky: Let B be the arena base address associated with the pool, B = -arenas[(POOL)->arenaindex].address. Then P belongs to the arena if and only if - - B <= P < B + ARENA_SIZE - -Subtracting B throughout, this is true iff - - 0 <= P-B < ARENA_SIZE - -By using unsigned arithmetic, the "0 <=" half of the test can be skipped. - -Obscure: A PyMem "free memory" function can call the pymalloc free or realloc -before the first arena has been allocated. `arenas` is still NULL in that -case. We're relying on that maxarenas is also 0 in that case, so that -(POOL)->arenaindex < maxarenas must be false, saving us from trying to index -into a NULL arenas. - -Details: given P and POOL, the arena_object corresponding to P is AO = -arenas[(POOL)->arenaindex]. Suppose obmalloc controls P. Then (barring wild -stores, etc), POOL is the correct address of P's pool, AO.address is the -correct base address of the pool's arena, and P must be within ARENA_SIZE of -AO.address. In addition, AO.address is not 0 (no arena can start at address 0 -(NULL)). Therefore Py_ADDRESS_IN_RANGE correctly reports that obmalloc -controls P. - -Now suppose obmalloc does not control P (e.g., P was obtained via a direct -call to the system malloc() or realloc()). (POOL)->arenaindex may be anything -in this case -- it may even be uninitialized trash. If the trash arenaindex -is >= maxarenas, the macro correctly concludes at once that obmalloc doesn't -control P. - -Else arenaindex is < maxarena, and AO is read up. If AO corresponds to an -allocated arena, obmalloc controls all the memory in slice AO.address : -AO.address+ARENA_SIZE. By case assumption, P is not controlled by obmalloc, -so P doesn't lie in that slice, so the macro correctly reports that P is not -controlled by obmalloc. - -Finally, if P is not controlled by obmalloc and AO corresponds to an unused -arena_object (one not currently associated with an allocated arena), -AO.address is 0, and the second test in the macro reduces to: - - P < ARENA_SIZE - -If P >= ARENA_SIZE (extremely likely), the macro again correctly concludes -that P is not controlled by obmalloc. However, if P < ARENA_SIZE, this part -of the test still passes, and the third clause (AO.address != 0) is necessary -to get the correct result: AO.address is 0 in this case, so the macro -correctly reports that P is not controlled by obmalloc (despite that P lies in -slice AO.address : AO.address + ARENA_SIZE). - -Note: The third (AO.address != 0) clause was added in Python 2.5. Before -2.5, arenas were never free()'ed, and an arenaindex < maxarena always -corresponded to a currently-allocated arena, so the "P is not controlled by -obmalloc, AO corresponds to an unused arena_object, and P < ARENA_SIZE" case -was impossible. - -Note that the logic is excruciating, and reading up possibly uninitialized -memory when P is not controlled by obmalloc (to get at (POOL)->arenaindex) -creates problems for some memory debuggers. The overwhelming advantage is -that this test determines whether an arbitrary address is controlled by -obmalloc in a small constant time, independent of the number of arenas -obmalloc controls. Since this test is needed at every entry point, it's -extremely desirable that it be this fast. -*/ -#define Py_ADDRESS_IN_RANGE(P, POOL) \ - ((POOL)->arenaindex < maxarenas && \ - (uptr)(P) - arenas[(POOL)->arenaindex].address < (uptr)ARENA_SIZE && \ - arenas[(POOL)->arenaindex].address != 0) - - -/* This is only useful when running memory debuggers such as - * Purify or Valgrind. Uncomment to use. - * -#define Py_USING_MEMORY_DEBUGGER - */ - -#ifdef Py_USING_MEMORY_DEBUGGER - -/* Py_ADDRESS_IN_RANGE may access uninitialized memory by design - * This leads to thousands of spurious warnings when using - * Purify or Valgrind. By making a function, we can easily - * suppress the uninitialized memory reads in this one function. - * So we won't ignore real errors elsewhere. - * - * Disable the macro and use a function. - */ - -#undef Py_ADDRESS_IN_RANGE - -#if defined(__GNUC__) && ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) || \ - (__GNUC__ >= 4)) -#define Py_NO_INLINE __attribute__((__noinline__)) -#else -#define Py_NO_INLINE -#endif - -/* Don't make static, to try to ensure this isn't inlined. */ -int Py_ADDRESS_IN_RANGE(void *P, poolp pool) Py_NO_INLINE; -#undef Py_NO_INLINE -#endif - -/*==========================================================================*/ - -/* malloc. Note that nbytes==0 tries to return a non-NULL pointer, distinct - * from all other currently live pointers. This may not be possible. - */ - -/* - * The basic blocks are ordered by decreasing execution frequency, - * which minimizes the number of jumps in the most common cases, - * improves branching prediction and instruction scheduling (small - * block allocations typically result in a couple of instructions). - * Unless the optimizer reorders everything, being too smart... - */ - -#undef PyObject_Malloc -void * -PyObject_Malloc(size_t nbytes) -{ - block *bp; - poolp pool; - poolp next; - uint size; - - /* - * This implicitly redirects malloc(0). - */ - if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) { - LOCK(); - /* - * Most frequent paths first - */ - size = (uint)(nbytes - 1) >> ALIGNMENT_SHIFT; - pool = usedpools[size + size]; - if (pool != pool->nextpool) { - /* - * There is a used pool for this size class. - * Pick up the head block of its free list. - */ - ++pool->ref.count; - bp = pool->freeblock; - assert(bp != NULL); - if ((pool->freeblock = *(block **)bp) != NULL) { - UNLOCK(); - return (void *)bp; - } - /* - * Reached the end of the free list, try to extend it. - */ - if (pool->nextoffset <= pool->maxnextoffset) { - /* There is room for another block. */ - pool->freeblock = (block*)pool + - pool->nextoffset; - pool->nextoffset += INDEX2SIZE(size); - *(block **)(pool->freeblock) = NULL; - UNLOCK(); - return (void *)bp; - } - /* Pool is full, unlink from used pools. */ - next = pool->nextpool; - pool = pool->prevpool; - next->prevpool = pool; - pool->nextpool = next; - UNLOCK(); - return (void *)bp; - } - - /* There isn't a pool of the right size class immediately - * available: use a free pool. - */ - if (usable_arenas == NULL) { - /* No arena has a free pool: allocate a new arena. */ -#ifdef WITH_MEMORY_LIMITS - if (narenas_currently_allocated >= MAX_ARENAS) { - UNLOCK(); - goto redirect; - } -#endif - usable_arenas = new_arena(); - if (usable_arenas == NULL) { - UNLOCK(); - goto redirect; - } - usable_arenas->nextarena = - usable_arenas->prevarena = NULL; - } - assert(usable_arenas->address != 0); - - /* Try to get a cached free pool. */ - pool = usable_arenas->freepools; - if (pool != NULL) { - /* Unlink from cached pools. */ - usable_arenas->freepools = pool->nextpool; - - /* This arena already had the smallest nfreepools - * value, so decreasing nfreepools doesn't change - * that, and we don't need to rearrange the - * usable_arenas list. However, if the arena has - * become wholly allocated, we need to remove its - * arena_object from usable_arenas. - */ - --usable_arenas->nfreepools; - if (usable_arenas->nfreepools == 0) { - /* Wholly allocated: remove. */ - assert(usable_arenas->freepools == NULL); - assert(usable_arenas->nextarena == NULL || - usable_arenas->nextarena->prevarena == - usable_arenas); - - usable_arenas = usable_arenas->nextarena; - if (usable_arenas != NULL) { - usable_arenas->prevarena = NULL; - assert(usable_arenas->address != 0); - } - } - else { - /* nfreepools > 0: it must be that freepools - * isn't NULL, or that we haven't yet carved - * off all the arena's pools for the first - * time. - */ - assert(usable_arenas->freepools != NULL || - usable_arenas->pool_address <= - (block*)usable_arenas->address + - ARENA_SIZE - POOL_SIZE); - } - init_pool: - /* Frontlink to used pools. */ - next = usedpools[size + size]; /* == prev */ - pool->nextpool = next; - pool->prevpool = next; - next->nextpool = pool; - next->prevpool = pool; - pool->ref.count = 1; - if (pool->szidx == size) { - /* Luckily, this pool last contained blocks - * of the same size class, so its header - * and free list are already initialized. - */ - bp = pool->freeblock; - pool->freeblock = *(block **)bp; - UNLOCK(); - return (void *)bp; - } - /* - * Initialize the pool header, set up the free list to - * contain just the second block, and return the first - * block. - */ - pool->szidx = size; - size = INDEX2SIZE(size); - bp = (block *)pool + POOL_OVERHEAD; - pool->nextoffset = POOL_OVERHEAD + (size << 1); - pool->maxnextoffset = POOL_SIZE - size; - pool->freeblock = bp + size; - *(block **)(pool->freeblock) = NULL; - UNLOCK(); - return (void *)bp; - } - - /* Carve off a new pool. */ - assert(usable_arenas->nfreepools > 0); - assert(usable_arenas->freepools == NULL); - pool = (poolp)usable_arenas->pool_address; - assert((block*)pool <= (block*)usable_arenas->address + - ARENA_SIZE - POOL_SIZE); - pool->arenaindex = usable_arenas - arenas; - assert(&arenas[pool->arenaindex] == usable_arenas); - pool->szidx = DUMMY_SIZE_IDX; - usable_arenas->pool_address += POOL_SIZE; - --usable_arenas->nfreepools; - - if (usable_arenas->nfreepools == 0) { - assert(usable_arenas->nextarena == NULL || - usable_arenas->nextarena->prevarena == - usable_arenas); - /* Unlink the arena: it is completely allocated. */ - usable_arenas = usable_arenas->nextarena; - if (usable_arenas != NULL) { - usable_arenas->prevarena = NULL; - assert(usable_arenas->address != 0); - } - } - - goto init_pool; - } - - /* The small block allocator ends here. */ - -redirect: - /* Redirect the original request to the underlying (libc) allocator. - * We jump here on bigger requests, on error in the code above (as a - * last chance to serve the request) or when the max memory limit - * has been reached. - */ - if (nbytes == 0) - nbytes = 1; - return (void *)malloc(nbytes); -} - -/* free */ - -#undef PyObject_Free -void -PyObject_Free(void *p) -{ - poolp pool; - block *lastfree; - poolp next, prev; - uint size; - - if (p == NULL) /* free(NULL) has no effect */ - return; - - pool = POOL_ADDR(p); - if (Py_ADDRESS_IN_RANGE(p, pool)) { - /* We allocated this address. */ - LOCK(); - /* Link p to the start of the pool's freeblock list. Since - * the pool had at least the p block outstanding, the pool - * wasn't empty (so it's already in a usedpools[] list, or - * was full and is in no list -- it's not in the freeblocks - * list in any case). - */ - assert(pool->ref.count > 0); /* else it was empty */ - *(block **)p = lastfree = pool->freeblock; - pool->freeblock = (block *)p; - if (lastfree) { - struct arena_object* ao; - uint nf; /* ao->nfreepools */ - - /* freeblock wasn't NULL, so the pool wasn't full, - * and the pool is in a usedpools[] list. - */ - if (--pool->ref.count != 0) { - /* pool isn't empty: leave it in usedpools */ - UNLOCK(); - return; - } - /* Pool is now empty: unlink from usedpools, and - * link to the front of freepools. This ensures that - * previously freed pools will be allocated later - * (being not referenced, they are perhaps paged out). - */ - next = pool->nextpool; - prev = pool->prevpool; - next->prevpool = prev; - prev->nextpool = next; - - /* Link the pool to freepools. This is a singly-linked - * list, and pool->prevpool isn't used there. - */ - ao = &arenas[pool->arenaindex]; - pool->nextpool = ao->freepools; - ao->freepools = pool; - nf = ++ao->nfreepools; - - /* All the rest is arena management. We just freed - * a pool, and there are 4 cases for arena mgmt: - * 1. If all the pools are free, return the arena to - * the system free(). - * 2. If this is the only free pool in the arena, - * add the arena back to the `usable_arenas` list. - * 3. If the "next" arena has a smaller count of free - * pools, we have to "slide this arena right" to - * restore that usable_arenas is sorted in order of - * nfreepools. - * 4. Else there's nothing more to do. - */ - if (nf == ao->ntotalpools) { - /* Case 1. First unlink ao from usable_arenas. - */ - assert(ao->prevarena == NULL || - ao->prevarena->address != 0); - assert(ao ->nextarena == NULL || - ao->nextarena->address != 0); - - /* Fix the pointer in the prevarena, or the - * usable_arenas pointer. - */ - if (ao->prevarena == NULL) { - usable_arenas = ao->nextarena; - assert(usable_arenas == NULL || - usable_arenas->address != 0); - } - else { - assert(ao->prevarena->nextarena == ao); - ao->prevarena->nextarena = - ao->nextarena; - } - /* Fix the pointer in the nextarena. */ - if (ao->nextarena != NULL) { - assert(ao->nextarena->prevarena == ao); - ao->nextarena->prevarena = - ao->prevarena; - } - /* Record that this arena_object slot is - * available to be reused. - */ - ao->nextarena = unused_arena_objects; - unused_arena_objects = ao; - - /* Free the entire arena. */ - free((void *)ao->address); - ao->address = 0; /* mark unassociated */ - --narenas_currently_allocated; - - UNLOCK(); - return; - } - if (nf == 1) { - /* Case 2. Put ao at the head of - * usable_arenas. Note that because - * ao->nfreepools was 0 before, ao isn't - * currently on the usable_arenas list. - */ - ao->nextarena = usable_arenas; - ao->prevarena = NULL; - if (usable_arenas) - usable_arenas->prevarena = ao; - usable_arenas = ao; - assert(usable_arenas->address != 0); - - UNLOCK(); - return; - } - /* If this arena is now out of order, we need to keep - * the list sorted. The list is kept sorted so that - * the "most full" arenas are used first, which allows - * the nearly empty arenas to be completely freed. In - * a few un-scientific tests, it seems like this - * approach allowed a lot more memory to be freed. - */ - if (ao->nextarena == NULL || - nf <= ao->nextarena->nfreepools) { - /* Case 4. Nothing to do. */ - UNLOCK(); - return; - } - /* Case 3: We have to move the arena towards the end - * of the list, because it has more free pools than - * the arena to its right. - * First unlink ao from usable_arenas. - */ - if (ao->prevarena != NULL) { - /* ao isn't at the head of the list */ - assert(ao->prevarena->nextarena == ao); - ao->prevarena->nextarena = ao->nextarena; - } - else { - /* ao is at the head of the list */ - assert(usable_arenas == ao); - usable_arenas = ao->nextarena; - } - ao->nextarena->prevarena = ao->prevarena; - - /* Locate the new insertion point by iterating over - * the list, using our nextarena pointer. - */ - while (ao->nextarena != NULL && - nf > ao->nextarena->nfreepools) { - ao->prevarena = ao->nextarena; - ao->nextarena = ao->nextarena->nextarena; - } - - /* Insert ao at this point. */ - assert(ao->nextarena == NULL || - ao->prevarena == ao->nextarena->prevarena); - assert(ao->prevarena->nextarena == ao->nextarena); - - ao->prevarena->nextarena = ao; - if (ao->nextarena != NULL) - ao->nextarena->prevarena = ao; - - /* Verify that the swaps worked. */ - assert(ao->nextarena == NULL || - nf <= ao->nextarena->nfreepools); - assert(ao->prevarena == NULL || - nf > ao->prevarena->nfreepools); - assert(ao->nextarena == NULL || - ao->nextarena->prevarena == ao); - assert((usable_arenas == ao && - ao->prevarena == NULL) || - ao->prevarena->nextarena == ao); - - UNLOCK(); - return; - } - /* Pool was full, so doesn't currently live in any list: - * link it to the front of the appropriate usedpools[] list. - * This mimics LRU pool usage for new allocations and - * targets optimal filling when several pools contain - * blocks of the same size class. - */ - --pool->ref.count; - assert(pool->ref.count > 0); /* else the pool is empty */ - size = pool->szidx; - next = usedpools[size + size]; - prev = next->prevpool; - /* insert pool before next: prev <-> pool <-> next */ - pool->nextpool = next; - pool->prevpool = prev; - next->prevpool = pool; - prev->nextpool = pool; - UNLOCK(); - return; - } - - /* We didn't allocate this address. */ - free(p); -} - -/* realloc. If p is NULL, this acts like malloc(nbytes). Else if nbytes==0, - * then as the Python docs promise, we do not treat this like free(p), and - * return a non-NULL result. - */ - -#undef PyObject_Realloc -void * -PyObject_Realloc(void *p, size_t nbytes) -{ - void *bp; - poolp pool; - size_t size; - - if (p == NULL) - return PyObject_Malloc(nbytes); - - pool = POOL_ADDR(p); - if (Py_ADDRESS_IN_RANGE(p, pool)) { - /* We're in charge of this block */ - size = INDEX2SIZE(pool->szidx); - if (nbytes <= size) { - /* The block is staying the same or shrinking. If - * it's shrinking, there's a tradeoff: it costs - * cycles to copy the block to a smaller size class, - * but it wastes memory not to copy it. The - * compromise here is to copy on shrink only if at - * least 25% of size can be shaved off. - */ - if (4 * nbytes > 3 * size) { - /* It's the same, - * or shrinking and new/old > 3/4. - */ - return p; - } - size = nbytes; - } - bp = PyObject_Malloc(nbytes); - if (bp != NULL) { - memcpy(bp, p, size); - PyObject_Free(p); - } - return bp; - } - /* We're not managing this block. If nbytes <= - * SMALL_REQUEST_THRESHOLD, it's tempting to try to take over this - * block. However, if we do, we need to copy the valid data from - * the C-managed block to one of our blocks, and there's no portable - * way to know how much of the memory space starting at p is valid. - * As bug 1185883 pointed out the hard way, it's possible that the - * C-managed block is "at the end" of allocated VM space, so that - * a memory fault can occur if we try to copy nbytes bytes starting - * at p. Instead we punt: let C continue to manage this block. - */ - if (nbytes) - return realloc(p, nbytes); - /* C doesn't define the result of realloc(p, 0) (it may or may not - * return NULL then), but Python's docs promise that nbytes==0 never - * returns NULL. We don't pass 0 to realloc(), to avoid that endcase - * to begin with. Even then, we can't be sure that realloc() won't - * return NULL. - */ - bp = realloc(p, 1); - return bp ? bp : p; -} - -#else /* ! WITH_PYMALLOC */ - -/*==========================================================================*/ -/* pymalloc not enabled: Redirect the entry points to malloc. These will - * only be used by extensions that are compiled with pymalloc enabled. */ - -void * -PyObject_Malloc(size_t n) -{ - return PyMem_MALLOC(n); -} - -void * -PyObject_Realloc(void *p, size_t n) -{ - return PyMem_REALLOC(p, n); -} - -void -PyObject_Free(void *p) -{ - PyMem_FREE(p); -} -#endif /* WITH_PYMALLOC */ - -#ifdef PYMALLOC_DEBUG -/*==========================================================================*/ -/* A x-platform debugging allocator. This doesn't manage memory directly, - * it wraps a real allocator, adding extra debugging info to the memory blocks. - */ - -/* Special bytes broadcast into debug memory blocks at appropriate times. - * Strings of these are unlikely to be valid addresses, floats, ints or - * 7-bit ASCII. - */ -#undef CLEANBYTE -#undef DEADBYTE -#undef FORBIDDENBYTE -#define CLEANBYTE 0xCB /* clean (newly allocated) memory */ -#define DEADBYTE 0xDB /* dead (newly freed) memory */ -#define FORBIDDENBYTE 0xFB /* untouchable bytes at each end of a block */ - -static size_t serialno = 0; /* incremented on each debug {m,re}alloc */ - -/* serialno is always incremented via calling this routine. The point is - * to supply a single place to set a breakpoint. - */ -static void -bumpserialno(void) -{ - ++serialno; -} - -#define SST SIZEOF_SIZE_T - -/* Read sizeof(size_t) bytes at p as a big-endian size_t. */ -static size_t -read_size_t(const void *p) -{ - const uchar *q = (const uchar *)p; - size_t result = *q++; - int i; - - for (i = SST; --i > 0; ++q) - result = (result << 8) | *q; - return result; -} - -/* Write n as a big-endian size_t, MSB at address p, LSB at - * p + sizeof(size_t) - 1. - */ -static void -write_size_t(void *p, size_t n) -{ - uchar *q = (uchar *)p + SST - 1; - int i; - - for (i = SST; --i >= 0; --q) { - *q = (uchar)(n & 0xff); - n >>= 8; - } -} - -#ifdef Py_DEBUG -/* Is target in the list? The list is traversed via the nextpool pointers. - * The list may be NULL-terminated, or circular. Return 1 if target is in - * list, else 0. - */ -static int -pool_is_in_list(const poolp target, poolp list) -{ - poolp origlist = list; - assert(target != NULL); - if (list == NULL) - return 0; - do { - if (target == list) - return 1; - list = list->nextpool; - } while (list != NULL && list != origlist); - return 0; -} - -#else -#define pool_is_in_list(X, Y) 1 - -#endif /* Py_DEBUG */ - -/* Let S = sizeof(size_t). The debug malloc asks for 4*S extra bytes and - fills them with useful stuff, here calling the underlying malloc's result p: - -p[0: S] - Number of bytes originally asked for. This is a size_t, big-endian (easier - to read in a memory dump). -p[S: 2*S] - Copies of FORBIDDENBYTE. Used to catch under- writes and reads. -p[2*S: 2*S+n] - The requested memory, filled with copies of CLEANBYTE. - Used to catch reference to uninitialized memory. - &p[2*S] is returned. Note that this is 8-byte aligned if pymalloc - handled the request itself. -p[2*S+n: 2*S+n+S] - Copies of FORBIDDENBYTE. Used to catch over- writes and reads. -p[2*S+n+S: 2*S+n+2*S] - A serial number, incremented by 1 on each call to _PyObject_DebugMalloc - and _PyObject_DebugRealloc. - This is a big-endian size_t. - If "bad memory" is detected later, the serial number gives an - excellent way to set a breakpoint on the next run, to capture the - instant at which this block was passed out. -*/ - -void * -_PyObject_DebugMalloc(size_t nbytes) -{ - uchar *p; /* base address of malloc'ed block */ - uchar *tail; /* p + 2*SST + nbytes == pointer to tail pad bytes */ - size_t total; /* nbytes + 4*SST */ - - bumpserialno(); - total = nbytes + 4*SST; - if (total < nbytes) - /* overflow: can't represent total as a size_t */ - return NULL; - - p = (uchar *)PyObject_Malloc(total); - if (p == NULL) - return NULL; - - write_size_t(p, nbytes); - memset(p + SST, FORBIDDENBYTE, SST); - - if (nbytes > 0) - memset(p + 2*SST, CLEANBYTE, nbytes); - - tail = p + 2*SST + nbytes; - memset(tail, FORBIDDENBYTE, SST); - write_size_t(tail + SST, serialno); - - return p + 2*SST; -} - -/* The debug free first checks the 2*SST bytes on each end for sanity (in - particular, that the FORBIDDENBYTEs are still intact). - Then fills the original bytes with DEADBYTE. - Then calls the underlying free. -*/ -void -_PyObject_DebugFree(void *p) -{ - uchar *q = (uchar *)p - 2*SST; /* address returned from malloc */ - size_t nbytes; - - if (p == NULL) - return; - _PyObject_DebugCheckAddress(p); - nbytes = read_size_t(q); - if (nbytes > 0) - memset(q, DEADBYTE, nbytes); - PyObject_Free(q); -} - -void * -_PyObject_DebugRealloc(void *p, size_t nbytes) -{ - uchar *q = (uchar *)p; - uchar *tail; - size_t total; /* nbytes + 4*SST */ - size_t original_nbytes; - int i; - - if (p == NULL) - return _PyObject_DebugMalloc(nbytes); - - _PyObject_DebugCheckAddress(p); - bumpserialno(); - original_nbytes = read_size_t(q - 2*SST); - total = nbytes + 4*SST; - if (total < nbytes) - /* overflow: can't represent total as a size_t */ - return NULL; - - if (nbytes < original_nbytes) { - /* shrinking: mark old extra memory dead */ - memset(q + nbytes, DEADBYTE, original_nbytes - nbytes); - } - - /* Resize and add decorations. */ - q = (uchar *)PyObject_Realloc(q - 2*SST, total); - if (q == NULL) - return NULL; - - write_size_t(q, nbytes); - for (i = 0; i < SST; ++i) - assert(q[SST + i] == FORBIDDENBYTE); - q += 2*SST; - tail = q + nbytes; - memset(tail, FORBIDDENBYTE, SST); - write_size_t(tail + SST, serialno); - - if (nbytes > original_nbytes) { - /* growing: mark new extra memory clean */ - memset(q + original_nbytes, CLEANBYTE, - nbytes - original_nbytes); - } - - return q; -} - -/* Check the forbidden bytes on both ends of the memory allocated for p. - * If anything is wrong, print info to stderr via _PyObject_DebugDumpAddress, - * and call Py_FatalError to kill the program. - */ - void -_PyObject_DebugCheckAddress(const void *p) -{ - const uchar *q = (const uchar *)p; - char *msg; - size_t nbytes; - const uchar *tail; - int i; - - if (p == NULL) { - msg = "didn't expect a NULL pointer"; - goto error; - } - - /* Check the stuff at the start of p first: if there's underwrite - * corruption, the number-of-bytes field may be nuts, and checking - * the tail could lead to a segfault then. - */ - for (i = SST; i >= 1; --i) { - if (*(q-i) != FORBIDDENBYTE) { - msg = "bad leading pad byte"; - goto error; - } - } - - nbytes = read_size_t(q - 2*SST); - tail = q + nbytes; - for (i = 0; i < SST; ++i) { - if (tail[i] != FORBIDDENBYTE) { - msg = "bad trailing pad byte"; - goto error; - } - } - - return; - -error: - _PyObject_DebugDumpAddress(p); - Py_FatalError(msg); -} - -/* Display info to stderr about the memory block at p. */ -void -_PyObject_DebugDumpAddress(const void *p) -{ - const uchar *q = (const uchar *)p; - const uchar *tail; - size_t nbytes, serial; - int i; - int ok; - - fprintf(stderr, "Debug memory block at address p=%p:\n", p); - if (p == NULL) - return; - - nbytes = read_size_t(q - 2*SST); - fprintf(stderr, " %" PY_FORMAT_SIZE_T "u bytes originally " - "requested\n", nbytes); - - /* In case this is nuts, check the leading pad bytes first. */ - fprintf(stderr, " The %d pad bytes at p-%d are ", SST, SST); - ok = 1; - for (i = 1; i <= SST; ++i) { - if (*(q-i) != FORBIDDENBYTE) { - ok = 0; - break; - } - } - if (ok) - fputs("FORBIDDENBYTE, as expected.\n", stderr); - else { - fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", - FORBIDDENBYTE); - for (i = SST; i >= 1; --i) { - const uchar byte = *(q-i); - fprintf(stderr, " at p-%d: 0x%02x", i, byte); - if (byte != FORBIDDENBYTE) - fputs(" *** OUCH", stderr); - fputc('\n', stderr); - } - - fputs(" Because memory is corrupted at the start, the " - "count of bytes requested\n" - " may be bogus, and checking the trailing pad " - "bytes may segfault.\n", stderr); - } - - tail = q + nbytes; - fprintf(stderr, " The %d pad bytes at tail=%p are ", SST, tail); - ok = 1; - for (i = 0; i < SST; ++i) { - if (tail[i] != FORBIDDENBYTE) { - ok = 0; - break; - } - } - if (ok) - fputs("FORBIDDENBYTE, as expected.\n", stderr); - else { - fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", - FORBIDDENBYTE); - for (i = 0; i < SST; ++i) { - const uchar byte = tail[i]; - fprintf(stderr, " at tail+%d: 0x%02x", - i, byte); - if (byte != FORBIDDENBYTE) - fputs(" *** OUCH", stderr); - fputc('\n', stderr); - } - } - - serial = read_size_t(tail + SST); - fprintf(stderr, " The block was made by call #%" PY_FORMAT_SIZE_T - "u to debug malloc/realloc.\n", serial); - - if (nbytes > 0) { - i = 0; - fputs(" Data at p:", stderr); - /* print up to 8 bytes at the start */ - while (q < tail && i < 8) { - fprintf(stderr, " %02x", *q); - ++i; - ++q; - } - /* and up to 8 at the end */ - if (q < tail) { - if (tail - q > 8) { - fputs(" ...", stderr); - q = tail - 8; - } - while (q < tail) { - fprintf(stderr, " %02x", *q); - ++q; - } - } - fputc('\n', stderr); - } -} - -static size_t -printone(const char* msg, size_t value) -{ - int i, k; - char buf[100]; - size_t origvalue = value; - - fputs(msg, stderr); - for (i = (int)strlen(msg); i < 35; ++i) - fputc(' ', stderr); - fputc('=', stderr); - - /* Write the value with commas. */ - i = 22; - buf[i--] = '\0'; - buf[i--] = '\n'; - k = 3; - do { - size_t nextvalue = value / 10; - uint digit = (uint)(value - nextvalue * 10); - value = nextvalue; - buf[i--] = (char)(digit + '0'); - --k; - if (k == 0 && value && i >= 0) { - k = 3; - buf[i--] = ','; - } - } while (value && i >= 0); - - while (i >= 0) - buf[i--] = ' '; - fputs(buf, stderr); - - return origvalue; -} - -/* Print summary info to stderr about the state of pymalloc's structures. - * In Py_DEBUG mode, also perform some expensive internal consistency - * checks. - */ -void -_PyObject_DebugMallocStats(void) -{ - uint i; - const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT; - /* # of pools, allocated blocks, and free blocks per class index */ - size_t numpools[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; - size_t numblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; - size_t numfreeblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; - /* total # of allocated bytes in used and full pools */ - size_t allocated_bytes = 0; - /* total # of available bytes in used pools */ - size_t available_bytes = 0; - /* # of free pools + pools not yet carved out of current arena */ - uint numfreepools = 0; - /* # of bytes for arena alignment padding */ - size_t arena_alignment = 0; - /* # of bytes in used and full pools used for pool_headers */ - size_t pool_header_bytes = 0; - /* # of bytes in used and full pools wasted due to quantization, - * i.e. the necessarily leftover space at the ends of used and - * full pools. - */ - size_t quantization = 0; - /* # of arenas actually allocated. */ - size_t narenas = 0; - /* running total -- should equal narenas * ARENA_SIZE */ - size_t total; - char buf[128]; - - fprintf(stderr, "Small block threshold = %d, in %u size classes.\n", - SMALL_REQUEST_THRESHOLD, numclasses); - - for (i = 0; i < numclasses; ++i) - numpools[i] = numblocks[i] = numfreeblocks[i] = 0; - - /* Because full pools aren't linked to from anything, it's easiest - * to march over all the arenas. If we're lucky, most of the memory - * will be living in full pools -- would be a shame to miss them. - */ - for (i = 0; i < maxarenas; ++i) { - uint poolsinarena; - uint j; - uptr base = arenas[i].address; - - /* Skip arenas which are not allocated. */ - if (arenas[i].address == (uptr)NULL) - continue; - narenas += 1; - - poolsinarena = arenas[i].ntotalpools; - numfreepools += arenas[i].nfreepools; - - /* round up to pool alignment */ - if (base & (uptr)POOL_SIZE_MASK) { - arena_alignment += POOL_SIZE; - base &= ~(uptr)POOL_SIZE_MASK; - base += POOL_SIZE; - } - - /* visit every pool in the arena */ - assert(base <= (uptr) arenas[i].pool_address); - for (j = 0; - base < (uptr) arenas[i].pool_address; - ++j, base += POOL_SIZE) { - poolp p = (poolp)base; - const uint sz = p->szidx; - uint freeblocks; - - if (p->ref.count == 0) { - /* currently unused */ - assert(pool_is_in_list(p, arenas[i].freepools)); - continue; - } - ++numpools[sz]; - numblocks[sz] += p->ref.count; - freeblocks = NUMBLOCKS(sz) - p->ref.count; - numfreeblocks[sz] += freeblocks; -#ifdef Py_DEBUG - if (freeblocks > 0) - assert(pool_is_in_list(p, usedpools[sz + sz])); -#endif - } - } - assert(narenas == narenas_currently_allocated); - - fputc('\n', stderr); - fputs("class size num pools blocks in use avail blocks\n" - "----- ---- --------- ------------- ------------\n", - stderr); - - for (i = 0; i < numclasses; ++i) { - size_t p = numpools[i]; - size_t b = numblocks[i]; - size_t f = numfreeblocks[i]; - uint size = INDEX2SIZE(i); - if (p == 0) { - assert(b == 0 && f == 0); - continue; - } - fprintf(stderr, "%5u %6u " - "%11" PY_FORMAT_SIZE_T "u " - "%15" PY_FORMAT_SIZE_T "u " - "%13" PY_FORMAT_SIZE_T "u\n", - i, size, p, b, f); - allocated_bytes += b * size; - available_bytes += f * size; - pool_header_bytes += p * POOL_OVERHEAD; - quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size); - } - fputc('\n', stderr); - (void)printone("# times object malloc called", serialno); - - (void)printone("# arenas allocated total", ntimes_arena_allocated); - (void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas); - (void)printone("# arenas highwater mark", narenas_highwater); - (void)printone("# arenas allocated current", narenas); - - PyOS_snprintf(buf, sizeof(buf), - "%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena", - narenas, ARENA_SIZE); - (void)printone(buf, narenas * ARENA_SIZE); - - fputc('\n', stderr); - - total = printone("# bytes in allocated blocks", allocated_bytes); - total += printone("# bytes in available blocks", available_bytes); - - PyOS_snprintf(buf, sizeof(buf), - "%u unused pools * %d bytes", numfreepools, POOL_SIZE); - total += printone(buf, (size_t)numfreepools * POOL_SIZE); - - total += printone("# bytes lost to pool headers", pool_header_bytes); - total += printone("# bytes lost to quantization", quantization); - total += printone("# bytes lost to arena alignment", arena_alignment); - (void)printone("Total", total); -} - -#endif /* PYMALLOC_DEBUG */ - -#ifdef Py_USING_MEMORY_DEBUGGER -/* Make this function last so gcc won't inline it since the definition is - * after the reference. - */ -int -Py_ADDRESS_IN_RANGE(void *P, poolp pool) -{ - return pool->arenaindex < maxarenas && - (uptr)P - arenas[pool->arenaindex].address < (uptr)ARENA_SIZE && - arenas[pool->arenaindex].address != 0; -} -#endif diff --git a/sys/src/cmd/python/Objects/rangeobject.c b/sys/src/cmd/python/Objects/rangeobject.c deleted file mode 100644 index c48bee016..000000000 --- a/sys/src/cmd/python/Objects/rangeobject.c +++ /dev/null @@ -1,301 +0,0 @@ -/* Range object implementation */ - -#include "Python.h" - -typedef struct { - PyObject_HEAD - long start; - long step; - long len; -} rangeobject; - -/* Return number of items in range/xrange (lo, hi, step). step > 0 - * required. Return a value < 0 if & only if the true value is too - * large to fit in a signed long. - */ -static long -get_len_of_range(long lo, long hi, long step) -{ - /* ------------------------------------------------------------- - If lo >= hi, the range is empty. - Else if n values are in the range, the last one is - lo + (n-1)*step, which must be <= hi-1. Rearranging, - n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives - the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so - the RHS is non-negative and so truncation is the same as the - floor. Letting M be the largest positive long, the worst case - for the RHS numerator is hi=M, lo=-M-1, and then - hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough - precision to compute the RHS exactly. - ---------------------------------------------------------------*/ - long n = 0; - if (lo < hi) { - unsigned long uhi = (unsigned long)hi; - unsigned long ulo = (unsigned long)lo; - unsigned long diff = uhi - ulo - 1; - n = (long)(diff / (unsigned long)step + 1); - } - return n; -} - -static PyObject * -range_new(PyTypeObject *type, PyObject *args, PyObject *kw) -{ - rangeobject *obj; - long ilow = 0, ihigh = 0, istep = 1; - long n; - - if (!_PyArg_NoKeywords("xrange()", kw)) - return NULL; - - if (PyTuple_Size(args) <= 1) { - if (!PyArg_ParseTuple(args, - "l;xrange() requires 1-3 int arguments", - &ihigh)) - return NULL; - } - else { - if (!PyArg_ParseTuple(args, - "ll|l;xrange() requires 1-3 int arguments", - &ilow, &ihigh, &istep)) - return NULL; - } - if (istep == 0) { - PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero"); - return NULL; - } - if (istep > 0) - n = get_len_of_range(ilow, ihigh, istep); - else - n = get_len_of_range(ihigh, ilow, -istep); - if (n < 0) { - PyErr_SetString(PyExc_OverflowError, - "xrange() result has too many items"); - return NULL; - } - - obj = PyObject_New(rangeobject, &PyRange_Type); - if (obj == NULL) - return NULL; - obj->start = ilow; - obj->len = n; - obj->step = istep; - return (PyObject *) obj; -} - -PyDoc_STRVAR(range_doc, -"xrange([start,] stop[, step]) -> xrange object\n\ -\n\ -Like range(), but instead of returning a list, returns an object that\n\ -generates the numbers in the range on demand. For looping, this is \n\ -slightly faster than range() and more memory efficient."); - -static PyObject * -range_item(rangeobject *r, Py_ssize_t i) -{ - if (i < 0 || i >= r->len) { - PyErr_SetString(PyExc_IndexError, - "xrange object index out of range"); - return NULL; - } - return PyInt_FromSsize_t(r->start + (i % r->len) * r->step); -} - -static Py_ssize_t -range_length(rangeobject *r) -{ - return (Py_ssize_t)(r->len); -} - -static PyObject * -range_repr(rangeobject *r) -{ - PyObject *rtn; - - if (r->start == 0 && r->step == 1) - rtn = PyString_FromFormat("xrange(%ld)", - r->start + r->len * r->step); - - else if (r->step == 1) - rtn = PyString_FromFormat("xrange(%ld, %ld)", - r->start, - r->start + r->len * r->step); - - else - rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)", - r->start, - r->start + r->len * r->step, - r->step); - return rtn; -} - -static PySequenceMethods range_as_sequence = { - (lenfunc)range_length, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)range_item, /* sq_item */ - 0, /* sq_slice */ -}; - -static PyObject * range_iter(PyObject *seq); -static PyObject * range_reverse(PyObject *seq); - -PyDoc_STRVAR(reverse_doc, -"Returns a reverse iterator."); - -static PyMethodDef range_methods[] = { - {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc}, - {NULL, NULL} /* sentinel */ -}; - -PyTypeObject PyRange_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* Number of items for varobject */ - "xrange", /* Name of this type */ - sizeof(rangeobject), /* Basic object size */ - 0, /* Item size for varobject */ - (destructor)PyObject_Del, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)range_repr, /* tp_repr */ - 0, /* tp_as_number */ - &range_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - range_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - range_iter, /* tp_iter */ - 0, /* tp_iternext */ - range_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - range_new, /* tp_new */ -}; - -/*********************** Xrange Iterator **************************/ - -typedef struct { - PyObject_HEAD - long index; - long start; - long step; - long len; -} rangeiterobject; - -static PyObject * -rangeiter_next(rangeiterobject *r) -{ - if (r->index < r->len) - return PyInt_FromLong(r->start + (r->index++) * r->step); - return NULL; -} - -static PyObject * -rangeiter_len(rangeiterobject *r) -{ - return PyInt_FromLong(r->len - r->index); -} - -PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - -static PyMethodDef rangeiter_methods[] = { - {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, length_hint_doc}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject Pyrangeiter_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "rangeiterator", /* tp_name */ - sizeof(rangeiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)PyObject_Del, /* 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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)rangeiter_next, /* tp_iternext */ - rangeiter_methods, /* tp_methods */ - 0, -}; - -static PyObject * -range_iter(PyObject *seq) -{ - rangeiterobject *it; - - if (!PyRange_Check(seq)) { - PyErr_BadInternalCall(); - return NULL; - } - it = PyObject_New(rangeiterobject, &Pyrangeiter_Type); - if (it == NULL) - return NULL; - it->index = 0; - it->start = ((rangeobject *)seq)->start; - it->step = ((rangeobject *)seq)->step; - it->len = ((rangeobject *)seq)->len; - return (PyObject *)it; -} - -static PyObject * -range_reverse(PyObject *seq) -{ - rangeiterobject *it; - long start, step, len; - - if (!PyRange_Check(seq)) { - PyErr_BadInternalCall(); - return NULL; - } - it = PyObject_New(rangeiterobject, &Pyrangeiter_Type); - if (it == NULL) - return NULL; - - start = ((rangeobject *)seq)->start; - step = ((rangeobject *)seq)->step; - len = ((rangeobject *)seq)->len; - - it->index = 0; - it->start = start + (len-1) * step; - it->step = -step; - it->len = len; - - return (PyObject *)it; -} diff --git a/sys/src/cmd/python/Objects/setobject.c b/sys/src/cmd/python/Objects/setobject.c deleted file mode 100644 index b336fba7a..000000000 --- a/sys/src/cmd/python/Objects/setobject.c +++ /dev/null @@ -1,2312 +0,0 @@ - -/* set object implementation - Written and maintained by Raymond D. Hettinger <python@rcn.com> - Derived from Lib/sets.py and Objects/dictobject.c. - - Copyright (c) 2003-6 Python Software Foundation. - All rights reserved. -*/ - -#include "Python.h" -#include "structmember.h" - -/* Set a key error with the specified argument, wrapping it in a - * tuple automatically so that tuple keys are not unpacked as the - * exception arguments. */ -static void -set_key_error(PyObject *arg) -{ - PyObject *tup; - tup = PyTuple_Pack(1, arg); - if (!tup) - return; /* caller will expect error to be set anyway */ - PyErr_SetObject(PyExc_KeyError, tup); - Py_DECREF(tup); -} - -/* This must be >= 1. */ -#define PERTURB_SHIFT 5 - -/* Object used as dummy key to fill deleted entries */ -static PyObject *dummy = NULL; /* Initialized by first call to make_new_set() */ - -#ifdef Py_REF_DEBUG -PyObject * -_PySet_Dummy(void) -{ - return dummy; -} -#endif - -#define INIT_NONZERO_SET_SLOTS(so) do { \ - (so)->table = (so)->smalltable; \ - (so)->mask = PySet_MINSIZE - 1; \ - (so)->hash = -1; \ - } while(0) - -#define EMPTY_TO_MINSIZE(so) do { \ - memset((so)->smalltable, 0, sizeof((so)->smalltable)); \ - (so)->used = (so)->fill = 0; \ - INIT_NONZERO_SET_SLOTS(so); \ - } while(0) - -/* Reuse scheme to save calls to malloc, free, and memset */ -#define MAXFREESETS 80 -static PySetObject *free_sets[MAXFREESETS]; -static int num_free_sets = 0; - -/* -The basic lookup function used by all operations. -This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4. -Open addressing is preferred over chaining since the link overhead for -chaining would be substantial (100% with typical malloc overhead). - -The initial probe index is computed as hash mod the table size. Subsequent -probe indices are computed as explained in Objects/dictobject.c. - -All arithmetic on hash should ignore overflow. - -Unlike the dictionary implementation, the lookkey functions can return -NULL if the rich comparison returns an error. -*/ - -static setentry * -set_lookkey(PySetObject *so, PyObject *key, register long hash) -{ - register Py_ssize_t i; - register size_t perturb; - register setentry *freeslot; - register size_t mask = so->mask; - setentry *table = so->table; - register setentry *entry; - register int cmp; - PyObject *startkey; - - i = hash & mask; - entry = &table[i]; - if (entry->key == NULL || entry->key == key) - return entry; - - if (entry->key == dummy) - freeslot = entry; - else { - if (entry->hash == hash) { - startkey = entry->key; - cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); - if (cmp < 0) - return NULL; - if (table == so->table && entry->key == startkey) { - if (cmp > 0) - return entry; - } - else { - /* The compare did major nasty stuff to the - * set: start over. - */ - return set_lookkey(so, key, hash); - } - } - freeslot = NULL; - } - - /* In the loop, key == dummy is by far (factor of 100s) the - least likely outcome, so test for that last. */ - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - entry = &table[i & mask]; - if (entry->key == NULL) { - if (freeslot != NULL) - entry = freeslot; - break; - } - if (entry->key == key) - break; - if (entry->hash == hash && entry->key != dummy) { - startkey = entry->key; - cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); - if (cmp < 0) - return NULL; - if (table == so->table && entry->key == startkey) { - if (cmp > 0) - break; - } - else { - /* The compare did major nasty stuff to the - * set: start over. - */ - return set_lookkey(so, key, hash); - } - } - else if (entry->key == dummy && freeslot == NULL) - freeslot = entry; - } - return entry; -} - -/* - * Hacked up version of set_lookkey which can assume keys are always strings; - * This means we can always use _PyString_Eq directly and not have to check to - * see if the comparison altered the table. - */ -static setentry * -set_lookkey_string(PySetObject *so, PyObject *key, register long hash) -{ - register Py_ssize_t i; - register size_t perturb; - register setentry *freeslot; - register size_t mask = so->mask; - setentry *table = so->table; - register setentry *entry; - - /* Make sure this function doesn't have to handle non-string keys, - including subclasses of str; e.g., one reason to subclass - strings is to override __eq__, and for speed we don't cater to - that here. */ - if (!PyString_CheckExact(key)) { - so->lookup = set_lookkey; - return set_lookkey(so, key, hash); - } - i = hash & mask; - entry = &table[i]; - if (entry->key == NULL || entry->key == key) - return entry; - if (entry->key == dummy) - freeslot = entry; - else { - if (entry->hash == hash && _PyString_Eq(entry->key, key)) - return entry; - freeslot = NULL; - } - - /* In the loop, key == dummy is by far (factor of 100s) the - least likely outcome, so test for that last. */ - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - entry = &table[i & mask]; - if (entry->key == NULL) - return freeslot == NULL ? entry : freeslot; - if (entry->key == key - || (entry->hash == hash - && entry->key != dummy - && _PyString_Eq(entry->key, key))) - return entry; - if (entry->key == dummy && freeslot == NULL) - freeslot = entry; - } - assert(0); /* NOT REACHED */ - return 0; -} - -/* -Internal routine to insert a new key into the table. -Used by the public insert routine. -Eats a reference to key. -*/ -static int -set_insert_key(register PySetObject *so, PyObject *key, long hash) -{ - register setentry *entry; - typedef setentry *(*lookupfunc)(PySetObject *, PyObject *, long); - - assert(so->lookup != NULL); - entry = so->lookup(so, key, hash); - if (entry == NULL) - return -1; - if (entry->key == NULL) { - /* UNUSED */ - so->fill++; - entry->key = key; - entry->hash = hash; - so->used++; - } else if (entry->key == dummy) { - /* DUMMY */ - entry->key = key; - entry->hash = hash; - so->used++; - Py_DECREF(dummy); - } else { - /* ACTIVE */ - Py_DECREF(key); - } - return 0; -} - -/* -Internal routine used by set_table_resize() to insert an item which is -known to be absent from the set. This routine also assumes that -the set contains no deleted entries. Besides the performance benefit, -using set_insert_clean() in set_table_resize() is dangerous (SF bug #1456209). -Note that no refcounts are changed by this routine; if needed, the caller -is responsible for incref'ing `key`. -*/ -static void -set_insert_clean(register PySetObject *so, PyObject *key, long hash) -{ - register size_t i; - register size_t perturb; - register size_t mask = (size_t)so->mask; - setentry *table = so->table; - register setentry *entry; - - i = hash & mask; - entry = &table[i]; - for (perturb = hash; entry->key != NULL; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - entry = &table[i & mask]; - } - so->fill++; - entry->key = key; - entry->hash = hash; - so->used++; -} - -/* -Restructure the table by allocating a new table and reinserting all -keys again. When entries have been deleted, the new table may -actually be smaller than the old one. -*/ -static int -set_table_resize(PySetObject *so, Py_ssize_t minused) -{ - Py_ssize_t newsize; - setentry *oldtable, *newtable, *entry; - Py_ssize_t i; - int is_oldtable_malloced; - setentry small_copy[PySet_MINSIZE]; - - assert(minused >= 0); - - /* Find the smallest table size > minused. */ - for (newsize = PySet_MINSIZE; - newsize <= minused && newsize > 0; - newsize <<= 1) - ; - if (newsize <= 0) { - PyErr_NoMemory(); - return -1; - } - - /* Get space for a new table. */ - oldtable = so->table; - assert(oldtable != NULL); - is_oldtable_malloced = oldtable != so->smalltable; - - if (newsize == PySet_MINSIZE) { - /* A large table is shrinking, or we can't get any smaller. */ - newtable = so->smalltable; - if (newtable == oldtable) { - if (so->fill == so->used) { - /* No dummies, so no point doing anything. */ - return 0; - } - /* We're not going to resize it, but rebuild the - table anyway to purge old dummy entries. - Subtle: This is *necessary* if fill==size, - as set_lookkey needs at least one virgin slot to - terminate failing searches. If fill < size, it's - merely desirable, as dummies slow searches. */ - assert(so->fill > so->used); - memcpy(small_copy, oldtable, sizeof(small_copy)); - oldtable = small_copy; - } - } - else { - newtable = PyMem_NEW(setentry, newsize); - if (newtable == NULL) { - PyErr_NoMemory(); - return -1; - } - } - - /* Make the set empty, using the new table. */ - assert(newtable != oldtable); - so->table = newtable; - so->mask = newsize - 1; - memset(newtable, 0, sizeof(setentry) * newsize); - so->used = 0; - i = so->fill; - so->fill = 0; - - /* Copy the data over; this is refcount-neutral for active entries; - dummy entries aren't copied over, of course */ - for (entry = oldtable; i > 0; entry++) { - if (entry->key == NULL) { - /* UNUSED */ - ; - } else if (entry->key == dummy) { - /* DUMMY */ - --i; - assert(entry->key == dummy); - Py_DECREF(entry->key); - } else { - /* ACTIVE */ - --i; - set_insert_clean(so, entry->key, entry->hash); - } - } - - if (is_oldtable_malloced) - PyMem_DEL(oldtable); - return 0; -} - -/* CAUTION: set_add_key/entry() must guarantee it won't resize the table */ - -static int -set_add_entry(register PySetObject *so, setentry *entry) -{ - register Py_ssize_t n_used; - - assert(so->fill <= so->mask); /* at least one empty slot */ - n_used = so->used; - Py_INCREF(entry->key); - if (set_insert_key(so, entry->key, entry->hash) == -1) { - Py_DECREF(entry->key); - return -1; - } - if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2)) - return 0; - return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); -} - -static int -set_add_key(register PySetObject *so, PyObject *key) -{ - register long hash; - register Py_ssize_t n_used; - - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return -1; - } - assert(so->fill <= so->mask); /* at least one empty slot */ - n_used = so->used; - Py_INCREF(key); - if (set_insert_key(so, key, hash) == -1) { - Py_DECREF(key); - return -1; - } - if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2)) - return 0; - return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); -} - -#define DISCARD_NOTFOUND 0 -#define DISCARD_FOUND 1 - -static int -set_discard_entry(PySetObject *so, setentry *oldentry) -{ register setentry *entry; - PyObject *old_key; - - entry = (so->lookup)(so, oldentry->key, oldentry->hash); - if (entry == NULL) - return -1; - if (entry->key == NULL || entry->key == dummy) - return DISCARD_NOTFOUND; - old_key = entry->key; - Py_INCREF(dummy); - entry->key = dummy; - so->used--; - Py_DECREF(old_key); - return DISCARD_FOUND; -} - -static int -set_discard_key(PySetObject *so, PyObject *key) -{ - register long hash; - register setentry *entry; - PyObject *old_key; - - assert (PyAnySet_Check(so)); - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return -1; - } - entry = (so->lookup)(so, key, hash); - if (entry == NULL) - return -1; - if (entry->key == NULL || entry->key == dummy) - return DISCARD_NOTFOUND; - old_key = entry->key; - Py_INCREF(dummy); - entry->key = dummy; - so->used--; - Py_DECREF(old_key); - return DISCARD_FOUND; -} - -static int -set_clear_internal(PySetObject *so) -{ - setentry *entry, *table; - int table_is_malloced; - Py_ssize_t fill; - setentry small_copy[PySet_MINSIZE]; -#ifdef Py_DEBUG - Py_ssize_t i, n; - assert (PyAnySet_Check(so)); - - n = so->mask + 1; - i = 0; -#endif - - table = so->table; - assert(table != NULL); - table_is_malloced = table != so->smalltable; - - /* This is delicate. During the process of clearing the set, - * decrefs can cause the set to mutate. To avoid fatal confusion - * (voice of experience), we have to make the set empty before - * clearing the slots, and never refer to anything via so->ref while - * clearing. - */ - fill = so->fill; - if (table_is_malloced) - EMPTY_TO_MINSIZE(so); - - else if (fill > 0) { - /* It's a small table with something that needs to be cleared. - * Afraid the only safe way is to copy the set entries into - * another small table first. - */ - memcpy(small_copy, table, sizeof(small_copy)); - table = small_copy; - EMPTY_TO_MINSIZE(so); - } - /* else it's a small table that's already empty */ - - /* Now we can finally clear things. If C had refcounts, we could - * assert that the refcount on table is 1 now, i.e. that this function - * has unique access to it, so decref side-effects can't alter it. - */ - for (entry = table; fill > 0; ++entry) { -#ifdef Py_DEBUG - assert(i < n); - ++i; -#endif - if (entry->key) { - --fill; - Py_DECREF(entry->key); - } -#ifdef Py_DEBUG - else - assert(entry->key == NULL); -#endif - } - - if (table_is_malloced) - PyMem_DEL(table); - return 0; -} - -/* - * Iterate over a set table. Use like so: - * - * Py_ssize_t pos; - * setentry *entry; - * pos = 0; # important! pos should not otherwise be changed by you - * while (set_next(yourset, &pos, &entry)) { - * Refer to borrowed reference in entry->key. - * } - * - * CAUTION: In general, it isn't safe to use set_next in a loop that - * mutates the table. - */ -static int -set_next(PySetObject *so, Py_ssize_t *pos_ptr, setentry **entry_ptr) -{ - Py_ssize_t i; - Py_ssize_t mask; - register setentry *table; - - assert (PyAnySet_Check(so)); - i = *pos_ptr; - assert(i >= 0); - table = so->table; - mask = so->mask; - while (i <= mask && (table[i].key == NULL || table[i].key == dummy)) - i++; - *pos_ptr = i+1; - if (i > mask) - return 0; - assert(table[i].key != NULL); - *entry_ptr = &table[i]; - return 1; -} - -static void -set_dealloc(PySetObject *so) -{ - register setentry *entry; - Py_ssize_t fill = so->fill; - PyObject_GC_UnTrack(so); - Py_TRASHCAN_SAFE_BEGIN(so) - if (so->weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) so); - - for (entry = so->table; fill > 0; entry++) { - if (entry->key) { - --fill; - Py_DECREF(entry->key); - } - } - if (so->table != so->smalltable) - PyMem_DEL(so->table); - if (num_free_sets < MAXFREESETS && PyAnySet_CheckExact(so)) - free_sets[num_free_sets++] = so; - else - so->ob_type->tp_free(so); - Py_TRASHCAN_SAFE_END(so) -} - -static int -set_tp_print(PySetObject *so, FILE *fp, int flags) -{ - setentry *entry; - Py_ssize_t pos=0; - char *emit = ""; /* No separator emitted on first pass */ - char *separator = ", "; - int status = Py_ReprEnter((PyObject*)so); - - if (status != 0) { - if (status < 0) - return status; - fprintf(fp, "%s(...)", so->ob_type->tp_name); - return 0; - } - - fprintf(fp, "%s([", so->ob_type->tp_name); - while (set_next(so, &pos, &entry)) { - fputs(emit, fp); - emit = separator; - if (PyObject_Print(entry->key, fp, 0) != 0) { - Py_ReprLeave((PyObject*)so); - return -1; - } - } - fputs("])", fp); - Py_ReprLeave((PyObject*)so); - return 0; -} - -static PyObject * -set_repr(PySetObject *so) -{ - PyObject *keys, *result=NULL, *listrepr; - int status = Py_ReprEnter((PyObject*)so); - - if (status != 0) { - if (status < 0) - return NULL; - return PyString_FromFormat("%s(...)", so->ob_type->tp_name); - } - - keys = PySequence_List((PyObject *)so); - if (keys == NULL) - goto done; - listrepr = PyObject_Repr(keys); - Py_DECREF(keys); - if (listrepr == NULL) - goto done; - - result = PyString_FromFormat("%s(%s)", so->ob_type->tp_name, - PyString_AS_STRING(listrepr)); - Py_DECREF(listrepr); -done: - Py_ReprLeave((PyObject*)so); - return result; -} - -static Py_ssize_t -set_len(PyObject *so) -{ - return ((PySetObject *)so)->used; -} - -static int -set_merge(PySetObject *so, PyObject *otherset) -{ - PySetObject *other; - register Py_ssize_t i; - register setentry *entry; - - assert (PyAnySet_Check(so)); - assert (PyAnySet_Check(otherset)); - - other = (PySetObject*)otherset; - if (other == so || other->used == 0) - /* a.update(a) or a.update({}); nothing to do */ - return 0; - /* Do one big resize at the start, rather than - * incrementally resizing as we insert new keys. Expect - * that there will be no (or few) overlapping keys. - */ - if ((so->fill + other->used)*3 >= (so->mask+1)*2) { - if (set_table_resize(so, (so->used + other->used)*2) != 0) - return -1; - } - for (i = 0; i <= other->mask; i++) { - entry = &other->table[i]; - if (entry->key != NULL && - entry->key != dummy) { - Py_INCREF(entry->key); - if (set_insert_key(so, entry->key, entry->hash) == -1) { - Py_DECREF(entry->key); - return -1; - } - } - } - return 0; -} - -static int -set_contains_key(PySetObject *so, PyObject *key) -{ - long hash; - setentry *entry; - - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) { - hash = PyObject_Hash(key); - if (hash == -1) - return -1; - } - entry = (so->lookup)(so, key, hash); - if (entry == NULL) - return -1; - key = entry->key; - return key != NULL && key != dummy; -} - -static int -set_contains_entry(PySetObject *so, setentry *entry) -{ - PyObject *key; - setentry *lu_entry; - - lu_entry = (so->lookup)(so, entry->key, entry->hash); - if (lu_entry == NULL) - return -1; - key = lu_entry->key; - return key != NULL && key != dummy; -} - -static PyObject * -set_pop(PySetObject *so) -{ - register Py_ssize_t i = 0; - register setentry *entry; - PyObject *key; - - assert (PyAnySet_Check(so)); - if (so->used == 0) { - PyErr_SetString(PyExc_KeyError, "pop from an empty set"); - return NULL; - } - - /* Set entry to "the first" unused or dummy set entry. We abuse - * the hash field of slot 0 to hold a search finger: - * If slot 0 has a value, use slot 0. - * Else slot 0 is being used to hold a search finger, - * and we use its hash value as the first index to look. - */ - entry = &so->table[0]; - if (entry->key == NULL || entry->key == dummy) { - i = entry->hash; - /* The hash field may be a real hash value, or it may be a - * legit search finger, or it may be a once-legit search - * finger that's out of bounds now because it wrapped around - * or the table shrunk -- simply make sure it's in bounds now. - */ - if (i > so->mask || i < 1) - i = 1; /* skip slot 0 */ - while ((entry = &so->table[i])->key == NULL || entry->key==dummy) { - i++; - if (i > so->mask) - i = 1; - } - } - key = entry->key; - Py_INCREF(dummy); - entry->key = dummy; - so->used--; - so->table[0].hash = i + 1; /* next place to start */ - return key; -} - -PyDoc_STRVAR(pop_doc, "Remove and return an arbitrary set element."); - -static int -set_traverse(PySetObject *so, visitproc visit, void *arg) -{ - Py_ssize_t pos = 0; - setentry *entry; - - while (set_next(so, &pos, &entry)) - Py_VISIT(entry->key); - return 0; -} - -static long -frozenset_hash(PyObject *self) -{ - PySetObject *so = (PySetObject *)self; - long h, hash = 1927868237L; - setentry *entry; - Py_ssize_t pos = 0; - - if (so->hash != -1) - return so->hash; - - hash *= PySet_GET_SIZE(self) + 1; - while (set_next(so, &pos, &entry)) { - /* Work to increase the bit dispersion for closely spaced hash - values. The is important because some use cases have many - combinations of a small number of elements with nearby - hashes so that many distinct combinations collapse to only - a handful of distinct hash values. */ - h = entry->hash; - hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u; - } - hash = hash * 69069L + 907133923L; - if (hash == -1) - hash = 590923713L; - so->hash = hash; - return hash; -} - -static long -set_nohash(PyObject *self) -{ - PyErr_SetString(PyExc_TypeError, "set objects are unhashable"); - return -1; -} - -/***** Set iterator type ***********************************************/ - -typedef struct { - PyObject_HEAD - PySetObject *si_set; /* Set to NULL when iterator is exhausted */ - Py_ssize_t si_used; - Py_ssize_t si_pos; - Py_ssize_t len; -} setiterobject; - -static void -setiter_dealloc(setiterobject *si) -{ - Py_XDECREF(si->si_set); - PyObject_Del(si); -} - -static PyObject * -setiter_len(setiterobject *si) -{ - Py_ssize_t len = 0; - if (si->si_set != NULL && si->si_used == si->si_set->used) - len = si->len; - return PyInt_FromLong(len); -} - -PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - -static PyMethodDef setiter_methods[] = { - {"__length_hint__", (PyCFunction)setiter_len, METH_NOARGS, length_hint_doc}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject *setiter_iternext(setiterobject *si) -{ - PyObject *key; - register Py_ssize_t i, mask; - register setentry *entry; - PySetObject *so = si->si_set; - - if (so == NULL) - return NULL; - assert (PyAnySet_Check(so)); - - if (si->si_used != so->used) { - PyErr_SetString(PyExc_RuntimeError, - "Set changed size during iteration"); - si->si_used = -1; /* Make this state sticky */ - return NULL; - } - - i = si->si_pos; - assert(i>=0); - entry = so->table; - mask = so->mask; - while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) - i++; - si->si_pos = i+1; - if (i > mask) - goto fail; - si->len--; - key = entry[i].key; - Py_INCREF(key); - return key; - -fail: - Py_DECREF(so); - si->si_set = NULL; - return NULL; -} - -static PyTypeObject PySetIter_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "setiterator", /* tp_name */ - sizeof(setiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)setiter_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)setiter_iternext, /* tp_iternext */ - setiter_methods, /* tp_methods */ - 0, -}; - -static PyObject * -set_iter(PySetObject *so) -{ - setiterobject *si = PyObject_New(setiterobject, &PySetIter_Type); - if (si == NULL) - return NULL; - Py_INCREF(so); - si->si_set = so; - si->si_used = so->used; - si->si_pos = 0; - si->len = so->used; - return (PyObject *)si; -} - -static int -set_update_internal(PySetObject *so, PyObject *other) -{ - PyObject *key, *it; - - if (PyAnySet_Check(other)) - return set_merge(so, other); - - if (PyDict_CheckExact(other)) { - PyObject *value; - Py_ssize_t pos = 0; - long hash; - Py_ssize_t dictsize = PyDict_Size(other); - - /* Do one big resize at the start, rather than - * incrementally resizing as we insert new keys. Expect - * that there will be no (or few) overlapping keys. - */ - if (dictsize == -1) - return -1; - if ((so->fill + dictsize)*3 >= (so->mask+1)*2) { - if (set_table_resize(so, (so->used + dictsize)*2) != 0) - return -1; - } - while (_PyDict_Next(other, &pos, &key, &value, &hash)) { - setentry an_entry; - - an_entry.hash = hash; - an_entry.key = key; - if (set_add_entry(so, &an_entry) == -1) - return -1; - } - return 0; - } - - it = PyObject_GetIter(other); - if (it == NULL) - return -1; - - while ((key = PyIter_Next(it)) != NULL) { - if (set_add_key(so, key) == -1) { - Py_DECREF(it); - Py_DECREF(key); - return -1; - } - Py_DECREF(key); - } - Py_DECREF(it); - if (PyErr_Occurred()) - return -1; - return 0; -} - -static PyObject * -set_update(PySetObject *so, PyObject *other) -{ - if (set_update_internal(so, other) == -1) - return NULL; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(update_doc, -"Update a set with the union of itself and another."); - -static PyObject * -make_new_set(PyTypeObject *type, PyObject *iterable) -{ - register PySetObject *so = NULL; - - if (dummy == NULL) { /* Auto-initialize dummy */ - dummy = PyString_FromString("<dummy key>"); - if (dummy == NULL) - return NULL; - } - - /* create PySetObject structure */ - if (num_free_sets && - (type == &PySet_Type || type == &PyFrozenSet_Type)) { - so = free_sets[--num_free_sets]; - assert (so != NULL && PyAnySet_CheckExact(so)); - so->ob_type = type; - _Py_NewReference((PyObject *)so); - EMPTY_TO_MINSIZE(so); - PyObject_GC_Track(so); - } else { - so = (PySetObject *)type->tp_alloc(type, 0); - if (so == NULL) - return NULL; - /* tp_alloc has already zeroed the structure */ - assert(so->table == NULL && so->fill == 0 && so->used == 0); - INIT_NONZERO_SET_SLOTS(so); - } - - so->lookup = set_lookkey_string; - so->weakreflist = NULL; - - if (iterable != NULL) { - if (set_update_internal(so, iterable) == -1) { - Py_DECREF(so); - return NULL; - } - } - - return (PyObject *)so; -} - -/* The empty frozenset is a singleton */ -static PyObject *emptyfrozenset = NULL; - -static PyObject * -frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *iterable = NULL, *result; - - if (type == &PyFrozenSet_Type && !_PyArg_NoKeywords("frozenset()", kwds)) - return NULL; - - if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) - return NULL; - - if (type != &PyFrozenSet_Type) - return make_new_set(type, iterable); - - if (iterable != NULL) { - /* frozenset(f) is idempotent */ - if (PyFrozenSet_CheckExact(iterable)) { - Py_INCREF(iterable); - return iterable; - } - result = make_new_set(type, iterable); - if (result == NULL || PySet_GET_SIZE(result)) - return result; - Py_DECREF(result); - } - /* The empty frozenset is a singleton */ - if (emptyfrozenset == NULL) - emptyfrozenset = make_new_set(type, NULL); - Py_XINCREF(emptyfrozenset); - return emptyfrozenset; -} - -void -PySet_Fini(void) -{ - PySetObject *so; - - while (num_free_sets) { - num_free_sets--; - so = free_sets[num_free_sets]; - PyObject_GC_Del(so); - } - Py_CLEAR(dummy); - Py_CLEAR(emptyfrozenset); -} - -static PyObject * -set_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - if (type == &PySet_Type && !_PyArg_NoKeywords("set()", kwds)) - return NULL; - - return make_new_set(type, NULL); -} - -/* set_swap_bodies() switches the contents of any two sets by moving their - internal data pointers and, if needed, copying the internal smalltables. - Semantically equivalent to: - - t=set(a); a.clear(); a.update(b); b.clear(); b.update(t); del t - - The function always succeeds and it leaves both objects in a stable state. - Useful for creating temporary frozensets from sets for membership testing - in __contains__(), discard(), and remove(). Also useful for operations - that update in-place (by allowing an intermediate result to be swapped - into one of the original inputs). -*/ - -static void -set_swap_bodies(PySetObject *a, PySetObject *b) -{ - Py_ssize_t t; - setentry *u; - setentry *(*f)(PySetObject *so, PyObject *key, long hash); - setentry tab[PySet_MINSIZE]; - long h; - - t = a->fill; a->fill = b->fill; b->fill = t; - t = a->used; a->used = b->used; b->used = t; - t = a->mask; a->mask = b->mask; b->mask = t; - - u = a->table; - if (a->table == a->smalltable) - u = b->smalltable; - a->table = b->table; - if (b->table == b->smalltable) - a->table = a->smalltable; - b->table = u; - - f = a->lookup; a->lookup = b->lookup; b->lookup = f; - - if (a->table == a->smalltable || b->table == b->smalltable) { - memcpy(tab, a->smalltable, sizeof(tab)); - memcpy(a->smalltable, b->smalltable, sizeof(tab)); - memcpy(b->smalltable, tab, sizeof(tab)); - } - - if (PyType_IsSubtype(a->ob_type, &PyFrozenSet_Type) && - PyType_IsSubtype(b->ob_type, &PyFrozenSet_Type)) { - h = a->hash; a->hash = b->hash; b->hash = h; - } else { - a->hash = -1; - b->hash = -1; - } -} - -static PyObject * -set_copy(PySetObject *so) -{ - return make_new_set(so->ob_type, (PyObject *)so); -} - -static PyObject * -frozenset_copy(PySetObject *so) -{ - if (PyFrozenSet_CheckExact(so)) { - Py_INCREF(so); - return (PyObject *)so; - } - return set_copy(so); -} - -PyDoc_STRVAR(copy_doc, "Return a shallow copy of a set."); - -static PyObject * -set_clear(PySetObject *so) -{ - set_clear_internal(so); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(clear_doc, "Remove all elements from this set."); - -static PyObject * -set_union(PySetObject *so, PyObject *other) -{ - PySetObject *result; - - result = (PySetObject *)set_copy(so); - if (result == NULL) - return NULL; - if ((PyObject *)so == other) - return (PyObject *)result; - if (set_update_internal(result, other) == -1) { - Py_DECREF(result); - return NULL; - } - return (PyObject *)result; -} - -PyDoc_STRVAR(union_doc, - "Return the union of two sets as a new set.\n\ -\n\ -(i.e. all elements that are in either set.)"); - -static PyObject * -set_or(PySetObject *so, PyObject *other) -{ - if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return set_union(so, other); -} - -static PyObject * -set_ior(PySetObject *so, PyObject *other) -{ - if (!PyAnySet_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - if (set_update_internal(so, other) == -1) - return NULL; - Py_INCREF(so); - return (PyObject *)so; -} - -static PyObject * -set_intersection(PySetObject *so, PyObject *other) -{ - PySetObject *result; - PyObject *key, *it, *tmp; - - if ((PyObject *)so == other) - return set_copy(so); - - result = (PySetObject *)make_new_set(so->ob_type, NULL); - if (result == NULL) - return NULL; - - if (PyAnySet_Check(other)) { - Py_ssize_t pos = 0; - setentry *entry; - - if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) { - tmp = (PyObject *)so; - so = (PySetObject *)other; - other = tmp; - } - - while (set_next((PySetObject *)other, &pos, &entry)) { - int rv = set_contains_entry(so, entry); - if (rv == -1) { - Py_DECREF(result); - return NULL; - } - if (rv) { - if (set_add_entry(result, entry) == -1) { - Py_DECREF(result); - return NULL; - } - } - } - return (PyObject *)result; - } - - it = PyObject_GetIter(other); - if (it == NULL) { - Py_DECREF(result); - return NULL; - } - - while ((key = PyIter_Next(it)) != NULL) { - int rv; - setentry entry; - long hash = PyObject_Hash(key); - - if (hash == -1) { - Py_DECREF(it); - Py_DECREF(result); - Py_DECREF(key); - return NULL; - } - entry.hash = hash; - entry.key = key; - rv = set_contains_entry(so, &entry); - if (rv == -1) { - Py_DECREF(it); - Py_DECREF(result); - Py_DECREF(key); - return NULL; - } - if (rv) { - if (set_add_entry(result, &entry) == -1) { - Py_DECREF(it); - Py_DECREF(result); - Py_DECREF(key); - return NULL; - } - } - Py_DECREF(key); - } - Py_DECREF(it); - if (PyErr_Occurred()) { - Py_DECREF(result); - return NULL; - } - return (PyObject *)result; -} - -PyDoc_STRVAR(intersection_doc, -"Return the intersection of two sets as a new set.\n\ -\n\ -(i.e. all elements that are in both sets.)"); - -static PyObject * -set_intersection_update(PySetObject *so, PyObject *other) -{ - PyObject *tmp; - - tmp = set_intersection(so, other); - if (tmp == NULL) - return NULL; - set_swap_bodies(so, (PySetObject *)tmp); - Py_DECREF(tmp); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(intersection_update_doc, -"Update a set with the intersection of itself and another."); - -static PyObject * -set_and(PySetObject *so, PyObject *other) -{ - if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return set_intersection(so, other); -} - -static PyObject * -set_iand(PySetObject *so, PyObject *other) -{ - PyObject *result; - - if (!PyAnySet_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - result = set_intersection_update(so, other); - if (result == NULL) - return NULL; - Py_DECREF(result); - Py_INCREF(so); - return (PyObject *)so; -} - -static int -set_difference_update_internal(PySetObject *so, PyObject *other) -{ - if ((PyObject *)so == other) - return set_clear_internal(so); - - if (PyAnySet_Check(other)) { - setentry *entry; - Py_ssize_t pos = 0; - - while (set_next((PySetObject *)other, &pos, &entry)) - if (set_discard_entry(so, entry) == -1) - return -1; - } else { - PyObject *key, *it; - it = PyObject_GetIter(other); - if (it == NULL) - return -1; - - while ((key = PyIter_Next(it)) != NULL) { - if (set_discard_key(so, key) == -1) { - Py_DECREF(it); - Py_DECREF(key); - return -1; - } - Py_DECREF(key); - } - Py_DECREF(it); - if (PyErr_Occurred()) - return -1; - } - /* If more than 1/5 are dummies, then resize them away. */ - if ((so->fill - so->used) * 5 < so->mask) - return 0; - return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); -} - -static PyObject * -set_difference_update(PySetObject *so, PyObject *other) -{ - if (set_difference_update_internal(so, other) != -1) - Py_RETURN_NONE; - return NULL; -} - -PyDoc_STRVAR(difference_update_doc, -"Remove all elements of another set from this set."); - -static PyObject * -set_difference(PySetObject *so, PyObject *other) -{ - PyObject *result; - setentry *entry; - Py_ssize_t pos = 0; - - if (!PyAnySet_Check(other) && !PyDict_CheckExact(other)) { - result = set_copy(so); - if (result == NULL) - return NULL; - if (set_difference_update_internal((PySetObject *)result, other) != -1) - return result; - Py_DECREF(result); - return NULL; - } - - result = make_new_set(so->ob_type, NULL); - if (result == NULL) - return NULL; - - if (PyDict_CheckExact(other)) { - while (set_next(so, &pos, &entry)) { - setentry entrycopy; - entrycopy.hash = entry->hash; - entrycopy.key = entry->key; - if (!_PyDict_Contains(other, entry->key, entry->hash)) { - if (set_add_entry((PySetObject *)result, &entrycopy) == -1) { - Py_DECREF(result); - return NULL; - } - } - } - return result; - } - - while (set_next(so, &pos, &entry)) { - int rv = set_contains_entry((PySetObject *)other, entry); - if (rv == -1) { - Py_DECREF(result); - return NULL; - } - if (!rv) { - if (set_add_entry((PySetObject *)result, entry) == -1) { - Py_DECREF(result); - return NULL; - } - } - } - return result; -} - -PyDoc_STRVAR(difference_doc, -"Return the difference of two sets as a new set.\n\ -\n\ -(i.e. all elements that are in this set but not the other.)"); -static PyObject * -set_sub(PySetObject *so, PyObject *other) -{ - if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return set_difference(so, other); -} - -static PyObject * -set_isub(PySetObject *so, PyObject *other) -{ - PyObject *result; - - if (!PyAnySet_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - result = set_difference_update(so, other); - if (result == NULL) - return NULL; - Py_DECREF(result); - Py_INCREF(so); - return (PyObject *)so; -} - -static PyObject * -set_symmetric_difference_update(PySetObject *so, PyObject *other) -{ - PySetObject *otherset; - PyObject *key; - Py_ssize_t pos = 0; - setentry *entry; - - if ((PyObject *)so == other) - return set_clear(so); - - if (PyDict_CheckExact(other)) { - PyObject *value; - int rv; - long hash; - while (_PyDict_Next(other, &pos, &key, &value, &hash)) { - setentry an_entry; - - an_entry.hash = hash; - an_entry.key = key; - rv = set_discard_entry(so, &an_entry); - if (rv == -1) - return NULL; - if (rv == DISCARD_NOTFOUND) { - if (set_add_entry(so, &an_entry) == -1) - return NULL; - } - } - Py_RETURN_NONE; - } - - if (PyAnySet_Check(other)) { - Py_INCREF(other); - otherset = (PySetObject *)other; - } else { - otherset = (PySetObject *)make_new_set(so->ob_type, other); - if (otherset == NULL) - return NULL; - } - - while (set_next(otherset, &pos, &entry)) { - int rv = set_discard_entry(so, entry); - if (rv == -1) { - Py_DECREF(otherset); - return NULL; - } - if (rv == DISCARD_NOTFOUND) { - if (set_add_entry(so, entry) == -1) { - Py_DECREF(otherset); - return NULL; - } - } - } - Py_DECREF(otherset); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(symmetric_difference_update_doc, -"Update a set with the symmetric difference of itself and another."); - -static PyObject * -set_symmetric_difference(PySetObject *so, PyObject *other) -{ - PyObject *rv; - PySetObject *otherset; - - otherset = (PySetObject *)make_new_set(so->ob_type, other); - if (otherset == NULL) - return NULL; - rv = set_symmetric_difference_update(otherset, (PyObject *)so); - if (rv == NULL) - return NULL; - Py_DECREF(rv); - return (PyObject *)otherset; -} - -PyDoc_STRVAR(symmetric_difference_doc, -"Return the symmetric difference of two sets as a new set.\n\ -\n\ -(i.e. all elements that are in exactly one of the sets.)"); - -static PyObject * -set_xor(PySetObject *so, PyObject *other) -{ - if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return set_symmetric_difference(so, other); -} - -static PyObject * -set_ixor(PySetObject *so, PyObject *other) -{ - PyObject *result; - - if (!PyAnySet_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - result = set_symmetric_difference_update(so, other); - if (result == NULL) - return NULL; - Py_DECREF(result); - Py_INCREF(so); - return (PyObject *)so; -} - -static PyObject * -set_issubset(PySetObject *so, PyObject *other) -{ - setentry *entry; - Py_ssize_t pos = 0; - - if (!PyAnySet_Check(other)) { - PyObject *tmp, *result; - tmp = make_new_set(&PySet_Type, other); - if (tmp == NULL) - return NULL; - result = set_issubset(so, tmp); - Py_DECREF(tmp); - return result; - } - if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other)) - Py_RETURN_FALSE; - - while (set_next(so, &pos, &entry)) { - int rv = set_contains_entry((PySetObject *)other, entry); - if (rv == -1) - return NULL; - if (!rv) - Py_RETURN_FALSE; - } - Py_RETURN_TRUE; -} - -PyDoc_STRVAR(issubset_doc, "Report whether another set contains this set."); - -static PyObject * -set_issuperset(PySetObject *so, PyObject *other) -{ - PyObject *tmp, *result; - - if (!PyAnySet_Check(other)) { - tmp = make_new_set(&PySet_Type, other); - if (tmp == NULL) - return NULL; - result = set_issuperset(so, tmp); - Py_DECREF(tmp); - return result; - } - return set_issubset((PySetObject *)other, (PyObject *)so); -} - -PyDoc_STRVAR(issuperset_doc, "Report whether this set contains another set."); - -static PyObject * -set_richcompare(PySetObject *v, PyObject *w, int op) -{ - PyObject *r1, *r2; - - if(!PyAnySet_Check(w)) { - if (op == Py_EQ) - Py_RETURN_FALSE; - if (op == Py_NE) - Py_RETURN_TRUE; - PyErr_SetString(PyExc_TypeError, "can only compare to a set"); - return NULL; - } - switch (op) { - case Py_EQ: - if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w)) - Py_RETURN_FALSE; - if (v->hash != -1 && - ((PySetObject *)w)->hash != -1 && - v->hash != ((PySetObject *)w)->hash) - Py_RETURN_FALSE; - return set_issubset(v, w); - case Py_NE: - r1 = set_richcompare(v, w, Py_EQ); - if (r1 == NULL) - return NULL; - r2 = PyBool_FromLong(PyObject_Not(r1)); - Py_DECREF(r1); - return r2; - case Py_LE: - return set_issubset(v, w); - case Py_GE: - return set_issuperset(v, w); - case Py_LT: - if (PySet_GET_SIZE(v) >= PySet_GET_SIZE(w)) - Py_RETURN_FALSE; - return set_issubset(v, w); - case Py_GT: - if (PySet_GET_SIZE(v) <= PySet_GET_SIZE(w)) - Py_RETURN_FALSE; - return set_issuperset(v, w); - } - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -static int -set_nocmp(PyObject *self, PyObject *other) -{ - PyErr_SetString(PyExc_TypeError, "cannot compare sets using cmp()"); - return -1; -} - -static PyObject * -set_add(PySetObject *so, PyObject *key) -{ - if (set_add_key(so, key) == -1) - return NULL; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(add_doc, -"Add an element to a set.\n\ -\n\ -This has no effect if the element is already present."); - -static int -set_contains(PySetObject *so, PyObject *key) -{ - PyObject *tmpkey; - int rv; - - rv = set_contains_key(so, key); - if (rv == -1) { - if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) - return -1; - PyErr_Clear(); - tmpkey = make_new_set(&PyFrozenSet_Type, NULL); - if (tmpkey == NULL) - return -1; - set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - rv = set_contains(so, tmpkey); - set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - Py_DECREF(tmpkey); - } - return rv; -} - -static PyObject * -set_direct_contains(PySetObject *so, PyObject *key) -{ - long result; - - result = set_contains(so, key); - if (result == -1) - return NULL; - return PyBool_FromLong(result); -} - -PyDoc_STRVAR(contains_doc, "x.__contains__(y) <==> y in x."); - -static PyObject * -set_remove(PySetObject *so, PyObject *key) -{ - PyObject *tmpkey, *result; - int rv; - - rv = set_discard_key(so, key); - if (rv == -1) { - if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) - return NULL; - PyErr_Clear(); - tmpkey = make_new_set(&PyFrozenSet_Type, NULL); - if (tmpkey == NULL) - return NULL; - set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - result = set_remove(so, tmpkey); - set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - Py_DECREF(tmpkey); - return result; - } else if (rv == DISCARD_NOTFOUND) { - set_key_error(key); - return NULL; - } - Py_RETURN_NONE; -} - -PyDoc_STRVAR(remove_doc, -"Remove an element from a set; it must be a member.\n\ -\n\ -If the element is not a member, raise a KeyError."); - -static PyObject * -set_discard(PySetObject *so, PyObject *key) -{ - PyObject *tmpkey, *result; - int rv; - - rv = set_discard_key(so, key); - if (rv == -1) { - if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) - return NULL; - PyErr_Clear(); - tmpkey = make_new_set(&PyFrozenSet_Type, NULL); - if (tmpkey == NULL) - return NULL; - set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - result = set_discard(so, tmpkey); - set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - Py_DECREF(tmpkey); - return result; - } - Py_RETURN_NONE; -} - -PyDoc_STRVAR(discard_doc, -"Remove an element from a set if it is a member.\n\ -\n\ -If the element is not a member, do nothing."); - -static PyObject * -set_reduce(PySetObject *so) -{ - PyObject *keys=NULL, *args=NULL, *result=NULL, *dict=NULL; - - keys = PySequence_List((PyObject *)so); - if (keys == NULL) - goto done; - args = PyTuple_Pack(1, keys); - if (args == NULL) - goto done; - dict = PyObject_GetAttrString((PyObject *)so, "__dict__"); - if (dict == NULL) { - PyErr_Clear(); - dict = Py_None; - Py_INCREF(dict); - } - result = PyTuple_Pack(3, so->ob_type, args, dict); -done: - Py_XDECREF(args); - Py_XDECREF(keys); - Py_XDECREF(dict); - return result; -} - -PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); - -static int -set_init(PySetObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *iterable = NULL; - - if (!PyAnySet_Check(self)) - return -1; - if (!PyArg_UnpackTuple(args, self->ob_type->tp_name, 0, 1, &iterable)) - return -1; - set_clear_internal(self); - self->hash = -1; - if (iterable == NULL) - return 0; - return set_update_internal(self, iterable); -} - -static PySequenceMethods set_as_sequence = { - set_len, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - 0, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)set_contains, /* sq_contains */ -}; - -/* set object ********************************************************/ - -#ifdef Py_DEBUG -static PyObject *test_c_api(PySetObject *so); - -PyDoc_STRVAR(test_c_api_doc, "Exercises C API. Returns True.\n\ -All is well if assertions don't fail."); -#endif - -static PyMethodDef set_methods[] = { - {"add", (PyCFunction)set_add, METH_O, - add_doc}, - {"clear", (PyCFunction)set_clear, METH_NOARGS, - clear_doc}, - {"__contains__",(PyCFunction)set_direct_contains, METH_O | METH_COEXIST, - contains_doc}, - {"copy", (PyCFunction)set_copy, METH_NOARGS, - copy_doc}, - {"discard", (PyCFunction)set_discard, METH_O, - discard_doc}, - {"difference", (PyCFunction)set_difference, METH_O, - difference_doc}, - {"difference_update", (PyCFunction)set_difference_update, METH_O, - difference_update_doc}, - {"intersection",(PyCFunction)set_intersection, METH_O, - intersection_doc}, - {"intersection_update",(PyCFunction)set_intersection_update, METH_O, - intersection_update_doc}, - {"issubset", (PyCFunction)set_issubset, METH_O, - issubset_doc}, - {"issuperset", (PyCFunction)set_issuperset, METH_O, - issuperset_doc}, - {"pop", (PyCFunction)set_pop, METH_NOARGS, - pop_doc}, - {"__reduce__", (PyCFunction)set_reduce, METH_NOARGS, - reduce_doc}, - {"remove", (PyCFunction)set_remove, METH_O, - remove_doc}, - {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, - symmetric_difference_doc}, - {"symmetric_difference_update",(PyCFunction)set_symmetric_difference_update, METH_O, - symmetric_difference_update_doc}, -#ifdef Py_DEBUG - {"test_c_api", (PyCFunction)test_c_api, METH_NOARGS, - test_c_api_doc}, -#endif - {"union", (PyCFunction)set_union, METH_O, - union_doc}, - {"update", (PyCFunction)set_update, METH_O, - update_doc}, - {NULL, NULL} /* sentinel */ -}; - -static PyNumberMethods set_as_number = { - 0, /*nb_add*/ - (binaryfunc)set_sub, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - 0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - (binaryfunc)set_and, /*nb_and*/ - (binaryfunc)set_xor, /*nb_xor*/ - (binaryfunc)set_or, /*nb_or*/ - 0, /*nb_coerce*/ - 0, /*nb_int*/ - 0, /*nb_long*/ - 0, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ - 0, /*nb_inplace_add*/ - (binaryfunc)set_isub, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_divide*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - (binaryfunc)set_iand, /*nb_inplace_and*/ - (binaryfunc)set_ixor, /*nb_inplace_xor*/ - (binaryfunc)set_ior, /*nb_inplace_or*/ -}; - -PyDoc_STRVAR(set_doc, -"set(iterable) --> set object\n\ -\n\ -Build an unordered collection of unique elements."); - -PyTypeObject PySet_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "set", /* tp_name */ - sizeof(PySetObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)set_dealloc, /* tp_dealloc */ - (printfunc)set_tp_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - set_nocmp, /* tp_compare */ - (reprfunc)set_repr, /* tp_repr */ - &set_as_number, /* tp_as_number */ - &set_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - set_nohash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - set_doc, /* tp_doc */ - (traverseproc)set_traverse, /* tp_traverse */ - (inquiry)set_clear_internal, /* tp_clear */ - (richcmpfunc)set_richcompare, /* tp_richcompare */ - offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ - (getiterfunc)set_iter, /* tp_iter */ - 0, /* tp_iternext */ - set_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)set_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - set_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - -/* frozenset object ********************************************************/ - - -static PyMethodDef frozenset_methods[] = { - {"__contains__",(PyCFunction)set_direct_contains, METH_O | METH_COEXIST, - contains_doc}, - {"copy", (PyCFunction)frozenset_copy, METH_NOARGS, - copy_doc}, - {"difference", (PyCFunction)set_difference, METH_O, - difference_doc}, - {"intersection",(PyCFunction)set_intersection, METH_O, - intersection_doc}, - {"issubset", (PyCFunction)set_issubset, METH_O, - issubset_doc}, - {"issuperset", (PyCFunction)set_issuperset, METH_O, - issuperset_doc}, - {"__reduce__", (PyCFunction)set_reduce, METH_NOARGS, - reduce_doc}, - {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, - symmetric_difference_doc}, - {"union", (PyCFunction)set_union, METH_O, - union_doc}, - {NULL, NULL} /* sentinel */ -}; - -static PyNumberMethods frozenset_as_number = { - 0, /*nb_add*/ - (binaryfunc)set_sub, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - 0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - (binaryfunc)set_and, /*nb_and*/ - (binaryfunc)set_xor, /*nb_xor*/ - (binaryfunc)set_or, /*nb_or*/ -}; - -PyDoc_STRVAR(frozenset_doc, -"frozenset(iterable) --> frozenset object\n\ -\n\ -Build an immutable unordered collection of unique elements."); - -PyTypeObject PyFrozenSet_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "frozenset", /* tp_name */ - sizeof(PySetObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)set_dealloc, /* tp_dealloc */ - (printfunc)set_tp_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - set_nocmp, /* tp_compare */ - (reprfunc)set_repr, /* tp_repr */ - &frozenset_as_number, /* tp_as_number */ - &set_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - frozenset_hash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - frozenset_doc, /* tp_doc */ - (traverseproc)set_traverse, /* tp_traverse */ - (inquiry)set_clear_internal, /* tp_clear */ - (richcmpfunc)set_richcompare, /* tp_richcompare */ - offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ - (getiterfunc)set_iter, /* tp_iter */ - 0, /* tp_iternext */ - frozenset_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - frozenset_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - - -/***** C API functions *************************************************/ - -PyObject * -PySet_New(PyObject *iterable) -{ - return make_new_set(&PySet_Type, iterable); -} - -PyObject * -PyFrozenSet_New(PyObject *iterable) -{ - PyObject *args, *result; - - if (iterable == NULL) - args = PyTuple_New(0); - else - args = PyTuple_Pack(1, iterable); - if (args == NULL) - return NULL; - result = frozenset_new(&PyFrozenSet_Type, args, NULL); - Py_DECREF(args); - return result; -} - -Py_ssize_t -PySet_Size(PyObject *anyset) -{ - if (!PyAnySet_Check(anyset)) { - PyErr_BadInternalCall(); - return -1; - } - return PySet_GET_SIZE(anyset); -} - -int -PySet_Clear(PyObject *set) -{ - if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { - PyErr_BadInternalCall(); - return -1; - } - return set_clear_internal((PySetObject *)set); -} - -int -PySet_Contains(PyObject *anyset, PyObject *key) -{ - if (!PyAnySet_Check(anyset)) { - PyErr_BadInternalCall(); - return -1; - } - return set_contains_key((PySetObject *)anyset, key); -} - -int -PySet_Discard(PyObject *set, PyObject *key) -{ - if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { - PyErr_BadInternalCall(); - return -1; - } - return set_discard_key((PySetObject *)set, key); -} - -int -PySet_Add(PyObject *set, PyObject *key) -{ - if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { - PyErr_BadInternalCall(); - return -1; - } - return set_add_key((PySetObject *)set, key); -} - -int -_PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key) -{ - setentry *entry_ptr; - - if (!PyAnySet_Check(set)) { - PyErr_BadInternalCall(); - return -1; - } - if (set_next((PySetObject *)set, pos, &entry_ptr) == 0) - return 0; - *key = entry_ptr->key; - return 1; -} - -int -_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash) -{ - setentry *entry; - - if (!PyAnySet_Check(set)) { - PyErr_BadInternalCall(); - return -1; - } - if (set_next((PySetObject *)set, pos, &entry) == 0) - return 0; - *key = entry->key; - *hash = entry->hash; - return 1; -} - -PyObject * -PySet_Pop(PyObject *set) -{ - if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { - PyErr_BadInternalCall(); - return NULL; - } - return set_pop((PySetObject *)set); -} - -int -_PySet_Update(PyObject *set, PyObject *iterable) -{ - if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { - PyErr_BadInternalCall(); - return -1; - } - return set_update_internal((PySetObject *)set, iterable); -} - -#ifdef Py_DEBUG - -/* Test code to be called with any three element set. - Returns True and original set is restored. */ - -#define assertRaises(call_return_value, exception) \ - do { \ - assert(call_return_value); \ - assert(PyErr_ExceptionMatches(exception)); \ - PyErr_Clear(); \ - } while(0) - -static PyObject * -test_c_api(PySetObject *so) -{ - Py_ssize_t count; - char *s; - Py_ssize_t i; - PyObject *elem, *dup, *t, *f, *dup2; - PyObject *ob = (PyObject *)so; - - /* Verify preconditions and exercise type/size checks */ - assert(PyAnySet_Check(ob)); - assert(PyAnySet_CheckExact(ob)); - assert(!PyFrozenSet_CheckExact(ob)); - assert(PySet_Size(ob) == 3); - assert(PySet_GET_SIZE(ob) == 3); - - /* Raise TypeError for non-iterable constructor arguments */ - assertRaises(PySet_New(Py_None) == NULL, PyExc_TypeError); - assertRaises(PyFrozenSet_New(Py_None) == NULL, PyExc_TypeError); - - /* Raise TypeError for unhashable key */ - dup = PySet_New(ob); - assertRaises(PySet_Discard(ob, dup) == -1, PyExc_TypeError); - assertRaises(PySet_Contains(ob, dup) == -1, PyExc_TypeError); - assertRaises(PySet_Add(ob, dup) == -1, PyExc_TypeError); - - /* Exercise successful pop, contains, add, and discard */ - elem = PySet_Pop(ob); - assert(PySet_Contains(ob, elem) == 0); - assert(PySet_GET_SIZE(ob) == 2); - assert(PySet_Add(ob, elem) == 0); - assert(PySet_Contains(ob, elem) == 1); - assert(PySet_GET_SIZE(ob) == 3); - assert(PySet_Discard(ob, elem) == 1); - assert(PySet_GET_SIZE(ob) == 2); - assert(PySet_Discard(ob, elem) == 0); - assert(PySet_GET_SIZE(ob) == 2); - - /* Exercise clear */ - dup2 = PySet_New(dup); - assert(PySet_Clear(dup2) == 0); - assert(PySet_Size(dup2) == 0); - Py_DECREF(dup2); - - /* Raise SystemError on clear or update of frozen set */ - f = PyFrozenSet_New(dup); - assertRaises(PySet_Clear(f) == -1, PyExc_SystemError); - assertRaises(_PySet_Update(f, dup) == -1, PyExc_SystemError); - Py_DECREF(f); - - /* Exercise direct iteration */ - i = 0, count = 0; - while (_PySet_Next((PyObject *)dup, &i, &elem)) { - s = PyString_AsString(elem); - assert(s && (s[0] == 'a' || s[0] == 'b' || s[0] == 'c')); - count++; - } - assert(count == 3); - - /* Exercise updates */ - dup2 = PySet_New(NULL); - assert(_PySet_Update(dup2, dup) == 0); - assert(PySet_Size(dup2) == 3); - assert(_PySet_Update(dup2, dup) == 0); - assert(PySet_Size(dup2) == 3); - Py_DECREF(dup2); - - /* Raise SystemError when self argument is not a set or frozenset. */ - t = PyTuple_New(0); - assertRaises(PySet_Size(t) == -1, PyExc_SystemError); - assertRaises(PySet_Contains(t, elem) == -1, PyExc_SystemError); - Py_DECREF(t); - - /* Raise SystemError when self argument is not a set. */ - f = PyFrozenSet_New(dup); - assert(PySet_Size(f) == 3); - assert(PyFrozenSet_CheckExact(f)); - assertRaises(PySet_Add(f, elem) == -1, PyExc_SystemError); - assertRaises(PySet_Discard(f, elem) == -1, PyExc_SystemError); - assertRaises(PySet_Pop(f) == NULL, PyExc_SystemError); - Py_DECREF(f); - - /* Raise KeyError when popping from an empty set */ - assert(PyNumber_InPlaceSubtract(ob, ob) == ob); - Py_DECREF(ob); - assert(PySet_GET_SIZE(ob) == 0); - assertRaises(PySet_Pop(ob) == NULL, PyExc_KeyError); - - /* Restore the set from the copy using the PyNumber API */ - assert(PyNumber_InPlaceOr(ob, dup) == ob); - Py_DECREF(ob); - - /* Verify constructors accept NULL arguments */ - f = PySet_New(NULL); - assert(f != NULL); - assert(PySet_GET_SIZE(f) == 0); - Py_DECREF(f); - f = PyFrozenSet_New(NULL); - assert(f != NULL); - assert(PyFrozenSet_CheckExact(f)); - assert(PySet_GET_SIZE(f) == 0); - Py_DECREF(f); - - Py_DECREF(elem); - Py_DECREF(dup); - Py_RETURN_TRUE; -} - -#undef assertRaises - -#endif diff --git a/sys/src/cmd/python/Objects/sliceobject.c b/sys/src/cmd/python/Objects/sliceobject.c deleted file mode 100644 index d8a24653a..000000000 --- a/sys/src/cmd/python/Objects/sliceobject.c +++ /dev/null @@ -1,351 +0,0 @@ -/* -Written by Jim Hugunin and Chris Chase. - -This includes both the singular ellipsis object and slice objects. - -Guido, feel free to do whatever you want in the way of copyrights -for this file. -*/ - -/* -Py_Ellipsis encodes the '...' rubber index token. It is similar to -the Py_NoneStruct in that there is no way to create other objects of -this type and there is exactly one in existence. -*/ - -#include "Python.h" -#include "structmember.h" - -static PyObject * -ellipsis_repr(PyObject *op) -{ - return PyString_FromString("Ellipsis"); -} - -static PyTypeObject PyEllipsis_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "ellipsis", /* tp_name */ - 0, /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /*never called*/ /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - ellipsis_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ -}; - -PyObject _Py_EllipsisObject = { - PyObject_HEAD_INIT(&PyEllipsis_Type) -}; - - -/* Slice object implementation - - start, stop, and step are python objects with None indicating no - index is present. -*/ - -PyObject * -PySlice_New(PyObject *start, PyObject *stop, PyObject *step) -{ - PySliceObject *obj = PyObject_New(PySliceObject, &PySlice_Type); - - if (obj == NULL) - return NULL; - - if (step == NULL) step = Py_None; - Py_INCREF(step); - if (start == NULL) start = Py_None; - Py_INCREF(start); - if (stop == NULL) stop = Py_None; - Py_INCREF(stop); - - obj->step = step; - obj->start = start; - obj->stop = stop; - - return (PyObject *) obj; -} - -PyObject * -_PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop) -{ - PyObject *start, *end, *slice; - start = PyInt_FromSsize_t(istart); - if (!start) - return NULL; - end = PyInt_FromSsize_t(istop); - if (!end) { - Py_DECREF(start); - return NULL; - } - - slice = PySlice_New(start, end, NULL); - Py_DECREF(start); - Py_DECREF(end); - return slice; -} - -int -PySlice_GetIndices(PySliceObject *r, Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step) -{ - /* XXX support long ints */ - if (r->step == Py_None) { - *step = 1; - } else { - if (!PyInt_Check(r->step) && !PyLong_Check(r->step)) return -1; - *step = PyInt_AsSsize_t(r->step); - } - if (r->start == Py_None) { - *start = *step < 0 ? length-1 : 0; - } else { - if (!PyInt_Check(r->start) && !PyLong_Check(r->step)) return -1; - *start = PyInt_AsSsize_t(r->start); - if (*start < 0) *start += length; - } - if (r->stop == Py_None) { - *stop = *step < 0 ? -1 : length; - } else { - if (!PyInt_Check(r->stop) && !PyLong_Check(r->step)) return -1; - *stop = PyInt_AsSsize_t(r->stop); - if (*stop < 0) *stop += length; - } - if (*stop > length) return -1; - if (*start >= length) return -1; - if (*step == 0) return -1; - return 0; -} - -int -PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength) -{ - /* this is harder to get right than you might think */ - - Py_ssize_t defstart, defstop; - - if (r->step == Py_None) { - *step = 1; - } - else { - if (!_PyEval_SliceIndex(r->step, step)) return -1; - if (*step == 0) { - PyErr_SetString(PyExc_ValueError, - "slice step cannot be zero"); - return -1; - } - } - - defstart = *step < 0 ? length-1 : 0; - defstop = *step < 0 ? -1 : length; - - if (r->start == Py_None) { - *start = defstart; - } - else { - if (!_PyEval_SliceIndex(r->start, start)) return -1; - if (*start < 0) *start += length; - if (*start < 0) *start = (*step < 0) ? -1 : 0; - if (*start >= length) - *start = (*step < 0) ? length - 1 : length; - } - - if (r->stop == Py_None) { - *stop = defstop; - } - else { - if (!_PyEval_SliceIndex(r->stop, stop)) return -1; - if (*stop < 0) *stop += length; - if (*stop < 0) *stop = -1; - if (*stop > length) *stop = length; - } - - if ((*step < 0 && *stop >= *start) - || (*step > 0 && *start >= *stop)) { - *slicelength = 0; - } - else if (*step < 0) { - *slicelength = (*stop-*start+1)/(*step)+1; - } - else { - *slicelength = (*stop-*start-1)/(*step)+1; - } - - return 0; -} - -static PyObject * -slice_new(PyTypeObject *type, PyObject *args, PyObject *kw) -{ - PyObject *start, *stop, *step; - - start = stop = step = NULL; - - if (!_PyArg_NoKeywords("slice()", kw)) - return NULL; - - if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step)) - return NULL; - - /* This swapping of stop and start is to maintain similarity with - range(). */ - if (stop == NULL) { - stop = start; - start = NULL; - } - return PySlice_New(start, stop, step); -} - -PyDoc_STRVAR(slice_doc, -"slice([start,] stop[, step])\n\ -\n\ -Create a slice object. This is used for extended slicing (e.g. a[0:10:2])."); - -static void -slice_dealloc(PySliceObject *r) -{ - Py_DECREF(r->step); - Py_DECREF(r->start); - Py_DECREF(r->stop); - PyObject_Del(r); -} - -static PyObject * -slice_repr(PySliceObject *r) -{ - PyObject *s, *comma; - - s = PyString_FromString("slice("); - comma = PyString_FromString(", "); - PyString_ConcatAndDel(&s, PyObject_Repr(r->start)); - PyString_Concat(&s, comma); - PyString_ConcatAndDel(&s, PyObject_Repr(r->stop)); - PyString_Concat(&s, comma); - PyString_ConcatAndDel(&s, PyObject_Repr(r->step)); - PyString_ConcatAndDel(&s, PyString_FromString(")")); - Py_DECREF(comma); - return s; -} - -static PyMemberDef slice_members[] = { - {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY}, - {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY}, - {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY}, - {0} -}; - -static PyObject* -slice_indices(PySliceObject* self, PyObject* len) -{ - Py_ssize_t ilen, start, stop, step, slicelength; - - ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError); - - if (ilen == -1 && PyErr_Occurred()) { - return NULL; - } - - if (PySlice_GetIndicesEx(self, ilen, &start, &stop, - &step, &slicelength) < 0) { - return NULL; - } - - return Py_BuildValue("(nnn)", start, stop, step); -} - -PyDoc_STRVAR(slice_indices_doc, -"S.indices(len) -> (start, stop, stride)\n\ -\n\ -Assuming a sequence of length len, calculate the start and stop\n\ -indices, and the stride length of the extended slice described by\n\ -S. Out of bounds indices are clipped in a manner consistent with the\n\ -handling of normal slices."); - -static PyMethodDef slice_methods[] = { - {"indices", (PyCFunction)slice_indices, - METH_O, slice_indices_doc}, - {NULL, NULL} -}; - -static int -slice_compare(PySliceObject *v, PySliceObject *w) -{ - int result = 0; - - if (v == w) - return 0; - - if (PyObject_Cmp(v->start, w->start, &result) < 0) - return -2; - if (result != 0) - return result; - if (PyObject_Cmp(v->stop, w->stop, &result) < 0) - return -2; - if (result != 0) - return result; - if (PyObject_Cmp(v->step, w->step, &result) < 0) - return -2; - return result; -} - -static long -slice_hash(PySliceObject *v) -{ - PyErr_SetString(PyExc_TypeError, "unhashable type"); - return -1L; -} - -PyTypeObject PySlice_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* Number of items for varobject */ - "slice", /* Name of this type */ - sizeof(PySliceObject), /* Basic object size */ - 0, /* Item size for varobject */ - (destructor)slice_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)slice_compare, /* tp_compare */ - (reprfunc)slice_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)slice_hash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - slice_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - slice_methods, /* tp_methods */ - slice_members, /* tp_members */ - 0, /* 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 */ - slice_new, /* tp_new */ -}; diff --git a/sys/src/cmd/python/Objects/stringlib/README.txt b/sys/src/cmd/python/Objects/stringlib/README.txt deleted file mode 100644 index 82a877465..000000000 --- a/sys/src/cmd/python/Objects/stringlib/README.txt +++ /dev/null @@ -1,34 +0,0 @@ -bits shared by the stringobject and unicodeobject implementations (and -possibly other modules, in a not too distant future). - -the stuff in here is included into relevant places; see the individual -source files for details. - --------------------------------------------------------------------- -the following defines used by the different modules: - -STRINGLIB_CHAR - - the type used to hold a character (char or Py_UNICODE) - -STRINGLIB_EMPTY - - a PyObject representing the empty string - -int STRINGLIB_CMP(STRINGLIB_CHAR*, STRINGLIB_CHAR*, Py_ssize_t) - - compares two strings. returns 0 if they match, and non-zero if not. - -Py_ssize_t STRINGLIB_LEN(PyObject*) - - returns the length of the given string object (which must be of the - right type) - -PyObject* STRINGLIB_NEW(STRINGLIB_CHAR*, Py_ssize_t) - - creates a new string object - -STRINGLIB_CHAR* STRINGLIB_STR(PyObject*) - - returns the pointer to the character data for the given string - object (which must be of the right type) diff --git a/sys/src/cmd/python/Objects/stringlib/count.h b/sys/src/cmd/python/Objects/stringlib/count.h deleted file mode 100644 index 367a15c51..000000000 --- a/sys/src/cmd/python/Objects/stringlib/count.h +++ /dev/null @@ -1,37 +0,0 @@ -/* stringlib: count implementation */ - -#ifndef STRINGLIB_COUNT_H -#define STRINGLIB_COUNT_H - -#ifndef STRINGLIB_FASTSEARCH_H -#error must include "stringlib/fastsearch.h" before including this module -#endif - -Py_LOCAL_INLINE(Py_ssize_t) -stringlib_count(const STRINGLIB_CHAR* str, Py_ssize_t str_len, - const STRINGLIB_CHAR* sub, Py_ssize_t sub_len) -{ - Py_ssize_t count; - - if (sub_len == 0) { - if (str_len < 0) - return 0; /* start > len(str) */ - return str_len + 1; - } - - count = fastsearch(str, str_len, sub, sub_len, FAST_COUNT); - - if (count < 0) - count = 0; /* no match */ - - return count; -} - -#endif - -/* -Local variables: -c-basic-offset: 4 -indent-tabs-mode: nil -End: -*/ diff --git a/sys/src/cmd/python/Objects/stringlib/fastsearch.h b/sys/src/cmd/python/Objects/stringlib/fastsearch.h deleted file mode 100644 index 8f79c360d..000000000 --- a/sys/src/cmd/python/Objects/stringlib/fastsearch.h +++ /dev/null @@ -1,104 +0,0 @@ -/* stringlib: fastsearch implementation */ - -#ifndef STRINGLIB_FASTSEARCH_H -#define STRINGLIB_FASTSEARCH_H - -/* fast search/count implementation, based on a mix between boyer- - moore and horspool, with a few more bells and whistles on the top. - for some more background, see: http://effbot.org/stringlib */ - -/* note: fastsearch may access s[n], which isn't a problem when using - Python's ordinary string types, but may cause problems if you're - using this code in other contexts. also, the count mode returns -1 - if there cannot possible be a match in the target string, and 0 if - it has actually checked for matches, but didn't find any. callers - beware! */ - -#define FAST_COUNT 0 -#define FAST_SEARCH 1 - -Py_LOCAL_INLINE(Py_ssize_t) -fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, - const STRINGLIB_CHAR* p, Py_ssize_t m, - int mode) -{ - long mask; - Py_ssize_t skip, count = 0; - Py_ssize_t i, j, mlast, w; - - w = n - m; - - if (w < 0) - return -1; - - /* look for special cases */ - if (m <= 1) { - if (m <= 0) - return -1; - /* use special case for 1-character strings */ - if (mode == FAST_COUNT) { - for (i = 0; i < n; i++) - if (s[i] == p[0]) - count++; - return count; - } else { - for (i = 0; i < n; i++) - if (s[i] == p[0]) - return i; - } - return -1; - } - - mlast = m - 1; - - /* create compressed boyer-moore delta 1 table */ - skip = mlast - 1; - /* process pattern[:-1] */ - for (mask = i = 0; i < mlast; i++) { - mask |= (1 << (p[i] & 0x1F)); - if (p[i] == p[mlast]) - skip = mlast - i - 1; - } - /* process pattern[-1] outside the loop */ - mask |= (1 << (p[mlast] & 0x1F)); - - for (i = 0; i <= w; i++) { - /* note: using mlast in the skip path slows things down on x86 */ - if (s[i+m-1] == p[m-1]) { - /* candidate match */ - for (j = 0; j < mlast; j++) - if (s[i+j] != p[j]) - break; - if (j == mlast) { - /* got a match! */ - if (mode != FAST_COUNT) - return i; - count++; - i = i + mlast; - continue; - } - /* miss: check if next character is part of pattern */ - if (!(mask & (1 << (s[i+m] & 0x1F)))) - i = i + m; - else - i = i + skip; - } else { - /* skip: check if next character is part of pattern */ - if (!(mask & (1 << (s[i+m] & 0x1F)))) - i = i + m; - } - } - - if (mode != FAST_COUNT) - return -1; - return count; -} - -#endif - -/* -Local variables: -c-basic-offset: 4 -indent-tabs-mode: nil -End: -*/ diff --git a/sys/src/cmd/python/Objects/stringlib/find.h b/sys/src/cmd/python/Objects/stringlib/find.h deleted file mode 100644 index 4cdbb096d..000000000 --- a/sys/src/cmd/python/Objects/stringlib/find.h +++ /dev/null @@ -1,113 +0,0 @@ -/* stringlib: find/index implementation */ - -#ifndef STRINGLIB_FIND_H -#define STRINGLIB_FIND_H - -#ifndef STRINGLIB_FASTSEARCH_H -#error must include "stringlib/fastsearch.h" before including this module -#endif - -Py_LOCAL_INLINE(Py_ssize_t) -stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, - const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, - Py_ssize_t offset) -{ - Py_ssize_t pos; - - if (sub_len == 0) { - if (str_len < 0) - return -1; - return offset; - } - - pos = fastsearch(str, str_len, sub, sub_len, FAST_SEARCH); - - if (pos >= 0) - pos += offset; - - return pos; -} - -Py_LOCAL_INLINE(Py_ssize_t) -stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, - const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, - Py_ssize_t offset) -{ - /* XXX - create reversefastsearch helper! */ - if (sub_len == 0) { - if (str_len < 0) - return -1; - return str_len + offset; - } else { - Py_ssize_t j, pos = -1; - for (j = str_len - sub_len; j >= 0; --j) - if (STRINGLIB_CMP(str+j, sub, sub_len) == 0) { - pos = j + offset; - break; - } - return pos; - } -} - -Py_LOCAL_INLINE(Py_ssize_t) -stringlib_find_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, - const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, - Py_ssize_t start, Py_ssize_t end) -{ - if (start < 0) - start += str_len; - if (start < 0) - start = 0; - if (end > str_len) - end = str_len; - if (end < 0) - end += str_len; - if (end < 0) - end = 0; - - return stringlib_find( - str + start, end - start, - sub, sub_len, start - ); -} - -Py_LOCAL_INLINE(Py_ssize_t) -stringlib_rfind_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, - const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, - Py_ssize_t start, Py_ssize_t end) -{ - if (start < 0) - start += str_len; - if (start < 0) - start = 0; - if (end > str_len) - end = str_len; - if (end < 0) - end += str_len; - if (end < 0) - end = 0; - - return stringlib_rfind(str + start, end - start, sub, sub_len, start); -} - -#ifdef STRINGLIB_STR - -Py_LOCAL_INLINE(int) -stringlib_contains_obj(PyObject* str, PyObject* sub) -{ - return stringlib_find( - STRINGLIB_STR(str), STRINGLIB_LEN(str), - STRINGLIB_STR(sub), STRINGLIB_LEN(sub), 0 - ) != -1; -} - -#endif /* STRINGLIB_STR */ - -#endif /* STRINGLIB_FIND_H */ - -/* -Local variables: -c-basic-offset: 4 -indent-tabs-mode: nil -End: -*/ diff --git a/sys/src/cmd/python/Objects/stringlib/partition.h b/sys/src/cmd/python/Objects/stringlib/partition.h deleted file mode 100644 index 105ba317d..000000000 --- a/sys/src/cmd/python/Objects/stringlib/partition.h +++ /dev/null @@ -1,111 +0,0 @@ -/* stringlib: partition implementation */ - -#ifndef STRINGLIB_PARTITION_H -#define STRINGLIB_PARTITION_H - -#ifndef STRINGLIB_FASTSEARCH_H -#error must include "stringlib/fastsearch.h" before including this module -#endif - -Py_LOCAL_INLINE(PyObject*) -stringlib_partition( - PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, - PyObject* sep_obj, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len - ) -{ - PyObject* out; - Py_ssize_t pos; - - if (sep_len == 0) { - PyErr_SetString(PyExc_ValueError, "empty separator"); - return NULL; - } - - out = PyTuple_New(3); - if (!out) - return NULL; - - pos = fastsearch(str, str_len, sep, sep_len, FAST_SEARCH); - - if (pos < 0) { - Py_INCREF(str_obj); - PyTuple_SET_ITEM(out, 0, (PyObject*) str_obj); - Py_INCREF(STRINGLIB_EMPTY); - PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY); - Py_INCREF(STRINGLIB_EMPTY); - PyTuple_SET_ITEM(out, 2, (PyObject*) STRINGLIB_EMPTY); - return out; - } - - PyTuple_SET_ITEM(out, 0, STRINGLIB_NEW(str, pos)); - Py_INCREF(sep_obj); - PyTuple_SET_ITEM(out, 1, sep_obj); - pos += sep_len; - PyTuple_SET_ITEM(out, 2, STRINGLIB_NEW(str + pos, str_len - pos)); - - if (PyErr_Occurred()) { - Py_DECREF(out); - return NULL; - } - - return out; -} - -Py_LOCAL_INLINE(PyObject*) -stringlib_rpartition( - PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, - PyObject* sep_obj, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len - ) -{ - PyObject* out; - Py_ssize_t pos, j; - - if (sep_len == 0) { - PyErr_SetString(PyExc_ValueError, "empty separator"); - return NULL; - } - - out = PyTuple_New(3); - if (!out) - return NULL; - - /* XXX - create reversefastsearch helper! */ - pos = -1; - for (j = str_len - sep_len; j >= 0; --j) - if (STRINGLIB_CMP(str+j, sep, sep_len) == 0) { - pos = j; - break; - } - - if (pos < 0) { - Py_INCREF(STRINGLIB_EMPTY); - PyTuple_SET_ITEM(out, 0, (PyObject*) STRINGLIB_EMPTY); - Py_INCREF(STRINGLIB_EMPTY); - PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY); - Py_INCREF(str_obj); - PyTuple_SET_ITEM(out, 2, (PyObject*) str_obj); - return out; - } - - PyTuple_SET_ITEM(out, 0, STRINGLIB_NEW(str, pos)); - Py_INCREF(sep_obj); - PyTuple_SET_ITEM(out, 1, sep_obj); - pos += sep_len; - PyTuple_SET_ITEM(out, 2, STRINGLIB_NEW(str + pos, str_len - pos)); - - if (PyErr_Occurred()) { - Py_DECREF(out); - return NULL; - } - - return out; -} - -#endif - -/* -Local variables: -c-basic-offset: 4 -indent-tabs-mode: nil -End: -*/ diff --git a/sys/src/cmd/python/Objects/stringobject.c b/sys/src/cmd/python/Objects/stringobject.c deleted file mode 100644 index 5ae2ca06c..000000000 --- a/sys/src/cmd/python/Objects/stringobject.c +++ /dev/null @@ -1,5009 +0,0 @@ -/* String object implementation */ - -#define PY_SSIZE_T_CLEAN - -#include "Python.h" - -#include <ctype.h> - -#ifdef COUNT_ALLOCS -int null_strings, one_strings; -#endif - -static PyStringObject *characters[UCHAR_MAX + 1]; -static PyStringObject *nullstring; - -/* This dictionary holds all interned strings. Note that references to - strings in this dictionary are *not* counted in the string's ob_refcnt. - When the interned string reaches a refcnt of 0 the string deallocation - function will delete the reference from this dictionary. - - Another way to look at this is that to say that the actual reference - count of a string is: s->ob_refcnt + (s->ob_sstate?2:0) -*/ -static PyObject *interned; - -/* - For both PyString_FromString() and PyString_FromStringAndSize(), the - parameter `size' denotes number of characters to allocate, not counting any - null terminating character. - - For PyString_FromString(), the parameter `str' points to a null-terminated - string containing exactly `size' bytes. - - For PyString_FromStringAndSize(), the parameter the parameter `str' is - either NULL or else points to a string containing at least `size' bytes. - For PyString_FromStringAndSize(), the string in the `str' parameter does - not have to be null-terminated. (Therefore it is safe to construct a - substring by calling `PyString_FromStringAndSize(origstring, substrlen)'.) - If `str' is NULL then PyString_FromStringAndSize() will allocate `size+1' - bytes (setting the last byte to the null terminating character) and you can - fill in the data yourself. If `str' is non-NULL then the resulting - PyString object must be treated as immutable and you must not fill in nor - alter the data yourself, since the strings may be shared. - - The PyObject member `op->ob_size', which denotes the number of "extra - items" in a variable-size object, will contain the number of bytes - allocated for string data, not counting the null terminating character. It - is therefore equal to the equal to the `size' parameter (for - PyString_FromStringAndSize()) or the length of the string in the `str' - parameter (for PyString_FromString()). -*/ -PyObject * -PyString_FromStringAndSize(const char *str, Py_ssize_t size) -{ - register PyStringObject *op; - assert(size >= 0); - if (size == 0 && (op = nullstring) != NULL) { -#ifdef COUNT_ALLOCS - null_strings++; -#endif - Py_INCREF(op); - return (PyObject *)op; - } - if (size == 1 && str != NULL && - (op = characters[*str & UCHAR_MAX]) != NULL) - { -#ifdef COUNT_ALLOCS - one_strings++; -#endif - Py_INCREF(op); - return (PyObject *)op; - } - - /* Inline PyObject_NewVar */ - op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); - if (op == NULL) - return PyErr_NoMemory(); - PyObject_INIT_VAR(op, &PyString_Type, size); - op->ob_shash = -1; - op->ob_sstate = SSTATE_NOT_INTERNED; - if (str != NULL) - Py_MEMCPY(op->ob_sval, str, size); - op->ob_sval[size] = '\0'; - /* share short strings */ - if (size == 0) { - PyObject *t = (PyObject *)op; - PyString_InternInPlace(&t); - op = (PyStringObject *)t; - nullstring = op; - Py_INCREF(op); - } else if (size == 1 && str != NULL) { - PyObject *t = (PyObject *)op; - PyString_InternInPlace(&t); - op = (PyStringObject *)t; - characters[*str & UCHAR_MAX] = op; - Py_INCREF(op); - } - return (PyObject *) op; -} - -PyObject * -PyString_FromString(const char *str) -{ - register size_t size; - register PyStringObject *op; - - assert(str != NULL); - size = strlen(str); - if (size > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "string is too long for a Python string"); - return NULL; - } - if (size == 0 && (op = nullstring) != NULL) { -#ifdef COUNT_ALLOCS - null_strings++; -#endif - Py_INCREF(op); - return (PyObject *)op; - } - if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) { -#ifdef COUNT_ALLOCS - one_strings++; -#endif - Py_INCREF(op); - return (PyObject *)op; - } - - /* Inline PyObject_NewVar */ - op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); - if (op == NULL) - return PyErr_NoMemory(); - PyObject_INIT_VAR(op, &PyString_Type, size); - op->ob_shash = -1; - op->ob_sstate = SSTATE_NOT_INTERNED; - Py_MEMCPY(op->ob_sval, str, size+1); - /* share short strings */ - if (size == 0) { - PyObject *t = (PyObject *)op; - PyString_InternInPlace(&t); - op = (PyStringObject *)t; - nullstring = op; - Py_INCREF(op); - } else if (size == 1) { - PyObject *t = (PyObject *)op; - PyString_InternInPlace(&t); - op = (PyStringObject *)t; - characters[*str & UCHAR_MAX] = op; - Py_INCREF(op); - } - return (PyObject *) op; -} - -PyObject * -PyString_FromFormatV(const char *format, va_list vargs) -{ - va_list count; - Py_ssize_t n = 0; - const char* f; - char *s; - PyObject* string; - -#ifdef VA_LIST_IS_ARRAY - Py_MEMCPY(count, vargs, sizeof(va_list)); -#else -#ifdef __va_copy - __va_copy(count, vargs); -#else - count = vargs; -#endif -#endif - /* step 1: figure out how large a buffer we need */ - for (f = format; *f; f++) { - if (*f == '%') { - const char* p = f; - while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f))) - ; - - /* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since - * they don't affect the amount of space we reserve. - */ - if ((*f == 'l' || *f == 'z') && - (f[1] == 'd' || f[1] == 'u')) - ++f; - - switch (*f) { - case 'c': - (void)va_arg(count, int); - /* fall through... */ - case '%': - n++; - break; - case 'd': case 'u': case 'i': case 'x': - (void) va_arg(count, int); - /* 20 bytes is enough to hold a 64-bit - integer. Decimal takes the most space. - This isn't enough for octal. */ - n += 20; - break; - case 's': - s = va_arg(count, char*); - n += strlen(s); - break; - case 'p': - (void) va_arg(count, int); - /* maximum 64-bit pointer representation: - * 0xffffffffffffffff - * so 19 characters is enough. - * XXX I count 18 -- what's the extra for? - */ - n += 19; - break; - default: - /* if we stumble upon an unknown - formatting code, copy the rest of - the format string to the output - string. (we cannot just skip the - code, since there's no way to know - what's in the argument list) */ - n += strlen(p); - goto expand; - } - } else - n++; - } - expand: - /* step 2: fill the buffer */ - /* Since we've analyzed how much space we need for the worst case, - use sprintf directly instead of the slower PyOS_snprintf. */ - string = PyString_FromStringAndSize(NULL, n); - if (!string) - return NULL; - - s = PyString_AsString(string); - - for (f = format; *f; f++) { - if (*f == '%') { - const char* p = f++; - Py_ssize_t i; - int longflag = 0; - int size_tflag = 0; - /* parse the width.precision part (we're only - interested in the precision value, if any) */ - n = 0; - while (isdigit(Py_CHARMASK(*f))) - n = (n*10) + *f++ - '0'; - if (*f == '.') { - f++; - n = 0; - while (isdigit(Py_CHARMASK(*f))) - n = (n*10) + *f++ - '0'; - } - while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f))) - f++; - /* handle the long flag, but only for %ld and %lu. - others can be added when necessary. */ - if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) { - longflag = 1; - ++f; - } - /* handle the size_t flag. */ - if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) { - size_tflag = 1; - ++f; - } - - switch (*f) { - case 'c': - *s++ = va_arg(vargs, int); - break; - case 'd': - if (longflag) - sprintf(s, "%ld", va_arg(vargs, long)); - else if (size_tflag) - sprintf(s, "%" PY_FORMAT_SIZE_T "d", - va_arg(vargs, Py_ssize_t)); - else - sprintf(s, "%d", va_arg(vargs, int)); - s += strlen(s); - break; - case 'u': - if (longflag) - sprintf(s, "%lu", - va_arg(vargs, unsigned long)); - else if (size_tflag) - sprintf(s, "%" PY_FORMAT_SIZE_T "u", - va_arg(vargs, size_t)); - else - sprintf(s, "%u", - va_arg(vargs, unsigned int)); - s += strlen(s); - break; - case 'i': - sprintf(s, "%i", va_arg(vargs, int)); - s += strlen(s); - break; - case 'x': - sprintf(s, "%x", va_arg(vargs, int)); - s += strlen(s); - break; - case 's': - p = va_arg(vargs, char*); - i = strlen(p); - if (n > 0 && i > n) - i = n; - Py_MEMCPY(s, p, i); - s += i; - break; - case 'p': - sprintf(s, "%p", va_arg(vargs, void*)); - /* %p is ill-defined: ensure leading 0x. */ - if (s[1] == 'X') - s[1] = 'x'; - else if (s[1] != 'x') { - memmove(s+2, s, strlen(s)+1); - s[0] = '0'; - s[1] = 'x'; - } - s += strlen(s); - break; - case '%': - *s++ = '%'; - break; - default: - strcpy(s, p); - s += strlen(s); - goto end; - } - } else - *s++ = *f; - } - - end: - _PyString_Resize(&string, s - PyString_AS_STRING(string)); - return string; -} - -PyObject * -PyString_FromFormat(const char *format, ...) -{ - PyObject* ret; - va_list vargs; - -#ifdef HAVE_STDARG_PROTOTYPES - va_start(vargs, format); -#else - va_start(vargs); -#endif - ret = PyString_FromFormatV(format, vargs); - va_end(vargs); - return ret; -} - - -PyObject *PyString_Decode(const char *s, - Py_ssize_t size, - const char *encoding, - const char *errors) -{ - PyObject *v, *str; - - str = PyString_FromStringAndSize(s, size); - if (str == NULL) - return NULL; - v = PyString_AsDecodedString(str, encoding, errors); - Py_DECREF(str); - return v; -} - -PyObject *PyString_AsDecodedObject(PyObject *str, - const char *encoding, - const char *errors) -{ - PyObject *v; - - if (!PyString_Check(str)) { - PyErr_BadArgument(); - goto onError; - } - - if (encoding == NULL) { -#ifdef Py_USING_UNICODE - encoding = PyUnicode_GetDefaultEncoding(); -#else - PyErr_SetString(PyExc_ValueError, "no encoding specified"); - goto onError; -#endif - } - - /* Decode via the codec registry */ - v = PyCodec_Decode(str, encoding, errors); - if (v == NULL) - goto onError; - - return v; - - onError: - return NULL; -} - -PyObject *PyString_AsDecodedString(PyObject *str, - const char *encoding, - const char *errors) -{ - PyObject *v; - - v = PyString_AsDecodedObject(str, encoding, errors); - if (v == NULL) - goto onError; - -#ifdef Py_USING_UNICODE - /* Convert Unicode to a string using the default encoding */ - if (PyUnicode_Check(v)) { - PyObject *temp = v; - v = PyUnicode_AsEncodedString(v, NULL, NULL); - Py_DECREF(temp); - if (v == NULL) - goto onError; - } -#endif - if (!PyString_Check(v)) { - PyErr_Format(PyExc_TypeError, - "decoder did not return a string object (type=%.400s)", - v->ob_type->tp_name); - Py_DECREF(v); - goto onError; - } - - return v; - - onError: - return NULL; -} - -PyObject *PyString_Encode(const char *s, - Py_ssize_t size, - const char *encoding, - const char *errors) -{ - PyObject *v, *str; - - str = PyString_FromStringAndSize(s, size); - if (str == NULL) - return NULL; - v = PyString_AsEncodedString(str, encoding, errors); - Py_DECREF(str); - return v; -} - -PyObject *PyString_AsEncodedObject(PyObject *str, - const char *encoding, - const char *errors) -{ - PyObject *v; - - if (!PyString_Check(str)) { - PyErr_BadArgument(); - goto onError; - } - - if (encoding == NULL) { -#ifdef Py_USING_UNICODE - encoding = PyUnicode_GetDefaultEncoding(); -#else - PyErr_SetString(PyExc_ValueError, "no encoding specified"); - goto onError; -#endif - } - - /* Encode via the codec registry */ - v = PyCodec_Encode(str, encoding, errors); - if (v == NULL) - goto onError; - - return v; - - onError: - return NULL; -} - -PyObject *PyString_AsEncodedString(PyObject *str, - const char *encoding, - const char *errors) -{ - PyObject *v; - - v = PyString_AsEncodedObject(str, encoding, errors); - if (v == NULL) - goto onError; - -#ifdef Py_USING_UNICODE - /* Convert Unicode to a string using the default encoding */ - if (PyUnicode_Check(v)) { - PyObject *temp = v; - v = PyUnicode_AsEncodedString(v, NULL, NULL); - Py_DECREF(temp); - if (v == NULL) - goto onError; - } -#endif - if (!PyString_Check(v)) { - PyErr_Format(PyExc_TypeError, - "encoder did not return a string object (type=%.400s)", - v->ob_type->tp_name); - Py_DECREF(v); - goto onError; - } - - return v; - - onError: - return NULL; -} - -static void -string_dealloc(PyObject *op) -{ - switch (PyString_CHECK_INTERNED(op)) { - case SSTATE_NOT_INTERNED: - break; - - case SSTATE_INTERNED_MORTAL: - /* revive dead object temporarily for DelItem */ - op->ob_refcnt = 3; - if (PyDict_DelItem(interned, op) != 0) - Py_FatalError( - "deletion of interned string failed"); - break; - - case SSTATE_INTERNED_IMMORTAL: - Py_FatalError("Immortal interned string died."); - - default: - Py_FatalError("Inconsistent interned string state."); - } - op->ob_type->tp_free(op); -} - -/* Unescape a backslash-escaped string. If unicode is non-zero, - the string is a u-literal. If recode_encoding is non-zero, - the string is UTF-8 encoded and should be re-encoded in the - specified encoding. */ - -PyObject *PyString_DecodeEscape(const char *s, - Py_ssize_t len, - const char *errors, - Py_ssize_t unicode, - const char *recode_encoding) -{ - int c; - char *p, *buf; - const char *end; - PyObject *v; - Py_ssize_t newlen = recode_encoding ? 4*len:len; - v = PyString_FromStringAndSize((char *)NULL, newlen); - if (v == NULL) - return NULL; - p = buf = PyString_AsString(v); - end = s + len; - while (s < end) { - if (*s != '\\') { - non_esc: -#ifdef Py_USING_UNICODE - if (recode_encoding && (*s & 0x80)) { - PyObject *u, *w; - char *r; - const char* t; - Py_ssize_t rn; - t = s; - /* Decode non-ASCII bytes as UTF-8. */ - while (t < end && (*t & 0x80)) t++; - u = PyUnicode_DecodeUTF8(s, t - s, errors); - if(!u) goto failed; - - /* Recode them in target encoding. */ - w = PyUnicode_AsEncodedString( - u, recode_encoding, errors); - Py_DECREF(u); - if (!w) goto failed; - - /* Append bytes to output buffer. */ - assert(PyString_Check(w)); - r = PyString_AS_STRING(w); - rn = PyString_GET_SIZE(w); - Py_MEMCPY(p, r, rn); - p += rn; - Py_DECREF(w); - s = t; - } else { - *p++ = *s++; - } -#else - *p++ = *s++; -#endif - continue; - } - s++; - if (s==end) { - PyErr_SetString(PyExc_ValueError, - "Trailing \\ in string"); - goto failed; - } - switch (*s++) { - /* XXX This assumes ASCII! */ - case '\n': break; - case '\\': *p++ = '\\'; break; - case '\'': *p++ = '\''; break; - case '\"': *p++ = '\"'; break; - case 'b': *p++ = '\b'; break; - case 'f': *p++ = '\014'; break; /* FF */ - case 't': *p++ = '\t'; break; - case 'n': *p++ = '\n'; break; - case 'r': *p++ = '\r'; break; - case 'v': *p++ = '\013'; break; /* VT */ - case 'a': *p++ = '\007'; break; /* BEL, not classic C */ - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - c = s[-1] - '0'; - if ('0' <= *s && *s <= '7') { - c = (c<<3) + *s++ - '0'; - if ('0' <= *s && *s <= '7') - c = (c<<3) + *s++ - '0'; - } - *p++ = c; - break; - case 'x': - if (isxdigit(Py_CHARMASK(s[0])) - && isxdigit(Py_CHARMASK(s[1]))) { - unsigned int x = 0; - c = Py_CHARMASK(*s); - s++; - if (isdigit(c)) - x = c - '0'; - else if (islower(c)) - x = 10 + c - 'a'; - else - x = 10 + c - 'A'; - x = x << 4; - c = Py_CHARMASK(*s); - s++; - if (isdigit(c)) - x += c - '0'; - else if (islower(c)) - x += 10 + c - 'a'; - else - x += 10 + c - 'A'; - *p++ = x; - break; - } - if (!errors || strcmp(errors, "strict") == 0) { - PyErr_SetString(PyExc_ValueError, - "invalid \\x escape"); - goto failed; - } - if (strcmp(errors, "replace") == 0) { - *p++ = '?'; - } else if (strcmp(errors, "ignore") == 0) - /* do nothing */; - else { - PyErr_Format(PyExc_ValueError, - "decoding error; " - "unknown error handling code: %.400s", - errors); - goto failed; - } -#ifndef Py_USING_UNICODE - case 'u': - case 'U': - case 'N': - if (unicode) { - PyErr_SetString(PyExc_ValueError, - "Unicode escapes not legal " - "when Unicode disabled"); - goto failed; - } -#endif - default: - *p++ = '\\'; - s--; - goto non_esc; /* an arbitry number of unescaped - UTF-8 bytes may follow. */ - } - } - if (p-buf < newlen) - _PyString_Resize(&v, p - buf); - return v; - failed: - Py_DECREF(v); - return NULL; -} - -/* -------------------------------------------------------------------- */ -/* object api */ - -static Py_ssize_t -string_getsize(register PyObject *op) -{ - char *s; - Py_ssize_t len; - if (PyString_AsStringAndSize(op, &s, &len)) - return -1; - return len; -} - -static /*const*/ char * -string_getbuffer(register PyObject *op) -{ - char *s; - Py_ssize_t len; - if (PyString_AsStringAndSize(op, &s, &len)) - return NULL; - return s; -} - -Py_ssize_t -PyString_Size(register PyObject *op) -{ - if (!PyString_Check(op)) - return string_getsize(op); - return ((PyStringObject *)op) -> ob_size; -} - -/*const*/ char * -PyString_AsString(register PyObject *op) -{ - if (!PyString_Check(op)) - return string_getbuffer(op); - return ((PyStringObject *)op) -> ob_sval; -} - -int -PyString_AsStringAndSize(register PyObject *obj, - register char **s, - register Py_ssize_t *len) -{ - if (s == NULL) { - PyErr_BadInternalCall(); - return -1; - } - - if (!PyString_Check(obj)) { -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(obj)) { - obj = _PyUnicode_AsDefaultEncodedString(obj, NULL); - if (obj == NULL) - return -1; - } - else -#endif - { - PyErr_Format(PyExc_TypeError, - "expected string or Unicode object, " - "%.200s found", obj->ob_type->tp_name); - return -1; - } - } - - *s = PyString_AS_STRING(obj); - if (len != NULL) - *len = PyString_GET_SIZE(obj); - else if (strlen(*s) != (size_t)PyString_GET_SIZE(obj)) { - PyErr_SetString(PyExc_TypeError, - "expected string without null bytes"); - return -1; - } - return 0; -} - -/* -------------------------------------------------------------------- */ -/* Methods */ - -#define STRINGLIB_CHAR char - -#define STRINGLIB_CMP memcmp -#define STRINGLIB_LEN PyString_GET_SIZE -#define STRINGLIB_NEW PyString_FromStringAndSize -#define STRINGLIB_STR PyString_AS_STRING - -#define STRINGLIB_EMPTY nullstring - -#include "stringlib/fastsearch.h" - -#include "stringlib/count.h" -#include "stringlib/find.h" -#include "stringlib/partition.h" - - -static int -string_print(PyStringObject *op, FILE *fp, int flags) -{ - Py_ssize_t i; - char c; - int quote; - - /* XXX Ought to check for interrupts when writing long strings */ - if (! PyString_CheckExact(op)) { - int ret; - /* A str subclass may have its own __str__ method. */ - op = (PyStringObject *) PyObject_Str((PyObject *)op); - if (op == NULL) - return -1; - ret = string_print(op, fp, flags); - Py_DECREF(op); - return ret; - } - if (flags & Py_PRINT_RAW) { - char *data = op->ob_sval; - Py_ssize_t size = op->ob_size; - while (size > INT_MAX) { - /* Very long strings cannot be written atomically. - * But don't write exactly INT_MAX bytes at a time - * to avoid memory aligment issues. - */ - const int chunk_size = INT_MAX & ~0x3FFF; - fwrite(data, 1, chunk_size, fp); - data += chunk_size; - size -= chunk_size; - } -#ifdef __VMS - if (size) fwrite(data, (int)size, 1, fp); -#else - fwrite(data, 1, (int)size, fp); -#endif - return 0; - } - - /* figure out which quote to use; single is preferred */ - quote = '\''; - if (memchr(op->ob_sval, '\'', op->ob_size) && - !memchr(op->ob_sval, '"', op->ob_size)) - quote = '"'; - - fputc(quote, fp); - for (i = 0; i < op->ob_size; i++) { - c = op->ob_sval[i]; - if (c == quote || c == '\\') - fprintf(fp, "\\%c", c); - else if (c == '\t') - fprintf(fp, "\\t"); - else if (c == '\n') - fprintf(fp, "\\n"); - else if (c == '\r') - fprintf(fp, "\\r"); - else if (c < ' ' || c >= 0x7f) - fprintf(fp, "\\x%02x", c & 0xff); - else - fputc(c, fp); - } - fputc(quote, fp); - return 0; -} - -PyObject * -PyString_Repr(PyObject *obj, int smartquotes) -{ - register PyStringObject* op = (PyStringObject*) obj; - size_t newsize = 2 + 4 * op->ob_size; - PyObject *v; - if (newsize > PY_SSIZE_T_MAX || newsize / 4 != op->ob_size) { - PyErr_SetString(PyExc_OverflowError, - "string is too large to make repr"); - } - v = PyString_FromStringAndSize((char *)NULL, newsize); - if (v == NULL) { - return NULL; - } - else { - register Py_ssize_t i; - register char c; - register char *p; - int quote; - - /* figure out which quote to use; single is preferred */ - quote = '\''; - if (smartquotes && - memchr(op->ob_sval, '\'', op->ob_size) && - !memchr(op->ob_sval, '"', op->ob_size)) - quote = '"'; - - p = PyString_AS_STRING(v); - *p++ = quote; - for (i = 0; i < op->ob_size; i++) { - /* There's at least enough room for a hex escape - and a closing quote. */ - assert(newsize - (p - PyString_AS_STRING(v)) >= 5); - c = op->ob_sval[i]; - if (c == quote || c == '\\') - *p++ = '\\', *p++ = c; - else if (c == '\t') - *p++ = '\\', *p++ = 't'; - else if (c == '\n') - *p++ = '\\', *p++ = 'n'; - else if (c == '\r') - *p++ = '\\', *p++ = 'r'; - else if (c < ' ' || c >= 0x7f) { - /* For performance, we don't want to call - PyOS_snprintf here (extra layers of - function call). */ - sprintf(p, "\\x%02x", c & 0xff); - p += 4; - } - else - *p++ = c; - } - assert(newsize - (p - PyString_AS_STRING(v)) >= 1); - *p++ = quote; - *p = '\0'; - _PyString_Resize( - &v, (p - PyString_AS_STRING(v))); - return v; - } -} - -static PyObject * -string_repr(PyObject *op) -{ - return PyString_Repr(op, 1); -} - -static PyObject * -string_str(PyObject *s) -{ - assert(PyString_Check(s)); - if (PyString_CheckExact(s)) { - Py_INCREF(s); - return s; - } - else { - /* Subtype -- return genuine string with the same value. */ - PyStringObject *t = (PyStringObject *) s; - return PyString_FromStringAndSize(t->ob_sval, t->ob_size); - } -} - -static Py_ssize_t -string_length(PyStringObject *a) -{ - return a->ob_size; -} - -static PyObject * -string_concat(register PyStringObject *a, register PyObject *bb) -{ - register Py_ssize_t size; - register PyStringObject *op; - if (!PyString_Check(bb)) { -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(bb)) - return PyUnicode_Concat((PyObject *)a, bb); -#endif - PyErr_Format(PyExc_TypeError, - "cannot concatenate 'str' and '%.200s' objects", - bb->ob_type->tp_name); - return NULL; - } -#define b ((PyStringObject *)bb) - /* Optimize cases with empty left or right operand */ - if ((a->ob_size == 0 || b->ob_size == 0) && - PyString_CheckExact(a) && PyString_CheckExact(b)) { - if (a->ob_size == 0) { - Py_INCREF(bb); - return bb; - } - Py_INCREF(a); - return (PyObject *)a; - } - size = a->ob_size + b->ob_size; - if (size < 0) { - PyErr_SetString(PyExc_OverflowError, - "strings are too large to concat"); - return NULL; - } - - /* Inline PyObject_NewVar */ - op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); - if (op == NULL) - return PyErr_NoMemory(); - PyObject_INIT_VAR(op, &PyString_Type, size); - op->ob_shash = -1; - op->ob_sstate = SSTATE_NOT_INTERNED; - Py_MEMCPY(op->ob_sval, a->ob_sval, a->ob_size); - Py_MEMCPY(op->ob_sval + a->ob_size, b->ob_sval, b->ob_size); - op->ob_sval[size] = '\0'; - return (PyObject *) op; -#undef b -} - -static PyObject * -string_repeat(register PyStringObject *a, register Py_ssize_t n) -{ - register Py_ssize_t i; - register Py_ssize_t j; - register Py_ssize_t size; - register PyStringObject *op; - size_t nbytes; - if (n < 0) - n = 0; - /* watch out for overflows: the size can overflow int, - * and the # of bytes needed can overflow size_t - */ - size = a->ob_size * n; - if (n && size / n != a->ob_size) { - PyErr_SetString(PyExc_OverflowError, - "repeated string is too long"); - return NULL; - } - if (size == a->ob_size && PyString_CheckExact(a)) { - Py_INCREF(a); - return (PyObject *)a; - } - nbytes = (size_t)size; - if (nbytes + sizeof(PyStringObject) <= nbytes) { - PyErr_SetString(PyExc_OverflowError, - "repeated string is too long"); - return NULL; - } - op = (PyStringObject *) - PyObject_MALLOC(sizeof(PyStringObject) + nbytes); - if (op == NULL) - return PyErr_NoMemory(); - PyObject_INIT_VAR(op, &PyString_Type, size); - op->ob_shash = -1; - op->ob_sstate = SSTATE_NOT_INTERNED; - op->ob_sval[size] = '\0'; - if (a->ob_size == 1 && n > 0) { - memset(op->ob_sval, a->ob_sval[0] , n); - return (PyObject *) op; - } - i = 0; - if (i < size) { - Py_MEMCPY(op->ob_sval, a->ob_sval, a->ob_size); - i = a->ob_size; - } - while (i < size) { - j = (i <= size-i) ? i : size-i; - Py_MEMCPY(op->ob_sval+i, op->ob_sval, j); - i += j; - } - return (PyObject *) op; -} - -/* String slice a[i:j] consists of characters a[i] ... a[j-1] */ - -static PyObject * -string_slice(register PyStringObject *a, register Py_ssize_t i, - register Py_ssize_t j) - /* j -- may be negative! */ -{ - if (i < 0) - i = 0; - if (j < 0) - j = 0; /* Avoid signed/unsigned bug in next line */ - if (j > a->ob_size) - j = a->ob_size; - if (i == 0 && j == a->ob_size && PyString_CheckExact(a)) { - /* It's the same as a */ - Py_INCREF(a); - return (PyObject *)a; - } - if (j < i) - j = i; - return PyString_FromStringAndSize(a->ob_sval + i, j-i); -} - -static int -string_contains(PyObject *str_obj, PyObject *sub_obj) -{ - if (!PyString_CheckExact(sub_obj)) { -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(sub_obj)) - return PyUnicode_Contains(str_obj, sub_obj); -#endif - if (!PyString_Check(sub_obj)) { - PyErr_SetString(PyExc_TypeError, - "'in <string>' requires string as left operand"); - return -1; - } - } - - return stringlib_contains_obj(str_obj, sub_obj); -} - -static PyObject * -string_item(PyStringObject *a, register Py_ssize_t i) -{ - char pchar; - PyObject *v; - if (i < 0 || i >= a->ob_size) { - PyErr_SetString(PyExc_IndexError, "string index out of range"); - return NULL; - } - pchar = a->ob_sval[i]; - v = (PyObject *)characters[pchar & UCHAR_MAX]; - if (v == NULL) - v = PyString_FromStringAndSize(&pchar, 1); - else { -#ifdef COUNT_ALLOCS - one_strings++; -#endif - Py_INCREF(v); - } - return v; -} - -static PyObject* -string_richcompare(PyStringObject *a, PyStringObject *b, int op) -{ - int c; - Py_ssize_t len_a, len_b; - Py_ssize_t min_len; - PyObject *result; - - /* Make sure both arguments are strings. */ - if (!(PyString_Check(a) && PyString_Check(b))) { - result = Py_NotImplemented; - goto out; - } - if (a == b) { - switch (op) { - case Py_EQ:case Py_LE:case Py_GE: - result = Py_True; - goto out; - case Py_NE:case Py_LT:case Py_GT: - result = Py_False; - goto out; - } - } - if (op == Py_EQ) { - /* Supporting Py_NE here as well does not save - much time, since Py_NE is rarely used. */ - if (a->ob_size == b->ob_size - && (a->ob_sval[0] == b->ob_sval[0] - && memcmp(a->ob_sval, b->ob_sval, - a->ob_size) == 0)) { - result = Py_True; - } else { - result = Py_False; - } - goto out; - } - len_a = a->ob_size; len_b = b->ob_size; - min_len = (len_a < len_b) ? len_a : len_b; - if (min_len > 0) { - c = Py_CHARMASK(*a->ob_sval) - Py_CHARMASK(*b->ob_sval); - if (c==0) - c = memcmp(a->ob_sval, b->ob_sval, min_len); - }else - c = 0; - if (c == 0) - c = (len_a < len_b) ? -1 : (len_a > len_b) ? 1 : 0; - switch (op) { - case Py_LT: c = c < 0; break; - case Py_LE: c = c <= 0; break; - case Py_EQ: assert(0); break; /* unreachable */ - case Py_NE: c = c != 0; break; - case Py_GT: c = c > 0; break; - case Py_GE: c = c >= 0; break; - default: - result = Py_NotImplemented; - goto out; - } - result = c ? Py_True : Py_False; - out: - Py_INCREF(result); - return result; -} - -int -_PyString_Eq(PyObject *o1, PyObject *o2) -{ - PyStringObject *a = (PyStringObject*) o1; - PyStringObject *b = (PyStringObject*) o2; - return a->ob_size == b->ob_size - && *a->ob_sval == *b->ob_sval - && memcmp(a->ob_sval, b->ob_sval, a->ob_size) == 0; -} - -static long -string_hash(PyStringObject *a) -{ - register Py_ssize_t len; - register unsigned char *p; - register long x; - - if (a->ob_shash != -1) - return a->ob_shash; - len = a->ob_size; - p = (unsigned char *) a->ob_sval; - x = *p << 7; - while (--len >= 0) - x = (1000003*x) ^ *p++; - x ^= a->ob_size; - if (x == -1) - x = -2; - a->ob_shash = x; - return x; -} - -static PyObject* -string_subscript(PyStringObject* self, PyObject* item) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += PyString_GET_SIZE(self); - return string_item(self, i); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength, cur, i; - char* source_buf; - char* result_buf; - PyObject* result; - - if (PySlice_GetIndicesEx((PySliceObject*)item, - PyString_GET_SIZE(self), - &start, &stop, &step, &slicelength) < 0) { - return NULL; - } - - if (slicelength <= 0) { - return PyString_FromStringAndSize("", 0); - } - else { - source_buf = PyString_AsString((PyObject*)self); - result_buf = (char *)PyMem_Malloc(slicelength); - if (result_buf == NULL) - return PyErr_NoMemory(); - - for (cur = start, i = 0; i < slicelength; - cur += step, i++) { - result_buf[i] = source_buf[cur]; - } - - result = PyString_FromStringAndSize(result_buf, - slicelength); - PyMem_Free(result_buf); - return result; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "string indices must be integers"); - return NULL; - } -} - -static Py_ssize_t -string_buffer_getreadbuf(PyStringObject *self, Py_ssize_t index, const void **ptr) -{ - if ( index != 0 ) { - PyErr_SetString(PyExc_SystemError, - "accessing non-existent string segment"); - return -1; - } - *ptr = (void *)self->ob_sval; - return self->ob_size; -} - -static Py_ssize_t -string_buffer_getwritebuf(PyStringObject *self, Py_ssize_t index, const void **ptr) -{ - PyErr_SetString(PyExc_TypeError, - "Cannot use string as modifiable buffer"); - return -1; -} - -static Py_ssize_t -string_buffer_getsegcount(PyStringObject *self, Py_ssize_t *lenp) -{ - if ( lenp ) - *lenp = self->ob_size; - return 1; -} - -static Py_ssize_t -string_buffer_getcharbuf(PyStringObject *self, Py_ssize_t index, const char **ptr) -{ - if ( index != 0 ) { - PyErr_SetString(PyExc_SystemError, - "accessing non-existent string segment"); - return -1; - } - *ptr = self->ob_sval; - return self->ob_size; -} - -static PySequenceMethods string_as_sequence = { - (lenfunc)string_length, /*sq_length*/ - (binaryfunc)string_concat, /*sq_concat*/ - (ssizeargfunc)string_repeat, /*sq_repeat*/ - (ssizeargfunc)string_item, /*sq_item*/ - (ssizessizeargfunc)string_slice, /*sq_slice*/ - 0, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ - (objobjproc)string_contains /*sq_contains*/ -}; - -static PyMappingMethods string_as_mapping = { - (lenfunc)string_length, - (binaryfunc)string_subscript, - 0, -}; - -static PyBufferProcs string_as_buffer = { - (readbufferproc)string_buffer_getreadbuf, - (writebufferproc)string_buffer_getwritebuf, - (segcountproc)string_buffer_getsegcount, - (charbufferproc)string_buffer_getcharbuf, -}; - - - -#define LEFTSTRIP 0 -#define RIGHTSTRIP 1 -#define BOTHSTRIP 2 - -/* Arrays indexed by above */ -static const char *stripformat[] = {"|O:lstrip", "|O:rstrip", "|O:strip"}; - -#define STRIPNAME(i) (stripformat[i]+3) - - -/* Don't call if length < 2 */ -#define Py_STRING_MATCH(target, offset, pattern, length) \ - (target[offset] == pattern[0] && \ - target[offset+length-1] == pattern[length-1] && \ - !memcmp(target+offset+1, pattern+1, length-2) ) - - -/* Overallocate the initial list to reduce the number of reallocs for small - split sizes. Eg, "A A A A A A A A A A".split() (10 elements) has three - resizes, to sizes 4, 8, then 16. Most observed string splits are for human - text (roughly 11 words per line) and field delimited data (usually 1-10 - fields). For large strings the split algorithms are bandwidth limited - so increasing the preallocation likely will not improve things.*/ - -#define MAX_PREALLOC 12 - -/* 5 splits gives 6 elements */ -#define PREALLOC_SIZE(maxsplit) \ - (maxsplit >= MAX_PREALLOC ? MAX_PREALLOC : maxsplit+1) - -#define SPLIT_APPEND(data, left, right) \ - str = PyString_FromStringAndSize((data) + (left), \ - (right) - (left)); \ - if (str == NULL) \ - goto onError; \ - if (PyList_Append(list, str)) { \ - Py_DECREF(str); \ - goto onError; \ - } \ - else \ - Py_DECREF(str); - -#define SPLIT_ADD(data, left, right) { \ - str = PyString_FromStringAndSize((data) + (left), \ - (right) - (left)); \ - if (str == NULL) \ - goto onError; \ - if (count < MAX_PREALLOC) { \ - PyList_SET_ITEM(list, count, str); \ - } else { \ - if (PyList_Append(list, str)) { \ - Py_DECREF(str); \ - goto onError; \ - } \ - else \ - Py_DECREF(str); \ - } \ - count++; } - -/* Always force the list to the expected size. */ -#define FIX_PREALLOC_SIZE(list) ((PyListObject *)list)->ob_size = count - -#define SKIP_SPACE(s, i, len) { while (i<len && isspace(Py_CHARMASK(s[i]))) i++; } -#define SKIP_NONSPACE(s, i, len) { while (i<len && !isspace(Py_CHARMASK(s[i]))) i++; } -#define RSKIP_SPACE(s, i) { while (i>=0 && isspace(Py_CHARMASK(s[i]))) i--; } -#define RSKIP_NONSPACE(s, i) { while (i>=0 && !isspace(Py_CHARMASK(s[i]))) i--; } - -Py_LOCAL_INLINE(PyObject *) -split_whitespace(const char *s, Py_ssize_t len, Py_ssize_t maxsplit) -{ - Py_ssize_t i, j, count=0; - PyObject *str; - PyObject *list = PyList_New(PREALLOC_SIZE(maxsplit)); - - if (list == NULL) - return NULL; - - i = j = 0; - - while (maxsplit-- > 0) { - SKIP_SPACE(s, i, len); - if (i==len) break; - j = i; i++; - SKIP_NONSPACE(s, i, len); - SPLIT_ADD(s, j, i); - } - - if (i < len) { - /* Only occurs when maxsplit was reached */ - /* Skip any remaining whitespace and copy to end of string */ - SKIP_SPACE(s, i, len); - if (i != len) - SPLIT_ADD(s, i, len); - } - FIX_PREALLOC_SIZE(list); - return list; - onError: - Py_DECREF(list); - return NULL; -} - -Py_LOCAL_INLINE(PyObject *) -split_char(const char *s, Py_ssize_t len, char ch, Py_ssize_t maxcount) -{ - register Py_ssize_t i, j, count=0; - PyObject *str; - PyObject *list = PyList_New(PREALLOC_SIZE(maxcount)); - - if (list == NULL) - return NULL; - - i = j = 0; - while ((j < len) && (maxcount-- > 0)) { - for(; j<len; j++) { - /* I found that using memchr makes no difference */ - if (s[j] == ch) { - SPLIT_ADD(s, i, j); - i = j = j + 1; - break; - } - } - } - if (i <= len) { - SPLIT_ADD(s, i, len); - } - FIX_PREALLOC_SIZE(list); - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -PyDoc_STRVAR(split__doc__, -"S.split([sep [,maxsplit]]) -> list of strings\n\ -\n\ -Return a list of the words in the string S, using sep as the\n\ -delimiter string. If maxsplit is given, at most maxsplit\n\ -splits are done. If sep is not specified or is None, any\n\ -whitespace string is a separator."); - -static PyObject * -string_split(PyStringObject *self, PyObject *args) -{ - Py_ssize_t len = PyString_GET_SIZE(self), n, i, j; - Py_ssize_t maxsplit = -1, count=0; - const char *s = PyString_AS_STRING(self), *sub; - PyObject *list, *str, *subobj = Py_None; -#ifdef USE_FAST - Py_ssize_t pos; -#endif - - if (!PyArg_ParseTuple(args, "|On:split", &subobj, &maxsplit)) - return NULL; - if (maxsplit < 0) - maxsplit = PY_SSIZE_T_MAX; - if (subobj == Py_None) - return split_whitespace(s, len, maxsplit); - if (PyString_Check(subobj)) { - sub = PyString_AS_STRING(subobj); - n = PyString_GET_SIZE(subobj); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(subobj)) - return PyUnicode_Split((PyObject *)self, subobj, maxsplit); -#endif - else if (PyObject_AsCharBuffer(subobj, &sub, &n)) - return NULL; - - if (n == 0) { - PyErr_SetString(PyExc_ValueError, "empty separator"); - return NULL; - } - else if (n == 1) - return split_char(s, len, sub[0], maxsplit); - - list = PyList_New(PREALLOC_SIZE(maxsplit)); - if (list == NULL) - return NULL; - -#ifdef USE_FAST - i = j = 0; - while (maxsplit-- > 0) { - pos = fastsearch(s+i, len-i, sub, n, FAST_SEARCH); - if (pos < 0) - break; - j = i+pos; - SPLIT_ADD(s, i, j); - i = j + n; - } -#else - i = j = 0; - while ((j+n <= len) && (maxsplit-- > 0)) { - for (; j+n <= len; j++) { - if (Py_STRING_MATCH(s, j, sub, n)) { - SPLIT_ADD(s, i, j); - i = j = j + n; - break; - } - } - } -#endif - SPLIT_ADD(s, i, len); - FIX_PREALLOC_SIZE(list); - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -PyDoc_STRVAR(partition__doc__, -"S.partition(sep) -> (head, sep, tail)\n\ -\n\ -Searches for the separator sep in S, and returns the part before it,\n\ -the separator itself, and the part after it. If the separator is not\n\ -found, returns S and two empty strings."); - -static PyObject * -string_partition(PyStringObject *self, PyObject *sep_obj) -{ - const char *sep; - Py_ssize_t sep_len; - - if (PyString_Check(sep_obj)) { - sep = PyString_AS_STRING(sep_obj); - sep_len = PyString_GET_SIZE(sep_obj); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(sep_obj)) - return PyUnicode_Partition((PyObject *) self, sep_obj); -#endif - else if (PyObject_AsCharBuffer(sep_obj, &sep, &sep_len)) - return NULL; - - return stringlib_partition( - (PyObject*) self, - PyString_AS_STRING(self), PyString_GET_SIZE(self), - sep_obj, sep, sep_len - ); -} - -PyDoc_STRVAR(rpartition__doc__, -"S.rpartition(sep) -> (tail, sep, head)\n\ -\n\ -Searches for the separator sep in S, starting at the end of S, and returns\n\ -the part before it, the separator itself, and the part after it. If the\n\ -separator is not found, returns two empty strings and S."); - -static PyObject * -string_rpartition(PyStringObject *self, PyObject *sep_obj) -{ - const char *sep; - Py_ssize_t sep_len; - - if (PyString_Check(sep_obj)) { - sep = PyString_AS_STRING(sep_obj); - sep_len = PyString_GET_SIZE(sep_obj); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(sep_obj)) - return PyUnicode_Partition((PyObject *) self, sep_obj); -#endif - else if (PyObject_AsCharBuffer(sep_obj, &sep, &sep_len)) - return NULL; - - return stringlib_rpartition( - (PyObject*) self, - PyString_AS_STRING(self), PyString_GET_SIZE(self), - sep_obj, sep, sep_len - ); -} - -Py_LOCAL_INLINE(PyObject *) -rsplit_whitespace(const char *s, Py_ssize_t len, Py_ssize_t maxsplit) -{ - Py_ssize_t i, j, count=0; - PyObject *str; - PyObject *list = PyList_New(PREALLOC_SIZE(maxsplit)); - - if (list == NULL) - return NULL; - - i = j = len-1; - - while (maxsplit-- > 0) { - RSKIP_SPACE(s, i); - if (i<0) break; - j = i; i--; - RSKIP_NONSPACE(s, i); - SPLIT_ADD(s, i + 1, j + 1); - } - if (i >= 0) { - /* Only occurs when maxsplit was reached */ - /* Skip any remaining whitespace and copy to beginning of string */ - RSKIP_SPACE(s, i); - if (i >= 0) - SPLIT_ADD(s, 0, i + 1); - - } - FIX_PREALLOC_SIZE(list); - if (PyList_Reverse(list) < 0) - goto onError; - return list; - onError: - Py_DECREF(list); - return NULL; -} - -Py_LOCAL_INLINE(PyObject *) -rsplit_char(const char *s, Py_ssize_t len, char ch, Py_ssize_t maxcount) -{ - register Py_ssize_t i, j, count=0; - PyObject *str; - PyObject *list = PyList_New(PREALLOC_SIZE(maxcount)); - - if (list == NULL) - return NULL; - - i = j = len - 1; - while ((i >= 0) && (maxcount-- > 0)) { - for (; i >= 0; i--) { - if (s[i] == ch) { - SPLIT_ADD(s, i + 1, j + 1); - j = i = i - 1; - break; - } - } - } - if (j >= -1) { - SPLIT_ADD(s, 0, j + 1); - } - FIX_PREALLOC_SIZE(list); - if (PyList_Reverse(list) < 0) - goto onError; - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -PyDoc_STRVAR(rsplit__doc__, -"S.rsplit([sep [,maxsplit]]) -> list of strings\n\ -\n\ -Return a list of the words in the string S, using sep as the\n\ -delimiter string, starting at the end of the string and working\n\ -to the front. If maxsplit is given, at most maxsplit splits are\n\ -done. If sep is not specified or is None, any whitespace string\n\ -is a separator."); - -static PyObject * -string_rsplit(PyStringObject *self, PyObject *args) -{ - Py_ssize_t len = PyString_GET_SIZE(self), n, i, j; - Py_ssize_t maxsplit = -1, count=0; - const char *s = PyString_AS_STRING(self), *sub; - PyObject *list, *str, *subobj = Py_None; - - if (!PyArg_ParseTuple(args, "|On:rsplit", &subobj, &maxsplit)) - return NULL; - if (maxsplit < 0) - maxsplit = PY_SSIZE_T_MAX; - if (subobj == Py_None) - return rsplit_whitespace(s, len, maxsplit); - if (PyString_Check(subobj)) { - sub = PyString_AS_STRING(subobj); - n = PyString_GET_SIZE(subobj); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(subobj)) - return PyUnicode_RSplit((PyObject *)self, subobj, maxsplit); -#endif - else if (PyObject_AsCharBuffer(subobj, &sub, &n)) - return NULL; - - if (n == 0) { - PyErr_SetString(PyExc_ValueError, "empty separator"); - return NULL; - } - else if (n == 1) - return rsplit_char(s, len, sub[0], maxsplit); - - list = PyList_New(PREALLOC_SIZE(maxsplit)); - if (list == NULL) - return NULL; - - j = len; - i = j - n; - - while ( (i >= 0) && (maxsplit-- > 0) ) { - for (; i>=0; i--) { - if (Py_STRING_MATCH(s, i, sub, n)) { - SPLIT_ADD(s, i + n, j); - j = i; - i -= n; - break; - } - } - } - SPLIT_ADD(s, 0, j); - FIX_PREALLOC_SIZE(list); - if (PyList_Reverse(list) < 0) - goto onError; - return list; - -onError: - Py_DECREF(list); - return NULL; -} - - -PyDoc_STRVAR(join__doc__, -"S.join(sequence) -> string\n\ -\n\ -Return a string which is the concatenation of the strings in the\n\ -sequence. The separator between elements is S."); - -static PyObject * -string_join(PyStringObject *self, PyObject *orig) -{ - char *sep = PyString_AS_STRING(self); - const Py_ssize_t seplen = PyString_GET_SIZE(self); - PyObject *res = NULL; - char *p; - Py_ssize_t seqlen = 0; - size_t sz = 0; - Py_ssize_t i; - PyObject *seq, *item; - - seq = PySequence_Fast(orig, ""); - if (seq == NULL) { - return NULL; - } - - seqlen = PySequence_Size(seq); - if (seqlen == 0) { - Py_DECREF(seq); - return PyString_FromString(""); - } - if (seqlen == 1) { - item = PySequence_Fast_GET_ITEM(seq, 0); - if (PyString_CheckExact(item) || PyUnicode_CheckExact(item)) { - Py_INCREF(item); - Py_DECREF(seq); - return item; - } - } - - /* There are at least two things to join, or else we have a subclass - * of the builtin types in the sequence. - * Do a pre-pass to figure out the total amount of space we'll - * need (sz), see whether any argument is absurd, and defer to - * the Unicode join if appropriate. - */ - for (i = 0; i < seqlen; i++) { - const size_t old_sz = sz; - item = PySequence_Fast_GET_ITEM(seq, i); - if (!PyString_Check(item)){ -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(item)) { - /* Defer to Unicode join. - * CAUTION: There's no gurantee that the - * original sequence can be iterated over - * again, so we must pass seq here. - */ - PyObject *result; - result = PyUnicode_Join((PyObject *)self, seq); - Py_DECREF(seq); - return result; - } -#endif - PyErr_Format(PyExc_TypeError, - "sequence item %zd: expected string," - " %.80s found", - i, item->ob_type->tp_name); - Py_DECREF(seq); - return NULL; - } - sz += PyString_GET_SIZE(item); - if (i != 0) - sz += seplen; - if (sz < old_sz || sz > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "join() result is too long for a Python string"); - Py_DECREF(seq); - return NULL; - } - } - - /* Allocate result space. */ - res = PyString_FromStringAndSize((char*)NULL, sz); - if (res == NULL) { - Py_DECREF(seq); - return NULL; - } - - /* Catenate everything. */ - p = PyString_AS_STRING(res); - for (i = 0; i < seqlen; ++i) { - size_t n; - item = PySequence_Fast_GET_ITEM(seq, i); - n = PyString_GET_SIZE(item); - Py_MEMCPY(p, PyString_AS_STRING(item), n); - p += n; - if (i < seqlen - 1) { - Py_MEMCPY(p, sep, seplen); - p += seplen; - } - } - - Py_DECREF(seq); - return res; -} - -PyObject * -_PyString_Join(PyObject *sep, PyObject *x) -{ - assert(sep != NULL && PyString_Check(sep)); - assert(x != NULL); - return string_join((PyStringObject *)sep, x); -} - -Py_LOCAL_INLINE(void) -string_adjust_indices(Py_ssize_t *start, Py_ssize_t *end, Py_ssize_t len) -{ - if (*end > len) - *end = len; - else if (*end < 0) - *end += len; - if (*end < 0) - *end = 0; - if (*start < 0) - *start += len; - if (*start < 0) - *start = 0; -} - -Py_LOCAL_INLINE(Py_ssize_t) -string_find_internal(PyStringObject *self, PyObject *args, int dir) -{ - PyObject *subobj; - const char *sub; - Py_ssize_t sub_len; - Py_ssize_t start=0, end=PY_SSIZE_T_MAX; - - if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return -2; - if (PyString_Check(subobj)) { - sub = PyString_AS_STRING(subobj); - sub_len = PyString_GET_SIZE(subobj); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(subobj)) - return PyUnicode_Find( - (PyObject *)self, subobj, start, end, dir); -#endif - else if (PyObject_AsCharBuffer(subobj, &sub, &sub_len)) - /* XXX - the "expected a character buffer object" is pretty - confusing for a non-expert. remap to something else ? */ - return -2; - - if (dir > 0) - return stringlib_find_slice( - PyString_AS_STRING(self), PyString_GET_SIZE(self), - sub, sub_len, start, end); - else - return stringlib_rfind_slice( - PyString_AS_STRING(self), PyString_GET_SIZE(self), - sub, sub_len, start, end); -} - - -PyDoc_STRVAR(find__doc__, -"S.find(sub [,start [,end]]) -> int\n\ -\n\ -Return the lowest index in S where substring sub is found,\n\ -such that sub is contained within s[start,end]. Optional\n\ -arguments start and end are interpreted as in slice notation.\n\ -\n\ -Return -1 on failure."); - -static PyObject * -string_find(PyStringObject *self, PyObject *args) -{ - Py_ssize_t result = string_find_internal(self, args, +1); - if (result == -2) - return NULL; - return PyInt_FromSsize_t(result); -} - - -PyDoc_STRVAR(index__doc__, -"S.index(sub [,start [,end]]) -> int\n\ -\n\ -Like S.find() but raise ValueError when the substring is not found."); - -static PyObject * -string_index(PyStringObject *self, PyObject *args) -{ - Py_ssize_t result = string_find_internal(self, args, +1); - if (result == -2) - return NULL; - if (result == -1) { - PyErr_SetString(PyExc_ValueError, - "substring not found"); - return NULL; - } - return PyInt_FromSsize_t(result); -} - - -PyDoc_STRVAR(rfind__doc__, -"S.rfind(sub [,start [,end]]) -> int\n\ -\n\ -Return the highest index in S where substring sub is found,\n\ -such that sub is contained within s[start,end]. Optional\n\ -arguments start and end are interpreted as in slice notation.\n\ -\n\ -Return -1 on failure."); - -static PyObject * -string_rfind(PyStringObject *self, PyObject *args) -{ - Py_ssize_t result = string_find_internal(self, args, -1); - if (result == -2) - return NULL; - return PyInt_FromSsize_t(result); -} - - -PyDoc_STRVAR(rindex__doc__, -"S.rindex(sub [,start [,end]]) -> int\n\ -\n\ -Like S.rfind() but raise ValueError when the substring is not found."); - -static PyObject * -string_rindex(PyStringObject *self, PyObject *args) -{ - Py_ssize_t result = string_find_internal(self, args, -1); - if (result == -2) - return NULL; - if (result == -1) { - PyErr_SetString(PyExc_ValueError, - "substring not found"); - return NULL; - } - return PyInt_FromSsize_t(result); -} - - -Py_LOCAL_INLINE(PyObject *) -do_xstrip(PyStringObject *self, int striptype, PyObject *sepobj) -{ - char *s = PyString_AS_STRING(self); - Py_ssize_t len = PyString_GET_SIZE(self); - char *sep = PyString_AS_STRING(sepobj); - Py_ssize_t seplen = PyString_GET_SIZE(sepobj); - Py_ssize_t i, j; - - i = 0; - if (striptype != RIGHTSTRIP) { - while (i < len && memchr(sep, Py_CHARMASK(s[i]), seplen)) { - i++; - } - } - - j = len; - if (striptype != LEFTSTRIP) { - do { - j--; - } while (j >= i && memchr(sep, Py_CHARMASK(s[j]), seplen)); - j++; - } - - if (i == 0 && j == len && PyString_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*)self; - } - else - return PyString_FromStringAndSize(s+i, j-i); -} - - -Py_LOCAL_INLINE(PyObject *) -do_strip(PyStringObject *self, int striptype) -{ - char *s = PyString_AS_STRING(self); - Py_ssize_t len = PyString_GET_SIZE(self), i, j; - - i = 0; - if (striptype != RIGHTSTRIP) { - while (i < len && isspace(Py_CHARMASK(s[i]))) { - i++; - } - } - - j = len; - if (striptype != LEFTSTRIP) { - do { - j--; - } while (j >= i && isspace(Py_CHARMASK(s[j]))); - j++; - } - - if (i == 0 && j == len && PyString_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*)self; - } - else - return PyString_FromStringAndSize(s+i, j-i); -} - - -Py_LOCAL_INLINE(PyObject *) -do_argstrip(PyStringObject *self, int striptype, PyObject *args) -{ - PyObject *sep = NULL; - - if (!PyArg_ParseTuple(args, (char *)stripformat[striptype], &sep)) - return NULL; - - if (sep != NULL && sep != Py_None) { - if (PyString_Check(sep)) - return do_xstrip(self, striptype, sep); -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(sep)) { - PyObject *uniself = PyUnicode_FromObject((PyObject *)self); - PyObject *res; - if (uniself==NULL) - return NULL; - res = _PyUnicode_XStrip((PyUnicodeObject *)uniself, - striptype, sep); - Py_DECREF(uniself); - return res; - } -#endif - PyErr_Format(PyExc_TypeError, -#ifdef Py_USING_UNICODE - "%s arg must be None, str or unicode", -#else - "%s arg must be None or str", -#endif - STRIPNAME(striptype)); - return NULL; - } - - return do_strip(self, striptype); -} - - -PyDoc_STRVAR(strip__doc__, -"S.strip([chars]) -> string or unicode\n\ -\n\ -Return a copy of the string S with leading and trailing\n\ -whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead.\n\ -If chars is unicode, S will be converted to unicode before stripping"); - -static PyObject * -string_strip(PyStringObject *self, PyObject *args) -{ - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, BOTHSTRIP); /* Common case */ - else - return do_argstrip(self, BOTHSTRIP, args); -} - - -PyDoc_STRVAR(lstrip__doc__, -"S.lstrip([chars]) -> string or unicode\n\ -\n\ -Return a copy of the string S with leading whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead.\n\ -If chars is unicode, S will be converted to unicode before stripping"); - -static PyObject * -string_lstrip(PyStringObject *self, PyObject *args) -{ - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, LEFTSTRIP); /* Common case */ - else - return do_argstrip(self, LEFTSTRIP, args); -} - - -PyDoc_STRVAR(rstrip__doc__, -"S.rstrip([chars]) -> string or unicode\n\ -\n\ -Return a copy of the string S with trailing whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead.\n\ -If chars is unicode, S will be converted to unicode before stripping"); - -static PyObject * -string_rstrip(PyStringObject *self, PyObject *args) -{ - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, RIGHTSTRIP); /* Common case */ - else - return do_argstrip(self, RIGHTSTRIP, args); -} - - -PyDoc_STRVAR(lower__doc__, -"S.lower() -> string\n\ -\n\ -Return a copy of the string S converted to lowercase."); - -/* _tolower and _toupper are defined by SUSv2, but they're not ISO C */ -#ifndef _tolower -#define _tolower tolower -#endif - -static PyObject * -string_lower(PyStringObject *self) -{ - char *s; - Py_ssize_t i, n = PyString_GET_SIZE(self); - PyObject *newobj; - - newobj = PyString_FromStringAndSize(NULL, n); - if (!newobj) - return NULL; - - s = PyString_AS_STRING(newobj); - - Py_MEMCPY(s, PyString_AS_STRING(self), n); - - for (i = 0; i < n; i++) { - int c = Py_CHARMASK(s[i]); - if (isupper(c)) - s[i] = _tolower(c); - } - - return newobj; -} - -PyDoc_STRVAR(upper__doc__, -"S.upper() -> string\n\ -\n\ -Return a copy of the string S converted to uppercase."); - -#ifndef _toupper -#define _toupper toupper -#endif - -static PyObject * -string_upper(PyStringObject *self) -{ - char *s; - Py_ssize_t i, n = PyString_GET_SIZE(self); - PyObject *newobj; - - newobj = PyString_FromStringAndSize(NULL, n); - if (!newobj) - return NULL; - - s = PyString_AS_STRING(newobj); - - Py_MEMCPY(s, PyString_AS_STRING(self), n); - - for (i = 0; i < n; i++) { - int c = Py_CHARMASK(s[i]); - if (islower(c)) - s[i] = _toupper(c); - } - - return newobj; -} - -PyDoc_STRVAR(title__doc__, -"S.title() -> string\n\ -\n\ -Return a titlecased version of S, i.e. words start with uppercase\n\ -characters, all remaining cased characters have lowercase."); - -static PyObject* -string_title(PyStringObject *self) -{ - char *s = PyString_AS_STRING(self), *s_new; - Py_ssize_t i, n = PyString_GET_SIZE(self); - int previous_is_cased = 0; - PyObject *newobj; - - newobj = PyString_FromStringAndSize(NULL, n); - if (newobj == NULL) - return NULL; - s_new = PyString_AsString(newobj); - for (i = 0; i < n; i++) { - int c = Py_CHARMASK(*s++); - if (islower(c)) { - if (!previous_is_cased) - c = toupper(c); - previous_is_cased = 1; - } else if (isupper(c)) { - if (previous_is_cased) - c = tolower(c); - previous_is_cased = 1; - } else - previous_is_cased = 0; - *s_new++ = c; - } - return newobj; -} - -PyDoc_STRVAR(capitalize__doc__, -"S.capitalize() -> string\n\ -\n\ -Return a copy of the string S with only its first character\n\ -capitalized."); - -static PyObject * -string_capitalize(PyStringObject *self) -{ - char *s = PyString_AS_STRING(self), *s_new; - Py_ssize_t i, n = PyString_GET_SIZE(self); - PyObject *newobj; - - newobj = PyString_FromStringAndSize(NULL, n); - if (newobj == NULL) - return NULL; - s_new = PyString_AsString(newobj); - if (0 < n) { - int c = Py_CHARMASK(*s++); - if (islower(c)) - *s_new = toupper(c); - else - *s_new = c; - s_new++; - } - for (i = 1; i < n; i++) { - int c = Py_CHARMASK(*s++); - if (isupper(c)) - *s_new = tolower(c); - else - *s_new = c; - s_new++; - } - return newobj; -} - - -PyDoc_STRVAR(count__doc__, -"S.count(sub[, start[, end]]) -> int\n\ -\n\ -Return the number of non-overlapping occurrences of substring sub in\n\ -string S[start:end]. Optional arguments start and end are interpreted\n\ -as in slice notation."); - -static PyObject * -string_count(PyStringObject *self, PyObject *args) -{ - PyObject *sub_obj; - const char *str = PyString_AS_STRING(self), *sub; - Py_ssize_t sub_len; - Py_ssize_t start = 0, end = PY_SSIZE_T_MAX; - - if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - - if (PyString_Check(sub_obj)) { - sub = PyString_AS_STRING(sub_obj); - sub_len = PyString_GET_SIZE(sub_obj); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(sub_obj)) { - Py_ssize_t count; - count = PyUnicode_Count((PyObject *)self, sub_obj, start, end); - if (count == -1) - return NULL; - else - return PyInt_FromSsize_t(count); - } -#endif - else if (PyObject_AsCharBuffer(sub_obj, &sub, &sub_len)) - return NULL; - - string_adjust_indices(&start, &end, PyString_GET_SIZE(self)); - - return PyInt_FromSsize_t( - stringlib_count(str + start, end - start, sub, sub_len) - ); -} - -PyDoc_STRVAR(swapcase__doc__, -"S.swapcase() -> string\n\ -\n\ -Return a copy of the string S with uppercase characters\n\ -converted to lowercase and vice versa."); - -static PyObject * -string_swapcase(PyStringObject *self) -{ - char *s = PyString_AS_STRING(self), *s_new; - Py_ssize_t i, n = PyString_GET_SIZE(self); - PyObject *newobj; - - newobj = PyString_FromStringAndSize(NULL, n); - if (newobj == NULL) - return NULL; - s_new = PyString_AsString(newobj); - for (i = 0; i < n; i++) { - int c = Py_CHARMASK(*s++); - if (islower(c)) { - *s_new = toupper(c); - } - else if (isupper(c)) { - *s_new = tolower(c); - } - else - *s_new = c; - s_new++; - } - return newobj; -} - - -PyDoc_STRVAR(translate__doc__, -"S.translate(table [,deletechars]) -> string\n\ -\n\ -Return a copy of the string S, where all characters occurring\n\ -in the optional argument deletechars are removed, and the\n\ -remaining characters have been mapped through the given\n\ -translation table, which must be a string of length 256."); - -static PyObject * -string_translate(PyStringObject *self, PyObject *args) -{ - register char *input, *output; - register const char *table; - register Py_ssize_t i, c, changed = 0; - PyObject *input_obj = (PyObject*)self; - const char *table1, *output_start, *del_table=NULL; - Py_ssize_t inlen, tablen, dellen = 0; - PyObject *result; - int trans_table[256]; - PyObject *tableobj, *delobj = NULL; - - if (!PyArg_UnpackTuple(args, "translate", 1, 2, - &tableobj, &delobj)) - return NULL; - - if (PyString_Check(tableobj)) { - table1 = PyString_AS_STRING(tableobj); - tablen = PyString_GET_SIZE(tableobj); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(tableobj)) { - /* Unicode .translate() does not support the deletechars - parameter; instead a mapping to None will cause characters - to be deleted. */ - if (delobj != NULL) { - PyErr_SetString(PyExc_TypeError, - "deletions are implemented differently for unicode"); - return NULL; - } - return PyUnicode_Translate((PyObject *)self, tableobj, NULL); - } -#endif - else if (PyObject_AsCharBuffer(tableobj, &table1, &tablen)) - return NULL; - - if (tablen != 256) { - PyErr_SetString(PyExc_ValueError, - "translation table must be 256 characters long"); - return NULL; - } - - if (delobj != NULL) { - if (PyString_Check(delobj)) { - del_table = PyString_AS_STRING(delobj); - dellen = PyString_GET_SIZE(delobj); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(delobj)) { - PyErr_SetString(PyExc_TypeError, - "deletions are implemented differently for unicode"); - return NULL; - } -#endif - else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen)) - return NULL; - } - else { - del_table = NULL; - dellen = 0; - } - - table = table1; - inlen = PyString_GET_SIZE(input_obj); - result = PyString_FromStringAndSize((char *)NULL, inlen); - if (result == NULL) - return NULL; - output_start = output = PyString_AsString(result); - input = PyString_AS_STRING(input_obj); - - if (dellen == 0) { - /* If no deletions are required, use faster code */ - for (i = inlen; --i >= 0; ) { - c = Py_CHARMASK(*input++); - if (Py_CHARMASK((*output++ = table[c])) != c) - changed = 1; - } - if (changed || !PyString_CheckExact(input_obj)) - return result; - Py_DECREF(result); - Py_INCREF(input_obj); - return input_obj; - } - - for (i = 0; i < 256; i++) - trans_table[i] = Py_CHARMASK(table[i]); - - for (i = 0; i < dellen; i++) - trans_table[(int) Py_CHARMASK(del_table[i])] = -1; - - for (i = inlen; --i >= 0; ) { - c = Py_CHARMASK(*input++); - if (trans_table[c] != -1) - if (Py_CHARMASK(*output++ = (char)trans_table[c]) == c) - continue; - changed = 1; - } - if (!changed && PyString_CheckExact(input_obj)) { - Py_DECREF(result); - Py_INCREF(input_obj); - return input_obj; - } - /* Fix the size of the resulting string */ - if (inlen > 0) - _PyString_Resize(&result, output - output_start); - return result; -} - - -#define FORWARD 1 -#define REVERSE -1 - -/* find and count characters and substrings */ - -#define findchar(target, target_len, c) \ - ((char *)memchr((const void *)(target), c, target_len)) - -/* String ops must return a string. */ -/* If the object is subclass of string, create a copy */ -Py_LOCAL(PyStringObject *) -return_self(PyStringObject *self) -{ - if (PyString_CheckExact(self)) { - Py_INCREF(self); - return self; - } - return (PyStringObject *)PyString_FromStringAndSize( - PyString_AS_STRING(self), - PyString_GET_SIZE(self)); -} - -Py_LOCAL_INLINE(Py_ssize_t) -countchar(const char *target, int target_len, char c, Py_ssize_t maxcount) -{ - Py_ssize_t count=0; - const char *start=target; - const char *end=target+target_len; - - while ( (start=findchar(start, end-start, c)) != NULL ) { - count++; - if (count >= maxcount) - break; - start += 1; - } - return count; -} - -Py_LOCAL(Py_ssize_t) -findstring(const char *target, Py_ssize_t target_len, - const char *pattern, Py_ssize_t pattern_len, - Py_ssize_t start, - Py_ssize_t end, - int direction) -{ - if (start < 0) { - start += target_len; - if (start < 0) - start = 0; - } - if (end > target_len) { - end = target_len; - } else if (end < 0) { - end += target_len; - if (end < 0) - end = 0; - } - - /* zero-length substrings always match at the first attempt */ - if (pattern_len == 0) - return (direction > 0) ? start : end; - - end -= pattern_len; - - if (direction < 0) { - for (; end >= start; end--) - if (Py_STRING_MATCH(target, end, pattern, pattern_len)) - return end; - } else { - for (; start <= end; start++) - if (Py_STRING_MATCH(target, start, pattern, pattern_len)) - return start; - } - return -1; -} - -Py_LOCAL_INLINE(Py_ssize_t) -countstring(const char *target, Py_ssize_t target_len, - const char *pattern, Py_ssize_t pattern_len, - Py_ssize_t start, - Py_ssize_t end, - int direction, Py_ssize_t maxcount) -{ - Py_ssize_t count=0; - - if (start < 0) { - start += target_len; - if (start < 0) - start = 0; - } - if (end > target_len) { - end = target_len; - } else if (end < 0) { - end += target_len; - if (end < 0) - end = 0; - } - - /* zero-length substrings match everywhere */ - if (pattern_len == 0 || maxcount == 0) { - if (target_len+1 < maxcount) - return target_len+1; - return maxcount; - } - - end -= pattern_len; - if (direction < 0) { - for (; (end >= start); end--) - if (Py_STRING_MATCH(target, end, pattern, pattern_len)) { - count++; - if (--maxcount <= 0) break; - end -= pattern_len-1; - } - } else { - for (; (start <= end); start++) - if (Py_STRING_MATCH(target, start, pattern, pattern_len)) { - count++; - if (--maxcount <= 0) - break; - start += pattern_len-1; - } - } - return count; -} - - -/* Algorithms for different cases of string replacement */ - -/* len(self)>=1, from="", len(to)>=1, maxcount>=1 */ -Py_LOCAL(PyStringObject *) -replace_interleave(PyStringObject *self, - const char *to_s, Py_ssize_t to_len, - Py_ssize_t maxcount) -{ - char *self_s, *result_s; - Py_ssize_t self_len, result_len; - Py_ssize_t count, i, product; - PyStringObject *result; - - self_len = PyString_GET_SIZE(self); - - /* 1 at the end plus 1 after every character */ - count = self_len+1; - if (maxcount < count) - count = maxcount; - - /* Check for overflow */ - /* result_len = count * to_len + self_len; */ - product = count * to_len; - if (product / to_len != count) { - PyErr_SetString(PyExc_OverflowError, - "replace string is too long"); - return NULL; - } - result_len = product + self_len; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, - "replace string is too long"); - return NULL; - } - - if (! (result = (PyStringObject *) - PyString_FromStringAndSize(NULL, result_len)) ) - return NULL; - - self_s = PyString_AS_STRING(self); - result_s = PyString_AS_STRING(result); - - /* TODO: special case single character, which doesn't need memcpy */ - - /* Lay the first one down (guaranteed this will occur) */ - Py_MEMCPY(result_s, to_s, to_len); - result_s += to_len; - count -= 1; - - for (i=0; i<count; i++) { - *result_s++ = *self_s++; - Py_MEMCPY(result_s, to_s, to_len); - result_s += to_len; - } - - /* Copy the rest of the original string */ - Py_MEMCPY(result_s, self_s, self_len-i); - - return result; -} - -/* Special case for deleting a single character */ -/* len(self)>=1, len(from)==1, to="", maxcount>=1 */ -Py_LOCAL(PyStringObject *) -replace_delete_single_character(PyStringObject *self, - char from_c, Py_ssize_t maxcount) -{ - char *self_s, *result_s; - char *start, *next, *end; - Py_ssize_t self_len, result_len; - Py_ssize_t count; - PyStringObject *result; - - self_len = PyString_GET_SIZE(self); - self_s = PyString_AS_STRING(self); - - count = countchar(self_s, self_len, from_c, maxcount); - if (count == 0) { - return return_self(self); - } - - result_len = self_len - count; /* from_len == 1 */ - assert(result_len>=0); - - if ( (result = (PyStringObject *) - PyString_FromStringAndSize(NULL, result_len)) == NULL) - return NULL; - result_s = PyString_AS_STRING(result); - - start = self_s; - end = self_s + self_len; - while (count-- > 0) { - next = findchar(start, end-start, from_c); - if (next == NULL) - break; - Py_MEMCPY(result_s, start, next-start); - result_s += (next-start); - start = next+1; - } - Py_MEMCPY(result_s, start, end-start); - - return result; -} - -/* len(self)>=1, len(from)>=2, to="", maxcount>=1 */ - -Py_LOCAL(PyStringObject *) -replace_delete_substring(PyStringObject *self, - const char *from_s, Py_ssize_t from_len, - Py_ssize_t maxcount) { - char *self_s, *result_s; - char *start, *next, *end; - Py_ssize_t self_len, result_len; - Py_ssize_t count, offset; - PyStringObject *result; - - self_len = PyString_GET_SIZE(self); - self_s = PyString_AS_STRING(self); - - count = countstring(self_s, self_len, - from_s, from_len, - 0, self_len, 1, - maxcount); - - if (count == 0) { - /* no matches */ - return return_self(self); - } - - result_len = self_len - (count * from_len); - assert (result_len>=0); - - if ( (result = (PyStringObject *) - PyString_FromStringAndSize(NULL, result_len)) == NULL ) - return NULL; - - result_s = PyString_AS_STRING(result); - - start = self_s; - end = self_s + self_len; - while (count-- > 0) { - offset = findstring(start, end-start, - from_s, from_len, - 0, end-start, FORWARD); - if (offset == -1) - break; - next = start + offset; - - Py_MEMCPY(result_s, start, next-start); - - result_s += (next-start); - start = next+from_len; - } - Py_MEMCPY(result_s, start, end-start); - return result; -} - -/* len(self)>=1, len(from)==len(to)==1, maxcount>=1 */ -Py_LOCAL(PyStringObject *) -replace_single_character_in_place(PyStringObject *self, - char from_c, char to_c, - Py_ssize_t maxcount) -{ - char *self_s, *result_s, *start, *end, *next; - Py_ssize_t self_len; - PyStringObject *result; - - /* The result string will be the same size */ - self_s = PyString_AS_STRING(self); - self_len = PyString_GET_SIZE(self); - - next = findchar(self_s, self_len, from_c); - - if (next == NULL) { - /* No matches; return the original string */ - return return_self(self); - } - - /* Need to make a new string */ - result = (PyStringObject *) PyString_FromStringAndSize(NULL, self_len); - if (result == NULL) - return NULL; - result_s = PyString_AS_STRING(result); - Py_MEMCPY(result_s, self_s, self_len); - - /* change everything in-place, starting with this one */ - start = result_s + (next-self_s); - *start = to_c; - start++; - end = result_s + self_len; - - while (--maxcount > 0) { - next = findchar(start, end-start, from_c); - if (next == NULL) - break; - *next = to_c; - start = next+1; - } - - return result; -} - -/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */ -Py_LOCAL(PyStringObject *) -replace_substring_in_place(PyStringObject *self, - const char *from_s, Py_ssize_t from_len, - const char *to_s, Py_ssize_t to_len, - Py_ssize_t maxcount) -{ - char *result_s, *start, *end; - char *self_s; - Py_ssize_t self_len, offset; - PyStringObject *result; - - /* The result string will be the same size */ - - self_s = PyString_AS_STRING(self); - self_len = PyString_GET_SIZE(self); - - offset = findstring(self_s, self_len, - from_s, from_len, - 0, self_len, FORWARD); - if (offset == -1) { - /* No matches; return the original string */ - return return_self(self); - } - - /* Need to make a new string */ - result = (PyStringObject *) PyString_FromStringAndSize(NULL, self_len); - if (result == NULL) - return NULL; - result_s = PyString_AS_STRING(result); - Py_MEMCPY(result_s, self_s, self_len); - - /* change everything in-place, starting with this one */ - start = result_s + offset; - Py_MEMCPY(start, to_s, from_len); - start += from_len; - end = result_s + self_len; - - while ( --maxcount > 0) { - offset = findstring(start, end-start, - from_s, from_len, - 0, end-start, FORWARD); - if (offset==-1) - break; - Py_MEMCPY(start+offset, to_s, from_len); - start += offset+from_len; - } - - return result; -} - -/* len(self)>=1, len(from)==1, len(to)>=2, maxcount>=1 */ -Py_LOCAL(PyStringObject *) -replace_single_character(PyStringObject *self, - char from_c, - const char *to_s, Py_ssize_t to_len, - Py_ssize_t maxcount) -{ - char *self_s, *result_s; - char *start, *next, *end; - Py_ssize_t self_len, result_len; - Py_ssize_t count, product; - PyStringObject *result; - - self_s = PyString_AS_STRING(self); - self_len = PyString_GET_SIZE(self); - - count = countchar(self_s, self_len, from_c, maxcount); - if (count == 0) { - /* no matches, return unchanged */ - return return_self(self); - } - - /* use the difference between current and new, hence the "-1" */ - /* result_len = self_len + count * (to_len-1) */ - product = count * (to_len-1); - if (product / (to_len-1) != count) { - PyErr_SetString(PyExc_OverflowError, "replace string is too long"); - return NULL; - } - result_len = self_len + product; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, "replace string is too long"); - return NULL; - } - - if ( (result = (PyStringObject *) - PyString_FromStringAndSize(NULL, result_len)) == NULL) - return NULL; - result_s = PyString_AS_STRING(result); - - start = self_s; - end = self_s + self_len; - while (count-- > 0) { - next = findchar(start, end-start, from_c); - if (next == NULL) - break; - - if (next == start) { - /* replace with the 'to' */ - Py_MEMCPY(result_s, to_s, to_len); - result_s += to_len; - start += 1; - } else { - /* copy the unchanged old then the 'to' */ - Py_MEMCPY(result_s, start, next-start); - result_s += (next-start); - Py_MEMCPY(result_s, to_s, to_len); - result_s += to_len; - start = next+1; - } - } - /* Copy the remainder of the remaining string */ - Py_MEMCPY(result_s, start, end-start); - - return result; -} - -/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */ -Py_LOCAL(PyStringObject *) -replace_substring(PyStringObject *self, - const char *from_s, Py_ssize_t from_len, - const char *to_s, Py_ssize_t to_len, - Py_ssize_t maxcount) { - char *self_s, *result_s; - char *start, *next, *end; - Py_ssize_t self_len, result_len; - Py_ssize_t count, offset, product; - PyStringObject *result; - - self_s = PyString_AS_STRING(self); - self_len = PyString_GET_SIZE(self); - - count = countstring(self_s, self_len, - from_s, from_len, - 0, self_len, FORWARD, maxcount); - if (count == 0) { - /* no matches, return unchanged */ - return return_self(self); - } - - /* Check for overflow */ - /* result_len = self_len + count * (to_len-from_len) */ - product = count * (to_len-from_len); - if (product / (to_len-from_len) != count) { - PyErr_SetString(PyExc_OverflowError, "replace string is too long"); - return NULL; - } - result_len = self_len + product; - if (result_len < 0) { - PyErr_SetString(PyExc_OverflowError, "replace string is too long"); - return NULL; - } - - if ( (result = (PyStringObject *) - PyString_FromStringAndSize(NULL, result_len)) == NULL) - return NULL; - result_s = PyString_AS_STRING(result); - - start = self_s; - end = self_s + self_len; - while (count-- > 0) { - offset = findstring(start, end-start, - from_s, from_len, - 0, end-start, FORWARD); - if (offset == -1) - break; - next = start+offset; - if (next == start) { - /* replace with the 'to' */ - Py_MEMCPY(result_s, to_s, to_len); - result_s += to_len; - start += from_len; - } else { - /* copy the unchanged old then the 'to' */ - Py_MEMCPY(result_s, start, next-start); - result_s += (next-start); - Py_MEMCPY(result_s, to_s, to_len); - result_s += to_len; - start = next+from_len; - } - } - /* Copy the remainder of the remaining string */ - Py_MEMCPY(result_s, start, end-start); - - return result; -} - - -Py_LOCAL(PyStringObject *) -replace(PyStringObject *self, - const char *from_s, Py_ssize_t from_len, - const char *to_s, Py_ssize_t to_len, - Py_ssize_t maxcount) -{ - if (maxcount < 0) { - maxcount = PY_SSIZE_T_MAX; - } else if (maxcount == 0 || PyString_GET_SIZE(self) == 0) { - /* nothing to do; return the original string */ - return return_self(self); - } - - if (maxcount == 0 || - (from_len == 0 && to_len == 0)) { - /* nothing to do; return the original string */ - return return_self(self); - } - - /* Handle zero-length special cases */ - - if (from_len == 0) { - /* insert the 'to' string everywhere. */ - /* >>> "Python".replace("", ".") */ - /* '.P.y.t.h.o.n.' */ - return replace_interleave(self, to_s, to_len, maxcount); - } - - /* Except for "".replace("", "A") == "A" there is no way beyond this */ - /* point for an empty self string to generate a non-empty string */ - /* Special case so the remaining code always gets a non-empty string */ - if (PyString_GET_SIZE(self) == 0) { - return return_self(self); - } - - if (to_len == 0) { - /* delete all occurances of 'from' string */ - if (from_len == 1) { - return replace_delete_single_character( - self, from_s[0], maxcount); - } else { - return replace_delete_substring(self, from_s, from_len, maxcount); - } - } - - /* Handle special case where both strings have the same length */ - - if (from_len == to_len) { - if (from_len == 1) { - return replace_single_character_in_place( - self, - from_s[0], - to_s[0], - maxcount); - } else { - return replace_substring_in_place( - self, from_s, from_len, to_s, to_len, maxcount); - } - } - - /* Otherwise use the more generic algorithms */ - if (from_len == 1) { - return replace_single_character(self, from_s[0], - to_s, to_len, maxcount); - } else { - /* len('from')>=2, len('to')>=1 */ - return replace_substring(self, from_s, from_len, to_s, to_len, maxcount); - } -} - -PyDoc_STRVAR(replace__doc__, -"S.replace (old, new[, count]) -> string\n\ -\n\ -Return a copy of string S with all occurrences of substring\n\ -old replaced by new. If the optional argument count is\n\ -given, only the first count occurrences are replaced."); - -static PyObject * -string_replace(PyStringObject *self, PyObject *args) -{ - Py_ssize_t count = -1; - PyObject *from, *to; - const char *from_s, *to_s; - Py_ssize_t from_len, to_len; - - if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count)) - return NULL; - - if (PyString_Check(from)) { - from_s = PyString_AS_STRING(from); - from_len = PyString_GET_SIZE(from); - } -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(from)) - return PyUnicode_Replace((PyObject *)self, - from, to, count); -#endif - else if (PyObject_AsCharBuffer(from, &from_s, &from_len)) - return NULL; - - if (PyString_Check(to)) { - to_s = PyString_AS_STRING(to); - to_len = PyString_GET_SIZE(to); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(to)) - return PyUnicode_Replace((PyObject *)self, - from, to, count); -#endif - else if (PyObject_AsCharBuffer(to, &to_s, &to_len)) - return NULL; - - return (PyObject *)replace((PyStringObject *) self, - from_s, from_len, - to_s, to_len, count); -} - -/** End DALKE **/ - -/* Matches the end (direction >= 0) or start (direction < 0) of self - * against substr, using the start and end arguments. Returns - * -1 on error, 0 if not found and 1 if found. - */ -Py_LOCAL(int) -_string_tailmatch(PyStringObject *self, PyObject *substr, Py_ssize_t start, - Py_ssize_t end, int direction) -{ - Py_ssize_t len = PyString_GET_SIZE(self); - Py_ssize_t slen; - const char* sub; - const char* str; - - if (PyString_Check(substr)) { - sub = PyString_AS_STRING(substr); - slen = PyString_GET_SIZE(substr); - } -#ifdef Py_USING_UNICODE - else if (PyUnicode_Check(substr)) - return PyUnicode_Tailmatch((PyObject *)self, - substr, start, end, direction); -#endif - else if (PyObject_AsCharBuffer(substr, &sub, &slen)) - return -1; - str = PyString_AS_STRING(self); - - string_adjust_indices(&start, &end, len); - - if (direction < 0) { - /* startswith */ - if (start+slen > len) - return 0; - } else { - /* endswith */ - if (end-start < slen || start > len) - return 0; - - if (end-slen > start) - start = end - slen; - } - if (end-start >= slen) - return ! memcmp(str+start, sub, slen); - return 0; -} - - -PyDoc_STRVAR(startswith__doc__, -"S.startswith(prefix[, start[, end]]) -> bool\n\ -\n\ -Return True if S starts with the specified prefix, False otherwise.\n\ -With optional start, test S beginning at that position.\n\ -With optional end, stop comparing S at that position.\n\ -prefix can also be a tuple of strings to try."); - -static PyObject * -string_startswith(PyStringObject *self, PyObject *args) -{ - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - PyObject *subobj; - int result; - - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - if (PyTuple_Check(subobj)) { - Py_ssize_t i; - for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { - result = _string_tailmatch(self, - PyTuple_GET_ITEM(subobj, i), - start, end, -1); - if (result == -1) - return NULL; - else if (result) { - Py_RETURN_TRUE; - } - } - Py_RETURN_FALSE; - } - result = _string_tailmatch(self, subobj, start, end, -1); - if (result == -1) - return NULL; - else - return PyBool_FromLong(result); -} - - -PyDoc_STRVAR(endswith__doc__, -"S.endswith(suffix[, start[, end]]) -> bool\n\ -\n\ -Return True if S ends with the specified suffix, False otherwise.\n\ -With optional start, test S beginning at that position.\n\ -With optional end, stop comparing S at that position.\n\ -suffix can also be a tuple of strings to try."); - -static PyObject * -string_endswith(PyStringObject *self, PyObject *args) -{ - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - PyObject *subobj; - int result; - - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - if (PyTuple_Check(subobj)) { - Py_ssize_t i; - for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { - result = _string_tailmatch(self, - PyTuple_GET_ITEM(subobj, i), - start, end, +1); - if (result == -1) - return NULL; - else if (result) { - Py_RETURN_TRUE; - } - } - Py_RETURN_FALSE; - } - result = _string_tailmatch(self, subobj, start, end, +1); - if (result == -1) - return NULL; - else - return PyBool_FromLong(result); -} - - -PyDoc_STRVAR(encode__doc__, -"S.encode([encoding[,errors]]) -> object\n\ -\n\ -Encodes S using the codec registered for encoding. encoding defaults\n\ -to the default encoding. errors may be given to set a different error\n\ -handling scheme. Default is 'strict' meaning that encoding errors raise\n\ -a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and\n\ -'xmlcharrefreplace' as well as any other name registered with\n\ -codecs.register_error that is able to handle UnicodeEncodeErrors."); - -static PyObject * -string_encode(PyStringObject *self, PyObject *args) -{ - char *encoding = NULL; - char *errors = NULL; - PyObject *v; - - if (!PyArg_ParseTuple(args, "|ss:encode", &encoding, &errors)) - return NULL; - v = PyString_AsEncodedObject((PyObject *)self, encoding, errors); - if (v == NULL) - goto onError; - if (!PyString_Check(v) && !PyUnicode_Check(v)) { - PyErr_Format(PyExc_TypeError, - "encoder did not return a string/unicode object " - "(type=%.400s)", - v->ob_type->tp_name); - Py_DECREF(v); - return NULL; - } - return v; - - onError: - return NULL; -} - - -PyDoc_STRVAR(decode__doc__, -"S.decode([encoding[,errors]]) -> object\n\ -\n\ -Decodes S using the codec registered for encoding. encoding defaults\n\ -to the default encoding. errors may be given to set a different error\n\ -handling scheme. Default is 'strict' meaning that encoding errors raise\n\ -a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'\n\ -as well as any other name registerd with codecs.register_error that is\n\ -able to handle UnicodeDecodeErrors."); - -static PyObject * -string_decode(PyStringObject *self, PyObject *args) -{ - char *encoding = NULL; - char *errors = NULL; - PyObject *v; - - if (!PyArg_ParseTuple(args, "|ss:decode", &encoding, &errors)) - return NULL; - v = PyString_AsDecodedObject((PyObject *)self, encoding, errors); - if (v == NULL) - goto onError; - if (!PyString_Check(v) && !PyUnicode_Check(v)) { - PyErr_Format(PyExc_TypeError, - "decoder did not return a string/unicode object " - "(type=%.400s)", - v->ob_type->tp_name); - Py_DECREF(v); - return NULL; - } - return v; - - onError: - return NULL; -} - - -PyDoc_STRVAR(expandtabs__doc__, -"S.expandtabs([tabsize]) -> string\n\ -\n\ -Return a copy of S where all tab characters are expanded using spaces.\n\ -If tabsize is not given, a tab size of 8 characters is assumed."); - -static PyObject* -string_expandtabs(PyStringObject *self, PyObject *args) -{ - const char *e, *p; - char *q; - Py_ssize_t i, j; - PyObject *u; - int tabsize = 8; - - if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize)) - return NULL; - - /* First pass: determine size of output string */ - i = j = 0; - e = PyString_AS_STRING(self) + PyString_GET_SIZE(self); - for (p = PyString_AS_STRING(self); p < e; p++) - if (*p == '\t') { - if (tabsize > 0) - j += tabsize - (j % tabsize); - } - else { - j++; - if (*p == '\n' || *p == '\r') { - i += j; - j = 0; - } - } - - /* Second pass: create output string and fill it */ - u = PyString_FromStringAndSize(NULL, i + j); - if (!u) - return NULL; - - j = 0; - q = PyString_AS_STRING(u); - - for (p = PyString_AS_STRING(self); p < e; p++) - if (*p == '\t') { - if (tabsize > 0) { - i = tabsize - (j % tabsize); - j += i; - while (i--) - *q++ = ' '; - } - } - else { - j++; - *q++ = *p; - if (*p == '\n' || *p == '\r') - j = 0; - } - - return u; -} - -Py_LOCAL_INLINE(PyObject *) -pad(PyStringObject *self, Py_ssize_t left, Py_ssize_t right, char fill) -{ - PyObject *u; - - if (left < 0) - left = 0; - if (right < 0) - right = 0; - - if (left == 0 && right == 0 && PyString_CheckExact(self)) { - Py_INCREF(self); - return (PyObject *)self; - } - - u = PyString_FromStringAndSize(NULL, - left + PyString_GET_SIZE(self) + right); - if (u) { - if (left) - memset(PyString_AS_STRING(u), fill, left); - Py_MEMCPY(PyString_AS_STRING(u) + left, - PyString_AS_STRING(self), - PyString_GET_SIZE(self)); - if (right) - memset(PyString_AS_STRING(u) + left + PyString_GET_SIZE(self), - fill, right); - } - - return u; -} - -PyDoc_STRVAR(ljust__doc__, -"S.ljust(width[, fillchar]) -> string\n" -"\n" -"Return S left justified in a string of length width. Padding is\n" -"done using the specified fill character (default is a space)."); - -static PyObject * -string_ljust(PyStringObject *self, PyObject *args) -{ - Py_ssize_t width; - char fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|c:ljust", &width, &fillchar)) - return NULL; - - if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*) self; - } - - return pad(self, 0, width - PyString_GET_SIZE(self), fillchar); -} - - -PyDoc_STRVAR(rjust__doc__, -"S.rjust(width[, fillchar]) -> string\n" -"\n" -"Return S right justified in a string of length width. Padding is\n" -"done using the specified fill character (default is a space)"); - -static PyObject * -string_rjust(PyStringObject *self, PyObject *args) -{ - Py_ssize_t width; - char fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|c:rjust", &width, &fillchar)) - return NULL; - - if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*) self; - } - - return pad(self, width - PyString_GET_SIZE(self), 0, fillchar); -} - - -PyDoc_STRVAR(center__doc__, -"S.center(width[, fillchar]) -> string\n" -"\n" -"Return S centered in a string of length width. Padding is\n" -"done using the specified fill character (default is a space)"); - -static PyObject * -string_center(PyStringObject *self, PyObject *args) -{ - Py_ssize_t marg, left; - Py_ssize_t width; - char fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|c:center", &width, &fillchar)) - return NULL; - - if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*) self; - } - - marg = width - PyString_GET_SIZE(self); - left = marg / 2 + (marg & width & 1); - - return pad(self, left, marg - left, fillchar); -} - -PyDoc_STRVAR(zfill__doc__, -"S.zfill(width) -> string\n" -"\n" -"Pad a numeric string S with zeros on the left, to fill a field\n" -"of the specified width. The string S is never truncated."); - -static PyObject * -string_zfill(PyStringObject *self, PyObject *args) -{ - Py_ssize_t fill; - PyObject *s; - char *p; - Py_ssize_t width; - - if (!PyArg_ParseTuple(args, "n:zfill", &width)) - return NULL; - - if (PyString_GET_SIZE(self) >= width) { - if (PyString_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*) self; - } - else - return PyString_FromStringAndSize( - PyString_AS_STRING(self), - PyString_GET_SIZE(self) - ); - } - - fill = width - PyString_GET_SIZE(self); - - s = pad(self, fill, 0, '0'); - - if (s == NULL) - return NULL; - - p = PyString_AS_STRING(s); - if (p[fill] == '+' || p[fill] == '-') { - /* move sign to beginning of string */ - p[0] = p[fill]; - p[fill] = '0'; - } - - return (PyObject*) s; -} - -PyDoc_STRVAR(isspace__doc__, -"S.isspace() -> bool\n\ -\n\ -Return True if all characters in S are whitespace\n\ -and there is at least one character in S, False otherwise."); - -static PyObject* -string_isspace(PyStringObject *self) -{ - register const unsigned char *p - = (unsigned char *) PyString_AS_STRING(self); - register const unsigned char *e; - - /* Shortcut for single character strings */ - if (PyString_GET_SIZE(self) == 1 && - isspace(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyString_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyString_GET_SIZE(self); - for (; p < e; p++) { - if (!isspace(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - - -PyDoc_STRVAR(isalpha__doc__, -"S.isalpha() -> bool\n\ -\n\ -Return True if all characters in S are alphabetic\n\ -and there is at least one character in S, False otherwise."); - -static PyObject* -string_isalpha(PyStringObject *self) -{ - register const unsigned char *p - = (unsigned char *) PyString_AS_STRING(self); - register const unsigned char *e; - - /* Shortcut for single character strings */ - if (PyString_GET_SIZE(self) == 1 && - isalpha(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyString_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyString_GET_SIZE(self); - for (; p < e; p++) { - if (!isalpha(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - - -PyDoc_STRVAR(isalnum__doc__, -"S.isalnum() -> bool\n\ -\n\ -Return True if all characters in S are alphanumeric\n\ -and there is at least one character in S, False otherwise."); - -static PyObject* -string_isalnum(PyStringObject *self) -{ - register const unsigned char *p - = (unsigned char *) PyString_AS_STRING(self); - register const unsigned char *e; - - /* Shortcut for single character strings */ - if (PyString_GET_SIZE(self) == 1 && - isalnum(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyString_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyString_GET_SIZE(self); - for (; p < e; p++) { - if (!isalnum(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - - -PyDoc_STRVAR(isdigit__doc__, -"S.isdigit() -> bool\n\ -\n\ -Return True if all characters in S are digits\n\ -and there is at least one character in S, False otherwise."); - -static PyObject* -string_isdigit(PyStringObject *self) -{ - register const unsigned char *p - = (unsigned char *) PyString_AS_STRING(self); - register const unsigned char *e; - - /* Shortcut for single character strings */ - if (PyString_GET_SIZE(self) == 1 && - isdigit(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyString_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyString_GET_SIZE(self); - for (; p < e; p++) { - if (!isdigit(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - - -PyDoc_STRVAR(islower__doc__, -"S.islower() -> bool\n\ -\n\ -Return True if all cased characters in S are lowercase and there is\n\ -at least one cased character in S, False otherwise."); - -static PyObject* -string_islower(PyStringObject *self) -{ - register const unsigned char *p - = (unsigned char *) PyString_AS_STRING(self); - register const unsigned char *e; - int cased; - - /* Shortcut for single character strings */ - if (PyString_GET_SIZE(self) == 1) - return PyBool_FromLong(islower(*p) != 0); - - /* Special case for empty strings */ - if (PyString_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyString_GET_SIZE(self); - cased = 0; - for (; p < e; p++) { - if (isupper(*p)) - return PyBool_FromLong(0); - else if (!cased && islower(*p)) - cased = 1; - } - return PyBool_FromLong(cased); -} - - -PyDoc_STRVAR(isupper__doc__, -"S.isupper() -> bool\n\ -\n\ -Return True if all cased characters in S are uppercase and there is\n\ -at least one cased character in S, False otherwise."); - -static PyObject* -string_isupper(PyStringObject *self) -{ - register const unsigned char *p - = (unsigned char *) PyString_AS_STRING(self); - register const unsigned char *e; - int cased; - - /* Shortcut for single character strings */ - if (PyString_GET_SIZE(self) == 1) - return PyBool_FromLong(isupper(*p) != 0); - - /* Special case for empty strings */ - if (PyString_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyString_GET_SIZE(self); - cased = 0; - for (; p < e; p++) { - if (islower(*p)) - return PyBool_FromLong(0); - else if (!cased && isupper(*p)) - cased = 1; - } - return PyBool_FromLong(cased); -} - - -PyDoc_STRVAR(istitle__doc__, -"S.istitle() -> bool\n\ -\n\ -Return True if S is a titlecased string and there is at least one\n\ -character in S, i.e. uppercase characters may only follow uncased\n\ -characters and lowercase characters only cased ones. Return False\n\ -otherwise."); - -static PyObject* -string_istitle(PyStringObject *self, PyObject *uncased) -{ - register const unsigned char *p - = (unsigned char *) PyString_AS_STRING(self); - register const unsigned char *e; - int cased, previous_is_cased; - - /* Shortcut for single character strings */ - if (PyString_GET_SIZE(self) == 1) - return PyBool_FromLong(isupper(*p) != 0); - - /* Special case for empty strings */ - if (PyString_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyString_GET_SIZE(self); - cased = 0; - previous_is_cased = 0; - for (; p < e; p++) { - register const unsigned char ch = *p; - - if (isupper(ch)) { - if (previous_is_cased) - return PyBool_FromLong(0); - previous_is_cased = 1; - cased = 1; - } - else if (islower(ch)) { - if (!previous_is_cased) - return PyBool_FromLong(0); - previous_is_cased = 1; - cased = 1; - } - else - previous_is_cased = 0; - } - return PyBool_FromLong(cased); -} - - -PyDoc_STRVAR(splitlines__doc__, -"S.splitlines([keepends]) -> list of strings\n\ -\n\ -Return a list of the lines in S, breaking at line boundaries.\n\ -Line breaks are not included in the resulting list unless keepends\n\ -is given and true."); - -static PyObject* -string_splitlines(PyStringObject *self, PyObject *args) -{ - register Py_ssize_t i; - register Py_ssize_t j; - Py_ssize_t len; - int keepends = 0; - PyObject *list; - PyObject *str; - char *data; - - if (!PyArg_ParseTuple(args, "|i:splitlines", &keepends)) - return NULL; - - data = PyString_AS_STRING(self); - len = PyString_GET_SIZE(self); - - /* This does not use the preallocated list because splitlines is - usually run with hundreds of newlines. The overhead of - switching between PyList_SET_ITEM and append causes about a - 2-3% slowdown for that common case. A smarter implementation - could move the if check out, so the SET_ITEMs are done first - and the appends only done when the prealloc buffer is full. - That's too much work for little gain.*/ - - list = PyList_New(0); - if (!list) - goto onError; - - for (i = j = 0; i < len; ) { - Py_ssize_t eol; - - /* Find a line and append it */ - while (i < len && data[i] != '\n' && data[i] != '\r') - i++; - - /* Skip the line break reading CRLF as one line break */ - eol = i; - if (i < len) { - if (data[i] == '\r' && i + 1 < len && - data[i+1] == '\n') - i += 2; - else - i++; - if (keepends) - eol = i; - } - SPLIT_APPEND(data, j, eol); - j = i; - } - if (j < len) { - SPLIT_APPEND(data, j, len); - } - - return list; - - onError: - Py_XDECREF(list); - return NULL; -} - -#undef SPLIT_APPEND -#undef SPLIT_ADD -#undef MAX_PREALLOC -#undef PREALLOC_SIZE - -static PyObject * -string_getnewargs(PyStringObject *v) -{ - return Py_BuildValue("(s#)", v->ob_sval, v->ob_size); -} - - -static PyMethodDef -string_methods[] = { - /* Counterparts of the obsolete stropmodule functions; except - string.maketrans(). */ - {"join", (PyCFunction)string_join, METH_O, join__doc__}, - {"split", (PyCFunction)string_split, METH_VARARGS, split__doc__}, - {"rsplit", (PyCFunction)string_rsplit, METH_VARARGS, rsplit__doc__}, - {"lower", (PyCFunction)string_lower, METH_NOARGS, lower__doc__}, - {"upper", (PyCFunction)string_upper, METH_NOARGS, upper__doc__}, - {"islower", (PyCFunction)string_islower, METH_NOARGS, islower__doc__}, - {"isupper", (PyCFunction)string_isupper, METH_NOARGS, isupper__doc__}, - {"isspace", (PyCFunction)string_isspace, METH_NOARGS, isspace__doc__}, - {"isdigit", (PyCFunction)string_isdigit, METH_NOARGS, isdigit__doc__}, - {"istitle", (PyCFunction)string_istitle, METH_NOARGS, istitle__doc__}, - {"isalpha", (PyCFunction)string_isalpha, METH_NOARGS, isalpha__doc__}, - {"isalnum", (PyCFunction)string_isalnum, METH_NOARGS, isalnum__doc__}, - {"capitalize", (PyCFunction)string_capitalize, METH_NOARGS, - capitalize__doc__}, - {"count", (PyCFunction)string_count, METH_VARARGS, count__doc__}, - {"endswith", (PyCFunction)string_endswith, METH_VARARGS, - endswith__doc__}, - {"partition", (PyCFunction)string_partition, METH_O, partition__doc__}, - {"find", (PyCFunction)string_find, METH_VARARGS, find__doc__}, - {"index", (PyCFunction)string_index, METH_VARARGS, index__doc__}, - {"lstrip", (PyCFunction)string_lstrip, METH_VARARGS, lstrip__doc__}, - {"replace", (PyCFunction)string_replace, METH_VARARGS, replace__doc__}, - {"rfind", (PyCFunction)string_rfind, METH_VARARGS, rfind__doc__}, - {"rindex", (PyCFunction)string_rindex, METH_VARARGS, rindex__doc__}, - {"rstrip", (PyCFunction)string_rstrip, METH_VARARGS, rstrip__doc__}, - {"rpartition", (PyCFunction)string_rpartition, METH_O, - rpartition__doc__}, - {"startswith", (PyCFunction)string_startswith, METH_VARARGS, - startswith__doc__}, - {"strip", (PyCFunction)string_strip, METH_VARARGS, strip__doc__}, - {"swapcase", (PyCFunction)string_swapcase, METH_NOARGS, - swapcase__doc__}, - {"translate", (PyCFunction)string_translate, METH_VARARGS, - translate__doc__}, - {"title", (PyCFunction)string_title, METH_NOARGS, title__doc__}, - {"ljust", (PyCFunction)string_ljust, METH_VARARGS, ljust__doc__}, - {"rjust", (PyCFunction)string_rjust, METH_VARARGS, rjust__doc__}, - {"center", (PyCFunction)string_center, METH_VARARGS, center__doc__}, - {"zfill", (PyCFunction)string_zfill, METH_VARARGS, zfill__doc__}, - {"encode", (PyCFunction)string_encode, METH_VARARGS, encode__doc__}, - {"decode", (PyCFunction)string_decode, METH_VARARGS, decode__doc__}, - {"expandtabs", (PyCFunction)string_expandtabs, METH_VARARGS, - expandtabs__doc__}, - {"splitlines", (PyCFunction)string_splitlines, METH_VARARGS, - splitlines__doc__}, - {"__getnewargs__", (PyCFunction)string_getnewargs, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject * -str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static PyObject * -string_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *x = NULL; - static char *kwlist[] = {"object", 0}; - - if (type != &PyString_Type) - return str_subtype_new(type, args, kwds); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:str", kwlist, &x)) - return NULL; - if (x == NULL) - return PyString_FromString(""); - return PyObject_Str(x); -} - -static PyObject * -str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *tmp, *pnew; - Py_ssize_t n; - - assert(PyType_IsSubtype(type, &PyString_Type)); - tmp = string_new(&PyString_Type, args, kwds); - if (tmp == NULL) - return NULL; - assert(PyString_CheckExact(tmp)); - n = PyString_GET_SIZE(tmp); - pnew = type->tp_alloc(type, n); - if (pnew != NULL) { - Py_MEMCPY(PyString_AS_STRING(pnew), PyString_AS_STRING(tmp), n+1); - ((PyStringObject *)pnew)->ob_shash = - ((PyStringObject *)tmp)->ob_shash; - ((PyStringObject *)pnew)->ob_sstate = SSTATE_NOT_INTERNED; - } - Py_DECREF(tmp); - return pnew; -} - -static PyObject * -basestring_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyErr_SetString(PyExc_TypeError, - "The basestring type cannot be instantiated"); - return NULL; -} - -static PyObject * -string_mod(PyObject *v, PyObject *w) -{ - if (!PyString_Check(v)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyString_Format(v, w); -} - -PyDoc_STRVAR(basestring_doc, -"Type basestring cannot be instantiated; it is the base for str and unicode."); - -static PyNumberMethods string_as_number = { - 0, /*nb_add*/ - 0, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - string_mod, /*nb_remainder*/ -}; - - -PyTypeObject PyBaseString_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "basestring", - 0, - 0, - 0, /* 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 */ - basestring_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &PyBaseObject_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - basestring_new, /* tp_new */ - 0, /* tp_free */ -}; - -PyDoc_STRVAR(string_doc, -"str(object) -> string\n\ -\n\ -Return a nice string representation of the object.\n\ -If the argument is a string, the return value is the same object."); - -PyTypeObject PyString_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "str", - sizeof(PyStringObject), - sizeof(char), - string_dealloc, /* tp_dealloc */ - (printfunc)string_print, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - string_repr, /* tp_repr */ - &string_as_number, /* tp_as_number */ - &string_as_sequence, /* tp_as_sequence */ - &string_as_mapping, /* tp_as_mapping */ - (hashfunc)string_hash, /* tp_hash */ - 0, /* tp_call */ - string_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - &string_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - string_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)string_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - string_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &PyBaseString_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - string_new, /* tp_new */ - PyObject_Del, /* tp_free */ -}; - -void -PyString_Concat(register PyObject **pv, register PyObject *w) -{ - register PyObject *v; - if (*pv == NULL) - return; - if (w == NULL || !PyString_Check(*pv)) { - Py_DECREF(*pv); - *pv = NULL; - return; - } - v = string_concat((PyStringObject *) *pv, w); - Py_DECREF(*pv); - *pv = v; -} - -void -PyString_ConcatAndDel(register PyObject **pv, register PyObject *w) -{ - PyString_Concat(pv, w); - Py_XDECREF(w); -} - - -/* The following function breaks the notion that strings are immutable: - it changes the size of a string. We get away with this only if there - is only one module referencing the object. You can also think of it - as creating a new string object and destroying the old one, only - more efficiently. In any case, don't use this if the string may - already be known to some other part of the code... - Note that if there's not enough memory to resize the string, the original - string object at *pv is deallocated, *pv is set to NULL, an "out of - memory" exception is set, and -1 is returned. Else (on success) 0 is - returned, and the value in *pv may or may not be the same as on input. - As always, an extra byte is allocated for a trailing \0 byte (newsize - does *not* include that), and a trailing \0 byte is stored. -*/ - -int -_PyString_Resize(PyObject **pv, Py_ssize_t newsize) -{ - register PyObject *v; - register PyStringObject *sv; - v = *pv; - if (!PyString_Check(v) || v->ob_refcnt != 1 || newsize < 0 || - PyString_CHECK_INTERNED(v)) { - *pv = 0; - Py_DECREF(v); - PyErr_BadInternalCall(); - return -1; - } - /* XXX UNREF/NEWREF interface should be more symmetrical */ - _Py_DEC_REFTOTAL; - _Py_ForgetReference(v); - *pv = (PyObject *) - PyObject_REALLOC((char *)v, sizeof(PyStringObject) + newsize); - if (*pv == NULL) { - PyObject_Del(v); - PyErr_NoMemory(); - return -1; - } - _Py_NewReference(*pv); - sv = (PyStringObject *) *pv; - sv->ob_size = newsize; - sv->ob_sval[newsize] = '\0'; - sv->ob_shash = -1; /* invalidate cached hash value */ - return 0; -} - -/* Helpers for formatstring */ - -Py_LOCAL_INLINE(PyObject *) -getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) -{ - Py_ssize_t argidx = *p_argidx; - if (argidx < arglen) { - (*p_argidx)++; - if (arglen < 0) - return args; - else - return PyTuple_GetItem(args, argidx); - } - PyErr_SetString(PyExc_TypeError, - "not enough arguments for format string"); - return NULL; -} - -/* Format codes - * F_LJUST '-' - * F_SIGN '+' - * F_BLANK ' ' - * F_ALT '#' - * F_ZERO '0' - */ -#define F_LJUST (1<<0) -#define F_SIGN (1<<1) -#define F_BLANK (1<<2) -#define F_ALT (1<<3) -#define F_ZERO (1<<4) - -Py_LOCAL_INLINE(int) -formatfloat(char *buf, size_t buflen, int flags, - int prec, int type, PyObject *v) -{ - /* fmt = '%#.' + `prec` + `type` - worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/ - char fmt[20]; - double x; - x = PyFloat_AsDouble(v); - if (x == -1.0 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "float argument required"); - return -1; - } - if (prec < 0) - prec = 6; - if (type == 'f' && fabs(x)/1e25 >= 1e25) - type = 'g'; - /* Worst case length calc to ensure no buffer overrun: - - 'g' formats: - fmt = %#.<prec>g - buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp - for any double rep.) - len = 1 + prec + 1 + 2 + 5 = 9 + prec - - 'f' formats: - buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50) - len = 1 + 50 + 1 + prec = 52 + prec - - If prec=0 the effective precision is 1 (the leading digit is - always given), therefore increase the length by one. - - */ - if ((type == 'g' && buflen <= (size_t)10 + (size_t)prec) || - (type == 'f' && buflen <= (size_t)53 + (size_t)prec)) { - PyErr_SetString(PyExc_OverflowError, - "formatted float is too long (precision too large?)"); - return -1; - } - PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c", - (flags&F_ALT) ? "#" : "", - prec, type); - PyOS_ascii_formatd(buf, buflen, fmt, x); - return (int)strlen(buf); -} - -/* _PyString_FormatLong emulates the format codes d, u, o, x and X, and - * the F_ALT flag, for Python's long (unbounded) ints. It's not used for - * Python's regular ints. - * Return value: a new PyString*, or NULL if error. - * . *pbuf is set to point into it, - * *plen set to the # of chars following that. - * Caller must decref it when done using pbuf. - * The string starting at *pbuf is of the form - * "-"? ("0x" | "0X")? digit+ - * "0x"/"0X" are present only for x and X conversions, with F_ALT - * set in flags. The case of hex digits will be correct, - * There will be at least prec digits, zero-filled on the left if - * necessary to get that many. - * val object to be converted - * flags bitmask of format flags; only F_ALT is looked at - * prec minimum number of digits; 0-fill on left if needed - * type a character in [duoxX]; u acts the same as d - * - * CAUTION: o, x and X conversions on regular ints can never - * produce a '-' sign, but can for Python's unbounded ints. - */ -PyObject* -_PyString_FormatLong(PyObject *val, int flags, int prec, int type, - char **pbuf, int *plen) -{ - PyObject *result = NULL; - char *buf; - Py_ssize_t i; - int sign; /* 1 if '-', else 0 */ - int len; /* number of characters */ - Py_ssize_t llen; - int numdigits; /* len == numnondigits + numdigits */ - int numnondigits = 0; - - switch (type) { - case 'd': - case 'u': - result = val->ob_type->tp_str(val); - break; - case 'o': - result = val->ob_type->tp_as_number->nb_oct(val); - break; - case 'x': - case 'X': - numnondigits = 2; - result = val->ob_type->tp_as_number->nb_hex(val); - break; - default: - assert(!"'type' not in [duoxX]"); - } - if (!result) - return NULL; - - buf = PyString_AsString(result); - if (!buf) { - Py_DECREF(result); - return NULL; - } - - /* To modify the string in-place, there can only be one reference. */ - if (result->ob_refcnt != 1) { - PyErr_BadInternalCall(); - return NULL; - } - llen = PyString_Size(result); - if (llen > INT_MAX) { - PyErr_SetString(PyExc_ValueError, "string too large in _PyString_FormatLong"); - return NULL; - } - len = (int)llen; - if (buf[len-1] == 'L') { - --len; - buf[len] = '\0'; - } - sign = buf[0] == '-'; - numnondigits += sign; - numdigits = len - numnondigits; - assert(numdigits > 0); - - /* Get rid of base marker unless F_ALT */ - if ((flags & F_ALT) == 0) { - /* Need to skip 0x, 0X or 0. */ - int skipped = 0; - switch (type) { - case 'o': - assert(buf[sign] == '0'); - /* If 0 is only digit, leave it alone. */ - if (numdigits > 1) { - skipped = 1; - --numdigits; - } - break; - case 'x': - case 'X': - assert(buf[sign] == '0'); - assert(buf[sign + 1] == 'x'); - skipped = 2; - numnondigits -= 2; - break; - } - if (skipped) { - buf += skipped; - len -= skipped; - if (sign) - buf[0] = '-'; - } - assert(len == numnondigits + numdigits); - assert(numdigits > 0); - } - - /* Fill with leading zeroes to meet minimum width. */ - if (prec > numdigits) { - PyObject *r1 = PyString_FromStringAndSize(NULL, - numnondigits + prec); - char *b1; - if (!r1) { - Py_DECREF(result); - return NULL; - } - b1 = PyString_AS_STRING(r1); - for (i = 0; i < numnondigits; ++i) - *b1++ = *buf++; - for (i = 0; i < prec - numdigits; i++) - *b1++ = '0'; - for (i = 0; i < numdigits; i++) - *b1++ = *buf++; - *b1 = '\0'; - Py_DECREF(result); - result = r1; - buf = PyString_AS_STRING(result); - len = numnondigits + prec; - } - - /* Fix up case for hex conversions. */ - if (type == 'X') { - /* Need to convert all lower case letters to upper case. - and need to convert 0x to 0X (and -0x to -0X). */ - for (i = 0; i < len; i++) - if (buf[i] >= 'a' && buf[i] <= 'x') - buf[i] -= 'a'-'A'; - } - *pbuf = buf; - *plen = len; - return result; -} - -Py_LOCAL_INLINE(int) -formatint(char *buf, size_t buflen, int flags, - int prec, int type, PyObject *v) -{ - /* fmt = '%#.' + `prec` + 'l' + `type` - worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine) - + 1 + 1 = 24 */ - char fmt[64]; /* plenty big enough! */ - char *sign; - long x; - - x = PyInt_AsLong(v); - if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "int argument required"); - return -1; - } - if (x < 0 && type == 'u') { - type = 'd'; - } - if (x < 0 && (type == 'x' || type == 'X' || type == 'o')) - sign = "-"; - else - sign = ""; - if (prec < 0) - prec = 1; - - if ((flags & F_ALT) && - (type == 'x' || type == 'X')) { - /* When converting under %#x or %#X, there are a number - * of issues that cause pain: - * - when 0 is being converted, the C standard leaves off - * the '0x' or '0X', which is inconsistent with other - * %#x/%#X conversions and inconsistent with Python's - * hex() function - * - there are platforms that violate the standard and - * convert 0 with the '0x' or '0X' - * (Metrowerks, Compaq Tru64) - * - there are platforms that give '0x' when converting - * under %#X, but convert 0 in accordance with the - * standard (OS/2 EMX) - * - * We can achieve the desired consistency by inserting our - * own '0x' or '0X' prefix, and substituting %x/%X in place - * of %#x/%#X. - * - * Note that this is the same approach as used in - * formatint() in unicodeobject.c - */ - PyOS_snprintf(fmt, sizeof(fmt), "%s0%c%%.%dl%c", - sign, type, prec, type); - } - else { - PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c", - sign, (flags&F_ALT) ? "#" : "", - prec, type); - } - - /* buf = '+'/'-'/'' + '0'/'0x'/'' + '[0-9]'*max(prec, len(x in octal)) - * worst case buf = '-0x' + [0-9]*prec, where prec >= 11 - */ - if (buflen <= 14 || buflen <= (size_t)3 + (size_t)prec) { - PyErr_SetString(PyExc_OverflowError, - "formatted integer is too long (precision too large?)"); - return -1; - } - if (sign[0]) - PyOS_snprintf(buf, buflen, fmt, -x); - else - PyOS_snprintf(buf, buflen, fmt, x); - return (int)strlen(buf); -} - -Py_LOCAL_INLINE(int) -formatchar(char *buf, size_t buflen, PyObject *v) -{ - /* presume that the buffer is at least 2 characters long */ - if (PyString_Check(v)) { - if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0])) - return -1; - } - else { - if (!PyArg_Parse(v, "b;%c requires int or char", &buf[0])) - return -1; - } - buf[1] = '\0'; - return 1; -} - -/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) - - FORMATBUFLEN is the length of the buffer in which the floats, ints, & - chars are formatted. XXX This is a magic number. Each formatting - routine does bounds checking to ensure no overflow, but a better - solution may be to malloc a buffer of appropriate size for each - format. For now, the current solution is sufficient. -*/ -#define FORMATBUFLEN (size_t)120 - -PyObject * -PyString_Format(PyObject *format, PyObject *args) -{ - char *fmt, *res; - Py_ssize_t arglen, argidx; - Py_ssize_t reslen, rescnt, fmtcnt; - int args_owned = 0; - PyObject *result, *orig_args; -#ifdef Py_USING_UNICODE - PyObject *v, *w; -#endif - PyObject *dict = NULL; - if (format == NULL || !PyString_Check(format) || args == NULL) { - PyErr_BadInternalCall(); - return NULL; - } - orig_args = args; - fmt = PyString_AS_STRING(format); - fmtcnt = PyString_GET_SIZE(format); - reslen = rescnt = fmtcnt + 100; - result = PyString_FromStringAndSize((char *)NULL, reslen); - if (result == NULL) - return NULL; - res = PyString_AsString(result); - if (PyTuple_Check(args)) { - arglen = PyTuple_GET_SIZE(args); - argidx = 0; - } - else { - arglen = -1; - argidx = -2; - } - if (args->ob_type->tp_as_mapping && !PyTuple_Check(args) && - !PyObject_TypeCheck(args, &PyBaseString_Type)) - dict = args; - while (--fmtcnt >= 0) { - if (*fmt != '%') { - if (--rescnt < 0) { - rescnt = fmtcnt + 100; - reslen += rescnt; - if (_PyString_Resize(&result, reslen) < 0) - return NULL; - res = PyString_AS_STRING(result) - + reslen - rescnt; - --rescnt; - } - *res++ = *fmt++; - } - else { - /* Got a format specifier */ - int flags = 0; - Py_ssize_t width = -1; - int prec = -1; - int c = '\0'; - int fill; - PyObject *v = NULL; - PyObject *temp = NULL; - char *pbuf; - int sign; - Py_ssize_t len; - char formatbuf[FORMATBUFLEN]; - /* For format{float,int,char}() */ -#ifdef Py_USING_UNICODE - char *fmt_start = fmt; - Py_ssize_t argidx_start = argidx; -#endif - - fmt++; - if (*fmt == '(') { - char *keystart; - Py_ssize_t keylen; - PyObject *key; - int pcount = 1; - - if (dict == NULL) { - PyErr_SetString(PyExc_TypeError, - "format requires a mapping"); - goto error; - } - ++fmt; - --fmtcnt; - keystart = fmt; - /* Skip over balanced parentheses */ - while (pcount > 0 && --fmtcnt >= 0) { - if (*fmt == ')') - --pcount; - else if (*fmt == '(') - ++pcount; - fmt++; - } - keylen = fmt - keystart - 1; - if (fmtcnt < 0 || pcount > 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format key"); - goto error; - } - key = PyString_FromStringAndSize(keystart, - keylen); - if (key == NULL) - goto error; - if (args_owned) { - Py_DECREF(args); - args_owned = 0; - } - args = PyObject_GetItem(dict, key); - Py_DECREF(key); - if (args == NULL) { - goto error; - } - args_owned = 1; - arglen = -1; - argidx = -2; - } - while (--fmtcnt >= 0) { - switch (c = *fmt++) { - case '-': flags |= F_LJUST; continue; - case '+': flags |= F_SIGN; continue; - case ' ': flags |= F_BLANK; continue; - case '#': flags |= F_ALT; continue; - case '0': flags |= F_ZERO; continue; - } - break; - } - if (c == '*') { - v = getnextarg(args, arglen, &argidx); - if (v == NULL) - goto error; - if (!PyInt_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "* wants int"); - goto error; - } - width = PyInt_AsLong(v); - if (width < 0) { - flags |= F_LJUST; - width = -width; - } - if (--fmtcnt >= 0) - c = *fmt++; - } - else if (c >= 0 && isdigit(c)) { - width = c - '0'; - while (--fmtcnt >= 0) { - c = Py_CHARMASK(*fmt++); - if (!isdigit(c)) - break; - if ((width*10) / 10 != width) { - PyErr_SetString( - PyExc_ValueError, - "width too big"); - goto error; - } - width = width*10 + (c - '0'); - } - } - if (c == '.') { - prec = 0; - if (--fmtcnt >= 0) - c = *fmt++; - if (c == '*') { - v = getnextarg(args, arglen, &argidx); - if (v == NULL) - goto error; - if (!PyInt_Check(v)) { - PyErr_SetString( - PyExc_TypeError, - "* wants int"); - goto error; - } - prec = PyInt_AsLong(v); - if (prec < 0) - prec = 0; - if (--fmtcnt >= 0) - c = *fmt++; - } - else if (c >= 0 && isdigit(c)) { - prec = c - '0'; - while (--fmtcnt >= 0) { - c = Py_CHARMASK(*fmt++); - if (!isdigit(c)) - break; - if ((prec*10) / 10 != prec) { - PyErr_SetString( - PyExc_ValueError, - "prec too big"); - goto error; - } - prec = prec*10 + (c - '0'); - } - } - } /* prec */ - if (fmtcnt >= 0) { - if (c == 'h' || c == 'l' || c == 'L') { - if (--fmtcnt >= 0) - c = *fmt++; - } - } - if (fmtcnt < 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format"); - goto error; - } - if (c != '%') { - v = getnextarg(args, arglen, &argidx); - if (v == NULL) - goto error; - } - sign = 0; - fill = ' '; - switch (c) { - case '%': - pbuf = "%"; - len = 1; - break; - case 's': -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(v)) { - fmt = fmt_start; - argidx = argidx_start; - goto unicode; - } -#endif - temp = _PyObject_Str(v); -#ifdef Py_USING_UNICODE - if (temp != NULL && PyUnicode_Check(temp)) { - Py_DECREF(temp); - fmt = fmt_start; - argidx = argidx_start; - goto unicode; - } -#endif - /* Fall through */ - case 'r': - if (c == 'r') - temp = PyObject_Repr(v); - if (temp == NULL) - goto error; - if (!PyString_Check(temp)) { - PyErr_SetString(PyExc_TypeError, - "%s argument has non-string str()"); - Py_DECREF(temp); - goto error; - } - pbuf = PyString_AS_STRING(temp); - len = PyString_GET_SIZE(temp); - if (prec >= 0 && len > prec) - len = prec; - break; - case 'i': - case 'd': - case 'u': - case 'o': - case 'x': - case 'X': - if (c == 'i') - c = 'd'; - if (PyLong_Check(v)) { - int ilen; - temp = _PyString_FormatLong(v, flags, - prec, c, &pbuf, &ilen); - len = ilen; - if (!temp) - goto error; - sign = 1; - } - else { - pbuf = formatbuf; - len = formatint(pbuf, - sizeof(formatbuf), - flags, prec, c, v); - if (len < 0) - goto error; - sign = 1; - } - if (flags & F_ZERO) - fill = '0'; - break; - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - if (c == 'F') - c = 'f'; - pbuf = formatbuf; - len = formatfloat(pbuf, sizeof(formatbuf), - flags, prec, c, v); - if (len < 0) - goto error; - sign = 1; - if (flags & F_ZERO) - fill = '0'; - break; - case 'c': -#ifdef Py_USING_UNICODE - if (PyUnicode_Check(v)) { - fmt = fmt_start; - argidx = argidx_start; - goto unicode; - } -#endif - pbuf = formatbuf; - len = formatchar(pbuf, sizeof(formatbuf), v); - if (len < 0) - goto error; - break; - default: - PyErr_Format(PyExc_ValueError, - "unsupported format character '%c' (0x%x) " - "at index %zd", - c, c, - (Py_ssize_t)(fmt - 1 - - PyString_AsString(format))); - goto error; - } - if (sign) { - if (*pbuf == '-' || *pbuf == '+') { - sign = *pbuf++; - len--; - } - else if (flags & F_SIGN) - sign = '+'; - else if (flags & F_BLANK) - sign = ' '; - else - sign = 0; - } - if (width < len) - width = len; - if (rescnt - (sign != 0) < width) { - reslen -= rescnt; - rescnt = width + fmtcnt + 100; - reslen += rescnt; - if (reslen < 0) { - Py_DECREF(result); - Py_XDECREF(temp); - return PyErr_NoMemory(); - } - if (_PyString_Resize(&result, reslen) < 0) { - Py_XDECREF(temp); - return NULL; - } - res = PyString_AS_STRING(result) - + reslen - rescnt; - } - if (sign) { - if (fill != ' ') - *res++ = sign; - rescnt--; - if (width > len) - width--; - } - if ((flags & F_ALT) && (c == 'x' || c == 'X')) { - assert(pbuf[0] == '0'); - assert(pbuf[1] == c); - if (fill != ' ') { - *res++ = *pbuf++; - *res++ = *pbuf++; - } - rescnt -= 2; - width -= 2; - if (width < 0) - width = 0; - len -= 2; - } - if (width > len && !(flags & F_LJUST)) { - do { - --rescnt; - *res++ = fill; - } while (--width > len); - } - if (fill == ' ') { - if (sign) - *res++ = sign; - if ((flags & F_ALT) && - (c == 'x' || c == 'X')) { - assert(pbuf[0] == '0'); - assert(pbuf[1] == c); - *res++ = *pbuf++; - *res++ = *pbuf++; - } - } - Py_MEMCPY(res, pbuf, len); - res += len; - rescnt -= len; - while (--width >= len) { - --rescnt; - *res++ = ' '; - } - if (dict && (argidx < arglen) && c != '%') { - PyErr_SetString(PyExc_TypeError, - "not all arguments converted during string formatting"); - Py_XDECREF(temp); - goto error; - } - Py_XDECREF(temp); - } /* '%' */ - } /* until end */ - if (argidx < arglen && !dict) { - PyErr_SetString(PyExc_TypeError, - "not all arguments converted during string formatting"); - goto error; - } - if (args_owned) { - Py_DECREF(args); - } - _PyString_Resize(&result, reslen - rescnt); - return result; - -#ifdef Py_USING_UNICODE - unicode: - if (args_owned) { - Py_DECREF(args); - args_owned = 0; - } - /* Fiddle args right (remove the first argidx arguments) */ - if (PyTuple_Check(orig_args) && argidx > 0) { - PyObject *v; - Py_ssize_t n = PyTuple_GET_SIZE(orig_args) - argidx; - v = PyTuple_New(n); - if (v == NULL) - goto error; - while (--n >= 0) { - PyObject *w = PyTuple_GET_ITEM(orig_args, n + argidx); - Py_INCREF(w); - PyTuple_SET_ITEM(v, n, w); - } - args = v; - } else { - Py_INCREF(orig_args); - args = orig_args; - } - args_owned = 1; - /* Take what we have of the result and let the Unicode formatting - function format the rest of the input. */ - rescnt = res - PyString_AS_STRING(result); - if (_PyString_Resize(&result, rescnt)) - goto error; - fmtcnt = PyString_GET_SIZE(format) - \ - (fmt - PyString_AS_STRING(format)); - format = PyUnicode_Decode(fmt, fmtcnt, NULL, NULL); - if (format == NULL) - goto error; - v = PyUnicode_Format(format, args); - Py_DECREF(format); - if (v == NULL) - goto error; - /* Paste what we have (result) to what the Unicode formatting - function returned (v) and return the result (or error) */ - w = PyUnicode_Concat(result, v); - Py_DECREF(result); - Py_DECREF(v); - Py_DECREF(args); - return w; -#endif /* Py_USING_UNICODE */ - - error: - Py_DECREF(result); - if (args_owned) { - Py_DECREF(args); - } - return NULL; -} - -void -PyString_InternInPlace(PyObject **p) -{ - register PyStringObject *s = (PyStringObject *)(*p); - PyObject *t; - if (s == NULL || !PyString_Check(s)) - Py_FatalError("PyString_InternInPlace: strings only please!"); - /* If it's a string subclass, we don't really know what putting - it in the interned dict might do. */ - if (!PyString_CheckExact(s)) - return; - if (PyString_CHECK_INTERNED(s)) - return; - if (interned == NULL) { - interned = PyDict_New(); - if (interned == NULL) { - PyErr_Clear(); /* Don't leave an exception */ - return; - } - } - t = PyDict_GetItem(interned, (PyObject *)s); - if (t) { - Py_INCREF(t); - Py_DECREF(*p); - *p = t; - return; - } - - if (PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s) < 0) { - PyErr_Clear(); - return; - } - /* The two references in interned are not counted by refcnt. - The string deallocator will take care of this */ - s->ob_refcnt -= 2; - PyString_CHECK_INTERNED(s) = SSTATE_INTERNED_MORTAL; -} - -void -PyString_InternImmortal(PyObject **p) -{ - PyString_InternInPlace(p); - if (PyString_CHECK_INTERNED(*p) != SSTATE_INTERNED_IMMORTAL) { - PyString_CHECK_INTERNED(*p) = SSTATE_INTERNED_IMMORTAL; - Py_INCREF(*p); - } -} - - -PyObject * -PyString_InternFromString(const char *cp) -{ - PyObject *s = PyString_FromString(cp); - if (s == NULL) - return NULL; - PyString_InternInPlace(&s); - return s; -} - -void -PyString_Fini(void) -{ - int i; - for (i = 0; i < UCHAR_MAX + 1; i++) { - Py_XDECREF(characters[i]); - characters[i] = NULL; - } - Py_XDECREF(nullstring); - nullstring = NULL; -} - -void _Py_ReleaseInternedStrings(void) -{ - PyObject *keys; - PyStringObject *s; - Py_ssize_t i, n; - - if (interned == NULL || !PyDict_Check(interned)) - return; - keys = PyDict_Keys(interned); - if (keys == NULL || !PyList_Check(keys)) { - PyErr_Clear(); - return; - } - - /* Since _Py_ReleaseInternedStrings() is intended to help a leak - detector, interned strings are not forcibly deallocated; rather, we - give them their stolen references back, and then clear and DECREF - the interned dict. */ - - fprintf(stderr, "releasing interned strings\n"); - n = PyList_GET_SIZE(keys); - for (i = 0; i < n; i++) { - s = (PyStringObject *) PyList_GET_ITEM(keys, i); - switch (s->ob_sstate) { - case SSTATE_NOT_INTERNED: - /* XXX Shouldn't happen */ - break; - case SSTATE_INTERNED_IMMORTAL: - s->ob_refcnt += 1; - break; - case SSTATE_INTERNED_MORTAL: - s->ob_refcnt += 2; - break; - default: - Py_FatalError("Inconsistent interned string state."); - } - s->ob_sstate = SSTATE_NOT_INTERNED; - } - Py_DECREF(keys); - PyDict_Clear(interned); - Py_DECREF(interned); - interned = NULL; -} diff --git a/sys/src/cmd/python/Objects/structseq.c b/sys/src/cmd/python/Objects/structseq.c deleted file mode 100644 index 7ac2a1f61..000000000 --- a/sys/src/cmd/python/Objects/structseq.c +++ /dev/null @@ -1,407 +0,0 @@ -/* Implementation helper: a struct that looks like a tuple. See timemodule - and posixmodule for example uses. */ - -#include "Python.h" -#include "structmember.h" -#include "structseq.h" - -static char visible_length_key[] = "n_sequence_fields"; -static char real_length_key[] = "n_fields"; -static char unnamed_fields_key[] = "n_unnamed_fields"; - -/* Fields with this name have only a field index, not a field name. - They are only allowed for indices < n_visible_fields. */ -char *PyStructSequence_UnnamedField = "unnamed field"; - -#define VISIBLE_SIZE(op) ((op)->ob_size) -#define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \ - PyDict_GetItemString((tp)->tp_dict, visible_length_key)) - -#define REAL_SIZE_TP(tp) PyInt_AsLong( \ - PyDict_GetItemString((tp)->tp_dict, real_length_key)) -#define REAL_SIZE(op) REAL_SIZE_TP((op)->ob_type) - -#define UNNAMED_FIELDS_TP(tp) PyInt_AsLong( \ - PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key)) -#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP((op)->ob_type) - - -PyObject * -PyStructSequence_New(PyTypeObject *type) -{ - PyStructSequence *obj; - - obj = PyObject_New(PyStructSequence, type); - obj->ob_size = VISIBLE_SIZE_TP(type); - - return (PyObject*) obj; -} - -static void -structseq_dealloc(PyStructSequence *obj) -{ - Py_ssize_t i, size; - - size = REAL_SIZE(obj); - for (i = 0; i < size; ++i) { - Py_XDECREF(obj->ob_item[i]); - } - PyObject_Del(obj); -} - -static Py_ssize_t -structseq_length(PyStructSequence *obj) -{ - return VISIBLE_SIZE(obj); -} - -static PyObject* -structseq_item(PyStructSequence *obj, Py_ssize_t i) -{ - if (i < 0 || i >= VISIBLE_SIZE(obj)) { - PyErr_SetString(PyExc_IndexError, "tuple index out of range"); - return NULL; - } - Py_INCREF(obj->ob_item[i]); - return obj->ob_item[i]; -} - -static PyObject* -structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high) -{ - PyTupleObject *np; - Py_ssize_t i; - - if (low < 0) - low = 0; - if (high > VISIBLE_SIZE(obj)) - high = VISIBLE_SIZE(obj); - if (high < low) - high = low; - np = (PyTupleObject *)PyTuple_New(high-low); - if (np == NULL) - return NULL; - for(i = low; i < high; ++i) { - PyObject *v = obj->ob_item[i]; - Py_INCREF(v); - PyTuple_SET_ITEM(np, i-low, v); - } - return (PyObject *) np; -} - -static PyObject * -structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *arg = NULL; - PyObject *dict = NULL; - PyObject *ob; - PyStructSequence *res = NULL; - Py_ssize_t len, min_len, max_len, i, n_unnamed_fields; - static char *kwlist[] = {"sequence", "dict", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq", - kwlist, &arg, &dict)) - return NULL; - - arg = PySequence_Fast(arg, "constructor requires a sequence"); - - if (!arg) { - return NULL; - } - - if (dict && !PyDict_Check(dict)) { - PyErr_Format(PyExc_TypeError, - "%.500s() takes a dict as second arg, if any", - type->tp_name); - Py_DECREF(arg); - return NULL; - } - - len = PySequence_Fast_GET_SIZE(arg); - min_len = VISIBLE_SIZE_TP(type); - max_len = REAL_SIZE_TP(type); - n_unnamed_fields = UNNAMED_FIELDS_TP(type); - - if (min_len != max_len) { - if (len < min_len) { - PyErr_Format(PyExc_TypeError, - "%.500s() takes an at least %zd-sequence (%zd-sequence given)", - type->tp_name, min_len, len); - Py_DECREF(arg); - return NULL; - } - - if (len > max_len) { - PyErr_Format(PyExc_TypeError, - "%.500s() takes an at most %zd-sequence (%zd-sequence given)", - type->tp_name, max_len, len); - Py_DECREF(arg); - return NULL; - } - } - else { - if (len != min_len) { - PyErr_Format(PyExc_TypeError, - "%.500s() takes a %zd-sequence (%zd-sequence given)", - type->tp_name, min_len, len); - Py_DECREF(arg); - return NULL; - } - } - - res = (PyStructSequence*) PyStructSequence_New(type); - if (res == NULL) { - return NULL; - } - for (i = 0; i < len; ++i) { - PyObject *v = PySequence_Fast_GET_ITEM(arg, i); - Py_INCREF(v); - res->ob_item[i] = v; - } - for (; i < max_len; ++i) { - if (dict && (ob = PyDict_GetItemString( - dict, type->tp_members[i-n_unnamed_fields].name))) { - } - else { - ob = Py_None; - } - Py_INCREF(ob); - res->ob_item[i] = ob; - } - - Py_DECREF(arg); - return (PyObject*) res; -} - -static PyObject * -make_tuple(PyStructSequence *obj) -{ - return structseq_slice(obj, 0, VISIBLE_SIZE(obj)); -} - -static PyObject * -structseq_repr(PyStructSequence *obj) -{ - PyObject *tup, *str; - tup = make_tuple(obj); - str = PyObject_Repr(tup); - Py_DECREF(tup); - return str; -} - -static PyObject * -structseq_concat(PyStructSequence *obj, PyObject *b) -{ - PyObject *tup, *result; - tup = make_tuple(obj); - result = PySequence_Concat(tup, b); - Py_DECREF(tup); - return result; -} - -static PyObject * -structseq_repeat(PyStructSequence *obj, Py_ssize_t n) -{ - PyObject *tup, *result; - tup = make_tuple(obj); - result = PySequence_Repeat(tup, n); - Py_DECREF(tup); - return result; -} - -static int -structseq_contains(PyStructSequence *obj, PyObject *o) -{ - PyObject *tup; - int result; - tup = make_tuple(obj); - if (!tup) - return -1; - result = PySequence_Contains(tup, o); - Py_DECREF(tup); - return result; -} - -static long -structseq_hash(PyObject *obj) -{ - PyObject *tup; - long result; - tup = make_tuple((PyStructSequence*) obj); - if (!tup) - return -1; - result = PyObject_Hash(tup); - Py_DECREF(tup); - return result; -} - -static PyObject * -structseq_richcompare(PyObject *obj, PyObject *o2, int op) -{ - PyObject *tup, *result; - tup = make_tuple((PyStructSequence*) obj); - result = PyObject_RichCompare(tup, o2, op); - Py_DECREF(tup); - return result; -} - -static PyObject * -structseq_reduce(PyStructSequence* self) -{ - PyObject* tup; - PyObject* dict; - PyObject* result; - Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields; - int i; - - n_fields = REAL_SIZE(self); - n_visible_fields = VISIBLE_SIZE(self); - n_unnamed_fields = UNNAMED_FIELDS(self); - tup = PyTuple_New(n_visible_fields); - if (!tup) { - return NULL; - } - - dict = PyDict_New(); - if (!dict) { - Py_DECREF(tup); - return NULL; - } - - for (i = 0; i < n_visible_fields; i++) { - Py_INCREF(self->ob_item[i]); - PyTuple_SET_ITEM(tup, i, self->ob_item[i]); - } - - for (; i < n_fields; i++) { - char *n = self->ob_type->tp_members[i-n_unnamed_fields].name; - PyDict_SetItemString(dict, n, - self->ob_item[i]); - } - - result = Py_BuildValue("(O(OO))", self->ob_type, tup, dict); - - Py_DECREF(tup); - Py_DECREF(dict); - - return result; -} - -static PySequenceMethods structseq_as_sequence = { - (lenfunc)structseq_length, - (binaryfunc)structseq_concat, /* sq_concat */ - (ssizeargfunc)structseq_repeat, /* sq_repeat */ - (ssizeargfunc)structseq_item, /* sq_item */ - (ssizessizeargfunc)structseq_slice, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)structseq_contains, /* sq_contains */ -}; - -static PyMethodDef structseq_methods[] = { - {"__reduce__", (PyCFunction)structseq_reduce, - METH_NOARGS, NULL}, - {NULL, NULL} -}; - -static PyTypeObject _struct_sequence_template = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - NULL, /* tp_name */ - 0, /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)structseq_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)structseq_repr, /* tp_repr */ - 0, /* tp_as_number */ - &structseq_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - structseq_hash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - NULL, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - structseq_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - structseq_methods, /* tp_methods */ - NULL, /* tp_members */ - 0, /* 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 */ - structseq_new, /* tp_new */ -}; - -void -PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) -{ - PyObject *dict; - PyMemberDef* members; - int n_members, n_unnamed_members, i, k; - -#ifdef Py_TRACE_REFS - /* if the type object was chained, unchain it first - before overwriting its storage */ - if (type->_ob_next) { - _Py_ForgetReference((PyObject*)type); - } -#endif - - n_unnamed_members = 0; - for (i = 0; desc->fields[i].name != NULL; ++i) - if (desc->fields[i].name == PyStructSequence_UnnamedField) - n_unnamed_members++; - n_members = i; - - memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject)); - type->tp_name = desc->name; - type->tp_doc = desc->doc; - type->tp_basicsize = sizeof(PyStructSequence)+ - sizeof(PyObject*)*(n_members-1); - type->tp_itemsize = 0; - - members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1); - if (members == NULL) - return; - - for (i = k = 0; i < n_members; ++i) { - if (desc->fields[i].name == PyStructSequence_UnnamedField) - continue; - members[k].name = desc->fields[i].name; - members[k].type = T_OBJECT; - members[k].offset = offsetof(PyStructSequence, ob_item) - + i * sizeof(PyObject*); - members[k].flags = READONLY; - members[k].doc = desc->fields[i].doc; - k++; - } - members[k].name = NULL; - - type->tp_members = members; - - if (PyType_Ready(type) < 0) - return; - Py_INCREF(type); - - dict = type->tp_dict; - PyDict_SetItemString(dict, visible_length_key, - PyInt_FromLong((long) desc->n_in_sequence)); - PyDict_SetItemString(dict, real_length_key, - PyInt_FromLong((long) n_members)); - PyDict_SetItemString(dict, unnamed_fields_key, - PyInt_FromLong((long) n_unnamed_members)); -} diff --git a/sys/src/cmd/python/Objects/tupleobject.c b/sys/src/cmd/python/Objects/tupleobject.c deleted file mode 100644 index 6f3711f1f..000000000 --- a/sys/src/cmd/python/Objects/tupleobject.c +++ /dev/null @@ -1,890 +0,0 @@ - -/* Tuple object implementation */ - -#include "Python.h" - -/* Speed optimization to avoid frequent malloc/free of small tuples */ -#ifndef MAXSAVESIZE -#define MAXSAVESIZE 20 /* Largest tuple to save on free list */ -#endif -#ifndef MAXSAVEDTUPLES -#define MAXSAVEDTUPLES 2000 /* Maximum number of tuples of each size to save */ -#endif - -#if MAXSAVESIZE > 0 -/* Entries 1 up to MAXSAVESIZE are free lists, entry 0 is the empty - tuple () of which at most one instance will be allocated. -*/ -static PyTupleObject *free_tuples[MAXSAVESIZE]; -static int num_free_tuples[MAXSAVESIZE]; -#endif -#ifdef COUNT_ALLOCS -int fast_tuple_allocs; -int tuple_zero_allocs; -#endif - -PyObject * -PyTuple_New(register Py_ssize_t size) -{ - register PyTupleObject *op; - Py_ssize_t i; - if (size < 0) { - PyErr_BadInternalCall(); - return NULL; - } -#if MAXSAVESIZE > 0 - if (size == 0 && free_tuples[0]) { - op = free_tuples[0]; - Py_INCREF(op); -#ifdef COUNT_ALLOCS - tuple_zero_allocs++; -#endif - return (PyObject *) op; - } - if (size < MAXSAVESIZE && (op = free_tuples[size]) != NULL) { - free_tuples[size] = (PyTupleObject *) op->ob_item[0]; - num_free_tuples[size]--; -#ifdef COUNT_ALLOCS - fast_tuple_allocs++; -#endif - /* Inline PyObject_InitVar */ -#ifdef Py_TRACE_REFS - op->ob_size = size; - op->ob_type = &PyTuple_Type; -#endif - _Py_NewReference((PyObject *)op); - } - else -#endif - { - Py_ssize_t nbytes = size * sizeof(PyObject *); - /* Check for overflow */ - if (nbytes / sizeof(PyObject *) != (size_t)size || - (nbytes += sizeof(PyTupleObject) - sizeof(PyObject *)) - <= 0) - { - return PyErr_NoMemory(); - } - op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size); - if (op == NULL) - return NULL; - } - for (i=0; i < size; i++) - op->ob_item[i] = NULL; -#if MAXSAVESIZE > 0 - if (size == 0) { - free_tuples[0] = op; - ++num_free_tuples[0]; - Py_INCREF(op); /* extra INCREF so that this is never freed */ - } -#endif - _PyObject_GC_TRACK(op); - return (PyObject *) op; -} - -Py_ssize_t -PyTuple_Size(register PyObject *op) -{ - if (!PyTuple_Check(op)) { - PyErr_BadInternalCall(); - return -1; - } - else - return ((PyTupleObject *)op)->ob_size; -} - -PyObject * -PyTuple_GetItem(register PyObject *op, register Py_ssize_t i) -{ - if (!PyTuple_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - if (i < 0 || i >= ((PyTupleObject *)op) -> ob_size) { - PyErr_SetString(PyExc_IndexError, "tuple index out of range"); - return NULL; - } - return ((PyTupleObject *)op) -> ob_item[i]; -} - -int -PyTuple_SetItem(register PyObject *op, register Py_ssize_t i, PyObject *newitem) -{ - register PyObject *olditem; - register PyObject **p; - if (!PyTuple_Check(op) || op->ob_refcnt != 1) { - Py_XDECREF(newitem); - PyErr_BadInternalCall(); - return -1; - } - if (i < 0 || i >= ((PyTupleObject *)op) -> ob_size) { - Py_XDECREF(newitem); - PyErr_SetString(PyExc_IndexError, - "tuple assignment index out of range"); - return -1; - } - p = ((PyTupleObject *)op) -> ob_item + i; - olditem = *p; - *p = newitem; - Py_XDECREF(olditem); - return 0; -} - -PyObject * -PyTuple_Pack(Py_ssize_t n, ...) -{ - Py_ssize_t i; - PyObject *o; - PyObject *result; - PyObject **items; - va_list vargs; - - va_start(vargs, n); - result = PyTuple_New(n); - if (result == NULL) - return NULL; - items = ((PyTupleObject *)result)->ob_item; - for (i = 0; i < n; i++) { - o = va_arg(vargs, PyObject *); - Py_INCREF(o); - items[i] = o; - } - va_end(vargs); - return result; -} - - -/* Methods */ - -static void -tupledealloc(register PyTupleObject *op) -{ - register Py_ssize_t i; - register Py_ssize_t len = op->ob_size; - PyObject_GC_UnTrack(op); - Py_TRASHCAN_SAFE_BEGIN(op) - if (len > 0) { - i = len; - while (--i >= 0) - Py_XDECREF(op->ob_item[i]); -#if MAXSAVESIZE > 0 - if (len < MAXSAVESIZE && - num_free_tuples[len] < MAXSAVEDTUPLES && - op->ob_type == &PyTuple_Type) - { - op->ob_item[0] = (PyObject *) free_tuples[len]; - num_free_tuples[len]++; - free_tuples[len] = op; - goto done; /* return */ - } -#endif - } - op->ob_type->tp_free((PyObject *)op); -done: - Py_TRASHCAN_SAFE_END(op) -} - -static int -tupleprint(PyTupleObject *op, FILE *fp, int flags) -{ - Py_ssize_t i; - fprintf(fp, "("); - for (i = 0; i < op->ob_size; i++) { - if (i > 0) - fprintf(fp, ", "); - if (PyObject_Print(op->ob_item[i], fp, 0) != 0) - return -1; - } - if (op->ob_size == 1) - fprintf(fp, ","); - fprintf(fp, ")"); - return 0; -} - -static PyObject * -tuplerepr(PyTupleObject *v) -{ - Py_ssize_t i, n; - PyObject *s, *temp; - PyObject *pieces, *result = NULL; - - n = v->ob_size; - if (n == 0) - return PyString_FromString("()"); - - pieces = PyTuple_New(n); - if (pieces == NULL) - return NULL; - - /* Do repr() on each element. */ - for (i = 0; i < n; ++i) { - s = PyObject_Repr(v->ob_item[i]); - if (s == NULL) - goto Done; - PyTuple_SET_ITEM(pieces, i, s); - } - - /* Add "()" decorations to the first and last items. */ - assert(n > 0); - s = PyString_FromString("("); - if (s == NULL) - goto Done; - temp = PyTuple_GET_ITEM(pieces, 0); - PyString_ConcatAndDel(&s, temp); - PyTuple_SET_ITEM(pieces, 0, s); - if (s == NULL) - goto Done; - - s = PyString_FromString(n == 1 ? ",)" : ")"); - if (s == NULL) - goto Done; - temp = PyTuple_GET_ITEM(pieces, n-1); - PyString_ConcatAndDel(&temp, s); - PyTuple_SET_ITEM(pieces, n-1, temp); - if (temp == NULL) - goto Done; - - /* Paste them all together with ", " between. */ - s = PyString_FromString(", "); - if (s == NULL) - goto Done; - result = _PyString_Join(s, pieces); - Py_DECREF(s); - -Done: - Py_DECREF(pieces); - return result; -} - -/* The addend 82520, was selected from the range(0, 1000000) for - generating the greatest number of prime multipliers for tuples - upto length eight: - - 1082527, 1165049, 1082531, 1165057, 1247581, 1330103, 1082533, - 1330111, 1412633, 1165069, 1247599, 1495177, 1577699 -*/ - -static long -tuplehash(PyTupleObject *v) -{ - register long x, y; - register Py_ssize_t len = v->ob_size; - register PyObject **p; - long mult = 1000003L; - x = 0x345678L; - p = v->ob_item; - while (--len >= 0) { - y = PyObject_Hash(*p++); - if (y == -1) - return -1; - x = (x ^ y) * mult; - /* the cast might truncate len; that doesn't change hash stability */ - mult += (long)(82520L + len + len); - } - x += 97531L; - if (x == -1) - x = -2; - return x; -} - -static Py_ssize_t -tuplelength(PyTupleObject *a) -{ - return a->ob_size; -} - -static int -tuplecontains(PyTupleObject *a, PyObject *el) -{ - Py_ssize_t i; - int cmp; - - for (i = 0, cmp = 0 ; cmp == 0 && i < a->ob_size; ++i) - cmp = PyObject_RichCompareBool(el, PyTuple_GET_ITEM(a, i), - Py_EQ); - return cmp; -} - -static PyObject * -tupleitem(register PyTupleObject *a, register Py_ssize_t i) -{ - if (i < 0 || i >= a->ob_size) { - PyErr_SetString(PyExc_IndexError, "tuple index out of range"); - return NULL; - } - Py_INCREF(a->ob_item[i]); - return a->ob_item[i]; -} - -static PyObject * -tupleslice(register PyTupleObject *a, register Py_ssize_t ilow, - register Py_ssize_t ihigh) -{ - register PyTupleObject *np; - PyObject **src, **dest; - register Py_ssize_t i; - Py_ssize_t len; - if (ilow < 0) - ilow = 0; - if (ihigh > a->ob_size) - ihigh = a->ob_size; - if (ihigh < ilow) - ihigh = ilow; - if (ilow == 0 && ihigh == a->ob_size && PyTuple_CheckExact(a)) { - Py_INCREF(a); - return (PyObject *)a; - } - len = ihigh - ilow; - np = (PyTupleObject *)PyTuple_New(len); - if (np == NULL) - return NULL; - src = a->ob_item + ilow; - dest = np->ob_item; - for (i = 0; i < len; i++) { - PyObject *v = src[i]; - Py_INCREF(v); - dest[i] = v; - } - return (PyObject *)np; -} - -PyObject * -PyTuple_GetSlice(PyObject *op, Py_ssize_t i, Py_ssize_t j) -{ - if (op == NULL || !PyTuple_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - return tupleslice((PyTupleObject *)op, i, j); -} - -static PyObject * -tupleconcat(register PyTupleObject *a, register PyObject *bb) -{ - register Py_ssize_t size; - register Py_ssize_t i; - PyObject **src, **dest; - PyTupleObject *np; - if (!PyTuple_Check(bb)) { - PyErr_Format(PyExc_TypeError, - "can only concatenate tuple (not \"%.200s\") to tuple", - bb->ob_type->tp_name); - return NULL; - } -#define b ((PyTupleObject *)bb) - size = a->ob_size + b->ob_size; - if (size < 0) - return PyErr_NoMemory(); - np = (PyTupleObject *) PyTuple_New(size); - if (np == NULL) { - return NULL; - } - src = a->ob_item; - dest = np->ob_item; - for (i = 0; i < a->ob_size; i++) { - PyObject *v = src[i]; - Py_INCREF(v); - dest[i] = v; - } - src = b->ob_item; - dest = np->ob_item + a->ob_size; - for (i = 0; i < b->ob_size; i++) { - PyObject *v = src[i]; - Py_INCREF(v); - dest[i] = v; - } - return (PyObject *)np; -#undef b -} - -static PyObject * -tuplerepeat(PyTupleObject *a, Py_ssize_t n) -{ - Py_ssize_t i, j; - Py_ssize_t size; - PyTupleObject *np; - PyObject **p, **items; - if (n < 0) - n = 0; - if (a->ob_size == 0 || n == 1) { - if (PyTuple_CheckExact(a)) { - /* Since tuples are immutable, we can return a shared - copy in this case */ - Py_INCREF(a); - return (PyObject *)a; - } - if (a->ob_size == 0) - return PyTuple_New(0); - } - size = a->ob_size * n; - if (size/a->ob_size != n) - return PyErr_NoMemory(); - np = (PyTupleObject *) PyTuple_New(size); - if (np == NULL) - return NULL; - p = np->ob_item; - items = a->ob_item; - for (i = 0; i < n; i++) { - for (j = 0; j < a->ob_size; j++) { - *p = items[j]; - Py_INCREF(*p); - p++; - } - } - return (PyObject *) np; -} - -static int -tupletraverse(PyTupleObject *o, visitproc visit, void *arg) -{ - Py_ssize_t i; - - for (i = o->ob_size; --i >= 0; ) - Py_VISIT(o->ob_item[i]); - return 0; -} - -static PyObject * -tuplerichcompare(PyObject *v, PyObject *w, int op) -{ - PyTupleObject *vt, *wt; - Py_ssize_t i; - Py_ssize_t vlen, wlen; - - if (!PyTuple_Check(v) || !PyTuple_Check(w)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - vt = (PyTupleObject *)v; - wt = (PyTupleObject *)w; - - vlen = vt->ob_size; - wlen = wt->ob_size; - - /* Note: the corresponding code for lists has an "early out" test - * here when op is EQ or NE and the lengths differ. That pays there, - * but Tim was unable to find any real code where EQ/NE tuple - * compares don't have the same length, so testing for it here would - * have cost without benefit. - */ - - /* Search for the first index where items are different. - * Note that because tuples are immutable, it's safe to reuse - * vlen and wlen across the comparison calls. - */ - for (i = 0; i < vlen && i < wlen; i++) { - int k = PyObject_RichCompareBool(vt->ob_item[i], - wt->ob_item[i], Py_EQ); - if (k < 0) - return NULL; - if (!k) - break; - } - - if (i >= vlen || i >= wlen) { - /* No more items to compare -- compare sizes */ - int cmp; - PyObject *res; - switch (op) { - case Py_LT: cmp = vlen < wlen; break; - case Py_LE: cmp = vlen <= wlen; break; - case Py_EQ: cmp = vlen == wlen; break; - case Py_NE: cmp = vlen != wlen; break; - case Py_GT: cmp = vlen > wlen; break; - case Py_GE: cmp = vlen >= wlen; break; - default: return NULL; /* cannot happen */ - } - if (cmp) - res = Py_True; - else - res = Py_False; - Py_INCREF(res); - return res; - } - - /* We have an item that differs -- shortcuts for EQ/NE */ - if (op == Py_EQ) { - Py_INCREF(Py_False); - return Py_False; - } - if (op == Py_NE) { - Py_INCREF(Py_True); - return Py_True; - } - - /* Compare the final item again using the proper operator */ - return PyObject_RichCompare(vt->ob_item[i], wt->ob_item[i], op); -} - -static PyObject * -tuple_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static PyObject * -tuple_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *arg = NULL; - static char *kwlist[] = {"sequence", 0}; - - if (type != &PyTuple_Type) - return tuple_subtype_new(type, args, kwds); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:tuple", kwlist, &arg)) - return NULL; - - if (arg == NULL) - return PyTuple_New(0); - else - return PySequence_Tuple(arg); -} - -static PyObject * -tuple_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *tmp, *newobj, *item; - Py_ssize_t i, n; - - assert(PyType_IsSubtype(type, &PyTuple_Type)); - tmp = tuple_new(&PyTuple_Type, args, kwds); - if (tmp == NULL) - return NULL; - assert(PyTuple_Check(tmp)); - newobj = type->tp_alloc(type, n = PyTuple_GET_SIZE(tmp)); - if (newobj == NULL) - return NULL; - for (i = 0; i < n; i++) { - item = PyTuple_GET_ITEM(tmp, i); - Py_INCREF(item); - PyTuple_SET_ITEM(newobj, i, item); - } - Py_DECREF(tmp); - return newobj; -} - -PyDoc_STRVAR(tuple_doc, -"tuple() -> an empty tuple\n" -"tuple(sequence) -> tuple initialized from sequence's items\n" -"\n" -"If the argument is a tuple, the return value is the same object."); - -static PySequenceMethods tuple_as_sequence = { - (lenfunc)tuplelength, /* sq_length */ - (binaryfunc)tupleconcat, /* sq_concat */ - (ssizeargfunc)tuplerepeat, /* sq_repeat */ - (ssizeargfunc)tupleitem, /* sq_item */ - (ssizessizeargfunc)tupleslice, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)tuplecontains, /* sq_contains */ -}; - -static PyObject* -tuplesubscript(PyTupleObject* self, PyObject* item) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += PyTuple_GET_SIZE(self); - return tupleitem(self, i); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength, cur, i; - PyObject* result; - PyObject* it; - PyObject **src, **dest; - - if (PySlice_GetIndicesEx((PySliceObject*)item, - PyTuple_GET_SIZE(self), - &start, &stop, &step, &slicelength) < 0) { - return NULL; - } - - if (slicelength <= 0) { - return PyTuple_New(0); - } - else { - result = PyTuple_New(slicelength); - if (!result) return NULL; - - src = self->ob_item; - dest = ((PyTupleObject *)result)->ob_item; - for (cur = start, i = 0; i < slicelength; - cur += step, i++) { - it = src[cur]; - Py_INCREF(it); - dest[i] = it; - } - - return result; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "tuple indices must be integers"); - return NULL; - } -} - -static PyObject * -tuple_getnewargs(PyTupleObject *v) -{ - return Py_BuildValue("(N)", tupleslice(v, 0, v->ob_size)); - -} - -static PyMethodDef tuple_methods[] = { - {"__getnewargs__", (PyCFunction)tuple_getnewargs, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyMappingMethods tuple_as_mapping = { - (lenfunc)tuplelength, - (binaryfunc)tuplesubscript, - 0 -}; - -static PyObject *tuple_iter(PyObject *seq); - -PyTypeObject PyTuple_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "tuple", - sizeof(PyTupleObject) - sizeof(PyObject *), - sizeof(PyObject *), - (destructor)tupledealloc, /* tp_dealloc */ - (printfunc)tupleprint, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)tuplerepr, /* tp_repr */ - 0, /* tp_as_number */ - &tuple_as_sequence, /* tp_as_sequence */ - &tuple_as_mapping, /* tp_as_mapping */ - (hashfunc)tuplehash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - tuple_doc, /* tp_doc */ - (traverseproc)tupletraverse, /* tp_traverse */ - 0, /* tp_clear */ - tuplerichcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - tuple_iter, /* tp_iter */ - 0, /* tp_iternext */ - tuple_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - tuple_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - -/* The following function breaks the notion that tuples are immutable: - it changes the size of a tuple. We get away with this only if there - is only one module referencing the object. You can also think of it - as creating a new tuple object and destroying the old one, only more - efficiently. In any case, don't use this if the tuple may already be - known to some other part of the code. */ - -int -_PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) -{ - register PyTupleObject *v; - register PyTupleObject *sv; - Py_ssize_t i; - Py_ssize_t oldsize; - - v = (PyTupleObject *) *pv; - if (v == NULL || v->ob_type != &PyTuple_Type || - (v->ob_size != 0 && v->ob_refcnt != 1)) { - *pv = 0; - Py_XDECREF(v); - PyErr_BadInternalCall(); - return -1; - } - oldsize = v->ob_size; - if (oldsize == newsize) - return 0; - - if (oldsize == 0) { - /* Empty tuples are often shared, so we should never - resize them in-place even if we do own the only - (current) reference */ - Py_DECREF(v); - *pv = PyTuple_New(newsize); - return *pv == NULL ? -1 : 0; - } - - /* XXX UNREF/NEWREF interface should be more symmetrical */ - _Py_DEC_REFTOTAL; - _PyObject_GC_UNTRACK(v); - _Py_ForgetReference((PyObject *) v); - /* DECREF items deleted by shrinkage */ - for (i = newsize; i < oldsize; i++) { - Py_XDECREF(v->ob_item[i]); - v->ob_item[i] = NULL; - } - sv = PyObject_GC_Resize(PyTupleObject, v, newsize); - if (sv == NULL) { - *pv = NULL; - PyObject_GC_Del(v); - return -1; - } - _Py_NewReference((PyObject *) sv); - /* Zero out items added by growing */ - if (newsize > oldsize) - memset(&sv->ob_item[oldsize], 0, - sizeof(*sv->ob_item) * (newsize - oldsize)); - *pv = (PyObject *) sv; - _PyObject_GC_TRACK(sv); - return 0; -} - -void -PyTuple_Fini(void) -{ -#if MAXSAVESIZE > 0 - int i; - - Py_XDECREF(free_tuples[0]); - free_tuples[0] = NULL; - - for (i = 1; i < MAXSAVESIZE; i++) { - PyTupleObject *p, *q; - p = free_tuples[i]; - free_tuples[i] = NULL; - while (p) { - q = p; - p = (PyTupleObject *)(p->ob_item[0]); - PyObject_GC_Del(q); - } - } -#endif -} - -/*********************** Tuple Iterator **************************/ - -typedef struct { - PyObject_HEAD - long it_index; - PyTupleObject *it_seq; /* Set to NULL when iterator is exhausted */ -} tupleiterobject; - -static void -tupleiter_dealloc(tupleiterobject *it) -{ - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); -} - -static int -tupleiter_traverse(tupleiterobject *it, visitproc visit, void *arg) -{ - Py_VISIT(it->it_seq); - return 0; -} - -static PyObject * -tupleiter_next(tupleiterobject *it) -{ - PyTupleObject *seq; - PyObject *item; - - assert(it != NULL); - seq = it->it_seq; - if (seq == NULL) - return NULL; - assert(PyTuple_Check(seq)); - - if (it->it_index < PyTuple_GET_SIZE(seq)) { - item = PyTuple_GET_ITEM(seq, it->it_index); - ++it->it_index; - Py_INCREF(item); - return item; - } - - Py_DECREF(seq); - it->it_seq = NULL; - return NULL; -} - -static PyObject * -tupleiter_len(tupleiterobject *it) -{ - Py_ssize_t len = 0; - if (it->it_seq) - len = PyTuple_GET_SIZE(it->it_seq) - it->it_index; - return PyInt_FromSsize_t(len); -} - -PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - -static PyMethodDef tupleiter_methods[] = { - {"__length_hint__", (PyCFunction)tupleiter_len, METH_NOARGS, length_hint_doc}, - {NULL, NULL} /* sentinel */ -}; - -PyTypeObject PyTupleIter_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "tupleiterator", /* tp_name */ - sizeof(tupleiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)tupleiter_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)tupleiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)tupleiter_next, /* tp_iternext */ - tupleiter_methods, /* tp_methods */ - 0, -}; - -static PyObject * -tuple_iter(PyObject *seq) -{ - tupleiterobject *it; - - if (!PyTuple_Check(seq)) { - PyErr_BadInternalCall(); - return NULL; - } - it = PyObject_GC_New(tupleiterobject, &PyTupleIter_Type); - if (it == NULL) - return NULL; - it->it_index = 0; - Py_INCREF(seq); - it->it_seq = (PyTupleObject *)seq; - _PyObject_GC_TRACK(it); - return (PyObject *)it; -} diff --git a/sys/src/cmd/python/Objects/typeobject.c b/sys/src/cmd/python/Objects/typeobject.c deleted file mode 100644 index 8a6f78266..000000000 --- a/sys/src/cmd/python/Objects/typeobject.c +++ /dev/null @@ -1,5891 +0,0 @@ -/* Type object implementation */ - -#include "Python.h" -#include "structmember.h" - -#include <ctype.h> - -static PyMemberDef type_members[] = { - {"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY}, - {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY}, - {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY}, - {"__weakrefoffset__", T_LONG, - offsetof(PyTypeObject, tp_weaklistoffset), READONLY}, - {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY}, - {"__dictoffset__", T_LONG, - offsetof(PyTypeObject, tp_dictoffset), READONLY}, - {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY}, - {0} -}; - -static PyObject * -type_name(PyTypeObject *type, void *context) -{ - const char *s; - - if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { - PyHeapTypeObject* et = (PyHeapTypeObject*)type; - - Py_INCREF(et->ht_name); - return et->ht_name; - } - else { - s = strrchr(type->tp_name, '.'); - if (s == NULL) - s = type->tp_name; - else - s++; - return PyString_FromString(s); - } -} - -static int -type_set_name(PyTypeObject *type, PyObject *value, void *context) -{ - PyHeapTypeObject* et; - - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - PyErr_Format(PyExc_TypeError, - "can't set %s.__name__", type->tp_name); - return -1; - } - if (!value) { - PyErr_Format(PyExc_TypeError, - "can't delete %s.__name__", type->tp_name); - return -1; - } - if (!PyString_Check(value)) { - PyErr_Format(PyExc_TypeError, - "can only assign string to %s.__name__, not '%s'", - type->tp_name, value->ob_type->tp_name); - return -1; - } - if (strlen(PyString_AS_STRING(value)) - != (size_t)PyString_GET_SIZE(value)) { - PyErr_Format(PyExc_ValueError, - "__name__ must not contain null bytes"); - return -1; - } - - et = (PyHeapTypeObject*)type; - - Py_INCREF(value); - - Py_DECREF(et->ht_name); - et->ht_name = value; - - type->tp_name = PyString_AS_STRING(value); - - return 0; -} - -static PyObject * -type_module(PyTypeObject *type, void *context) -{ - PyObject *mod; - char *s; - - if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { - mod = PyDict_GetItemString(type->tp_dict, "__module__"); - if (!mod) { - PyErr_Format(PyExc_AttributeError, "__module__"); - return 0; - } - Py_XINCREF(mod); - return mod; - } - else { - s = strrchr(type->tp_name, '.'); - if (s != NULL) - return PyString_FromStringAndSize( - type->tp_name, (Py_ssize_t)(s - type->tp_name)); - return PyString_FromString("__builtin__"); - } -} - -static int -type_set_module(PyTypeObject *type, PyObject *value, void *context) -{ - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - PyErr_Format(PyExc_TypeError, - "can't set %s.__module__", type->tp_name); - return -1; - } - if (!value) { - PyErr_Format(PyExc_TypeError, - "can't delete %s.__module__", type->tp_name); - return -1; - } - - return PyDict_SetItemString(type->tp_dict, "__module__", value); -} - -static PyObject * -type_get_bases(PyTypeObject *type, void *context) -{ - Py_INCREF(type->tp_bases); - return type->tp_bases; -} - -static PyTypeObject *best_base(PyObject *); -static int mro_internal(PyTypeObject *); -static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); -static int add_subclass(PyTypeObject*, PyTypeObject*); -static void remove_subclass(PyTypeObject *, PyTypeObject *); -static void update_all_slots(PyTypeObject *); - -typedef int (*update_callback)(PyTypeObject *, void *); -static int update_subclasses(PyTypeObject *type, PyObject *name, - update_callback callback, void *data); -static int recurse_down_subclasses(PyTypeObject *type, PyObject *name, - update_callback callback, void *data); - -static int -mro_subclasses(PyTypeObject *type, PyObject* temp) -{ - PyTypeObject *subclass; - PyObject *ref, *subclasses, *old_mro; - Py_ssize_t i, n; - - subclasses = type->tp_subclasses; - if (subclasses == NULL) - return 0; - assert(PyList_Check(subclasses)); - n = PyList_GET_SIZE(subclasses); - for (i = 0; i < n; i++) { - ref = PyList_GET_ITEM(subclasses, i); - assert(PyWeakref_CheckRef(ref)); - subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref); - assert(subclass != NULL); - if ((PyObject *)subclass == Py_None) - continue; - assert(PyType_Check(subclass)); - old_mro = subclass->tp_mro; - if (mro_internal(subclass) < 0) { - subclass->tp_mro = old_mro; - return -1; - } - else { - PyObject* tuple; - tuple = PyTuple_Pack(2, subclass, old_mro); - Py_DECREF(old_mro); - if (!tuple) - return -1; - if (PyList_Append(temp, tuple) < 0) - return -1; - Py_DECREF(tuple); - } - if (mro_subclasses(subclass, temp) < 0) - return -1; - } - return 0; -} - -static int -type_set_bases(PyTypeObject *type, PyObject *value, void *context) -{ - Py_ssize_t i; - int r = 0; - PyObject *ob, *temp; - PyTypeObject *new_base, *old_base; - PyObject *old_bases, *old_mro; - - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - PyErr_Format(PyExc_TypeError, - "can't set %s.__bases__", type->tp_name); - return -1; - } - if (!value) { - PyErr_Format(PyExc_TypeError, - "can't delete %s.__bases__", type->tp_name); - return -1; - } - if (!PyTuple_Check(value)) { - PyErr_Format(PyExc_TypeError, - "can only assign tuple to %s.__bases__, not %s", - type->tp_name, value->ob_type->tp_name); - return -1; - } - if (PyTuple_GET_SIZE(value) == 0) { - PyErr_Format(PyExc_TypeError, - "can only assign non-empty tuple to %s.__bases__, not ()", - type->tp_name); - return -1; - } - for (i = 0; i < PyTuple_GET_SIZE(value); i++) { - ob = PyTuple_GET_ITEM(value, i); - if (!PyClass_Check(ob) && !PyType_Check(ob)) { - PyErr_Format( - PyExc_TypeError, - "%s.__bases__ must be tuple of old- or new-style classes, not '%s'", - type->tp_name, ob->ob_type->tp_name); - return -1; - } - if (PyType_Check(ob)) { - if (PyType_IsSubtype((PyTypeObject*)ob, type)) { - PyErr_SetString(PyExc_TypeError, - "a __bases__ item causes an inheritance cycle"); - return -1; - } - } - } - - new_base = best_base(value); - - if (!new_base) { - return -1; - } - - if (!compatible_for_assignment(type->tp_base, new_base, "__bases__")) - return -1; - - Py_INCREF(new_base); - Py_INCREF(value); - - old_bases = type->tp_bases; - old_base = type->tp_base; - old_mro = type->tp_mro; - - type->tp_bases = value; - type->tp_base = new_base; - - if (mro_internal(type) < 0) { - goto bail; - } - - temp = PyList_New(0); - if (!temp) - goto bail; - - r = mro_subclasses(type, temp); - - if (r < 0) { - for (i = 0; i < PyList_Size(temp); i++) { - PyTypeObject* cls; - PyObject* mro; - PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), - "", 2, 2, &cls, &mro); - Py_DECREF(cls->tp_mro); - cls->tp_mro = mro; - Py_INCREF(cls->tp_mro); - } - Py_DECREF(temp); - goto bail; - } - - Py_DECREF(temp); - - /* any base that was in __bases__ but now isn't, we - need to remove |type| from its tp_subclasses. - conversely, any class now in __bases__ that wasn't - needs to have |type| added to its subclasses. */ - - /* for now, sod that: just remove from all old_bases, - add to all new_bases */ - - for (i = PyTuple_GET_SIZE(old_bases) - 1; i >= 0; i--) { - ob = PyTuple_GET_ITEM(old_bases, i); - if (PyType_Check(ob)) { - remove_subclass( - (PyTypeObject*)ob, type); - } - } - - for (i = PyTuple_GET_SIZE(value) - 1; i >= 0; i--) { - ob = PyTuple_GET_ITEM(value, i); - if (PyType_Check(ob)) { - if (add_subclass((PyTypeObject*)ob, type) < 0) - r = -1; - } - } - - update_all_slots(type); - - Py_DECREF(old_bases); - Py_DECREF(old_base); - Py_DECREF(old_mro); - - return r; - - bail: - Py_DECREF(type->tp_bases); - Py_DECREF(type->tp_base); - if (type->tp_mro != old_mro) { - Py_DECREF(type->tp_mro); - } - - type->tp_bases = old_bases; - type->tp_base = old_base; - type->tp_mro = old_mro; - - return -1; -} - -static PyObject * -type_dict(PyTypeObject *type, void *context) -{ - if (type->tp_dict == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return PyDictProxy_New(type->tp_dict); -} - -static PyObject * -type_get_doc(PyTypeObject *type, void *context) -{ - PyObject *result; - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) - return PyString_FromString(type->tp_doc); - result = PyDict_GetItemString(type->tp_dict, "__doc__"); - if (result == NULL) { - result = Py_None; - Py_INCREF(result); - } - else if (result->ob_type->tp_descr_get) { - result = result->ob_type->tp_descr_get(result, NULL, - (PyObject *)type); - } - else { - Py_INCREF(result); - } - return result; -} - -static PyGetSetDef type_getsets[] = { - {"__name__", (getter)type_name, (setter)type_set_name, NULL}, - {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, - {"__module__", (getter)type_module, (setter)type_set_module, NULL}, - {"__dict__", (getter)type_dict, NULL, NULL}, - {"__doc__", (getter)type_get_doc, NULL, NULL}, - {0} -}; - -static int -type_compare(PyObject *v, PyObject *w) -{ - /* This is called with type objects only. So we - can just compare the addresses. */ - Py_uintptr_t vv = (Py_uintptr_t)v; - Py_uintptr_t ww = (Py_uintptr_t)w; - return (vv < ww) ? -1 : (vv > ww) ? 1 : 0; -} - -static PyObject * -type_repr(PyTypeObject *type) -{ - PyObject *mod, *name, *rtn; - char *kind; - - mod = type_module(type, NULL); - if (mod == NULL) - PyErr_Clear(); - else if (!PyString_Check(mod)) { - Py_DECREF(mod); - mod = NULL; - } - name = type_name(type, NULL); - if (name == NULL) - return NULL; - - if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) - kind = "class"; - else - kind = "type"; - - if (mod != NULL && strcmp(PyString_AS_STRING(mod), "__builtin__")) { - rtn = PyString_FromFormat("<%s '%s.%s'>", - kind, - PyString_AS_STRING(mod), - PyString_AS_STRING(name)); - } - else - rtn = PyString_FromFormat("<%s '%s'>", kind, type->tp_name); - - Py_XDECREF(mod); - Py_DECREF(name); - return rtn; -} - -static PyObject * -type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *obj; - - if (type->tp_new == NULL) { - PyErr_Format(PyExc_TypeError, - "cannot create '%.100s' instances", - type->tp_name); - return NULL; - } - - obj = type->tp_new(type, args, kwds); - if (obj != NULL) { - /* Ugly exception: when the call was type(something), - don't call tp_init on the result. */ - if (type == &PyType_Type && - PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && - (kwds == NULL || - (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) - return obj; - /* If the returned object is not an instance of type, - it won't be initialized. */ - if (!PyType_IsSubtype(obj->ob_type, type)) - return obj; - type = obj->ob_type; - if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) && - type->tp_init != NULL && - type->tp_init(obj, args, kwds) < 0) { - Py_DECREF(obj); - obj = NULL; - } - } - return obj; -} - -PyObject * -PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems) -{ - PyObject *obj; - const size_t size = _PyObject_VAR_SIZE(type, nitems+1); - /* note that we need to add one, for the sentinel */ - - if (PyType_IS_GC(type)) - obj = _PyObject_GC_Malloc(size); - else - obj = (PyObject *)PyObject_MALLOC(size); - - if (obj == NULL) - return PyErr_NoMemory(); - - memset(obj, '\0', size); - - if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) - Py_INCREF(type); - - if (type->tp_itemsize == 0) - PyObject_INIT(obj, type); - else - (void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems); - - if (PyType_IS_GC(type)) - _PyObject_GC_TRACK(obj); - return obj; -} - -PyObject * -PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - return type->tp_alloc(type, 0); -} - -/* Helpers for subtyping */ - -static int -traverse_slots(PyTypeObject *type, PyObject *self, visitproc visit, void *arg) -{ - Py_ssize_t i, n; - PyMemberDef *mp; - - n = type->ob_size; - mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); - for (i = 0; i < n; i++, mp++) { - if (mp->type == T_OBJECT_EX) { - char *addr = (char *)self + mp->offset; - PyObject *obj = *(PyObject **)addr; - if (obj != NULL) { - int err = visit(obj, arg); - if (err) - return err; - } - } - } - return 0; -} - -static int -subtype_traverse(PyObject *self, visitproc visit, void *arg) -{ - PyTypeObject *type, *base; - traverseproc basetraverse; - - /* Find the nearest base with a different tp_traverse, - and traverse slots while we're at it */ - type = self->ob_type; - base = type; - while ((basetraverse = base->tp_traverse) == subtype_traverse) { - if (base->ob_size) { - int err = traverse_slots(base, self, visit, arg); - if (err) - return err; - } - base = base->tp_base; - assert(base); - } - - if (type->tp_dictoffset != base->tp_dictoffset) { - PyObject **dictptr = _PyObject_GetDictPtr(self); - if (dictptr && *dictptr) - Py_VISIT(*dictptr); - } - - if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) - /* For a heaptype, the instances count as references - to the type. Traverse the type so the collector - can find cycles involving this link. */ - Py_VISIT(type); - - if (basetraverse) - return basetraverse(self, visit, arg); - return 0; -} - -static void -clear_slots(PyTypeObject *type, PyObject *self) -{ - Py_ssize_t i, n; - PyMemberDef *mp; - - n = type->ob_size; - mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); - for (i = 0; i < n; i++, mp++) { - if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) { - char *addr = (char *)self + mp->offset; - PyObject *obj = *(PyObject **)addr; - if (obj != NULL) { - *(PyObject **)addr = NULL; - Py_DECREF(obj); - } - } - } -} - -static int -subtype_clear(PyObject *self) -{ - PyTypeObject *type, *base; - inquiry baseclear; - - /* Find the nearest base with a different tp_clear - and clear slots while we're at it */ - type = self->ob_type; - base = type; - while ((baseclear = base->tp_clear) == subtype_clear) { - if (base->ob_size) - clear_slots(base, self); - base = base->tp_base; - assert(base); - } - - /* There's no need to clear the instance dict (if any); - the collector will call its tp_clear handler. */ - - if (baseclear) - return baseclear(self); - return 0; -} - -static void -subtype_dealloc(PyObject *self) -{ - PyTypeObject *type, *base; - destructor basedealloc; - - /* Extract the type; we expect it to be a heap type */ - type = self->ob_type; - assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); - - /* Test whether the type has GC exactly once */ - - if (!PyType_IS_GC(type)) { - /* It's really rare to find a dynamic type that doesn't have - GC; it can only happen when deriving from 'object' and not - adding any slots or instance variables. This allows - certain simplifications: there's no need to call - clear_slots(), or DECREF the dict, or clear weakrefs. */ - - /* Maybe call finalizer; exit early if resurrected */ - if (type->tp_del) { - type->tp_del(self); - if (self->ob_refcnt > 0) - return; - } - - /* Find the nearest base with a different tp_dealloc */ - base = type; - while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { - assert(base->ob_size == 0); - base = base->tp_base; - assert(base); - } - - /* Call the base tp_dealloc() */ - assert(basedealloc); - basedealloc(self); - - /* Can't reference self beyond this point */ - Py_DECREF(type); - - /* Done */ - return; - } - - /* We get here only if the type has GC */ - - /* UnTrack and re-Track around the trashcan macro, alas */ - /* See explanation at end of function for full disclosure */ - PyObject_GC_UnTrack(self); - ++_PyTrash_delete_nesting; - Py_TRASHCAN_SAFE_BEGIN(self); - --_PyTrash_delete_nesting; - /* DO NOT restore GC tracking at this point. weakref callbacks - * (if any, and whether directly here or indirectly in something we - * call) may trigger GC, and if self is tracked at that point, it - * will look like trash to GC and GC will try to delete self again. - */ - - /* Find the nearest base with a different tp_dealloc */ - base = type; - while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { - base = base->tp_base; - assert(base); - } - - /* If we added a weaklist, we clear it. Do this *before* calling - the finalizer (__del__), clearing slots, or clearing the instance - dict. */ - - if (type->tp_weaklistoffset && !base->tp_weaklistoffset) - PyObject_ClearWeakRefs(self); - - /* Maybe call finalizer; exit early if resurrected */ - if (type->tp_del) { - _PyObject_GC_TRACK(self); - type->tp_del(self); - if (self->ob_refcnt > 0) - goto endlabel; /* resurrected */ - else - _PyObject_GC_UNTRACK(self); - /* New weakrefs could be created during the finalizer call. - If this occurs, clear them out without calling their - finalizers since they might rely on part of the object - being finalized that has already been destroyed. */ - if (type->tp_weaklistoffset && !base->tp_weaklistoffset) { - /* Modeled after GET_WEAKREFS_LISTPTR() */ - PyWeakReference **list = (PyWeakReference **) \ - PyObject_GET_WEAKREFS_LISTPTR(self); - while (*list) - _PyWeakref_ClearRef(*list); - } - } - - /* Clear slots up to the nearest base with a different tp_dealloc */ - base = type; - while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { - if (base->ob_size) - clear_slots(base, self); - base = base->tp_base; - assert(base); - } - - /* If we added a dict, DECREF it */ - if (type->tp_dictoffset && !base->tp_dictoffset) { - PyObject **dictptr = _PyObject_GetDictPtr(self); - if (dictptr != NULL) { - PyObject *dict = *dictptr; - if (dict != NULL) { - Py_DECREF(dict); - *dictptr = NULL; - } - } - } - - /* Call the base tp_dealloc(); first retrack self if - * basedealloc knows about gc. - */ - if (PyType_IS_GC(base)) - _PyObject_GC_TRACK(self); - assert(basedealloc); - basedealloc(self); - - /* Can't reference self beyond this point */ - Py_DECREF(type); - - endlabel: - ++_PyTrash_delete_nesting; - Py_TRASHCAN_SAFE_END(self); - --_PyTrash_delete_nesting; - - /* Explanation of the weirdness around the trashcan macros: - - Q. What do the trashcan macros do? - - A. Read the comment titled "Trashcan mechanism" in object.h. - For one, this explains why there must be a call to GC-untrack - before the trashcan begin macro. Without understanding the - trashcan code, the answers to the following questions don't make - sense. - - Q. Why do we GC-untrack before the trashcan and then immediately - GC-track again afterward? - - A. In the case that the base class is GC-aware, the base class - probably GC-untracks the object. If it does that using the - UNTRACK macro, this will crash when the object is already - untracked. Because we don't know what the base class does, the - only safe thing is to make sure the object is tracked when we - call the base class dealloc. But... The trashcan begin macro - requires that the object is *untracked* before it is called. So - the dance becomes: - - GC untrack - trashcan begin - GC track - - Q. Why did the last question say "immediately GC-track again"? - It's nowhere near immediately. - - A. Because the code *used* to re-track immediately. Bad Idea. - self has a refcount of 0, and if gc ever gets its hands on it - (which can happen if any weakref callback gets invoked), it - looks like trash to gc too, and gc also tries to delete self - then. But we're already deleting self. Double dealloction is - a subtle disaster. - - Q. Why the bizarre (net-zero) manipulation of - _PyTrash_delete_nesting around the trashcan macros? - - A. Some base classes (e.g. list) also use the trashcan mechanism. - The following scenario used to be possible: - - - suppose the trashcan level is one below the trashcan limit - - - subtype_dealloc() is called - - - the trashcan limit is not yet reached, so the trashcan level - is incremented and the code between trashcan begin and end is - executed - - - this destroys much of the object's contents, including its - slots and __dict__ - - - basedealloc() is called; this is really list_dealloc(), or - some other type which also uses the trashcan macros - - - the trashcan limit is now reached, so the object is put on the - trashcan's to-be-deleted-later list - - - basedealloc() returns - - - subtype_dealloc() decrefs the object's type - - - subtype_dealloc() returns - - - later, the trashcan code starts deleting the objects from its - to-be-deleted-later list - - - subtype_dealloc() is called *AGAIN* for the same object - - - at the very least (if the destroyed slots and __dict__ don't - cause problems) the object's type gets decref'ed a second - time, which is *BAD*!!! - - The remedy is to make sure that if the code between trashcan - begin and end in subtype_dealloc() is called, the code between - trashcan begin and end in basedealloc() will also be called. - This is done by decrementing the level after passing into the - trashcan block, and incrementing it just before leaving the - block. - - But now it's possible that a chain of objects consisting solely - of objects whose deallocator is subtype_dealloc() will defeat - the trashcan mechanism completely: the decremented level means - that the effective level never reaches the limit. Therefore, we - *increment* the level *before* entering the trashcan block, and - matchingly decrement it after leaving. This means the trashcan - code will trigger a little early, but that's no big deal. - - Q. Are there any live examples of code in need of all this - complexity? - - A. Yes. See SF bug 668433 for code that crashed (when Python was - compiled in debug mode) before the trashcan level manipulations - were added. For more discussion, see SF patches 581742, 575073 - and bug 574207. - */ -} - -static PyTypeObject *solid_base(PyTypeObject *type); - -/* type test with subclassing support */ - -int -PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b) -{ - PyObject *mro; - - if (!(a->tp_flags & Py_TPFLAGS_HAVE_CLASS)) - return b == a || b == &PyBaseObject_Type; - - mro = a->tp_mro; - if (mro != NULL) { - /* Deal with multiple inheritance without recursion - by walking the MRO tuple */ - Py_ssize_t i, n; - assert(PyTuple_Check(mro)); - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) - return 1; - } - return 0; - } - else { - /* a is not completely initilized yet; follow tp_base */ - do { - if (a == b) - return 1; - a = a->tp_base; - } while (a != NULL); - return b == &PyBaseObject_Type; - } -} - -/* Internal routines to do a method lookup in the type - without looking in the instance dictionary - (so we can't use PyObject_GetAttr) but still binding - it to the instance. The arguments are the object, - the method name as a C string, and the address of a - static variable used to cache the interned Python string. - - Two variants: - - - lookup_maybe() returns NULL without raising an exception - when the _PyType_Lookup() call fails; - - - lookup_method() always raises an exception upon errors. -*/ - -static PyObject * -lookup_maybe(PyObject *self, char *attrstr, PyObject **attrobj) -{ - PyObject *res; - - if (*attrobj == NULL) { - *attrobj = PyString_InternFromString(attrstr); - if (*attrobj == NULL) - return NULL; - } - res = _PyType_Lookup(self->ob_type, *attrobj); - if (res != NULL) { - descrgetfunc f; - if ((f = res->ob_type->tp_descr_get) == NULL) - Py_INCREF(res); - else - res = f(res, self, (PyObject *)(self->ob_type)); - } - return res; -} - -static PyObject * -lookup_method(PyObject *self, char *attrstr, PyObject **attrobj) -{ - PyObject *res = lookup_maybe(self, attrstr, attrobj); - if (res == NULL && !PyErr_Occurred()) - PyErr_SetObject(PyExc_AttributeError, *attrobj); - return res; -} - -/* A variation of PyObject_CallMethod that uses lookup_method() - instead of PyObject_GetAttrString(). This uses the same convention - as lookup_method to cache the interned name string object. */ - -static PyObject * -call_method(PyObject *o, char *name, PyObject **nameobj, char *format, ...) -{ - va_list va; - PyObject *args, *func = 0, *retval; - va_start(va, format); - - func = lookup_maybe(o, name, nameobj); - if (func == NULL) { - va_end(va); - if (!PyErr_Occurred()) - PyErr_SetObject(PyExc_AttributeError, *nameobj); - return NULL; - } - - if (format && *format) - args = Py_VaBuildValue(format, va); - else - args = PyTuple_New(0); - - va_end(va); - - if (args == NULL) - return NULL; - - assert(PyTuple_Check(args)); - retval = PyObject_Call(func, args, NULL); - - Py_DECREF(args); - Py_DECREF(func); - - return retval; -} - -/* Clone of call_method() that returns NotImplemented when the lookup fails. */ - -static PyObject * -call_maybe(PyObject *o, char *name, PyObject **nameobj, char *format, ...) -{ - va_list va; - PyObject *args, *func = 0, *retval; - va_start(va, format); - - func = lookup_maybe(o, name, nameobj); - if (func == NULL) { - va_end(va); - if (!PyErr_Occurred()) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return NULL; - } - - if (format && *format) - args = Py_VaBuildValue(format, va); - else - args = PyTuple_New(0); - - va_end(va); - - if (args == NULL) - return NULL; - - assert(PyTuple_Check(args)); - retval = PyObject_Call(func, args, NULL); - - Py_DECREF(args); - Py_DECREF(func); - - return retval; -} - -static int -fill_classic_mro(PyObject *mro, PyObject *cls) -{ - PyObject *bases, *base; - Py_ssize_t i, n; - - assert(PyList_Check(mro)); - assert(PyClass_Check(cls)); - i = PySequence_Contains(mro, cls); - if (i < 0) - return -1; - if (!i) { - if (PyList_Append(mro, cls) < 0) - return -1; - } - bases = ((PyClassObject *)cls)->cl_bases; - assert(bases && PyTuple_Check(bases)); - n = PyTuple_GET_SIZE(bases); - for (i = 0; i < n; i++) { - base = PyTuple_GET_ITEM(bases, i); - if (fill_classic_mro(mro, base) < 0) - return -1; - } - return 0; -} - -static PyObject * -classic_mro(PyObject *cls) -{ - PyObject *mro; - - assert(PyClass_Check(cls)); - mro = PyList_New(0); - if (mro != NULL) { - if (fill_classic_mro(mro, cls) == 0) - return mro; - Py_DECREF(mro); - } - return NULL; -} - -/* - Method resolution order algorithm C3 described in - "A Monotonic Superclass Linearization for Dylan", - by Kim Barrett, Bob Cassel, Paul Haahr, - David A. Moon, Keith Playford, and P. Tucker Withington. - (OOPSLA 1996) - - Some notes about the rules implied by C3: - - No duplicate bases. - It isn't legal to repeat a class in a list of base classes. - - The next three properties are the 3 constraints in "C3". - - Local precendece order. - If A precedes B in C's MRO, then A will precede B in the MRO of all - subclasses of C. - - Monotonicity. - The MRO of a class must be an extension without reordering of the - MRO of each of its superclasses. - - Extended Precedence Graph (EPG). - Linearization is consistent if there is a path in the EPG from - each class to all its successors in the linearization. See - the paper for definition of EPG. - */ - -static int -tail_contains(PyObject *list, int whence, PyObject *o) { - Py_ssize_t j, size; - size = PyList_GET_SIZE(list); - - for (j = whence+1; j < size; j++) { - if (PyList_GET_ITEM(list, j) == o) - return 1; - } - return 0; -} - -static PyObject * -class_name(PyObject *cls) -{ - PyObject *name = PyObject_GetAttrString(cls, "__name__"); - if (name == NULL) { - PyErr_Clear(); - Py_XDECREF(name); - name = PyObject_Repr(cls); - } - if (name == NULL) - return NULL; - if (!PyString_Check(name)) { - Py_DECREF(name); - return NULL; - } - return name; -} - -static int -check_duplicates(PyObject *list) -{ - Py_ssize_t i, j, n; - /* Let's use a quadratic time algorithm, - assuming that the bases lists is short. - */ - n = PyList_GET_SIZE(list); - for (i = 0; i < n; i++) { - PyObject *o = PyList_GET_ITEM(list, i); - for (j = i + 1; j < n; j++) { - if (PyList_GET_ITEM(list, j) == o) { - o = class_name(o); - PyErr_Format(PyExc_TypeError, - "duplicate base class %s", - o ? PyString_AS_STRING(o) : "?"); - Py_XDECREF(o); - return -1; - } - } - } - return 0; -} - -/* Raise a TypeError for an MRO order disagreement. - - It's hard to produce a good error message. In the absence of better - insight into error reporting, report the classes that were candidates - to be put next into the MRO. There is some conflict between the - order in which they should be put in the MRO, but it's hard to - diagnose what constraint can't be satisfied. -*/ - -static void -set_mro_error(PyObject *to_merge, int *remain) -{ - Py_ssize_t i, n, off, to_merge_size; - char buf[1000]; - PyObject *k, *v; - PyObject *set = PyDict_New(); - if (!set) return; - - to_merge_size = PyList_GET_SIZE(to_merge); - for (i = 0; i < to_merge_size; i++) { - PyObject *L = PyList_GET_ITEM(to_merge, i); - if (remain[i] < PyList_GET_SIZE(L)) { - PyObject *c = PyList_GET_ITEM(L, remain[i]); - if (PyDict_SetItem(set, c, Py_None) < 0) { - Py_DECREF(set); - return; - } - } - } - n = PyDict_Size(set); - - off = PyOS_snprintf(buf, sizeof(buf), "Cannot create a \ -consistent method resolution\norder (MRO) for bases"); - i = 0; - while (PyDict_Next(set, &i, &k, &v) && (size_t)off < sizeof(buf)) { - PyObject *name = class_name(k); - off += PyOS_snprintf(buf + off, sizeof(buf) - off, " %s", - name ? PyString_AS_STRING(name) : "?"); - Py_XDECREF(name); - if (--n && (size_t)(off+1) < sizeof(buf)) { - buf[off++] = ','; - buf[off] = '\0'; - } - } - PyErr_SetString(PyExc_TypeError, buf); - Py_DECREF(set); -} - -static int -pmerge(PyObject *acc, PyObject* to_merge) { - Py_ssize_t i, j, to_merge_size, empty_cnt; - int *remain; - int ok; - - to_merge_size = PyList_GET_SIZE(to_merge); - - /* remain stores an index into each sublist of to_merge. - remain[i] is the index of the next base in to_merge[i] - that is not included in acc. - */ - remain = (int *)PyMem_MALLOC(SIZEOF_INT*to_merge_size); - if (remain == NULL) - return -1; - for (i = 0; i < to_merge_size; i++) - remain[i] = 0; - - again: - empty_cnt = 0; - for (i = 0; i < to_merge_size; i++) { - PyObject *candidate; - - PyObject *cur_list = PyList_GET_ITEM(to_merge, i); - - if (remain[i] >= PyList_GET_SIZE(cur_list)) { - empty_cnt++; - continue; - } - - /* Choose next candidate for MRO. - - The input sequences alone can determine the choice. - If not, choose the class which appears in the MRO - of the earliest direct superclass of the new class. - */ - - candidate = PyList_GET_ITEM(cur_list, remain[i]); - for (j = 0; j < to_merge_size; j++) { - PyObject *j_lst = PyList_GET_ITEM(to_merge, j); - if (tail_contains(j_lst, remain[j], candidate)) { - goto skip; /* continue outer loop */ - } - } - ok = PyList_Append(acc, candidate); - if (ok < 0) { - PyMem_Free(remain); - return -1; - } - for (j = 0; j < to_merge_size; j++) { - PyObject *j_lst = PyList_GET_ITEM(to_merge, j); - if (remain[j] < PyList_GET_SIZE(j_lst) && - PyList_GET_ITEM(j_lst, remain[j]) == candidate) { - remain[j]++; - } - } - goto again; - skip: ; - } - - if (empty_cnt == to_merge_size) { - PyMem_FREE(remain); - return 0; - } - set_mro_error(to_merge, remain); - PyMem_FREE(remain); - return -1; -} - -static PyObject * -mro_implementation(PyTypeObject *type) -{ - Py_ssize_t i, n; - int ok; - PyObject *bases, *result; - PyObject *to_merge, *bases_aslist; - - if(type->tp_dict == NULL) { - if(PyType_Ready(type) < 0) - return NULL; - } - - /* Find a superclass linearization that honors the constraints - of the explicit lists of bases and the constraints implied by - each base class. - - to_merge is a list of lists, where each list is a superclass - linearization implied by a base class. The last element of - to_merge is the declared list of bases. - */ - - bases = type->tp_bases; - n = PyTuple_GET_SIZE(bases); - - to_merge = PyList_New(n+1); - if (to_merge == NULL) - return NULL; - - for (i = 0; i < n; i++) { - PyObject *base = PyTuple_GET_ITEM(bases, i); - PyObject *parentMRO; - if (PyType_Check(base)) - parentMRO = PySequence_List( - ((PyTypeObject*)base)->tp_mro); - else - parentMRO = classic_mro(base); - if (parentMRO == NULL) { - Py_DECREF(to_merge); - return NULL; - } - - PyList_SET_ITEM(to_merge, i, parentMRO); - } - - bases_aslist = PySequence_List(bases); - if (bases_aslist == NULL) { - Py_DECREF(to_merge); - return NULL; - } - /* This is just a basic sanity check. */ - if (check_duplicates(bases_aslist) < 0) { - Py_DECREF(to_merge); - Py_DECREF(bases_aslist); - return NULL; - } - PyList_SET_ITEM(to_merge, n, bases_aslist); - - result = Py_BuildValue("[O]", (PyObject *)type); - if (result == NULL) { - Py_DECREF(to_merge); - return NULL; - } - - ok = pmerge(result, to_merge); - Py_DECREF(to_merge); - if (ok < 0) { - Py_DECREF(result); - return NULL; - } - - return result; -} - -static PyObject * -mro_external(PyObject *self) -{ - PyTypeObject *type = (PyTypeObject *)self; - - return mro_implementation(type); -} - -static int -mro_internal(PyTypeObject *type) -{ - PyObject *mro, *result, *tuple; - int checkit = 0; - - if (type->ob_type == &PyType_Type) { - result = mro_implementation(type); - } - else { - static PyObject *mro_str; - checkit = 1; - mro = lookup_method((PyObject *)type, "mro", &mro_str); - if (mro == NULL) - return -1; - result = PyObject_CallObject(mro, NULL); - Py_DECREF(mro); - } - if (result == NULL) - return -1; - tuple = PySequence_Tuple(result); - Py_DECREF(result); - if (tuple == NULL) - return -1; - if (checkit) { - Py_ssize_t i, len; - PyObject *cls; - PyTypeObject *solid; - - solid = solid_base(type); - - len = PyTuple_GET_SIZE(tuple); - - for (i = 0; i < len; i++) { - PyTypeObject *t; - cls = PyTuple_GET_ITEM(tuple, i); - if (PyClass_Check(cls)) - continue; - else if (!PyType_Check(cls)) { - PyErr_Format(PyExc_TypeError, - "mro() returned a non-class ('%.500s')", - cls->ob_type->tp_name); - Py_DECREF(tuple); - return -1; - } - t = (PyTypeObject*)cls; - if (!PyType_IsSubtype(solid, solid_base(t))) { - PyErr_Format(PyExc_TypeError, - "mro() returned base with unsuitable layout ('%.500s')", - t->tp_name); - Py_DECREF(tuple); - return -1; - } - } - } - type->tp_mro = tuple; - return 0; -} - - -/* Calculate the best base amongst multiple base classes. - This is the first one that's on the path to the "solid base". */ - -static PyTypeObject * -best_base(PyObject *bases) -{ - Py_ssize_t i, n; - PyTypeObject *base, *winner, *candidate, *base_i; - PyObject *base_proto; - - assert(PyTuple_Check(bases)); - n = PyTuple_GET_SIZE(bases); - assert(n > 0); - base = NULL; - winner = NULL; - for (i = 0; i < n; i++) { - base_proto = PyTuple_GET_ITEM(bases, i); - if (PyClass_Check(base_proto)) - continue; - if (!PyType_Check(base_proto)) { - PyErr_SetString( - PyExc_TypeError, - "bases must be types"); - return NULL; - } - base_i = (PyTypeObject *)base_proto; - if (base_i->tp_dict == NULL) { - if (PyType_Ready(base_i) < 0) - return NULL; - } - candidate = solid_base(base_i); - if (winner == NULL) { - winner = candidate; - base = base_i; - } - else if (PyType_IsSubtype(winner, candidate)) - ; - else if (PyType_IsSubtype(candidate, winner)) { - winner = candidate; - base = base_i; - } - else { - PyErr_SetString( - PyExc_TypeError, - "multiple bases have " - "instance lay-out conflict"); - return NULL; - } - } - if (base == NULL) - PyErr_SetString(PyExc_TypeError, - "a new-style class can't have only classic bases"); - return base; -} - -static int -extra_ivars(PyTypeObject *type, PyTypeObject *base) -{ - size_t t_size = type->tp_basicsize; - size_t b_size = base->tp_basicsize; - - assert(t_size >= b_size); /* Else type smaller than base! */ - if (type->tp_itemsize || base->tp_itemsize) { - /* If itemsize is involved, stricter rules */ - return t_size != b_size || - type->tp_itemsize != base->tp_itemsize; - } - if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 && - type->tp_weaklistoffset + sizeof(PyObject *) == t_size) - t_size -= sizeof(PyObject *); - if (type->tp_dictoffset && base->tp_dictoffset == 0 && - type->tp_dictoffset + sizeof(PyObject *) == t_size) - t_size -= sizeof(PyObject *); - - return t_size != b_size; -} - -static PyTypeObject * -solid_base(PyTypeObject *type) -{ - PyTypeObject *base; - - if (type->tp_base) - base = solid_base(type->tp_base); - else - base = &PyBaseObject_Type; - if (extra_ivars(type, base)) - return type; - else - return base; -} - -static void object_dealloc(PyObject *); -static int object_init(PyObject *, PyObject *, PyObject *); -static int update_slot(PyTypeObject *, PyObject *); -static void fixup_slot_dispatchers(PyTypeObject *); - -static PyObject * -subtype_dict(PyObject *obj, void *context) -{ - PyObject **dictptr = _PyObject_GetDictPtr(obj); - PyObject *dict; - - if (dictptr == NULL) { - PyErr_SetString(PyExc_AttributeError, - "This object has no __dict__"); - return NULL; - } - dict = *dictptr; - if (dict == NULL) - *dictptr = dict = PyDict_New(); - Py_XINCREF(dict); - return dict; -} - -static int -subtype_setdict(PyObject *obj, PyObject *value, void *context) -{ - PyObject **dictptr = _PyObject_GetDictPtr(obj); - PyObject *dict; - - if (dictptr == NULL) { - PyErr_SetString(PyExc_AttributeError, - "This object has no __dict__"); - return -1; - } - if (value != NULL && !PyDict_Check(value)) { - PyErr_Format(PyExc_TypeError, - "__dict__ must be set to a dictionary, " - "not a '%.200s'", value->ob_type->tp_name); - return -1; - } - dict = *dictptr; - Py_XINCREF(value); - *dictptr = value; - Py_XDECREF(dict); - return 0; -} - -static PyObject * -subtype_getweakref(PyObject *obj, void *context) -{ - PyObject **weaklistptr; - PyObject *result; - - if (obj->ob_type->tp_weaklistoffset == 0) { - PyErr_SetString(PyExc_AttributeError, - "This object has no __weakref__"); - return NULL; - } - assert(obj->ob_type->tp_weaklistoffset > 0); - assert(obj->ob_type->tp_weaklistoffset + sizeof(PyObject *) <= - (size_t)(obj->ob_type->tp_basicsize)); - weaklistptr = (PyObject **) - ((char *)obj + obj->ob_type->tp_weaklistoffset); - if (*weaklistptr == NULL) - result = Py_None; - else - result = *weaklistptr; - Py_INCREF(result); - return result; -} - -/* Three variants on the subtype_getsets list. */ - -static PyGetSetDef subtype_getsets_full[] = { - {"__dict__", subtype_dict, subtype_setdict, - PyDoc_STR("dictionary for instance variables (if defined)")}, - {"__weakref__", subtype_getweakref, NULL, - PyDoc_STR("list of weak references to the object (if defined)")}, - {0} -}; - -static PyGetSetDef subtype_getsets_dict_only[] = { - {"__dict__", subtype_dict, subtype_setdict, - PyDoc_STR("dictionary for instance variables (if defined)")}, - {0} -}; - -static PyGetSetDef subtype_getsets_weakref_only[] = { - {"__weakref__", subtype_getweakref, NULL, - PyDoc_STR("list of weak references to the object (if defined)")}, - {0} -}; - -static int -valid_identifier(PyObject *s) -{ - unsigned char *p; - Py_ssize_t i, n; - - if (!PyString_Check(s)) { - PyErr_Format(PyExc_TypeError, - "__slots__ items must be strings, not '%.200s'", - s->ob_type->tp_name); - return 0; - } - p = (unsigned char *) PyString_AS_STRING(s); - n = PyString_GET_SIZE(s); - /* We must reject an empty name. As a hack, we bump the - length to 1 so that the loop will balk on the trailing \0. */ - if (n == 0) - n = 1; - for (i = 0; i < n; i++, p++) { - if (!(i == 0 ? isalpha(*p) : isalnum(*p)) && *p != '_') { - PyErr_SetString(PyExc_TypeError, - "__slots__ must be identifiers"); - return 0; - } - } - return 1; -} - -#ifdef Py_USING_UNICODE -/* Replace Unicode objects in slots. */ - -static PyObject * -_unicode_to_string(PyObject *slots, Py_ssize_t nslots) -{ - PyObject *tmp = NULL; - PyObject *slot_name, *new_name; - Py_ssize_t i; - - for (i = 0; i < nslots; i++) { - if (PyUnicode_Check(slot_name = PyTuple_GET_ITEM(slots, i))) { - if (tmp == NULL) { - tmp = PySequence_List(slots); - if (tmp == NULL) - return NULL; - } - new_name = _PyUnicode_AsDefaultEncodedString(slot_name, - NULL); - if (new_name == NULL) { - Py_DECREF(tmp); - return NULL; - } - Py_INCREF(new_name); - PyList_SET_ITEM(tmp, i, new_name); - Py_DECREF(slot_name); - } - } - if (tmp != NULL) { - slots = PyList_AsTuple(tmp); - Py_DECREF(tmp); - } - return slots; -} -#endif - -static PyObject * -type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) -{ - PyObject *name, *bases, *dict; - static char *kwlist[] = {"name", "bases", "dict", 0}; - PyObject *slots, *tmp, *newslots; - PyTypeObject *type, *base, *tmptype, *winner; - PyHeapTypeObject *et; - PyMemberDef *mp; - Py_ssize_t i, nbases, nslots, slotoffset, add_dict, add_weak; - int j, may_add_dict, may_add_weak; - - assert(args != NULL && PyTuple_Check(args)); - assert(kwds == NULL || PyDict_Check(kwds)); - - /* Special case: type(x) should return x->ob_type */ - { - const Py_ssize_t nargs = PyTuple_GET_SIZE(args); - const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds); - - if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) { - PyObject *x = PyTuple_GET_ITEM(args, 0); - Py_INCREF(x->ob_type); - return (PyObject *) x->ob_type; - } - - /* SF bug 475327 -- if that didn't trigger, we need 3 - arguments. but PyArg_ParseTupleAndKeywords below may give - a msg saying type() needs exactly 3. */ - if (nargs + nkwds != 3) { - PyErr_SetString(PyExc_TypeError, - "type() takes 1 or 3 arguments"); - return NULL; - } - } - - /* Check arguments: (name, bases, dict) */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:type", kwlist, - &name, - &PyTuple_Type, &bases, - &PyDict_Type, &dict)) - return NULL; - - /* Determine the proper metatype to deal with this, - and check for metatype conflicts while we're at it. - Note that if some other metatype wins to contract, - it's possible that its instances are not types. */ - nbases = PyTuple_GET_SIZE(bases); - winner = metatype; - for (i = 0; i < nbases; i++) { - tmp = PyTuple_GET_ITEM(bases, i); - tmptype = tmp->ob_type; - if (tmptype == &PyClass_Type) - continue; /* Special case classic classes */ - if (PyType_IsSubtype(winner, tmptype)) - continue; - if (PyType_IsSubtype(tmptype, winner)) { - winner = tmptype; - continue; - } - PyErr_SetString(PyExc_TypeError, - "metaclass conflict: " - "the metaclass of a derived class " - "must be a (non-strict) subclass " - "of the metaclasses of all its bases"); - return NULL; - } - if (winner != metatype) { - if (winner->tp_new != type_new) /* Pass it to the winner */ - return winner->tp_new(winner, args, kwds); - metatype = winner; - } - - /* Adjust for empty tuple bases */ - if (nbases == 0) { - bases = PyTuple_Pack(1, &PyBaseObject_Type); - if (bases == NULL) - return NULL; - nbases = 1; - } - else - Py_INCREF(bases); - - /* XXX From here until type is allocated, "return NULL" leaks bases! */ - - /* Calculate best base, and check that all bases are type objects */ - base = best_base(bases); - if (base == NULL) { - Py_DECREF(bases); - return NULL; - } - if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) { - PyErr_Format(PyExc_TypeError, - "type '%.100s' is not an acceptable base type", - base->tp_name); - Py_DECREF(bases); - return NULL; - } - - /* Check for a __slots__ sequence variable in dict, and count it */ - slots = PyDict_GetItemString(dict, "__slots__"); - nslots = 0; - add_dict = 0; - add_weak = 0; - may_add_dict = base->tp_dictoffset == 0; - may_add_weak = base->tp_weaklistoffset == 0 && base->tp_itemsize == 0; - if (slots == NULL) { - if (may_add_dict) { - add_dict++; - } - if (may_add_weak) { - add_weak++; - } - } - else { - /* Have slots */ - - /* Make it into a tuple */ - if (PyString_Check(slots)) - slots = PyTuple_Pack(1, slots); - else - slots = PySequence_Tuple(slots); - if (slots == NULL) { - Py_DECREF(bases); - return NULL; - } - assert(PyTuple_Check(slots)); - - /* Are slots allowed? */ - nslots = PyTuple_GET_SIZE(slots); - if (nslots > 0 && base->tp_itemsize != 0) { - PyErr_Format(PyExc_TypeError, - "nonempty __slots__ " - "not supported for subtype of '%s'", - base->tp_name); - bad_slots: - Py_DECREF(bases); - Py_DECREF(slots); - return NULL; - } - -#ifdef Py_USING_UNICODE - tmp = _unicode_to_string(slots, nslots); - if (tmp == NULL) - goto bad_slots; - if (tmp != slots) { - Py_DECREF(slots); - slots = tmp; - } -#endif - /* Check for valid slot names and two special cases */ - for (i = 0; i < nslots; i++) { - PyObject *tmp = PyTuple_GET_ITEM(slots, i); - char *s; - if (!valid_identifier(tmp)) - goto bad_slots; - assert(PyString_Check(tmp)); - s = PyString_AS_STRING(tmp); - if (strcmp(s, "__dict__") == 0) { - if (!may_add_dict || add_dict) { - PyErr_SetString(PyExc_TypeError, - "__dict__ slot disallowed: " - "we already got one"); - goto bad_slots; - } - add_dict++; - } - if (strcmp(s, "__weakref__") == 0) { - if (!may_add_weak || add_weak) { - PyErr_SetString(PyExc_TypeError, - "__weakref__ slot disallowed: " - "either we already got one, " - "or __itemsize__ != 0"); - goto bad_slots; - } - add_weak++; - } - } - - /* Copy slots into yet another tuple, demangling names */ - newslots = PyTuple_New(nslots - add_dict - add_weak); - if (newslots == NULL) - goto bad_slots; - for (i = j = 0; i < nslots; i++) { - char *s; - tmp = PyTuple_GET_ITEM(slots, i); - s = PyString_AS_STRING(tmp); - if ((add_dict && strcmp(s, "__dict__") == 0) || - (add_weak && strcmp(s, "__weakref__") == 0)) - continue; - tmp =_Py_Mangle(name, tmp); - if (!tmp) - goto bad_slots; - PyTuple_SET_ITEM(newslots, j, tmp); - j++; - } - assert(j == nslots - add_dict - add_weak); - nslots = j; - Py_DECREF(slots); - slots = newslots; - - /* Secondary bases may provide weakrefs or dict */ - if (nbases > 1 && - ((may_add_dict && !add_dict) || - (may_add_weak && !add_weak))) { - for (i = 0; i < nbases; i++) { - tmp = PyTuple_GET_ITEM(bases, i); - if (tmp == (PyObject *)base) - continue; /* Skip primary base */ - if (PyClass_Check(tmp)) { - /* Classic base class provides both */ - if (may_add_dict && !add_dict) - add_dict++; - if (may_add_weak && !add_weak) - add_weak++; - break; - } - assert(PyType_Check(tmp)); - tmptype = (PyTypeObject *)tmp; - if (may_add_dict && !add_dict && - tmptype->tp_dictoffset != 0) - add_dict++; - if (may_add_weak && !add_weak && - tmptype->tp_weaklistoffset != 0) - add_weak++; - if (may_add_dict && !add_dict) - continue; - if (may_add_weak && !add_weak) - continue; - /* Nothing more to check */ - break; - } - } - } - - /* XXX From here until type is safely allocated, - "return NULL" may leak slots! */ - - /* Allocate the type object */ - type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots); - if (type == NULL) { - Py_XDECREF(slots); - Py_DECREF(bases); - return NULL; - } - - /* Keep name and slots alive in the extended type object */ - et = (PyHeapTypeObject *)type; - Py_INCREF(name); - et->ht_name = name; - et->ht_slots = slots; - - /* Initialize tp_flags */ - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | - Py_TPFLAGS_BASETYPE; - if (base->tp_flags & Py_TPFLAGS_HAVE_GC) - type->tp_flags |= Py_TPFLAGS_HAVE_GC; - - /* It's a new-style number unless it specifically inherits any - old-style numeric behavior */ - if ((base->tp_flags & Py_TPFLAGS_CHECKTYPES) || - (base->tp_as_number == NULL)) - type->tp_flags |= Py_TPFLAGS_CHECKTYPES; - - /* Initialize essential fields */ - type->tp_as_number = &et->as_number; - type->tp_as_sequence = &et->as_sequence; - type->tp_as_mapping = &et->as_mapping; - type->tp_as_buffer = &et->as_buffer; - type->tp_name = PyString_AS_STRING(name); - - /* Set tp_base and tp_bases */ - type->tp_bases = bases; - Py_INCREF(base); - type->tp_base = base; - - /* Initialize tp_dict from passed-in dict */ - type->tp_dict = dict = PyDict_Copy(dict); - if (dict == NULL) { - Py_DECREF(type); - return NULL; - } - - /* Set __module__ in the dict */ - if (PyDict_GetItemString(dict, "__module__") == NULL) { - tmp = PyEval_GetGlobals(); - if (tmp != NULL) { - tmp = PyDict_GetItemString(tmp, "__name__"); - if (tmp != NULL) { - if (PyDict_SetItemString(dict, "__module__", - tmp) < 0) - return NULL; - } - } - } - - /* Set tp_doc to a copy of dict['__doc__'], if the latter is there - and is a string. The __doc__ accessor will first look for tp_doc; - if that fails, it will still look into __dict__. - */ - { - PyObject *doc = PyDict_GetItemString(dict, "__doc__"); - if (doc != NULL && PyString_Check(doc)) { - const size_t n = (size_t)PyString_GET_SIZE(doc); - char *tp_doc = (char *)PyObject_MALLOC(n+1); - if (tp_doc == NULL) { - Py_DECREF(type); - return NULL; - } - memcpy(tp_doc, PyString_AS_STRING(doc), n+1); - type->tp_doc = tp_doc; - } - } - - /* Special-case __new__: if it's a plain function, - make it a static function */ - tmp = PyDict_GetItemString(dict, "__new__"); - if (tmp != NULL && PyFunction_Check(tmp)) { - tmp = PyStaticMethod_New(tmp); - if (tmp == NULL) { - Py_DECREF(type); - return NULL; - } - PyDict_SetItemString(dict, "__new__", tmp); - Py_DECREF(tmp); - } - - /* Add descriptors for custom slots from __slots__, or for __dict__ */ - mp = PyHeapType_GET_MEMBERS(et); - slotoffset = base->tp_basicsize; - if (slots != NULL) { - for (i = 0; i < nslots; i++, mp++) { - mp->name = PyString_AS_STRING( - PyTuple_GET_ITEM(slots, i)); - mp->type = T_OBJECT_EX; - mp->offset = slotoffset; - - /* __dict__ and __weakref__ are already filtered out */ - assert(strcmp(mp->name, "__dict__") != 0); - assert(strcmp(mp->name, "__weakref__") != 0); - - slotoffset += sizeof(PyObject *); - } - } - if (add_dict) { - if (base->tp_itemsize) - type->tp_dictoffset = -(long)sizeof(PyObject *); - else - type->tp_dictoffset = slotoffset; - slotoffset += sizeof(PyObject *); - } - if (add_weak) { - assert(!base->tp_itemsize); - type->tp_weaklistoffset = slotoffset; - slotoffset += sizeof(PyObject *); - } - type->tp_basicsize = slotoffset; - type->tp_itemsize = base->tp_itemsize; - type->tp_members = PyHeapType_GET_MEMBERS(et); - - if (type->tp_weaklistoffset && type->tp_dictoffset) - type->tp_getset = subtype_getsets_full; - else if (type->tp_weaklistoffset && !type->tp_dictoffset) - type->tp_getset = subtype_getsets_weakref_only; - else if (!type->tp_weaklistoffset && type->tp_dictoffset) - type->tp_getset = subtype_getsets_dict_only; - else - type->tp_getset = NULL; - - /* Special case some slots */ - if (type->tp_dictoffset != 0 || nslots > 0) { - if (base->tp_getattr == NULL && base->tp_getattro == NULL) - type->tp_getattro = PyObject_GenericGetAttr; - if (base->tp_setattr == NULL && base->tp_setattro == NULL) - type->tp_setattro = PyObject_GenericSetAttr; - } - type->tp_dealloc = subtype_dealloc; - - /* Enable GC unless there are really no instance variables possible */ - if (!(type->tp_basicsize == sizeof(PyObject) && - type->tp_itemsize == 0)) - type->tp_flags |= Py_TPFLAGS_HAVE_GC; - - /* Always override allocation strategy to use regular heap */ - type->tp_alloc = PyType_GenericAlloc; - if (type->tp_flags & Py_TPFLAGS_HAVE_GC) { - type->tp_free = PyObject_GC_Del; - type->tp_traverse = subtype_traverse; - type->tp_clear = subtype_clear; - } - else - type->tp_free = PyObject_Del; - - /* Initialize the rest */ - if (PyType_Ready(type) < 0) { - Py_DECREF(type); - return NULL; - } - - /* Put the proper slots in place */ - fixup_slot_dispatchers(type); - - return (PyObject *)type; -} - -/* Internal API to look for a name through the MRO. - This returns a borrowed reference, and doesn't set an exception! */ -PyObject * -_PyType_Lookup(PyTypeObject *type, PyObject *name) -{ - Py_ssize_t i, n; - PyObject *mro, *res, *base, *dict; - - /* Look in tp_dict of types in MRO */ - mro = type->tp_mro; - - /* If mro is NULL, the type is either not yet initialized - by PyType_Ready(), or already cleared by type_clear(). - Either way the safest thing to do is to return NULL. */ - if (mro == NULL) - return NULL; - - assert(PyTuple_Check(mro)); - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - base = PyTuple_GET_ITEM(mro, i); - if (PyClass_Check(base)) - dict = ((PyClassObject *)base)->cl_dict; - else { - assert(PyType_Check(base)); - dict = ((PyTypeObject *)base)->tp_dict; - } - assert(dict && PyDict_Check(dict)); - res = PyDict_GetItem(dict, name); - if (res != NULL) - return res; - } - return NULL; -} - -/* This is similar to PyObject_GenericGetAttr(), - but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ -static PyObject * -type_getattro(PyTypeObject *type, PyObject *name) -{ - PyTypeObject *metatype = type->ob_type; - PyObject *meta_attribute, *attribute; - descrgetfunc meta_get; - - /* Initialize this type (we'll assume the metatype is initialized) */ - if (type->tp_dict == NULL) { - if (PyType_Ready(type) < 0) - return NULL; - } - - /* No readable descriptor found yet */ - meta_get = NULL; - - /* Look for the attribute in the metatype */ - meta_attribute = _PyType_Lookup(metatype, name); - - if (meta_attribute != NULL) { - meta_get = meta_attribute->ob_type->tp_descr_get; - - if (meta_get != NULL && PyDescr_IsData(meta_attribute)) { - /* Data descriptors implement tp_descr_set to intercept - * writes. Assume the attribute is not overridden in - * type's tp_dict (and bases): call the descriptor now. - */ - return meta_get(meta_attribute, (PyObject *)type, - (PyObject *)metatype); - } - Py_INCREF(meta_attribute); - } - - /* No data descriptor found on metatype. Look in tp_dict of this - * type and its bases */ - attribute = _PyType_Lookup(type, name); - if (attribute != NULL) { - /* Implement descriptor functionality, if any */ - descrgetfunc local_get = attribute->ob_type->tp_descr_get; - - Py_XDECREF(meta_attribute); - - if (local_get != NULL) { - /* NULL 2nd argument indicates the descriptor was - * found on the target object itself (or a base) */ - return local_get(attribute, (PyObject *)NULL, - (PyObject *)type); - } - - Py_INCREF(attribute); - return attribute; - } - - /* No attribute found in local __dict__ (or bases): use the - * descriptor from the metatype, if any */ - if (meta_get != NULL) { - PyObject *res; - res = meta_get(meta_attribute, (PyObject *)type, - (PyObject *)metatype); - Py_DECREF(meta_attribute); - return res; - } - - /* If an ordinary attribute was found on the metatype, return it now */ - if (meta_attribute != NULL) { - return meta_attribute; - } - - /* Give up */ - PyErr_Format(PyExc_AttributeError, - "type object '%.50s' has no attribute '%.400s'", - type->tp_name, PyString_AS_STRING(name)); - return NULL; -} - -static int -type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) -{ - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - PyErr_Format( - PyExc_TypeError, - "can't set attributes of built-in/extension type '%s'", - type->tp_name); - return -1; - } - /* XXX Example of how I expect this to be used... - if (update_subclasses(type, name, invalidate_cache, NULL) < 0) - return -1; - */ - if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) - return -1; - return update_slot(type, name); -} - -static void -type_dealloc(PyTypeObject *type) -{ - PyHeapTypeObject *et; - - /* Assert this is a heap-allocated type object */ - assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); - _PyObject_GC_UNTRACK(type); - PyObject_ClearWeakRefs((PyObject *)type); - et = (PyHeapTypeObject *)type; - Py_XDECREF(type->tp_base); - Py_XDECREF(type->tp_dict); - Py_XDECREF(type->tp_bases); - Py_XDECREF(type->tp_mro); - Py_XDECREF(type->tp_cache); - Py_XDECREF(type->tp_subclasses); - /* A type's tp_doc is heap allocated, unlike the tp_doc slots - * of most other objects. It's okay to cast it to char *. - */ - PyObject_Free((char *)type->tp_doc); - Py_XDECREF(et->ht_name); - Py_XDECREF(et->ht_slots); - type->ob_type->tp_free((PyObject *)type); -} - -static PyObject * -type_subclasses(PyTypeObject *type, PyObject *args_ignored) -{ - PyObject *list, *raw, *ref; - Py_ssize_t i, n; - - list = PyList_New(0); - if (list == NULL) - return NULL; - raw = type->tp_subclasses; - if (raw == NULL) - return list; - assert(PyList_Check(raw)); - n = PyList_GET_SIZE(raw); - for (i = 0; i < n; i++) { - ref = PyList_GET_ITEM(raw, i); - assert(PyWeakref_CheckRef(ref)); - ref = PyWeakref_GET_OBJECT(ref); - if (ref != Py_None) { - if (PyList_Append(list, ref) < 0) { - Py_DECREF(list); - return NULL; - } - } - } - return list; -} - -static PyMethodDef type_methods[] = { - {"mro", (PyCFunction)mro_external, METH_NOARGS, - PyDoc_STR("mro() -> list\nreturn a type's method resolution order")}, - {"__subclasses__", (PyCFunction)type_subclasses, METH_NOARGS, - PyDoc_STR("__subclasses__() -> list of immediate subclasses")}, - {0} -}; - -PyDoc_STRVAR(type_doc, -"type(object) -> the object's type\n" -"type(name, bases, dict) -> a new type"); - -static int -type_traverse(PyTypeObject *type, visitproc visit, void *arg) -{ - /* Because of type_is_gc(), the collector only calls this - for heaptypes. */ - assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); - - Py_VISIT(type->tp_dict); - Py_VISIT(type->tp_cache); - Py_VISIT(type->tp_mro); - Py_VISIT(type->tp_bases); - Py_VISIT(type->tp_base); - - /* There's no need to visit type->tp_subclasses or - ((PyHeapTypeObject *)type)->ht_slots, because they can't be involved - in cycles; tp_subclasses is a list of weak references, - and slots is a tuple of strings. */ - - return 0; -} - -static int -type_clear(PyTypeObject *type) -{ - /* Because of type_is_gc(), the collector only calls this - for heaptypes. */ - assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); - - /* The only field we need to clear is tp_mro, which is part of a - hard cycle (its first element is the class itself) that won't - be broken otherwise (it's a tuple and tuples don't have a - tp_clear handler). None of the other fields need to be - cleared, and here's why: - - tp_dict: - It is a dict, so the collector will call its tp_clear. - - tp_cache: - Not used; if it were, it would be a dict. - - tp_bases, tp_base: - If these are involved in a cycle, there must be at least - one other, mutable object in the cycle, e.g. a base - class's dict; the cycle will be broken that way. - - tp_subclasses: - A list of weak references can't be part of a cycle; and - lists have their own tp_clear. - - slots (in PyHeapTypeObject): - A tuple of strings can't be part of a cycle. - */ - - Py_CLEAR(type->tp_mro); - - return 0; -} - -static int -type_is_gc(PyTypeObject *type) -{ - return type->tp_flags & Py_TPFLAGS_HEAPTYPE; -} - -PyTypeObject PyType_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "type", /* tp_name */ - sizeof(PyHeapTypeObject), /* tp_basicsize */ - sizeof(PyMemberDef), /* tp_itemsize */ - (destructor)type_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - type_compare, /* tp_compare */ - (reprfunc)type_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)_Py_HashPointer, /* tp_hash */ - (ternaryfunc)type_call, /* tp_call */ - 0, /* tp_str */ - (getattrofunc)type_getattro, /* tp_getattro */ - (setattrofunc)type_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - type_doc, /* tp_doc */ - (traverseproc)type_traverse, /* tp_traverse */ - (inquiry)type_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyTypeObject, tp_weaklist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - type_methods, /* tp_methods */ - type_members, /* tp_members */ - type_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(PyTypeObject, tp_dict), /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - type_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ - (inquiry)type_is_gc, /* tp_is_gc */ -}; - - -/* The base type of all types (eventually)... except itself. */ - -static int -object_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - return 0; -} - -/* If we don't have a tp_new for a new-style class, new will use this one. - Therefore this should take no arguments/keywords. However, this new may - also be inherited by objects that define a tp_init but no tp_new. These - objects WILL pass argumets to tp_new, because it gets the same args as - tp_init. So only allow arguments if we aren't using the default init, in - which case we expect init to handle argument parsing. */ -static PyObject * -object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - if (type->tp_init == object_init && (PyTuple_GET_SIZE(args) || - (kwds && PyDict_Check(kwds) && PyDict_Size(kwds)))) { - PyErr_SetString(PyExc_TypeError, - "default __new__ takes no parameters"); - return NULL; - } - return type->tp_alloc(type, 0); -} - -static void -object_dealloc(PyObject *self) -{ - self->ob_type->tp_free(self); -} - -static PyObject * -object_repr(PyObject *self) -{ - PyTypeObject *type; - PyObject *mod, *name, *rtn; - - type = self->ob_type; - mod = type_module(type, NULL); - if (mod == NULL) - PyErr_Clear(); - else if (!PyString_Check(mod)) { - Py_DECREF(mod); - mod = NULL; - } - name = type_name(type, NULL); - if (name == NULL) - return NULL; - if (mod != NULL && strcmp(PyString_AS_STRING(mod), "__builtin__")) - rtn = PyString_FromFormat("<%s.%s object at %p>", - PyString_AS_STRING(mod), - PyString_AS_STRING(name), - self); - else - rtn = PyString_FromFormat("<%s object at %p>", - type->tp_name, self); - Py_XDECREF(mod); - Py_DECREF(name); - return rtn; -} - -static PyObject * -object_str(PyObject *self) -{ - unaryfunc f; - - f = self->ob_type->tp_repr; - if (f == NULL) - f = object_repr; - return f(self); -} - -static long -object_hash(PyObject *self) -{ - return _Py_HashPointer(self); -} - -static PyObject * -object_get_class(PyObject *self, void *closure) -{ - Py_INCREF(self->ob_type); - return (PyObject *)(self->ob_type); -} - -static int -equiv_structs(PyTypeObject *a, PyTypeObject *b) -{ - return a == b || - (a != NULL && - b != NULL && - a->tp_basicsize == b->tp_basicsize && - a->tp_itemsize == b->tp_itemsize && - a->tp_dictoffset == b->tp_dictoffset && - a->tp_weaklistoffset == b->tp_weaklistoffset && - ((a->tp_flags & Py_TPFLAGS_HAVE_GC) == - (b->tp_flags & Py_TPFLAGS_HAVE_GC))); -} - -static int -same_slots_added(PyTypeObject *a, PyTypeObject *b) -{ - PyTypeObject *base = a->tp_base; - Py_ssize_t size; - - if (base != b->tp_base) - return 0; - if (equiv_structs(a, base) && equiv_structs(b, base)) - return 1; - size = base->tp_basicsize; - if (a->tp_dictoffset == size && b->tp_dictoffset == size) - size += sizeof(PyObject *); - if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size) - size += sizeof(PyObject *); - return size == a->tp_basicsize && size == b->tp_basicsize; -} - -static int -compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, char* attr) -{ - PyTypeObject *newbase, *oldbase; - - if (newto->tp_dealloc != oldto->tp_dealloc || - newto->tp_free != oldto->tp_free) - { - PyErr_Format(PyExc_TypeError, - "%s assignment: " - "'%s' deallocator differs from '%s'", - attr, - newto->tp_name, - oldto->tp_name); - return 0; - } - newbase = newto; - oldbase = oldto; - while (equiv_structs(newbase, newbase->tp_base)) - newbase = newbase->tp_base; - while (equiv_structs(oldbase, oldbase->tp_base)) - oldbase = oldbase->tp_base; - if (newbase != oldbase && - (newbase->tp_base != oldbase->tp_base || - !same_slots_added(newbase, oldbase))) { - PyErr_Format(PyExc_TypeError, - "%s assignment: " - "'%s' object layout differs from '%s'", - attr, - newto->tp_name, - oldto->tp_name); - return 0; - } - - return 1; -} - -static int -object_set_class(PyObject *self, PyObject *value, void *closure) -{ - PyTypeObject *oldto = self->ob_type; - PyTypeObject *newto; - - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "can't delete __class__ attribute"); - return -1; - } - if (!PyType_Check(value)) { - PyErr_Format(PyExc_TypeError, - "__class__ must be set to new-style class, not '%s' object", - value->ob_type->tp_name); - return -1; - } - newto = (PyTypeObject *)value; - if (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) || - !(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE)) - { - PyErr_Format(PyExc_TypeError, - "__class__ assignment: only for heap types"); - return -1; - } - if (compatible_for_assignment(newto, oldto, "__class__")) { - Py_INCREF(newto); - self->ob_type = newto; - Py_DECREF(oldto); - return 0; - } - else { - return -1; - } -} - -static PyGetSetDef object_getsets[] = { - {"__class__", object_get_class, object_set_class, - PyDoc_STR("the object's class")}, - {0} -}; - - -/* Stuff to implement __reduce_ex__ for pickle protocols >= 2. - We fall back to helpers in copy_reg for: - - pickle protocols < 2 - - calculating the list of slot names (done only once per class) - - the __newobj__ function (which is used as a token but never called) -*/ - -static PyObject * -import_copy_reg(void) -{ - static PyObject *copy_reg_str; - - if (!copy_reg_str) { - copy_reg_str = PyString_InternFromString("copy_reg"); - if (copy_reg_str == NULL) - return NULL; - } - - return PyImport_Import(copy_reg_str); -} - -static PyObject * -slotnames(PyObject *cls) -{ - PyObject *clsdict; - PyObject *copy_reg; - PyObject *slotnames; - - if (!PyType_Check(cls)) { - Py_INCREF(Py_None); - return Py_None; - } - - clsdict = ((PyTypeObject *)cls)->tp_dict; - slotnames = PyDict_GetItemString(clsdict, "__slotnames__"); - if (slotnames != NULL && PyList_Check(slotnames)) { - Py_INCREF(slotnames); - return slotnames; - } - - copy_reg = import_copy_reg(); - if (copy_reg == NULL) - return NULL; - - slotnames = PyObject_CallMethod(copy_reg, "_slotnames", "O", cls); - Py_DECREF(copy_reg); - if (slotnames != NULL && - slotnames != Py_None && - !PyList_Check(slotnames)) - { - PyErr_SetString(PyExc_TypeError, - "copy_reg._slotnames didn't return a list or None"); - Py_DECREF(slotnames); - slotnames = NULL; - } - - return slotnames; -} - -static PyObject * -reduce_2(PyObject *obj) -{ - PyObject *cls, *getnewargs; - PyObject *args = NULL, *args2 = NULL; - PyObject *getstate = NULL, *state = NULL, *names = NULL; - PyObject *slots = NULL, *listitems = NULL, *dictitems = NULL; - PyObject *copy_reg = NULL, *newobj = NULL, *res = NULL; - Py_ssize_t i, n; - - cls = PyObject_GetAttrString(obj, "__class__"); - if (cls == NULL) - return NULL; - - getnewargs = PyObject_GetAttrString(obj, "__getnewargs__"); - if (getnewargs != NULL) { - args = PyObject_CallObject(getnewargs, NULL); - Py_DECREF(getnewargs); - if (args != NULL && !PyTuple_Check(args)) { - PyErr_Format(PyExc_TypeError, - "__getnewargs__ should return a tuple, " - "not '%.200s'", args->ob_type->tp_name); - goto end; - } - } - else { - PyErr_Clear(); - args = PyTuple_New(0); - } - if (args == NULL) - goto end; - - getstate = PyObject_GetAttrString(obj, "__getstate__"); - if (getstate != NULL) { - state = PyObject_CallObject(getstate, NULL); - Py_DECREF(getstate); - if (state == NULL) - goto end; - } - else { - PyErr_Clear(); - state = PyObject_GetAttrString(obj, "__dict__"); - if (state == NULL) { - PyErr_Clear(); - state = Py_None; - Py_INCREF(state); - } - names = slotnames(cls); - if (names == NULL) - goto end; - if (names != Py_None) { - assert(PyList_Check(names)); - slots = PyDict_New(); - if (slots == NULL) - goto end; - n = 0; - /* Can't pre-compute the list size; the list - is stored on the class so accessible to other - threads, which may be run by DECREF */ - for (i = 0; i < PyList_GET_SIZE(names); i++) { - PyObject *name, *value; - name = PyList_GET_ITEM(names, i); - value = PyObject_GetAttr(obj, name); - if (value == NULL) - PyErr_Clear(); - else { - int err = PyDict_SetItem(slots, name, - value); - Py_DECREF(value); - if (err) - goto end; - n++; - } - } - if (n) { - state = Py_BuildValue("(NO)", state, slots); - if (state == NULL) - goto end; - } - } - } - - if (!PyList_Check(obj)) { - listitems = Py_None; - Py_INCREF(listitems); - } - else { - listitems = PyObject_GetIter(obj); - if (listitems == NULL) - goto end; - } - - if (!PyDict_Check(obj)) { - dictitems = Py_None; - Py_INCREF(dictitems); - } - else { - dictitems = PyObject_CallMethod(obj, "iteritems", ""); - if (dictitems == NULL) - goto end; - } - - copy_reg = import_copy_reg(); - if (copy_reg == NULL) - goto end; - newobj = PyObject_GetAttrString(copy_reg, "__newobj__"); - if (newobj == NULL) - goto end; - - n = PyTuple_GET_SIZE(args); - args2 = PyTuple_New(n+1); - if (args2 == NULL) - goto end; - PyTuple_SET_ITEM(args2, 0, cls); - cls = NULL; - for (i = 0; i < n; i++) { - PyObject *v = PyTuple_GET_ITEM(args, i); - Py_INCREF(v); - PyTuple_SET_ITEM(args2, i+1, v); - } - - res = PyTuple_Pack(5, newobj, args2, state, listitems, dictitems); - - end: - Py_XDECREF(cls); - Py_XDECREF(args); - Py_XDECREF(args2); - Py_XDECREF(slots); - Py_XDECREF(state); - Py_XDECREF(names); - Py_XDECREF(listitems); - Py_XDECREF(dictitems); - Py_XDECREF(copy_reg); - Py_XDECREF(newobj); - return res; -} - -/* - * There were two problems when object.__reduce__ and object.__reduce_ex__ - * were implemented in the same function: - * - trying to pickle an object with a custom __reduce__ method that - * fell back to object.__reduce__ in certain circumstances led to - * infinite recursion at Python level and eventual RuntimeError. - * - Pickling objects that lied about their type by overwriting the - * __class__ descriptor could lead to infinite recursion at C level - * and eventual segfault. - * - * Because of backwards compatibility, the two methods still have to - * behave in the same way, even if this is not required by the pickle - * protocol. This common functionality was moved to the _common_reduce - * function. - */ -static PyObject * -_common_reduce(PyObject *self, int proto) -{ - PyObject *copy_reg, *res; - - if (proto >= 2) - return reduce_2(self); - - copy_reg = import_copy_reg(); - if (!copy_reg) - return NULL; - - res = PyEval_CallMethod(copy_reg, "_reduce_ex", "(Oi)", self, proto); - Py_DECREF(copy_reg); - - return res; -} - -static PyObject * -object_reduce(PyObject *self, PyObject *args) -{ - int proto = 0; - - if (!PyArg_ParseTuple(args, "|i:__reduce__", &proto)) - return NULL; - - return _common_reduce(self, proto); -} - -static PyObject * -object_reduce_ex(PyObject *self, PyObject *args) -{ - PyObject *reduce, *res; - int proto = 0; - - if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) - return NULL; - - reduce = PyObject_GetAttrString(self, "__reduce__"); - if (reduce == NULL) - PyErr_Clear(); - else { - PyObject *cls, *clsreduce, *objreduce; - int override; - cls = PyObject_GetAttrString(self, "__class__"); - if (cls == NULL) { - Py_DECREF(reduce); - return NULL; - } - clsreduce = PyObject_GetAttrString(cls, "__reduce__"); - Py_DECREF(cls); - if (clsreduce == NULL) { - Py_DECREF(reduce); - return NULL; - } - objreduce = PyDict_GetItemString(PyBaseObject_Type.tp_dict, - "__reduce__"); - override = (clsreduce != objreduce); - Py_DECREF(clsreduce); - if (override) { - res = PyObject_CallObject(reduce, NULL); - Py_DECREF(reduce); - return res; - } - else - Py_DECREF(reduce); - } - - return _common_reduce(self, proto); -} - -static PyMethodDef object_methods[] = { - {"__reduce_ex__", object_reduce_ex, METH_VARARGS, - PyDoc_STR("helper for pickle")}, - {"__reduce__", object_reduce, METH_VARARGS, - PyDoc_STR("helper for pickle")}, - {0} -}; - - -PyTypeObject PyBaseObject_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "object", /* tp_name */ - sizeof(PyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - object_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - object_hash, /* tp_hash */ - 0, /* tp_call */ - object_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("The most base type"), /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - object_methods, /* tp_methods */ - 0, /* tp_members */ - object_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - object_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - object_new, /* tp_new */ - PyObject_Del, /* tp_free */ -}; - - -/* Initialize the __dict__ in a type object */ - -static int -add_methods(PyTypeObject *type, PyMethodDef *meth) -{ - PyObject *dict = type->tp_dict; - - for (; meth->ml_name != NULL; meth++) { - PyObject *descr; - if (PyDict_GetItemString(dict, meth->ml_name) && - !(meth->ml_flags & METH_COEXIST)) - continue; - if (meth->ml_flags & METH_CLASS) { - if (meth->ml_flags & METH_STATIC) { - PyErr_SetString(PyExc_ValueError, - "method cannot be both class and static"); - return -1; - } - descr = PyDescr_NewClassMethod(type, meth); - } - else if (meth->ml_flags & METH_STATIC) { - PyObject *cfunc = PyCFunction_New(meth, NULL); - if (cfunc == NULL) - return -1; - descr = PyStaticMethod_New(cfunc); - Py_DECREF(cfunc); - } - else { - descr = PyDescr_NewMethod(type, meth); - } - if (descr == NULL) - return -1; - if (PyDict_SetItemString(dict, meth->ml_name, descr) < 0) - return -1; - Py_DECREF(descr); - } - return 0; -} - -static int -add_members(PyTypeObject *type, PyMemberDef *memb) -{ - PyObject *dict = type->tp_dict; - - for (; memb->name != NULL; memb++) { - PyObject *descr; - if (PyDict_GetItemString(dict, memb->name)) - continue; - descr = PyDescr_NewMember(type, memb); - if (descr == NULL) - return -1; - if (PyDict_SetItemString(dict, memb->name, descr) < 0) - return -1; - Py_DECREF(descr); - } - return 0; -} - -static int -add_getset(PyTypeObject *type, PyGetSetDef *gsp) -{ - PyObject *dict = type->tp_dict; - - for (; gsp->name != NULL; gsp++) { - PyObject *descr; - if (PyDict_GetItemString(dict, gsp->name)) - continue; - descr = PyDescr_NewGetSet(type, gsp); - - if (descr == NULL) - return -1; - if (PyDict_SetItemString(dict, gsp->name, descr) < 0) - return -1; - Py_DECREF(descr); - } - return 0; -} - -static void -inherit_special(PyTypeObject *type, PyTypeObject *base) -{ - Py_ssize_t oldsize, newsize; - - /* Special flag magic */ - if (!type->tp_as_buffer && base->tp_as_buffer) { - type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER; - type->tp_flags |= - base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER; - } - if (!type->tp_as_sequence && base->tp_as_sequence) { - type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN; - type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN; - } - if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) != - (base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) { - if ((!type->tp_as_number && base->tp_as_number) || - (!type->tp_as_sequence && base->tp_as_sequence)) { - type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS; - if (!type->tp_as_number && !type->tp_as_sequence) { - type->tp_flags |= base->tp_flags & - Py_TPFLAGS_HAVE_INPLACEOPS; - } - } - /* Wow */ - } - if (!type->tp_as_number && base->tp_as_number) { - type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES; - type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES; - } - - /* Copying basicsize is connected to the GC flags */ - oldsize = base->tp_basicsize; - newsize = type->tp_basicsize ? type->tp_basicsize : oldsize; - if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) && - (base->tp_flags & Py_TPFLAGS_HAVE_GC) && - (type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) && - (!type->tp_traverse && !type->tp_clear)) { - type->tp_flags |= Py_TPFLAGS_HAVE_GC; - if (type->tp_traverse == NULL) - type->tp_traverse = base->tp_traverse; - if (type->tp_clear == NULL) - type->tp_clear = base->tp_clear; - } - if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { - /* The condition below could use some explanation. - It appears that tp_new is not inherited for static types - whose base class is 'object'; this seems to be a precaution - so that old extension types don't suddenly become - callable (object.__new__ wouldn't insure the invariants - that the extension type's own factory function ensures). - Heap types, of course, are under our control, so they do - inherit tp_new; static extension types that specify some - other built-in type as the default are considered - new-style-aware so they also inherit object.__new__. */ - if (base != &PyBaseObject_Type || - (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - if (type->tp_new == NULL) - type->tp_new = base->tp_new; - } - } - type->tp_basicsize = newsize; - - /* Copy other non-function slots */ - -#undef COPYVAL -#define COPYVAL(SLOT) \ - if (type->SLOT == 0) type->SLOT = base->SLOT - - COPYVAL(tp_itemsize); - if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_WEAKREFS) { - COPYVAL(tp_weaklistoffset); - } - if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { - COPYVAL(tp_dictoffset); - } -} - -static void -inherit_slots(PyTypeObject *type, PyTypeObject *base) -{ - PyTypeObject *basebase; - -#undef SLOTDEFINED -#undef COPYSLOT -#undef COPYNUM -#undef COPYSEQ -#undef COPYMAP -#undef COPYBUF - -#define SLOTDEFINED(SLOT) \ - (base->SLOT != 0 && \ - (basebase == NULL || base->SLOT != basebase->SLOT)) - -#define COPYSLOT(SLOT) \ - if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = base->SLOT - -#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT) -#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT) -#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT) -#define COPYBUF(SLOT) COPYSLOT(tp_as_buffer->SLOT) - - /* This won't inherit indirect slots (from tp_as_number etc.) - if type doesn't provide the space. */ - - if (type->tp_as_number != NULL && base->tp_as_number != NULL) { - basebase = base->tp_base; - if (basebase->tp_as_number == NULL) - basebase = NULL; - COPYNUM(nb_add); - COPYNUM(nb_subtract); - COPYNUM(nb_multiply); - COPYNUM(nb_divide); - COPYNUM(nb_remainder); - COPYNUM(nb_divmod); - COPYNUM(nb_power); - COPYNUM(nb_negative); - COPYNUM(nb_positive); - COPYNUM(nb_absolute); - COPYNUM(nb_nonzero); - COPYNUM(nb_invert); - COPYNUM(nb_lshift); - COPYNUM(nb_rshift); - COPYNUM(nb_and); - COPYNUM(nb_xor); - COPYNUM(nb_or); - COPYNUM(nb_coerce); - COPYNUM(nb_int); - COPYNUM(nb_long); - COPYNUM(nb_float); - COPYNUM(nb_oct); - COPYNUM(nb_hex); - COPYNUM(nb_inplace_add); - COPYNUM(nb_inplace_subtract); - COPYNUM(nb_inplace_multiply); - COPYNUM(nb_inplace_divide); - COPYNUM(nb_inplace_remainder); - COPYNUM(nb_inplace_power); - COPYNUM(nb_inplace_lshift); - COPYNUM(nb_inplace_rshift); - COPYNUM(nb_inplace_and); - COPYNUM(nb_inplace_xor); - COPYNUM(nb_inplace_or); - if (base->tp_flags & Py_TPFLAGS_CHECKTYPES) { - COPYNUM(nb_true_divide); - COPYNUM(nb_floor_divide); - COPYNUM(nb_inplace_true_divide); - COPYNUM(nb_inplace_floor_divide); - } - if (base->tp_flags & Py_TPFLAGS_HAVE_INDEX) { - COPYNUM(nb_index); - } - } - - if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) { - basebase = base->tp_base; - if (basebase->tp_as_sequence == NULL) - basebase = NULL; - COPYSEQ(sq_length); - COPYSEQ(sq_concat); - COPYSEQ(sq_repeat); - COPYSEQ(sq_item); - COPYSEQ(sq_slice); - COPYSEQ(sq_ass_item); - COPYSEQ(sq_ass_slice); - COPYSEQ(sq_contains); - COPYSEQ(sq_inplace_concat); - COPYSEQ(sq_inplace_repeat); - } - - if (type->tp_as_mapping != NULL && base->tp_as_mapping != NULL) { - basebase = base->tp_base; - if (basebase->tp_as_mapping == NULL) - basebase = NULL; - COPYMAP(mp_length); - COPYMAP(mp_subscript); - COPYMAP(mp_ass_subscript); - } - - if (type->tp_as_buffer != NULL && base->tp_as_buffer != NULL) { - basebase = base->tp_base; - if (basebase->tp_as_buffer == NULL) - basebase = NULL; - COPYBUF(bf_getreadbuffer); - COPYBUF(bf_getwritebuffer); - COPYBUF(bf_getsegcount); - COPYBUF(bf_getcharbuffer); - } - - basebase = base->tp_base; - - COPYSLOT(tp_dealloc); - COPYSLOT(tp_print); - if (type->tp_getattr == NULL && type->tp_getattro == NULL) { - type->tp_getattr = base->tp_getattr; - type->tp_getattro = base->tp_getattro; - } - if (type->tp_setattr == NULL && type->tp_setattro == NULL) { - type->tp_setattr = base->tp_setattr; - type->tp_setattro = base->tp_setattro; - } - /* tp_compare see tp_richcompare */ - COPYSLOT(tp_repr); - /* tp_hash see tp_richcompare */ - COPYSLOT(tp_call); - COPYSLOT(tp_str); - if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) { - if (type->tp_compare == NULL && - type->tp_richcompare == NULL && - type->tp_hash == NULL) - { - type->tp_compare = base->tp_compare; - type->tp_richcompare = base->tp_richcompare; - type->tp_hash = base->tp_hash; - } - } - else { - COPYSLOT(tp_compare); - } - if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_ITER) { - COPYSLOT(tp_iter); - COPYSLOT(tp_iternext); - } - if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { - COPYSLOT(tp_descr_get); - COPYSLOT(tp_descr_set); - COPYSLOT(tp_dictoffset); - COPYSLOT(tp_init); - COPYSLOT(tp_alloc); - COPYSLOT(tp_is_gc); - if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) == - (base->tp_flags & Py_TPFLAGS_HAVE_GC)) { - /* They agree about gc. */ - COPYSLOT(tp_free); - } - else if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) && - type->tp_free == NULL && - base->tp_free == _PyObject_Del) { - /* A bit of magic to plug in the correct default - * tp_free function when a derived class adds gc, - * didn't define tp_free, and the base uses the - * default non-gc tp_free. - */ - type->tp_free = PyObject_GC_Del; - } - /* else they didn't agree about gc, and there isn't something - * obvious to be done -- the type is on its own. - */ - } -} - -static int add_operators(PyTypeObject *); - -int -PyType_Ready(PyTypeObject *type) -{ - PyObject *dict, *bases; - PyTypeObject *base; - Py_ssize_t i, n; - - if (type->tp_flags & Py_TPFLAGS_READY) { - assert(type->tp_dict != NULL); - return 0; - } - assert((type->tp_flags & Py_TPFLAGS_READYING) == 0); - - type->tp_flags |= Py_TPFLAGS_READYING; - -#ifdef Py_TRACE_REFS - /* PyType_Ready is the closest thing we have to a choke point - * for type objects, so is the best place I can think of to try - * to get type objects into the doubly-linked list of all objects. - * Still, not all type objects go thru PyType_Ready. - */ - _Py_AddToAllObjects((PyObject *)type, 0); -#endif - - /* Initialize tp_base (defaults to BaseObject unless that's us) */ - base = type->tp_base; - if (base == NULL && type != &PyBaseObject_Type) { - base = type->tp_base = &PyBaseObject_Type; - Py_INCREF(base); - } - - /* Now the only way base can still be NULL is if type is - * &PyBaseObject_Type. - */ - - /* Initialize the base class */ - if (base && base->tp_dict == NULL) { - if (PyType_Ready(base) < 0) - goto error; - } - - /* Initialize ob_type if NULL. This means extensions that want to be - compilable separately on Windows can call PyType_Ready() instead of - initializing the ob_type field of their type objects. */ - /* The test for base != NULL is really unnecessary, since base is only - NULL when type is &PyBaseObject_Type, and we know its ob_type is - not NULL (it's initialized to &PyType_Type). But coverity doesn't - know that. */ - if (type->ob_type == NULL && base != NULL) - type->ob_type = base->ob_type; - - /* Initialize tp_bases */ - bases = type->tp_bases; - if (bases == NULL) { - if (base == NULL) - bases = PyTuple_New(0); - else - bases = PyTuple_Pack(1, base); - if (bases == NULL) - goto error; - type->tp_bases = bases; - } - - /* Initialize tp_dict */ - dict = type->tp_dict; - if (dict == NULL) { - dict = PyDict_New(); - if (dict == NULL) - goto error; - type->tp_dict = dict; - } - - /* Add type-specific descriptors to tp_dict */ - if (add_operators(type) < 0) - goto error; - if (type->tp_methods != NULL) { - if (add_methods(type, type->tp_methods) < 0) - goto error; - } - if (type->tp_members != NULL) { - if (add_members(type, type->tp_members) < 0) - goto error; - } - if (type->tp_getset != NULL) { - if (add_getset(type, type->tp_getset) < 0) - goto error; - } - - /* Calculate method resolution order */ - if (mro_internal(type) < 0) { - goto error; - } - - /* Inherit special flags from dominant base */ - if (type->tp_base != NULL) - inherit_special(type, type->tp_base); - - /* Initialize tp_dict properly */ - bases = type->tp_mro; - assert(bases != NULL); - assert(PyTuple_Check(bases)); - n = PyTuple_GET_SIZE(bases); - for (i = 1; i < n; i++) { - PyObject *b = PyTuple_GET_ITEM(bases, i); - if (PyType_Check(b)) - inherit_slots(type, (PyTypeObject *)b); - } - - /* Sanity check for tp_free. */ - if (PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) && - (type->tp_free == NULL || type->tp_free == PyObject_Del)) { - /* This base class needs to call tp_free, but doesn't have - * one, or its tp_free is for non-gc'ed objects. - */ - PyErr_Format(PyExc_TypeError, "type '%.100s' participates in " - "gc and is a base type but has inappropriate " - "tp_free slot", - type->tp_name); - goto error; - } - - /* if the type dictionary doesn't contain a __doc__, set it from - the tp_doc slot. - */ - if (PyDict_GetItemString(type->tp_dict, "__doc__") == NULL) { - if (type->tp_doc != NULL) { - PyObject *doc = PyString_FromString(type->tp_doc); - if (doc == NULL) - goto error; - PyDict_SetItemString(type->tp_dict, "__doc__", doc); - Py_DECREF(doc); - } else { - PyDict_SetItemString(type->tp_dict, - "__doc__", Py_None); - } - } - - /* Some more special stuff */ - base = type->tp_base; - if (base != NULL) { - if (type->tp_as_number == NULL) - type->tp_as_number = base->tp_as_number; - if (type->tp_as_sequence == NULL) - type->tp_as_sequence = base->tp_as_sequence; - if (type->tp_as_mapping == NULL) - type->tp_as_mapping = base->tp_as_mapping; - if (type->tp_as_buffer == NULL) - type->tp_as_buffer = base->tp_as_buffer; - } - - /* Link into each base class's list of subclasses */ - bases = type->tp_bases; - n = PyTuple_GET_SIZE(bases); - for (i = 0; i < n; i++) { - PyObject *b = PyTuple_GET_ITEM(bases, i); - if (PyType_Check(b) && - add_subclass((PyTypeObject *)b, type) < 0) - goto error; - } - - /* All done -- set the ready flag */ - assert(type->tp_dict != NULL); - type->tp_flags = - (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY; - return 0; - - error: - type->tp_flags &= ~Py_TPFLAGS_READYING; - return -1; -} - -static int -add_subclass(PyTypeObject *base, PyTypeObject *type) -{ - Py_ssize_t i; - int result; - PyObject *list, *ref, *newobj; - - list = base->tp_subclasses; - if (list == NULL) { - base->tp_subclasses = list = PyList_New(0); - if (list == NULL) - return -1; - } - assert(PyList_Check(list)); - newobj = PyWeakref_NewRef((PyObject *)type, NULL); - i = PyList_GET_SIZE(list); - while (--i >= 0) { - ref = PyList_GET_ITEM(list, i); - assert(PyWeakref_CheckRef(ref)); - if (PyWeakref_GET_OBJECT(ref) == Py_None) - return PyList_SetItem(list, i, newobj); - } - result = PyList_Append(list, newobj); - Py_DECREF(newobj); - return result; -} - -static void -remove_subclass(PyTypeObject *base, PyTypeObject *type) -{ - Py_ssize_t i; - PyObject *list, *ref; - - list = base->tp_subclasses; - if (list == NULL) { - return; - } - assert(PyList_Check(list)); - i = PyList_GET_SIZE(list); - while (--i >= 0) { - ref = PyList_GET_ITEM(list, i); - assert(PyWeakref_CheckRef(ref)); - if (PyWeakref_GET_OBJECT(ref) == (PyObject*)type) { - /* this can't fail, right? */ - PySequence_DelItem(list, i); - return; - } - } -} - -static int -check_num_args(PyObject *ob, int n) -{ - if (!PyTuple_CheckExact(ob)) { - PyErr_SetString(PyExc_SystemError, - "PyArg_UnpackTuple() argument list is not a tuple"); - return 0; - } - if (n == PyTuple_GET_SIZE(ob)) - return 1; - PyErr_Format( - PyExc_TypeError, - "expected %d arguments, got %zd", n, PyTuple_GET_SIZE(ob)); - return 0; -} - -/* Generic wrappers for overloadable 'operators' such as __getitem__ */ - -/* There's a wrapper *function* for each distinct function typedef used - for type object slots (e.g. binaryfunc, ternaryfunc, etc.). There's a - wrapper *table* for each distinct operation (e.g. __len__, __add__). - Most tables have only one entry; the tables for binary operators have two - entries, one regular and one with reversed arguments. */ - -static PyObject * -wrap_lenfunc(PyObject *self, PyObject *args, void *wrapped) -{ - lenfunc func = (lenfunc)wrapped; - Py_ssize_t res; - - if (!check_num_args(args, 0)) - return NULL; - res = (*func)(self); - if (res == -1 && PyErr_Occurred()) - return NULL; - return PyInt_FromLong((long)res); -} - -static PyObject * -wrap_inquirypred(PyObject *self, PyObject *args, void *wrapped) -{ - inquiry func = (inquiry)wrapped; - int res; - - if (!check_num_args(args, 0)) - return NULL; - res = (*func)(self); - if (res == -1 && PyErr_Occurred()) - return NULL; - return PyBool_FromLong((long)res); -} - -static PyObject * -wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped) -{ - binaryfunc func = (binaryfunc)wrapped; - PyObject *other; - - if (!check_num_args(args, 1)) - return NULL; - other = PyTuple_GET_ITEM(args, 0); - return (*func)(self, other); -} - -static PyObject * -wrap_binaryfunc_l(PyObject *self, PyObject *args, void *wrapped) -{ - binaryfunc func = (binaryfunc)wrapped; - PyObject *other; - - if (!check_num_args(args, 1)) - return NULL; - other = PyTuple_GET_ITEM(args, 0); - if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) && - !PyType_IsSubtype(other->ob_type, self->ob_type)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return (*func)(self, other); -} - -static PyObject * -wrap_binaryfunc_r(PyObject *self, PyObject *args, void *wrapped) -{ - binaryfunc func = (binaryfunc)wrapped; - PyObject *other; - - if (!check_num_args(args, 1)) - return NULL; - other = PyTuple_GET_ITEM(args, 0); - if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) && - !PyType_IsSubtype(other->ob_type, self->ob_type)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return (*func)(other, self); -} - -static PyObject * -wrap_coercefunc(PyObject *self, PyObject *args, void *wrapped) -{ - coercion func = (coercion)wrapped; - PyObject *other, *res; - int ok; - - if (!check_num_args(args, 1)) - return NULL; - other = PyTuple_GET_ITEM(args, 0); - ok = func(&self, &other); - if (ok < 0) - return NULL; - if (ok > 0) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - res = PyTuple_New(2); - if (res == NULL) { - Py_DECREF(self); - Py_DECREF(other); - return NULL; - } - PyTuple_SET_ITEM(res, 0, self); - PyTuple_SET_ITEM(res, 1, other); - return res; -} - -static PyObject * -wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped) -{ - ternaryfunc func = (ternaryfunc)wrapped; - PyObject *other; - PyObject *third = Py_None; - - /* Note: This wrapper only works for __pow__() */ - - if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) - return NULL; - return (*func)(self, other, third); -} - -static PyObject * -wrap_ternaryfunc_r(PyObject *self, PyObject *args, void *wrapped) -{ - ternaryfunc func = (ternaryfunc)wrapped; - PyObject *other; - PyObject *third = Py_None; - - /* Note: This wrapper only works for __pow__() */ - - if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) - return NULL; - return (*func)(other, self, third); -} - -static PyObject * -wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped) -{ - unaryfunc func = (unaryfunc)wrapped; - - if (!check_num_args(args, 0)) - return NULL; - return (*func)(self); -} - -static PyObject * -wrap_indexargfunc(PyObject *self, PyObject *args, void *wrapped) -{ - ssizeargfunc func = (ssizeargfunc)wrapped; - PyObject* o; - Py_ssize_t i; - - if (!PyArg_UnpackTuple(args, "", 1, 1, &o)) - return NULL; - i = PyNumber_AsSsize_t(o, PyExc_OverflowError); - if (i == -1 && PyErr_Occurred()) - return NULL; - return (*func)(self, i); -} - -static Py_ssize_t -getindex(PyObject *self, PyObject *arg) -{ - Py_ssize_t i; - - i = PyNumber_AsSsize_t(arg, PyExc_OverflowError); - if (i == -1 && PyErr_Occurred()) - return -1; - if (i < 0) { - PySequenceMethods *sq = self->ob_type->tp_as_sequence; - if (sq && sq->sq_length) { - Py_ssize_t n = (*sq->sq_length)(self); - if (n < 0) - return -1; - i += n; - } - } - return i; -} - -static PyObject * -wrap_sq_item(PyObject *self, PyObject *args, void *wrapped) -{ - ssizeargfunc func = (ssizeargfunc)wrapped; - PyObject *arg; - Py_ssize_t i; - - if (PyTuple_GET_SIZE(args) == 1) { - arg = PyTuple_GET_ITEM(args, 0); - i = getindex(self, arg); - if (i == -1 && PyErr_Occurred()) - return NULL; - return (*func)(self, i); - } - check_num_args(args, 1); - assert(PyErr_Occurred()); - return NULL; -} - -static PyObject * -wrap_ssizessizeargfunc(PyObject *self, PyObject *args, void *wrapped) -{ - ssizessizeargfunc func = (ssizessizeargfunc)wrapped; - Py_ssize_t i, j; - - if (!PyArg_ParseTuple(args, "nn", &i, &j)) - return NULL; - return (*func)(self, i, j); -} - -static PyObject * -wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped) -{ - ssizeobjargproc func = (ssizeobjargproc)wrapped; - Py_ssize_t i; - int res; - PyObject *arg, *value; - - if (!PyArg_UnpackTuple(args, "", 2, 2, &arg, &value)) - return NULL; - i = getindex(self, arg); - if (i == -1 && PyErr_Occurred()) - return NULL; - res = (*func)(self, i, value); - if (res == -1 && PyErr_Occurred()) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_sq_delitem(PyObject *self, PyObject *args, void *wrapped) -{ - ssizeobjargproc func = (ssizeobjargproc)wrapped; - Py_ssize_t i; - int res; - PyObject *arg; - - if (!check_num_args(args, 1)) - return NULL; - arg = PyTuple_GET_ITEM(args, 0); - i = getindex(self, arg); - if (i == -1 && PyErr_Occurred()) - return NULL; - res = (*func)(self, i, NULL); - if (res == -1 && PyErr_Occurred()) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_ssizessizeobjargproc(PyObject *self, PyObject *args, void *wrapped) -{ - ssizessizeobjargproc func = (ssizessizeobjargproc)wrapped; - Py_ssize_t i, j; - int res; - PyObject *value; - - if (!PyArg_ParseTuple(args, "nnO", &i, &j, &value)) - return NULL; - res = (*func)(self, i, j, value); - if (res == -1 && PyErr_Occurred()) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_delslice(PyObject *self, PyObject *args, void *wrapped) -{ - ssizessizeobjargproc func = (ssizessizeobjargproc)wrapped; - Py_ssize_t i, j; - int res; - - if (!PyArg_ParseTuple(args, "nn", &i, &j)) - return NULL; - res = (*func)(self, i, j, NULL); - if (res == -1 && PyErr_Occurred()) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -/* XXX objobjproc is a misnomer; should be objargpred */ -static PyObject * -wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped) -{ - objobjproc func = (objobjproc)wrapped; - int res; - PyObject *value; - - if (!check_num_args(args, 1)) - return NULL; - value = PyTuple_GET_ITEM(args, 0); - res = (*func)(self, value); - if (res == -1 && PyErr_Occurred()) - return NULL; - else - return PyBool_FromLong(res); -} - -static PyObject * -wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped) -{ - objobjargproc func = (objobjargproc)wrapped; - int res; - PyObject *key, *value; - - if (!PyArg_UnpackTuple(args, "", 2, 2, &key, &value)) - return NULL; - res = (*func)(self, key, value); - if (res == -1 && PyErr_Occurred()) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_delitem(PyObject *self, PyObject *args, void *wrapped) -{ - objobjargproc func = (objobjargproc)wrapped; - int res; - PyObject *key; - - if (!check_num_args(args, 1)) - return NULL; - key = PyTuple_GET_ITEM(args, 0); - res = (*func)(self, key, NULL); - if (res == -1 && PyErr_Occurred()) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped) -{ - cmpfunc func = (cmpfunc)wrapped; - int res; - PyObject *other; - - if (!check_num_args(args, 1)) - return NULL; - other = PyTuple_GET_ITEM(args, 0); - if (other->ob_type->tp_compare != func && - !PyType_IsSubtype(other->ob_type, self->ob_type)) { - PyErr_Format( - PyExc_TypeError, - "%s.__cmp__(x,y) requires y to be a '%s', not a '%s'", - self->ob_type->tp_name, - self->ob_type->tp_name, - other->ob_type->tp_name); - return NULL; - } - res = (*func)(self, other); - if (PyErr_Occurred()) - return NULL; - return PyInt_FromLong((long)res); -} - -/* Helper to check for object.__setattr__ or __delattr__ applied to a type. - This is called the Carlo Verre hack after its discoverer. */ -static int -hackcheck(PyObject *self, setattrofunc func, char *what) -{ - PyTypeObject *type = self->ob_type; - while (type && type->tp_flags & Py_TPFLAGS_HEAPTYPE) - type = type->tp_base; - /* If type is NULL now, this is a really weird type. - In the same of backwards compatibility (?), just shut up. */ - if (type && type->tp_setattro != func) { - PyErr_Format(PyExc_TypeError, - "can't apply this %s to %s object", - what, - type->tp_name); - return 0; - } - return 1; -} - -static PyObject * -wrap_setattr(PyObject *self, PyObject *args, void *wrapped) -{ - setattrofunc func = (setattrofunc)wrapped; - int res; - PyObject *name, *value; - - if (!PyArg_UnpackTuple(args, "", 2, 2, &name, &value)) - return NULL; - if (!hackcheck(self, func, "__setattr__")) - return NULL; - res = (*func)(self, name, value); - if (res < 0) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_delattr(PyObject *self, PyObject *args, void *wrapped) -{ - setattrofunc func = (setattrofunc)wrapped; - int res; - PyObject *name; - - if (!check_num_args(args, 1)) - return NULL; - name = PyTuple_GET_ITEM(args, 0); - if (!hackcheck(self, func, "__delattr__")) - return NULL; - res = (*func)(self, name, NULL); - if (res < 0) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped) -{ - hashfunc func = (hashfunc)wrapped; - long res; - - if (!check_num_args(args, 0)) - return NULL; - res = (*func)(self); - if (res == -1 && PyErr_Occurred()) - return NULL; - return PyInt_FromLong(res); -} - -static PyObject * -wrap_call(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) -{ - ternaryfunc func = (ternaryfunc)wrapped; - - return (*func)(self, args, kwds); -} - -static PyObject * -wrap_richcmpfunc(PyObject *self, PyObject *args, void *wrapped, int op) -{ - richcmpfunc func = (richcmpfunc)wrapped; - PyObject *other; - - if (!check_num_args(args, 1)) - return NULL; - other = PyTuple_GET_ITEM(args, 0); - return (*func)(self, other, op); -} - -#undef RICHCMP_WRAPPER -#define RICHCMP_WRAPPER(NAME, OP) \ -static PyObject * \ -richcmp_##NAME(PyObject *self, PyObject *args, void *wrapped) \ -{ \ - return wrap_richcmpfunc(self, args, wrapped, OP); \ -} - -RICHCMP_WRAPPER(lt, Py_LT) -RICHCMP_WRAPPER(le, Py_LE) -RICHCMP_WRAPPER(eq, Py_EQ) -RICHCMP_WRAPPER(ne, Py_NE) -RICHCMP_WRAPPER(gt, Py_GT) -RICHCMP_WRAPPER(ge, Py_GE) - -static PyObject * -wrap_next(PyObject *self, PyObject *args, void *wrapped) -{ - unaryfunc func = (unaryfunc)wrapped; - PyObject *res; - - if (!check_num_args(args, 0)) - return NULL; - res = (*func)(self); - if (res == NULL && !PyErr_Occurred()) - PyErr_SetNone(PyExc_StopIteration); - return res; -} - -static PyObject * -wrap_descr_get(PyObject *self, PyObject *args, void *wrapped) -{ - descrgetfunc func = (descrgetfunc)wrapped; - PyObject *obj; - PyObject *type = NULL; - - if (!PyArg_UnpackTuple(args, "", 1, 2, &obj, &type)) - return NULL; - if (obj == Py_None) - obj = NULL; - if (type == Py_None) - type = NULL; - if (type == NULL &&obj == NULL) { - PyErr_SetString(PyExc_TypeError, - "__get__(None, None) is invalid"); - return NULL; - } - return (*func)(self, obj, type); -} - -static PyObject * -wrap_descr_set(PyObject *self, PyObject *args, void *wrapped) -{ - descrsetfunc func = (descrsetfunc)wrapped; - PyObject *obj, *value; - int ret; - - if (!PyArg_UnpackTuple(args, "", 2, 2, &obj, &value)) - return NULL; - ret = (*func)(self, obj, value); - if (ret < 0) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_descr_delete(PyObject *self, PyObject *args, void *wrapped) -{ - descrsetfunc func = (descrsetfunc)wrapped; - PyObject *obj; - int ret; - - if (!check_num_args(args, 1)) - return NULL; - obj = PyTuple_GET_ITEM(args, 0); - ret = (*func)(self, obj, NULL); - if (ret < 0) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) -{ - initproc func = (initproc)wrapped; - - if (func(self, args, kwds) < 0) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds) -{ - PyTypeObject *type, *subtype, *staticbase; - PyObject *arg0, *res; - - if (self == NULL || !PyType_Check(self)) - Py_FatalError("__new__() called with non-type 'self'"); - type = (PyTypeObject *)self; - if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) { - PyErr_Format(PyExc_TypeError, - "%s.__new__(): not enough arguments", - type->tp_name); - return NULL; - } - arg0 = PyTuple_GET_ITEM(args, 0); - if (!PyType_Check(arg0)) { - PyErr_Format(PyExc_TypeError, - "%s.__new__(X): X is not a type object (%s)", - type->tp_name, - arg0->ob_type->tp_name); - return NULL; - } - subtype = (PyTypeObject *)arg0; - if (!PyType_IsSubtype(subtype, type)) { - PyErr_Format(PyExc_TypeError, - "%s.__new__(%s): %s is not a subtype of %s", - type->tp_name, - subtype->tp_name, - subtype->tp_name, - type->tp_name); - return NULL; - } - - /* Check that the use doesn't do something silly and unsafe like - object.__new__(dict). To do this, we check that the - most derived base that's not a heap type is this type. */ - staticbase = subtype; - while (staticbase && (staticbase->tp_flags & Py_TPFLAGS_HEAPTYPE)) - staticbase = staticbase->tp_base; - /* If staticbase is NULL now, it is a really weird type. - In the same of backwards compatibility (?), just shut up. */ - if (staticbase && staticbase->tp_new != type->tp_new) { - PyErr_Format(PyExc_TypeError, - "%s.__new__(%s) is not safe, use %s.__new__()", - type->tp_name, - subtype->tp_name, - staticbase == NULL ? "?" : staticbase->tp_name); - return NULL; - } - - args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); - if (args == NULL) - return NULL; - res = type->tp_new(subtype, args, kwds); - Py_DECREF(args); - return res; -} - -static struct PyMethodDef tp_new_methoddef[] = { - {"__new__", (PyCFunction)tp_new_wrapper, METH_KEYWORDS, - PyDoc_STR("T.__new__(S, ...) -> " - "a new object with type S, a subtype of T")}, - {0} -}; - -static int -add_tp_new_wrapper(PyTypeObject *type) -{ - PyObject *func; - - if (PyDict_GetItemString(type->tp_dict, "__new__") != NULL) - return 0; - func = PyCFunction_New(tp_new_methoddef, (PyObject *)type); - if (func == NULL) - return -1; - if (PyDict_SetItemString(type->tp_dict, "__new__", func)) { - Py_DECREF(func); - return -1; - } - Py_DECREF(func); - return 0; -} - -/* Slot wrappers that call the corresponding __foo__ slot. See comments - below at override_slots() for more explanation. */ - -#define SLOT0(FUNCNAME, OPSTR) \ -static PyObject * \ -FUNCNAME(PyObject *self) \ -{ \ - static PyObject *cache_str; \ - return call_method(self, OPSTR, &cache_str, "()"); \ -} - -#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \ -static PyObject * \ -FUNCNAME(PyObject *self, ARG1TYPE arg1) \ -{ \ - static PyObject *cache_str; \ - return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \ -} - -/* Boolean helper for SLOT1BINFULL(). - right.__class__ is a nontrivial subclass of left.__class__. */ -static int -method_is_overloaded(PyObject *left, PyObject *right, char *name) -{ - PyObject *a, *b; - int ok; - - b = PyObject_GetAttrString((PyObject *)(right->ob_type), name); - if (b == NULL) { - PyErr_Clear(); - /* If right doesn't have it, it's not overloaded */ - return 0; - } - - a = PyObject_GetAttrString((PyObject *)(left->ob_type), name); - if (a == NULL) { - PyErr_Clear(); - Py_DECREF(b); - /* If right has it but left doesn't, it's overloaded */ - return 1; - } - - ok = PyObject_RichCompareBool(a, b, Py_NE); - Py_DECREF(a); - Py_DECREF(b); - if (ok < 0) { - PyErr_Clear(); - return 0; - } - - return ok; -} - - -#define SLOT1BINFULL(FUNCNAME, TESTFUNC, SLOTNAME, OPSTR, ROPSTR) \ -static PyObject * \ -FUNCNAME(PyObject *self, PyObject *other) \ -{ \ - static PyObject *cache_str, *rcache_str; \ - int do_other = self->ob_type != other->ob_type && \ - other->ob_type->tp_as_number != NULL && \ - other->ob_type->tp_as_number->SLOTNAME == TESTFUNC; \ - if (self->ob_type->tp_as_number != NULL && \ - self->ob_type->tp_as_number->SLOTNAME == TESTFUNC) { \ - PyObject *r; \ - if (do_other && \ - PyType_IsSubtype(other->ob_type, self->ob_type) && \ - method_is_overloaded(self, other, ROPSTR)) { \ - r = call_maybe( \ - other, ROPSTR, &rcache_str, "(O)", self); \ - if (r != Py_NotImplemented) \ - return r; \ - Py_DECREF(r); \ - do_other = 0; \ - } \ - r = call_maybe( \ - self, OPSTR, &cache_str, "(O)", other); \ - if (r != Py_NotImplemented || \ - other->ob_type == self->ob_type) \ - return r; \ - Py_DECREF(r); \ - } \ - if (do_other) { \ - return call_maybe( \ - other, ROPSTR, &rcache_str, "(O)", self); \ - } \ - Py_INCREF(Py_NotImplemented); \ - return Py_NotImplemented; \ -} - -#define SLOT1BIN(FUNCNAME, SLOTNAME, OPSTR, ROPSTR) \ - SLOT1BINFULL(FUNCNAME, FUNCNAME, SLOTNAME, OPSTR, ROPSTR) - -#define SLOT2(FUNCNAME, OPSTR, ARG1TYPE, ARG2TYPE, ARGCODES) \ -static PyObject * \ -FUNCNAME(PyObject *self, ARG1TYPE arg1, ARG2TYPE arg2) \ -{ \ - static PyObject *cache_str; \ - return call_method(self, OPSTR, &cache_str, \ - "(" ARGCODES ")", arg1, arg2); \ -} - -static Py_ssize_t -slot_sq_length(PyObject *self) -{ - static PyObject *len_str; - PyObject *res = call_method(self, "__len__", &len_str, "()"); - Py_ssize_t len; - - if (res == NULL) - return -1; - len = PyInt_AsSsize_t(res); - Py_DECREF(res); - if (len < 0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_ValueError, - "__len__() should return >= 0"); - return -1; - } - return len; -} - -/* Super-optimized version of slot_sq_item. - Other slots could do the same... */ -static PyObject * -slot_sq_item(PyObject *self, Py_ssize_t i) -{ - static PyObject *getitem_str; - PyObject *func, *args = NULL, *ival = NULL, *retval = NULL; - descrgetfunc f; - - if (getitem_str == NULL) { - getitem_str = PyString_InternFromString("__getitem__"); - if (getitem_str == NULL) - return NULL; - } - func = _PyType_Lookup(self->ob_type, getitem_str); - if (func != NULL) { - if ((f = func->ob_type->tp_descr_get) == NULL) - Py_INCREF(func); - else { - func = f(func, self, (PyObject *)(self->ob_type)); - if (func == NULL) { - return NULL; - } - } - ival = PyInt_FromSsize_t(i); - if (ival != NULL) { - args = PyTuple_New(1); - if (args != NULL) { - PyTuple_SET_ITEM(args, 0, ival); - retval = PyObject_Call(func, args, NULL); - Py_XDECREF(args); - Py_XDECREF(func); - return retval; - } - } - } - else { - PyErr_SetObject(PyExc_AttributeError, getitem_str); - } - Py_XDECREF(args); - Py_XDECREF(ival); - Py_XDECREF(func); - return NULL; -} - -SLOT2(slot_sq_slice, "__getslice__", Py_ssize_t, Py_ssize_t, "nn") - -static int -slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value) -{ - PyObject *res; - static PyObject *delitem_str, *setitem_str; - - if (value == NULL) - res = call_method(self, "__delitem__", &delitem_str, - "(n)", index); - else - res = call_method(self, "__setitem__", &setitem_str, - "(nO)", index, value); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -static int -slot_sq_ass_slice(PyObject *self, Py_ssize_t i, Py_ssize_t j, PyObject *value) -{ - PyObject *res; - static PyObject *delslice_str, *setslice_str; - - if (value == NULL) - res = call_method(self, "__delslice__", &delslice_str, - "(nn)", i, j); - else - res = call_method(self, "__setslice__", &setslice_str, - "(nnO)", i, j, value); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -static int -slot_sq_contains(PyObject *self, PyObject *value) -{ - PyObject *func, *res, *args; - int result = -1; - - static PyObject *contains_str; - - func = lookup_maybe(self, "__contains__", &contains_str); - if (func != NULL) { - args = PyTuple_Pack(1, value); - if (args == NULL) - res = NULL; - else { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } - Py_DECREF(func); - if (res != NULL) { - result = PyObject_IsTrue(res); - Py_DECREF(res); - } - } - else if (! PyErr_Occurred()) { - /* Possible results: -1 and 1 */ - result = (int)_PySequence_IterSearch(self, value, - PY_ITERSEARCH_CONTAINS); - } - return result; -} - -#define slot_mp_length slot_sq_length - -SLOT1(slot_mp_subscript, "__getitem__", PyObject *, "O") - -static int -slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) -{ - PyObject *res; - static PyObject *delitem_str, *setitem_str; - - if (value == NULL) - res = call_method(self, "__delitem__", &delitem_str, - "(O)", key); - else - res = call_method(self, "__setitem__", &setitem_str, - "(OO)", key, value); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -SLOT1BIN(slot_nb_add, nb_add, "__add__", "__radd__") -SLOT1BIN(slot_nb_subtract, nb_subtract, "__sub__", "__rsub__") -SLOT1BIN(slot_nb_multiply, nb_multiply, "__mul__", "__rmul__") -SLOT1BIN(slot_nb_divide, nb_divide, "__div__", "__rdiv__") -SLOT1BIN(slot_nb_remainder, nb_remainder, "__mod__", "__rmod__") -SLOT1BIN(slot_nb_divmod, nb_divmod, "__divmod__", "__rdivmod__") - -static PyObject *slot_nb_power(PyObject *, PyObject *, PyObject *); - -SLOT1BINFULL(slot_nb_power_binary, slot_nb_power, - nb_power, "__pow__", "__rpow__") - -static PyObject * -slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus) -{ - static PyObject *pow_str; - - if (modulus == Py_None) - return slot_nb_power_binary(self, other); - /* Three-arg power doesn't use __rpow__. But ternary_op - can call this when the second argument's type uses - slot_nb_power, so check before calling self.__pow__. */ - if (self->ob_type->tp_as_number != NULL && - self->ob_type->tp_as_number->nb_power == slot_nb_power) { - return call_method(self, "__pow__", &pow_str, - "(OO)", other, modulus); - } - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -SLOT0(slot_nb_negative, "__neg__") -SLOT0(slot_nb_positive, "__pos__") -SLOT0(slot_nb_absolute, "__abs__") - -static int -slot_nb_nonzero(PyObject *self) -{ - PyObject *func, *args; - static PyObject *nonzero_str, *len_str; - int result = -1; - - func = lookup_maybe(self, "__nonzero__", &nonzero_str); - if (func == NULL) { - if (PyErr_Occurred()) - return -1; - func = lookup_maybe(self, "__len__", &len_str); - if (func == NULL) - return PyErr_Occurred() ? -1 : 1; - } - args = PyTuple_New(0); - if (args != NULL) { - PyObject *temp = PyObject_Call(func, args, NULL); - Py_DECREF(args); - if (temp != NULL) { - if (PyInt_CheckExact(temp) || PyBool_Check(temp)) - result = PyObject_IsTrue(temp); - else { - PyErr_Format(PyExc_TypeError, - "__nonzero__ should return " - "bool or int, returned %s", - temp->ob_type->tp_name); - result = -1; - } - Py_DECREF(temp); - } - } - Py_DECREF(func); - return result; -} - - -static PyObject * -slot_nb_index(PyObject *self) -{ - static PyObject *index_str; - return call_method(self, "__index__", &index_str, "()"); -} - - -SLOT0(slot_nb_invert, "__invert__") -SLOT1BIN(slot_nb_lshift, nb_lshift, "__lshift__", "__rlshift__") -SLOT1BIN(slot_nb_rshift, nb_rshift, "__rshift__", "__rrshift__") -SLOT1BIN(slot_nb_and, nb_and, "__and__", "__rand__") -SLOT1BIN(slot_nb_xor, nb_xor, "__xor__", "__rxor__") -SLOT1BIN(slot_nb_or, nb_or, "__or__", "__ror__") - -static int -slot_nb_coerce(PyObject **a, PyObject **b) -{ - static PyObject *coerce_str; - PyObject *self = *a, *other = *b; - - if (self->ob_type->tp_as_number != NULL && - self->ob_type->tp_as_number->nb_coerce == slot_nb_coerce) { - PyObject *r; - r = call_maybe( - self, "__coerce__", &coerce_str, "(O)", other); - if (r == NULL) - return -1; - if (r == Py_NotImplemented) { - Py_DECREF(r); - } - else { - if (!PyTuple_Check(r) || PyTuple_GET_SIZE(r) != 2) { - PyErr_SetString(PyExc_TypeError, - "__coerce__ didn't return a 2-tuple"); - Py_DECREF(r); - return -1; - } - *a = PyTuple_GET_ITEM(r, 0); - Py_INCREF(*a); - *b = PyTuple_GET_ITEM(r, 1); - Py_INCREF(*b); - Py_DECREF(r); - return 0; - } - } - if (other->ob_type->tp_as_number != NULL && - other->ob_type->tp_as_number->nb_coerce == slot_nb_coerce) { - PyObject *r; - r = call_maybe( - other, "__coerce__", &coerce_str, "(O)", self); - if (r == NULL) - return -1; - if (r == Py_NotImplemented) { - Py_DECREF(r); - return 1; - } - if (!PyTuple_Check(r) || PyTuple_GET_SIZE(r) != 2) { - PyErr_SetString(PyExc_TypeError, - "__coerce__ didn't return a 2-tuple"); - Py_DECREF(r); - return -1; - } - *a = PyTuple_GET_ITEM(r, 1); - Py_INCREF(*a); - *b = PyTuple_GET_ITEM(r, 0); - Py_INCREF(*b); - Py_DECREF(r); - return 0; - } - return 1; -} - -SLOT0(slot_nb_int, "__int__") -SLOT0(slot_nb_long, "__long__") -SLOT0(slot_nb_float, "__float__") -SLOT0(slot_nb_oct, "__oct__") -SLOT0(slot_nb_hex, "__hex__") -SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *, "O") -SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *, "O") -SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *, "O") -SLOT1(slot_nb_inplace_divide, "__idiv__", PyObject *, "O") -SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *, "O") -/* Can't use SLOT1 here, because nb_inplace_power is ternary */ -static PyObject * -slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2) -{ - static PyObject *cache_str; - return call_method(self, "__ipow__", &cache_str, "(" "O" ")", arg1); -} -SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *, "O") -SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *, "O") -SLOT1(slot_nb_inplace_and, "__iand__", PyObject *, "O") -SLOT1(slot_nb_inplace_xor, "__ixor__", PyObject *, "O") -SLOT1(slot_nb_inplace_or, "__ior__", PyObject *, "O") -SLOT1BIN(slot_nb_floor_divide, nb_floor_divide, - "__floordiv__", "__rfloordiv__") -SLOT1BIN(slot_nb_true_divide, nb_true_divide, "__truediv__", "__rtruediv__") -SLOT1(slot_nb_inplace_floor_divide, "__ifloordiv__", PyObject *, "O") -SLOT1(slot_nb_inplace_true_divide, "__itruediv__", PyObject *, "O") - -static int -half_compare(PyObject *self, PyObject *other) -{ - PyObject *func, *args, *res; - static PyObject *cmp_str; - Py_ssize_t c; - - func = lookup_method(self, "__cmp__", &cmp_str); - if (func == NULL) { - PyErr_Clear(); - } - else { - args = PyTuple_Pack(1, other); - if (args == NULL) - res = NULL; - else { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } - Py_DECREF(func); - if (res != Py_NotImplemented) { - if (res == NULL) - return -2; - c = PyInt_AsLong(res); - Py_DECREF(res); - if (c == -1 && PyErr_Occurred()) - return -2; - return (c < 0) ? -1 : (c > 0) ? 1 : 0; - } - Py_DECREF(res); - } - return 2; -} - -/* This slot is published for the benefit of try_3way_compare in object.c */ -int -_PyObject_SlotCompare(PyObject *self, PyObject *other) -{ - int c; - - if (self->ob_type->tp_compare == _PyObject_SlotCompare) { - c = half_compare(self, other); - if (c <= 1) - return c; - } - if (other->ob_type->tp_compare == _PyObject_SlotCompare) { - c = half_compare(other, self); - if (c < -1) - return -2; - if (c <= 1) - return -c; - } - return (void *)self < (void *)other ? -1 : - (void *)self > (void *)other ? 1 : 0; -} - -static PyObject * -slot_tp_repr(PyObject *self) -{ - PyObject *func, *res; - static PyObject *repr_str; - - func = lookup_method(self, "__repr__", &repr_str); - if (func != NULL) { - res = PyEval_CallObject(func, NULL); - Py_DECREF(func); - return res; - } - PyErr_Clear(); - return PyString_FromFormat("<%s object at %p>", - self->ob_type->tp_name, self); -} - -static PyObject * -slot_tp_str(PyObject *self) -{ - PyObject *func, *res; - static PyObject *str_str; - - func = lookup_method(self, "__str__", &str_str); - if (func != NULL) { - res = PyEval_CallObject(func, NULL); - Py_DECREF(func); - return res; - } - else { - PyErr_Clear(); - return slot_tp_repr(self); - } -} - -static long -slot_tp_hash(PyObject *self) -{ - PyObject *func; - static PyObject *hash_str, *eq_str, *cmp_str; - long h; - - func = lookup_method(self, "__hash__", &hash_str); - - if (func != NULL) { - PyObject *res = PyEval_CallObject(func, NULL); - Py_DECREF(func); - if (res == NULL) - return -1; - if (PyLong_Check(res)) - h = PyLong_Type.tp_hash(res); - else - h = PyInt_AsLong(res); - Py_DECREF(res); - } - else { - PyErr_Clear(); - func = lookup_method(self, "__eq__", &eq_str); - if (func == NULL) { - PyErr_Clear(); - func = lookup_method(self, "__cmp__", &cmp_str); - } - if (func != NULL) { - PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", - self->ob_type->tp_name); - Py_DECREF(func); - return -1; - } - PyErr_Clear(); - h = _Py_HashPointer((void *)self); - } - if (h == -1 && !PyErr_Occurred()) - h = -2; - return h; -} - -static PyObject * -slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds) -{ - static PyObject *call_str; - PyObject *meth = lookup_method(self, "__call__", &call_str); - PyObject *res; - - if (meth == NULL) - return NULL; - - /* PyObject_Call() will end up calling slot_tp_call() again if - the object returned for __call__ has __call__ itself defined - upon it. This can be an infinite recursion if you set - __call__ in a class to an instance of it. */ - if (Py_EnterRecursiveCall(" in __call__")) { - Py_DECREF(meth); - return NULL; - } - res = PyObject_Call(meth, args, kwds); - Py_LeaveRecursiveCall(); - - Py_DECREF(meth); - return res; -} - -/* There are two slot dispatch functions for tp_getattro. - - - slot_tp_getattro() is used when __getattribute__ is overridden - but no __getattr__ hook is present; - - - slot_tp_getattr_hook() is used when a __getattr__ hook is present. - - The code in update_one_slot() always installs slot_tp_getattr_hook(); this - detects the absence of __getattr__ and then installs the simpler slot if - necessary. */ - -static PyObject * -slot_tp_getattro(PyObject *self, PyObject *name) -{ - static PyObject *getattribute_str = NULL; - return call_method(self, "__getattribute__", &getattribute_str, - "(O)", name); -} - -static PyObject * -slot_tp_getattr_hook(PyObject *self, PyObject *name) -{ - PyTypeObject *tp = self->ob_type; - PyObject *getattr, *getattribute, *res; - static PyObject *getattribute_str = NULL; - static PyObject *getattr_str = NULL; - - if (getattr_str == NULL) { - getattr_str = PyString_InternFromString("__getattr__"); - if (getattr_str == NULL) - return NULL; - } - if (getattribute_str == NULL) { - getattribute_str = - PyString_InternFromString("__getattribute__"); - if (getattribute_str == NULL) - return NULL; - } - getattr = _PyType_Lookup(tp, getattr_str); - if (getattr == NULL) { - /* No __getattr__ hook: use a simpler dispatcher */ - tp->tp_getattro = slot_tp_getattro; - return slot_tp_getattro(self, name); - } - getattribute = _PyType_Lookup(tp, getattribute_str); - if (getattribute == NULL || - (getattribute->ob_type == &PyWrapperDescr_Type && - ((PyWrapperDescrObject *)getattribute)->d_wrapped == - (void *)PyObject_GenericGetAttr)) - res = PyObject_GenericGetAttr(self, name); - else - res = PyObject_CallFunctionObjArgs(getattribute, self, name, NULL); - if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - res = PyObject_CallFunctionObjArgs(getattr, self, name, NULL); - } - return res; -} - -static int -slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value) -{ - PyObject *res; - static PyObject *delattr_str, *setattr_str; - - if (value == NULL) - res = call_method(self, "__delattr__", &delattr_str, - "(O)", name); - else - res = call_method(self, "__setattr__", &setattr_str, - "(OO)", name, value); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -/* Map rich comparison operators to their __xx__ namesakes */ -static char *name_op[] = { - "__lt__", - "__le__", - "__eq__", - "__ne__", - "__gt__", - "__ge__", -}; - -static PyObject * -half_richcompare(PyObject *self, PyObject *other, int op) -{ - PyObject *func, *args, *res; - static PyObject *op_str[6]; - - func = lookup_method(self, name_op[op], &op_str[op]); - if (func == NULL) { - PyErr_Clear(); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - args = PyTuple_Pack(1, other); - if (args == NULL) - res = NULL; - else { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } - Py_DECREF(func); - return res; -} - -static PyObject * -slot_tp_richcompare(PyObject *self, PyObject *other, int op) -{ - PyObject *res; - - if (self->ob_type->tp_richcompare == slot_tp_richcompare) { - res = half_richcompare(self, other, op); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } - if (other->ob_type->tp_richcompare == slot_tp_richcompare) { - res = half_richcompare(other, self, _Py_SwappedOp[op]); - if (res != Py_NotImplemented) { - return res; - } - Py_DECREF(res); - } - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -static PyObject * -slot_tp_iter(PyObject *self) -{ - PyObject *func, *res; - static PyObject *iter_str, *getitem_str; - - func = lookup_method(self, "__iter__", &iter_str); - if (func != NULL) { - PyObject *args; - args = res = PyTuple_New(0); - if (args != NULL) { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } - Py_DECREF(func); - return res; - } - PyErr_Clear(); - func = lookup_method(self, "__getitem__", &getitem_str); - if (func == NULL) { - PyErr_Format(PyExc_TypeError, - "'%.200s' object is not iterable", - self->ob_type->tp_name); - return NULL; - } - Py_DECREF(func); - return PySeqIter_New(self); -} - -static PyObject * -slot_tp_iternext(PyObject *self) -{ - static PyObject *next_str; - return call_method(self, "next", &next_str, "()"); -} - -static PyObject * -slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type) -{ - PyTypeObject *tp = self->ob_type; - PyObject *get; - static PyObject *get_str = NULL; - - if (get_str == NULL) { - get_str = PyString_InternFromString("__get__"); - if (get_str == NULL) - return NULL; - } - get = _PyType_Lookup(tp, get_str); - if (get == NULL) { - /* Avoid further slowdowns */ - if (tp->tp_descr_get == slot_tp_descr_get) - tp->tp_descr_get = NULL; - Py_INCREF(self); - return self; - } - if (obj == NULL) - obj = Py_None; - if (type == NULL) - type = Py_None; - return PyObject_CallFunctionObjArgs(get, self, obj, type, NULL); -} - -static int -slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value) -{ - PyObject *res; - static PyObject *del_str, *set_str; - - if (value == NULL) - res = call_method(self, "__delete__", &del_str, - "(O)", target); - else - res = call_method(self, "__set__", &set_str, - "(OO)", target, value); - if (res == NULL) - return -1; - Py_DECREF(res); - return 0; -} - -static int -slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - static PyObject *init_str; - PyObject *meth = lookup_method(self, "__init__", &init_str); - PyObject *res; - - if (meth == NULL) - return -1; - res = PyObject_Call(meth, args, kwds); - Py_DECREF(meth); - if (res == NULL) - return -1; - if (res != Py_None) { - PyErr_Format(PyExc_TypeError, - "__init__() should return None, not '%.200s'", - res->ob_type->tp_name); - Py_DECREF(res); - return -1; - } - Py_DECREF(res); - return 0; -} - -static PyObject * -slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - static PyObject *new_str; - PyObject *func; - PyObject *newargs, *x; - Py_ssize_t i, n; - - if (new_str == NULL) { - new_str = PyString_InternFromString("__new__"); - if (new_str == NULL) - return NULL; - } - func = PyObject_GetAttr((PyObject *)type, new_str); - if (func == NULL) - return NULL; - assert(PyTuple_Check(args)); - n = PyTuple_GET_SIZE(args); - newargs = PyTuple_New(n+1); - if (newargs == NULL) - return NULL; - Py_INCREF(type); - PyTuple_SET_ITEM(newargs, 0, (PyObject *)type); - for (i = 0; i < n; i++) { - x = PyTuple_GET_ITEM(args, i); - Py_INCREF(x); - PyTuple_SET_ITEM(newargs, i+1, x); - } - x = PyObject_Call(func, newargs, kwds); - Py_DECREF(newargs); - Py_DECREF(func); - return x; -} - -static void -slot_tp_del(PyObject *self) -{ - static PyObject *del_str = NULL; - PyObject *del, *res; - PyObject *error_type, *error_value, *error_traceback; - - /* Temporarily resurrect the object. */ - assert(self->ob_refcnt == 0); - self->ob_refcnt = 1; - - /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - /* Execute __del__ method, if any. */ - del = lookup_maybe(self, "__del__", &del_str); - if (del != NULL) { - res = PyEval_CallObject(del, NULL); - if (res == NULL) - PyErr_WriteUnraisable(del); - else - Py_DECREF(res); - Py_DECREF(del); - } - - /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); - - /* Undo the temporary resurrection; can't use DECREF here, it would - * cause a recursive call. - */ - assert(self->ob_refcnt > 0); - if (--self->ob_refcnt == 0) - return; /* this is the normal path out */ - - /* __del__ resurrected it! Make it look like the original Py_DECREF - * never happened. - */ - { - Py_ssize_t refcnt = self->ob_refcnt; - _Py_NewReference(self); - self->ob_refcnt = refcnt; - } - assert(!PyType_IS_GC(self->ob_type) || - _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); - /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so - * we need to undo that. */ - _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --self->ob_type->tp_frees; - --self->ob_type->tp_allocs; -#endif -} - - -/* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper - functions. The offsets here are relative to the 'PyHeapTypeObject' - structure, which incorporates the additional structures used for numbers, - sequences and mappings. - Note that multiple names may map to the same slot (e.g. __eq__, - __ne__ etc. all map to tp_richcompare) and one name may map to multiple - slots (e.g. __str__ affects tp_str as well as tp_repr). The table is - terminated with an all-zero entry. (This table is further initialized and - sorted in init_slotdefs() below.) */ - -typedef struct wrapperbase slotdef; - -#undef TPSLOT -#undef FLSLOT -#undef ETSLOT -#undef SQSLOT -#undef MPSLOT -#undef NBSLOT -#undef UNSLOT -#undef IBSLOT -#undef BINSLOT -#undef RBINSLOT - -#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ - PyDoc_STR(DOC)} -#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \ - {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ - PyDoc_STR(DOC), FLAGS} -#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ - PyDoc_STR(DOC)} -#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, DOC) -#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER, DOC) -#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC) -#define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ - "x." NAME "() <==> " DOC) -#define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ - "x." NAME "(y) <==> x" DOC "y") -#define BINSLOT(NAME, SLOT, FUNCTION, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ - "x." NAME "(y) <==> x" DOC "y") -#define RBINSLOT(NAME, SLOT, FUNCTION, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ - "x." NAME "(y) <==> y" DOC "x") -#define BINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ - "x." NAME "(y) <==> " DOC) -#define RBINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ - "x." NAME "(y) <==> " DOC) - -static slotdef slotdefs[] = { - SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, - "x.__len__() <==> len(x)"), - /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL. - The logic in abstract.c always falls back to nb_add/nb_multiply in - this case. Defining both the nb_* and the sq_* slots to call the - user-defined methods has unexpected side-effects, as shown by - test_descr.notimplemented() */ - SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, - "x.__add__(y) <==> x+y"), - SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, - "x.__mul__(n) <==> x*n"), - SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, - "x.__rmul__(n) <==> n*x"), - SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, - "x.__getitem__(y) <==> x[y]"), - SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_ssizessizeargfunc, - "x.__getslice__(i, j) <==> x[i:j]\n\ - \n\ - Use of negative indices is not supported."), - SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, - "x.__setitem__(i, y) <==> x[i]=y"), - SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, - "x.__delitem__(y) <==> del x[y]"), - SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice, - wrap_ssizessizeobjargproc, - "x.__setslice__(i, j, y) <==> x[i:j]=y\n\ - \n\ - Use of negative indices is not supported."), - SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice, - "x.__delslice__(i, j) <==> del x[i:j]\n\ - \n\ - Use of negative indices is not supported."), - SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, - "x.__contains__(y) <==> y in x"), - SQSLOT("__iadd__", sq_inplace_concat, NULL, - wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"), - SQSLOT("__imul__", sq_inplace_repeat, NULL, - wrap_indexargfunc, "x.__imul__(y) <==> x*=y"), - - MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, - "x.__len__() <==> len(x)"), - MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, - wrap_binaryfunc, - "x.__getitem__(y) <==> x[y]"), - MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript, - wrap_objobjargproc, - "x.__setitem__(i, y) <==> x[i]=y"), - MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript, - wrap_delitem, - "x.__delitem__(y) <==> del x[y]"), - - BINSLOT("__add__", nb_add, slot_nb_add, - "+"), - RBINSLOT("__radd__", nb_add, slot_nb_add, - "+"), - BINSLOT("__sub__", nb_subtract, slot_nb_subtract, - "-"), - RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract, - "-"), - BINSLOT("__mul__", nb_multiply, slot_nb_multiply, - "*"), - RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply, - "*"), - BINSLOT("__div__", nb_divide, slot_nb_divide, - "/"), - RBINSLOT("__rdiv__", nb_divide, slot_nb_divide, - "/"), - BINSLOT("__mod__", nb_remainder, slot_nb_remainder, - "%"), - RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder, - "%"), - BINSLOTNOTINFIX("__divmod__", nb_divmod, slot_nb_divmod, - "divmod(x, y)"), - RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod, - "divmod(y, x)"), - NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc, - "x.__pow__(y[, z]) <==> pow(x, y[, z])"), - NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r, - "y.__rpow__(x[, z]) <==> pow(x, y[, z])"), - UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-x"), - UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+x"), - UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc, - "abs(x)"), - UNSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_inquirypred, - "x != 0"), - UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~x"), - BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"), - RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"), - BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"), - RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift, ">>"), - BINSLOT("__and__", nb_and, slot_nb_and, "&"), - RBINSLOT("__rand__", nb_and, slot_nb_and, "&"), - BINSLOT("__xor__", nb_xor, slot_nb_xor, "^"), - RBINSLOT("__rxor__", nb_xor, slot_nb_xor, "^"), - BINSLOT("__or__", nb_or, slot_nb_or, "|"), - RBINSLOT("__ror__", nb_or, slot_nb_or, "|"), - NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc, - "x.__coerce__(y) <==> coerce(x, y)"), - UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc, - "int(x)"), - UNSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc, - "long(x)"), - UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc, - "float(x)"), - UNSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc, - "oct(x)"), - UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc, - "hex(x)"), - NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, - "x[y:z] <==> x[y.__index__():z.__index__()]"), - IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add, - wrap_binaryfunc, "+"), - IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract, - wrap_binaryfunc, "-"), - IBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply, - wrap_binaryfunc, "*"), - IBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide, - wrap_binaryfunc, "/"), - IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder, - wrap_binaryfunc, "%"), - IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power, - wrap_binaryfunc, "**"), - IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift, - wrap_binaryfunc, "<<"), - IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift, - wrap_binaryfunc, ">>"), - IBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and, - wrap_binaryfunc, "&"), - IBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor, - wrap_binaryfunc, "^"), - IBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or, - wrap_binaryfunc, "|"), - BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide, "//"), - RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide, "//"), - BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide, "/"), - RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide, "/"), - IBSLOT("__ifloordiv__", nb_inplace_floor_divide, - slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"), - IBSLOT("__itruediv__", nb_inplace_true_divide, - slot_nb_inplace_true_divide, wrap_binaryfunc, "/"), - - TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, - "x.__str__() <==> str(x)"), - TPSLOT("__str__", tp_print, NULL, NULL, ""), - TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, - "x.__repr__() <==> repr(x)"), - TPSLOT("__repr__", tp_print, NULL, NULL, ""), - TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc, - "x.__cmp__(y) <==> cmp(x,y)"), - TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, - "x.__hash__() <==> hash(x)"), - FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, - "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS), - TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, - wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"), - TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""), - TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), - TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""), - TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, - "x.__setattr__('name', value) <==> x.name = value"), - TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), - TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, - "x.__delattr__('name') <==> del x.name"), - TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""), - TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt, - "x.__lt__(y) <==> x<y"), - TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le, - "x.__le__(y) <==> x<=y"), - TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq, - "x.__eq__(y) <==> x==y"), - TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne, - "x.__ne__(y) <==> x!=y"), - TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt, - "x.__gt__(y) <==> x>y"), - TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge, - "x.__ge__(y) <==> x>=y"), - TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, - "x.__iter__() <==> iter(x)"), - TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next, - "x.next() -> the next value, or raise StopIteration"), - TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, - "descr.__get__(obj[, type]) -> value"), - TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set, - "descr.__set__(obj, value)"), - TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set, - wrap_descr_delete, "descr.__delete__(obj)"), - FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, - "x.__init__(...) initializes x; " - "see x.__class__.__doc__ for signature", - PyWrapperFlag_KEYWORDS), - TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""), - TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""), - {NULL} -}; - -/* Given a type pointer and an offset gotten from a slotdef entry, return a - pointer to the actual slot. This is not quite the same as simply adding - the offset to the type pointer, since it takes care to indirect through the - proper indirection pointer (as_buffer, etc.); it returns NULL if the - indirection pointer is NULL. */ -static void ** -slotptr(PyTypeObject *type, int ioffset) -{ - char *ptr; - long offset = ioffset; - - /* Note: this depends on the order of the members of PyHeapTypeObject! */ - assert(offset >= 0); - assert((size_t)offset < offsetof(PyHeapTypeObject, as_buffer)); - if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) { - ptr = (char *)type->tp_as_sequence; - offset -= offsetof(PyHeapTypeObject, as_sequence); - } - else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_mapping)) { - ptr = (char *)type->tp_as_mapping; - offset -= offsetof(PyHeapTypeObject, as_mapping); - } - else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_number)) { - ptr = (char *)type->tp_as_number; - offset -= offsetof(PyHeapTypeObject, as_number); - } - else { - ptr = (char *)type; - } - if (ptr != NULL) - ptr += offset; - return (void **)ptr; -} - -/* Length of array of slotdef pointers used to store slots with the - same __name__. There should be at most MAX_EQUIV-1 slotdef entries with - the same __name__, for any __name__. Since that's a static property, it is - appropriate to declare fixed-size arrays for this. */ -#define MAX_EQUIV 10 - -/* Return a slot pointer for a given name, but ONLY if the attribute has - exactly one slot function. The name must be an interned string. */ -static void ** -resolve_slotdups(PyTypeObject *type, PyObject *name) -{ - /* XXX Maybe this could be optimized more -- but is it worth it? */ - - /* pname and ptrs act as a little cache */ - static PyObject *pname; - static slotdef *ptrs[MAX_EQUIV]; - slotdef *p, **pp; - void **res, **ptr; - - if (pname != name) { - /* Collect all slotdefs that match name into ptrs. */ - pname = name; - pp = ptrs; - for (p = slotdefs; p->name_strobj; p++) { - if (p->name_strobj == name) - *pp++ = p; - } - *pp = NULL; - } - - /* Look in all matching slots of the type; if exactly one of these has - a filled-in slot, return its value. Otherwise return NULL. */ - res = NULL; - for (pp = ptrs; *pp; pp++) { - ptr = slotptr(type, (*pp)->offset); - if (ptr == NULL || *ptr == NULL) - continue; - if (res != NULL) - return NULL; - res = ptr; - } - return res; -} - -/* Common code for update_slots_callback() and fixup_slot_dispatchers(). This - does some incredibly complex thinking and then sticks something into the - slot. (It sees if the adjacent slotdefs for the same slot have conflicting - interests, and then stores a generic wrapper or a specific function into - the slot.) Return a pointer to the next slotdef with a different offset, - because that's convenient for fixup_slot_dispatchers(). */ -static slotdef * -update_one_slot(PyTypeObject *type, slotdef *p) -{ - PyObject *descr; - PyWrapperDescrObject *d; - void *generic = NULL, *specific = NULL; - int use_generic = 0; - int offset = p->offset; - void **ptr = slotptr(type, offset); - - if (ptr == NULL) { - do { - ++p; - } while (p->offset == offset); - return p; - } - do { - descr = _PyType_Lookup(type, p->name_strobj); - if (descr == NULL) - continue; - if (descr->ob_type == &PyWrapperDescr_Type) { - void **tptr = resolve_slotdups(type, p->name_strobj); - if (tptr == NULL || tptr == ptr) - generic = p->function; - d = (PyWrapperDescrObject *)descr; - if (d->d_base->wrapper == p->wrapper && - PyType_IsSubtype(type, d->d_type)) - { - if (specific == NULL || - specific == d->d_wrapped) - specific = d->d_wrapped; - else - use_generic = 1; - } - } - else if (descr->ob_type == &PyCFunction_Type && - PyCFunction_GET_FUNCTION(descr) == - (PyCFunction)tp_new_wrapper && - strcmp(p->name, "__new__") == 0) - { - /* The __new__ wrapper is not a wrapper descriptor, - so must be special-cased differently. - If we don't do this, creating an instance will - always use slot_tp_new which will look up - __new__ in the MRO which will call tp_new_wrapper - which will look through the base classes looking - for a static base and call its tp_new (usually - PyType_GenericNew), after performing various - sanity checks and constructing a new argument - list. Cut all that nonsense short -- this speeds - up instance creation tremendously. */ - specific = (void *)type->tp_new; - /* XXX I'm not 100% sure that there isn't a hole - in this reasoning that requires additional - sanity checks. I'll buy the first person to - point out a bug in this reasoning a beer. */ - } - else { - use_generic = 1; - generic = p->function; - } - } while ((++p)->offset == offset); - if (specific && !use_generic) - *ptr = specific; - else - *ptr = generic; - return p; -} - -/* In the type, update the slots whose slotdefs are gathered in the pp array. - This is a callback for update_subclasses(). */ -static int -update_slots_callback(PyTypeObject *type, void *data) -{ - slotdef **pp = (slotdef **)data; - - for (; *pp; pp++) - update_one_slot(type, *pp); - return 0; -} - -/* Comparison function for qsort() to compare slotdefs by their offset, and - for equal offset by their address (to force a stable sort). */ -static int -slotdef_cmp(const void *aa, const void *bb) -{ - const slotdef *a = (const slotdef *)aa, *b = (const slotdef *)bb; - int c = a->offset - b->offset; - if (c != 0) - return c; - else - /* Cannot use a-b, as this gives off_t, - which may lose precision when converted to int. */ - return (a > b) ? 1 : (a < b) ? -1 : 0; -} - -/* Initialize the slotdefs table by adding interned string objects for the - names and sorting the entries. */ -static void -init_slotdefs(void) -{ - slotdef *p; - static int initialized = 0; - - if (initialized) - return; - for (p = slotdefs; p->name; p++) { - p->name_strobj = PyString_InternFromString(p->name); - if (!p->name_strobj) - Py_FatalError("Out of memory interning slotdef names"); - } - qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef), - slotdef_cmp); - initialized = 1; -} - -/* Update the slots after assignment to a class (type) attribute. */ -static int -update_slot(PyTypeObject *type, PyObject *name) -{ - slotdef *ptrs[MAX_EQUIV]; - slotdef *p; - slotdef **pp; - int offset; - - init_slotdefs(); - pp = ptrs; - for (p = slotdefs; p->name; p++) { - /* XXX assume name is interned! */ - if (p->name_strobj == name) - *pp++ = p; - } - *pp = NULL; - for (pp = ptrs; *pp; pp++) { - p = *pp; - offset = p->offset; - while (p > slotdefs && (p-1)->offset == offset) - --p; - *pp = p; - } - if (ptrs[0] == NULL) - return 0; /* Not an attribute that affects any slots */ - return update_subclasses(type, name, - update_slots_callback, (void *)ptrs); -} - -/* Store the proper functions in the slot dispatches at class (type) - definition time, based upon which operations the class overrides in its - dict. */ -static void -fixup_slot_dispatchers(PyTypeObject *type) -{ - slotdef *p; - - init_slotdefs(); - for (p = slotdefs; p->name; ) - p = update_one_slot(type, p); -} - -static void -update_all_slots(PyTypeObject* type) -{ - slotdef *p; - - init_slotdefs(); - for (p = slotdefs; p->name; p++) { - /* update_slot returns int but can't actually fail */ - update_slot(type, p->name_strobj); - } -} - -/* recurse_down_subclasses() and update_subclasses() are mutually - recursive functions to call a callback for all subclasses, - but refraining from recursing into subclasses that define 'name'. */ - -static int -update_subclasses(PyTypeObject *type, PyObject *name, - update_callback callback, void *data) -{ - if (callback(type, data) < 0) - return -1; - return recurse_down_subclasses(type, name, callback, data); -} - -static int -recurse_down_subclasses(PyTypeObject *type, PyObject *name, - update_callback callback, void *data) -{ - PyTypeObject *subclass; - PyObject *ref, *subclasses, *dict; - Py_ssize_t i, n; - - subclasses = type->tp_subclasses; - if (subclasses == NULL) - return 0; - assert(PyList_Check(subclasses)); - n = PyList_GET_SIZE(subclasses); - for (i = 0; i < n; i++) { - ref = PyList_GET_ITEM(subclasses, i); - assert(PyWeakref_CheckRef(ref)); - subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref); - assert(subclass != NULL); - if ((PyObject *)subclass == Py_None) - continue; - assert(PyType_Check(subclass)); - /* Avoid recursing down into unaffected classes */ - dict = subclass->tp_dict; - if (dict != NULL && PyDict_Check(dict) && - PyDict_GetItem(dict, name) != NULL) - continue; - if (update_subclasses(subclass, name, callback, data) < 0) - return -1; - } - return 0; -} - -/* This function is called by PyType_Ready() to populate the type's - dictionary with method descriptors for function slots. For each - function slot (like tp_repr) that's defined in the type, one or more - corresponding descriptors are added in the type's tp_dict dictionary - under the appropriate name (like __repr__). Some function slots - cause more than one descriptor to be added (for example, the nb_add - slot adds both __add__ and __radd__ descriptors) and some function - slots compete for the same descriptor (for example both sq_item and - mp_subscript generate a __getitem__ descriptor). - - In the latter case, the first slotdef entry encoutered wins. Since - slotdef entries are sorted by the offset of the slot in the - PyHeapTypeObject, this gives us some control over disambiguating - between competing slots: the members of PyHeapTypeObject are listed - from most general to least general, so the most general slot is - preferred. In particular, because as_mapping comes before as_sequence, - for a type that defines both mp_subscript and sq_item, mp_subscript - wins. - - This only adds new descriptors and doesn't overwrite entries in - tp_dict that were previously defined. The descriptors contain a - reference to the C function they must call, so that it's safe if they - are copied into a subtype's __dict__ and the subtype has a different - C function in its slot -- calling the method defined by the - descriptor will call the C function that was used to create it, - rather than the C function present in the slot when it is called. - (This is important because a subtype may have a C function in the - slot that calls the method from the dictionary, and we want to avoid - infinite recursion here.) */ - -static int -add_operators(PyTypeObject *type) -{ - PyObject *dict = type->tp_dict; - slotdef *p; - PyObject *descr; - void **ptr; - - init_slotdefs(); - for (p = slotdefs; p->name; p++) { - if (p->wrapper == NULL) - continue; - ptr = slotptr(type, p->offset); - if (!ptr || !*ptr) - continue; - if (PyDict_GetItem(dict, p->name_strobj)) - continue; - descr = PyDescr_NewWrapper(type, p, *ptr); - if (descr == NULL) - return -1; - if (PyDict_SetItem(dict, p->name_strobj, descr) < 0) - return -1; - Py_DECREF(descr); - } - if (type->tp_new != NULL) { - if (add_tp_new_wrapper(type) < 0) - return -1; - } - return 0; -} - - -/* Cooperative 'super' */ - -typedef struct { - PyObject_HEAD - PyTypeObject *type; - PyObject *obj; - PyTypeObject *obj_type; -} superobject; - -static PyMemberDef super_members[] = { - {"__thisclass__", T_OBJECT, offsetof(superobject, type), READONLY, - "the class invoking super()"}, - {"__self__", T_OBJECT, offsetof(superobject, obj), READONLY, - "the instance invoking super(); may be None"}, - {"__self_class__", T_OBJECT, offsetof(superobject, obj_type), READONLY, - "the type of the instance invoking super(); may be None"}, - {0} -}; - -static void -super_dealloc(PyObject *self) -{ - superobject *su = (superobject *)self; - - _PyObject_GC_UNTRACK(self); - Py_XDECREF(su->obj); - Py_XDECREF(su->type); - Py_XDECREF(su->obj_type); - self->ob_type->tp_free(self); -} - -static PyObject * -super_repr(PyObject *self) -{ - superobject *su = (superobject *)self; - - if (su->obj_type) - return PyString_FromFormat( - "<super: <class '%s'>, <%s object>>", - su->type ? su->type->tp_name : "NULL", - su->obj_type->tp_name); - else - return PyString_FromFormat( - "<super: <class '%s'>, NULL>", - su->type ? su->type->tp_name : "NULL"); -} - -static PyObject * -super_getattro(PyObject *self, PyObject *name) -{ - superobject *su = (superobject *)self; - int skip = su->obj_type == NULL; - - if (!skip) { - /* We want __class__ to return the class of the super object - (i.e. super, or a subclass), not the class of su->obj. */ - skip = (PyString_Check(name) && - PyString_GET_SIZE(name) == 9 && - strcmp(PyString_AS_STRING(name), "__class__") == 0); - } - - if (!skip) { - PyObject *mro, *res, *tmp, *dict; - PyTypeObject *starttype; - descrgetfunc f; - Py_ssize_t i, n; - - starttype = su->obj_type; - mro = starttype->tp_mro; - - if (mro == NULL) - n = 0; - else { - assert(PyTuple_Check(mro)); - n = PyTuple_GET_SIZE(mro); - } - for (i = 0; i < n; i++) { - if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) - break; - } - i++; - res = NULL; - for (; i < n; i++) { - tmp = PyTuple_GET_ITEM(mro, i); - if (PyType_Check(tmp)) - dict = ((PyTypeObject *)tmp)->tp_dict; - else if (PyClass_Check(tmp)) - dict = ((PyClassObject *)tmp)->cl_dict; - else - continue; - res = PyDict_GetItem(dict, name); - if (res != NULL) { - Py_INCREF(res); - f = res->ob_type->tp_descr_get; - if (f != NULL) { - tmp = f(res, - /* Only pass 'obj' param if - this is instance-mode super - (See SF ID #743627) - */ - (su->obj == (PyObject *) - su->obj_type - ? (PyObject *)NULL - : su->obj), - (PyObject *)starttype); - Py_DECREF(res); - res = tmp; - } - return res; - } - } - } - return PyObject_GenericGetAttr(self, name); -} - -static PyTypeObject * -supercheck(PyTypeObject *type, PyObject *obj) -{ - /* Check that a super() call makes sense. Return a type object. - - obj can be a new-style class, or an instance of one: - - - If it is a class, it must be a subclass of 'type'. This case is - used for class methods; the return value is obj. - - - If it is an instance, it must be an instance of 'type'. This is - the normal case; the return value is obj.__class__. - - But... when obj is an instance, we want to allow for the case where - obj->ob_type is not a subclass of type, but obj.__class__ is! - This will allow using super() with a proxy for obj. - */ - - /* Check for first bullet above (special case) */ - if (PyType_Check(obj) && PyType_IsSubtype((PyTypeObject *)obj, type)) { - Py_INCREF(obj); - return (PyTypeObject *)obj; - } - - /* Normal case */ - if (PyType_IsSubtype(obj->ob_type, type)) { - Py_INCREF(obj->ob_type); - return obj->ob_type; - } - else { - /* Try the slow way */ - static PyObject *class_str = NULL; - PyObject *class_attr; - - if (class_str == NULL) { - class_str = PyString_FromString("__class__"); - if (class_str == NULL) - return NULL; - } - - class_attr = PyObject_GetAttr(obj, class_str); - - if (class_attr != NULL && - PyType_Check(class_attr) && - (PyTypeObject *)class_attr != obj->ob_type) - { - int ok = PyType_IsSubtype( - (PyTypeObject *)class_attr, type); - if (ok) - return (PyTypeObject *)class_attr; - } - - if (class_attr == NULL) - PyErr_Clear(); - else - Py_DECREF(class_attr); - } - - PyErr_SetString(PyExc_TypeError, - "super(type, obj): " - "obj must be an instance or subtype of type"); - return NULL; -} - -static PyObject * -super_descr_get(PyObject *self, PyObject *obj, PyObject *type) -{ - superobject *su = (superobject *)self; - superobject *newobj; - - if (obj == NULL || obj == Py_None || su->obj != NULL) { - /* Not binding to an object, or already bound */ - Py_INCREF(self); - return self; - } - if (su->ob_type != &PySuper_Type) - /* If su is an instance of a (strict) subclass of super, - call its type */ - return PyObject_CallFunctionObjArgs((PyObject *)su->ob_type, - su->type, obj, NULL); - else { - /* Inline the common case */ - PyTypeObject *obj_type = supercheck(su->type, obj); - if (obj_type == NULL) - return NULL; - newobj = (superobject *)PySuper_Type.tp_new(&PySuper_Type, - NULL, NULL); - if (newobj == NULL) - return NULL; - Py_INCREF(su->type); - Py_INCREF(obj); - newobj->type = su->type; - newobj->obj = obj; - newobj->obj_type = obj_type; - return (PyObject *)newobj; - } -} - -static int -super_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - superobject *su = (superobject *)self; - PyTypeObject *type; - PyObject *obj = NULL; - PyTypeObject *obj_type = NULL; - - if (!_PyArg_NoKeywords("super", kwds)) - return -1; - if (!PyArg_ParseTuple(args, "O!|O:super", &PyType_Type, &type, &obj)) - return -1; - if (obj == Py_None) - obj = NULL; - if (obj != NULL) { - obj_type = supercheck(type, obj); - if (obj_type == NULL) - return -1; - Py_INCREF(obj); - } - Py_INCREF(type); - su->type = type; - su->obj = obj; - su->obj_type = obj_type; - return 0; -} - -PyDoc_STRVAR(super_doc, -"super(type) -> unbound super object\n" -"super(type, obj) -> bound super object; requires isinstance(obj, type)\n" -"super(type, type2) -> bound super object; requires issubclass(type2, type)\n" -"Typical use to call a cooperative superclass method:\n" -"class C(B):\n" -" def meth(self, arg):\n" -" super(C, self).meth(arg)"); - -static int -super_traverse(PyObject *self, visitproc visit, void *arg) -{ - superobject *su = (superobject *)self; - - Py_VISIT(su->obj); - Py_VISIT(su->type); - Py_VISIT(su->obj_type); - - return 0; -} - -PyTypeObject PySuper_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "super", /* tp_name */ - sizeof(superobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - super_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - super_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - super_getattro, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - super_doc, /* tp_doc */ - super_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - super_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - super_descr_get, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - super_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; diff --git a/sys/src/cmd/python/Objects/unicodectype.c b/sys/src/cmd/python/Objects/unicodectype.c deleted file mode 100644 index 73def09db..000000000 --- a/sys/src/cmd/python/Objects/unicodectype.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - Unicode character type helpers. - - Written by Marc-Andre Lemburg (mal@lemburg.com). - Modified for Python 2.0 by Fredrik Lundh (fredrik@pythonware.com) - - Copyright (c) Corporation for National Research Initiatives. - -*/ - -#include "Python.h" -#include "unicodeobject.h" - -#define ALPHA_MASK 0x01 -#define DECIMAL_MASK 0x02 -#define DIGIT_MASK 0x04 -#define LOWER_MASK 0x08 -#define LINEBREAK_MASK 0x10 -#define SPACE_MASK 0x20 -#define TITLE_MASK 0x40 -#define UPPER_MASK 0x80 - -typedef struct { - const Py_UNICODE upper; - const Py_UNICODE lower; - const Py_UNICODE title; - const unsigned char decimal; - const unsigned char digit; - const unsigned short flags; -} _PyUnicode_TypeRecord; - -#include "unicodetype_db.h" - -static const _PyUnicode_TypeRecord * -gettyperecord(Py_UNICODE code) -{ - int index; - -#ifdef Py_UNICODE_WIDE - if (code >= 0x110000) - index = 0; - else -#endif - { - index = index1[(code>>SHIFT)]; - index = index2[(index<<SHIFT)+(code&((1<<SHIFT)-1))]; - } - - return &_PyUnicode_TypeRecords[index]; -} - -/* Returns 1 for Unicode characters having the category 'Zl', 'Zp' or - type 'B', 0 otherwise. */ - -int _PyUnicode_IsLinebreak(register const Py_UNICODE ch) -{ - switch (ch) { - case 0x000A: /* LINE FEED */ - case 0x000D: /* CARRIAGE RETURN */ - case 0x001C: /* FILE SEPARATOR */ - case 0x001D: /* GROUP SEPARATOR */ - case 0x001E: /* RECORD SEPARATOR */ - case 0x0085: /* NEXT LINE */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - return 1; - default: - return 0; - } -} - -/* Returns the titlecase Unicode characters corresponding to ch or just - ch if no titlecase mapping is known. */ - -Py_UNICODE _PyUnicode_ToTitlecase(register Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - int delta; - - if (ctype->title) - delta = ctype->title; - else - delta = ctype->upper; - - if (delta >= 32768) - delta -= 65536; - - return ch + delta; -} - -/* Returns 1 for Unicode characters having the category 'Lt', 0 - otherwise. */ - -int _PyUnicode_IsTitlecase(Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - - return (ctype->flags & TITLE_MASK) != 0; -} - -/* Returns the integer decimal (0-9) for Unicode characters having - this property, -1 otherwise. */ - -int _PyUnicode_ToDecimalDigit(Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - - return (ctype->flags & DECIMAL_MASK) ? ctype->decimal : -1; -} - -int _PyUnicode_IsDecimalDigit(Py_UNICODE ch) -{ - if (_PyUnicode_ToDecimalDigit(ch) < 0) - return 0; - return 1; -} - -/* Returns the integer digit (0-9) for Unicode characters having - this property, -1 otherwise. */ - -int _PyUnicode_ToDigit(Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - - return (ctype->flags & DIGIT_MASK) ? ctype->digit : -1; -} - -int _PyUnicode_IsDigit(Py_UNICODE ch) -{ - if (_PyUnicode_ToDigit(ch) < 0) - return 0; - return 1; -} - -/* Returns the numeric value as double for Unicode characters having - this property, -1.0 otherwise. */ - -/* TODO: replace with unicodetype_db.h table */ - -double _PyUnicode_ToNumeric(Py_UNICODE ch) -{ - switch (ch) { - case 0x0F33: - return (double) -1 / 2; - case 0x17F0: - case 0x3007: -#ifdef Py_UNICODE_WIDE - case 0x1018A: -#endif - return (double) 0; - case 0x09F4: - case 0x17F1: - case 0x215F: - case 0x2160: - case 0x2170: - case 0x3021: - case 0x3192: - case 0x3220: - case 0x3280: -#ifdef Py_UNICODE_WIDE - case 0x10107: - case 0x10142: - case 0x10158: - case 0x10159: - case 0x1015A: - case 0x10320: - case 0x103D1: -#endif - return (double) 1; - case 0x00BD: - case 0x0F2A: - case 0x2CFD: -#ifdef Py_UNICODE_WIDE - case 0x10141: - case 0x10175: - case 0x10176: -#endif - return (double) 1 / 2; - case 0x2153: - return (double) 1 / 3; - case 0x00BC: -#ifdef Py_UNICODE_WIDE - case 0x10140: -#endif - return (double) 1 / 4; - case 0x2155: - return (double) 1 / 5; - case 0x2159: - return (double) 1 / 6; - case 0x215B: - return (double) 1 / 8; - case 0x0BF0: - case 0x1372: - case 0x2169: - case 0x2179: - case 0x2469: - case 0x247D: - case 0x2491: - case 0x24FE: - case 0x277F: - case 0x2789: - case 0x2793: - case 0x3038: - case 0x3229: - case 0x3289: -#ifdef Py_UNICODE_WIDE - case 0x10110: - case 0x10149: - case 0x10150: - case 0x10157: - case 0x10160: - case 0x10161: - case 0x10162: - case 0x10163: - case 0x10164: - case 0x10322: - case 0x103D3: - case 0x10A44: -#endif - return (double) 10; - case 0x0BF1: - case 0x137B: - case 0x216D: - case 0x217D: -#ifdef Py_UNICODE_WIDE - case 0x10119: - case 0x1014B: - case 0x10152: - case 0x1016A: - case 0x103D5: - case 0x10A46: -#endif - return (double) 100; - case 0x0BF2: - case 0x216F: - case 0x217F: - case 0x2180: -#ifdef Py_UNICODE_WIDE - case 0x10122: - case 0x1014D: - case 0x10154: - case 0x10171: - case 0x10A47: -#endif - return (double) 1000; - case 0x137C: - case 0x2182: -#ifdef Py_UNICODE_WIDE - case 0x1012B: - case 0x10155: -#endif - return (double) 10000; - case 0x216A: - case 0x217A: - case 0x246A: - case 0x247E: - case 0x2492: - case 0x24EB: - return (double) 11; - case 0x0F2F: - return (double) 11 / 2; - case 0x216B: - case 0x217B: - case 0x246B: - case 0x247F: - case 0x2493: - case 0x24EC: - return (double) 12; - case 0x246C: - case 0x2480: - case 0x2494: - case 0x24ED: - return (double) 13; - case 0x0F30: - return (double) 13 / 2; - case 0x246D: - case 0x2481: - case 0x2495: - case 0x24EE: - return (double) 14; - case 0x246E: - case 0x2482: - case 0x2496: - case 0x24EF: - return (double) 15; - case 0x0F31: - return (double) 15 / 2; - case 0x09F9: - case 0x246F: - case 0x2483: - case 0x2497: - case 0x24F0: - return (double) 16; - case 0x16EE: - case 0x2470: - case 0x2484: - case 0x2498: - case 0x24F1: - return (double) 17; - case 0x0F32: - return (double) 17 / 2; - case 0x16EF: - case 0x2471: - case 0x2485: - case 0x2499: - case 0x24F2: - return (double) 18; - case 0x16F0: - case 0x2472: - case 0x2486: - case 0x249A: - case 0x24F3: - return (double) 19; - case 0x09F5: - case 0x17F2: - case 0x2161: - case 0x2171: - case 0x3022: - case 0x3193: - case 0x3221: - case 0x3281: -#ifdef Py_UNICODE_WIDE - case 0x10108: - case 0x1015B: - case 0x1015C: - case 0x1015D: - case 0x1015E: - case 0x103D2: -#endif - return (double) 2; - case 0x2154: -#ifdef Py_UNICODE_WIDE - case 0x10177: -#endif - return (double) 2 / 3; - case 0x2156: - return (double) 2 / 5; - case 0x1373: - case 0x2473: - case 0x2487: - case 0x249B: - case 0x24F4: - case 0x3039: -#ifdef Py_UNICODE_WIDE - case 0x10111: - case 0x103D4: - case 0x10A45: -#endif - return (double) 20; -#ifdef Py_UNICODE_WIDE - case 0x1011A: - return (double) 200; - case 0x10123: - return (double) 2000; - case 0x1012C: - return (double) 20000; -#endif - case 0x3251: - return (double) 21; - case 0x3252: - return (double) 22; - case 0x3253: - return (double) 23; - case 0x3254: - return (double) 24; - case 0x3255: - return (double) 25; - case 0x3256: - return (double) 26; - case 0x3257: - return (double) 27; - case 0x3258: - return (double) 28; - case 0x3259: - return (double) 29; - case 0x09F6: - case 0x17F3: - case 0x2162: - case 0x2172: - case 0x3023: - case 0x3194: - case 0x3222: - case 0x3282: -#ifdef Py_UNICODE_WIDE - case 0x10109: -#endif - return (double) 3; - case 0x0F2B: - return (double) 3 / 2; - case 0x00BE: -#ifdef Py_UNICODE_WIDE - case 0x10178: -#endif - return (double) 3 / 4; - case 0x2157: - return (double) 3 / 5; - case 0x215C: - return (double) 3 / 8; - case 0x1374: - case 0x303A: - case 0x325A: -#ifdef Py_UNICODE_WIDE - case 0x10112: - case 0x10165: -#endif - return (double) 30; -#ifdef Py_UNICODE_WIDE - case 0x1011B: - case 0x1016B: - return (double) 300; - case 0x10124: - return (double) 3000; - case 0x1012D: - return (double) 30000; -#endif - case 0x325B: - return (double) 31; - case 0x325C: - return (double) 32; - case 0x325D: - return (double) 33; - case 0x325E: - return (double) 34; - case 0x325F: - return (double) 35; - case 0x32B1: - return (double) 36; - case 0x32B2: - return (double) 37; - case 0x32B3: - return (double) 38; - case 0x32B4: - return (double) 39; - case 0x09F7: - case 0x17F4: - case 0x2163: - case 0x2173: - case 0x3024: - case 0x3195: - case 0x3223: - case 0x3283: -#ifdef Py_UNICODE_WIDE - case 0x1010A: -#endif - return (double) 4; - case 0x2158: - return (double) 4 / 5; - case 0x1375: - case 0x32B5: -#ifdef Py_UNICODE_WIDE - case 0x10113: -#endif - return (double) 40; -#ifdef Py_UNICODE_WIDE - case 0x1011C: - return (double) 400; - case 0x10125: - return (double) 4000; - case 0x1012E: - return (double) 40000; -#endif - case 0x32B6: - return (double) 41; - case 0x32B7: - return (double) 42; - case 0x32B8: - return (double) 43; - case 0x32B9: - return (double) 44; - case 0x32BA: - return (double) 45; - case 0x32BB: - return (double) 46; - case 0x32BC: - return (double) 47; - case 0x32BD: - return (double) 48; - case 0x32BE: - return (double) 49; - case 0x17F5: - case 0x2164: - case 0x2174: - case 0x3025: - case 0x3224: - case 0x3284: -#ifdef Py_UNICODE_WIDE - case 0x1010B: - case 0x10143: - case 0x10148: - case 0x1014F: - case 0x1015F: - case 0x10173: - case 0x10321: -#endif - return (double) 5; - case 0x0F2C: - return (double) 5 / 2; - case 0x215A: - return (double) 5 / 6; - case 0x215D: - return (double) 5 / 8; - case 0x1376: - case 0x216C: - case 0x217C: - case 0x32BF: -#ifdef Py_UNICODE_WIDE - case 0x10114: - case 0x10144: - case 0x1014A: - case 0x10151: - case 0x10166: - case 0x10167: - case 0x10168: - case 0x10169: - case 0x10174: - case 0x10323: -#endif - return (double) 50; - case 0x216E: - case 0x217E: -#ifdef Py_UNICODE_WIDE - case 0x1011D: - case 0x10145: - case 0x1014C: - case 0x10153: - case 0x1016C: - case 0x1016D: - case 0x1016E: - case 0x1016F: - case 0x10170: -#endif - return (double) 500; - case 0x2181: -#ifdef Py_UNICODE_WIDE - case 0x10126: - case 0x10146: - case 0x1014E: - case 0x10172: -#endif - return (double) 5000; -#ifdef Py_UNICODE_WIDE - case 0x1012F: - case 0x10147: - case 0x10156: - return (double) 50000; -#endif - case 0x17F6: - case 0x2165: - case 0x2175: - case 0x3026: - case 0x3225: - case 0x3285: -#ifdef Py_UNICODE_WIDE - case 0x1010C: -#endif - return (double) 6; - case 0x1377: -#ifdef Py_UNICODE_WIDE - case 0x10115: -#endif - return (double) 60; -#ifdef Py_UNICODE_WIDE - case 0x1011E: - return (double) 600; - case 0x10127: - return (double) 6000; - case 0x10130: - return (double) 60000; -#endif - case 0x17F7: - case 0x2166: - case 0x2176: - case 0x3027: - case 0x3226: - case 0x3286: -#ifdef Py_UNICODE_WIDE - case 0x1010D: -#endif - return (double) 7; - case 0x0F2D: - return (double) 7 / 2; - case 0x215E: - return (double) 7 / 8; - case 0x1378: -#ifdef Py_UNICODE_WIDE - case 0x10116: -#endif - return (double) 70; -#ifdef Py_UNICODE_WIDE - case 0x1011F: - return (double) 700; - case 0x10128: - return (double) 7000; - case 0x10131: - return (double) 70000; -#endif - case 0x17F8: - case 0x2167: - case 0x2177: - case 0x3028: - case 0x3227: - case 0x3287: -#ifdef Py_UNICODE_WIDE - case 0x1010E: -#endif - return (double) 8; - case 0x1379: -#ifdef Py_UNICODE_WIDE - case 0x10117: -#endif - return (double) 80; -#ifdef Py_UNICODE_WIDE - case 0x10120: - return (double) 800; - case 0x10129: - return (double) 8000; - case 0x10132: - return (double) 80000; -#endif - case 0x17F9: - case 0x2168: - case 0x2178: - case 0x3029: - case 0x3228: - case 0x3288: -#ifdef Py_UNICODE_WIDE - case 0x1010F: -#endif - return (double) 9; - case 0x0F2E: - return (double) 9 / 2; - case 0x137A: -#ifdef Py_UNICODE_WIDE - case 0x10118: -#endif - return (double) 90; -#ifdef Py_UNICODE_WIDE - case 0x10121: - case 0x1034A: - return (double) 900; - case 0x1012A: - return (double) 9000; - case 0x10133: - return (double) 90000; -#endif - default: - return (double) _PyUnicode_ToDigit(ch); - } -} - -int _PyUnicode_IsNumeric(Py_UNICODE ch) -{ - return _PyUnicode_ToNumeric(ch) != -1.0; -} - -#ifndef WANT_WCTYPE_FUNCTIONS - -/* Returns 1 for Unicode characters having the bidirectional type - 'WS', 'B' or 'S' or the category 'Zs', 0 otherwise. */ - -int _PyUnicode_IsWhitespace(register const Py_UNICODE ch) -{ - switch (ch) { - case 0x0009: /* HORIZONTAL TABULATION */ - case 0x000A: /* LINE FEED */ - case 0x000B: /* VERTICAL TABULATION */ - case 0x000C: /* FORM FEED */ - case 0x000D: /* CARRIAGE RETURN */ - case 0x001C: /* FILE SEPARATOR */ - case 0x001D: /* GROUP SEPARATOR */ - case 0x001E: /* RECORD SEPARATOR */ - case 0x001F: /* UNIT SEPARATOR */ - case 0x0020: /* SPACE */ - case 0x0085: /* NEXT LINE */ - case 0x00A0: /* NO-BREAK SPACE */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x200B: /* ZERO WIDTH SPACE */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - case 0x202F: /* NARROW NO-BREAK SPACE */ - case 0x205F: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - return 1; - default: - return 0; - } -} - -/* Returns 1 for Unicode characters having the category 'Ll', 0 - otherwise. */ - -int _PyUnicode_IsLowercase(Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - - return (ctype->flags & LOWER_MASK) != 0; -} - -/* Returns 1 for Unicode characters having the category 'Lu', 0 - otherwise. */ - -int _PyUnicode_IsUppercase(Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - - return (ctype->flags & UPPER_MASK) != 0; -} - -/* Returns the uppercase Unicode characters corresponding to ch or just - ch if no uppercase mapping is known. */ - -Py_UNICODE _PyUnicode_ToUppercase(Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - int delta = ctype->upper; - if (delta >= 32768) - delta -= 65536; - return ch + delta; -} - -/* Returns the lowercase Unicode characters corresponding to ch or just - ch if no lowercase mapping is known. */ - -Py_UNICODE _PyUnicode_ToLowercase(Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - int delta = ctype->lower; - if (delta >= 32768) - delta -= 65536; - return ch + delta; -} - -/* Returns 1 for Unicode characters having the category 'Ll', 'Lu', 'Lt', - 'Lo' or 'Lm', 0 otherwise. */ - -int _PyUnicode_IsAlpha(Py_UNICODE ch) -{ - const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); - - return (ctype->flags & ALPHA_MASK) != 0; -} - -#else - -/* Export the interfaces using the wchar_t type for portability - reasons: */ - -int _PyUnicode_IsWhitespace(Py_UNICODE ch) -{ - return iswspace(ch); -} - -int _PyUnicode_IsLowercase(Py_UNICODE ch) -{ - return iswlower(ch); -} - -int _PyUnicode_IsUppercase(Py_UNICODE ch) -{ - return iswupper(ch); -} - -Py_UNICODE _PyUnicode_ToLowercase(Py_UNICODE ch) -{ - return towlower(ch); -} - -Py_UNICODE _PyUnicode_ToUppercase(Py_UNICODE ch) -{ - return towupper(ch); -} - -int _PyUnicode_IsAlpha(Py_UNICODE ch) -{ - return iswalpha(ch); -} - -#endif diff --git a/sys/src/cmd/python/Objects/unicodeobject.c b/sys/src/cmd/python/Objects/unicodeobject.c deleted file mode 100644 index 00f2018da..000000000 --- a/sys/src/cmd/python/Objects/unicodeobject.c +++ /dev/null @@ -1,8067 +0,0 @@ -/* - -Unicode implementation based on original code by Fredrik Lundh, -modified by Marc-Andre Lemburg <mal@lemburg.com> according to the -Unicode Integration Proposal (see file Misc/unicode.txt). - -Major speed upgrades to the method implementations at the Reykjavik -NeedForSpeed sprint, by Fredrik Lundh and Andrew Dalke. - -Copyright (c) Corporation for National Research Initiatives. - --------------------------------------------------------------------- -The original string type implementation is: - - Copyright (c) 1999 by Secret Labs AB - Copyright (c) 1999 by Fredrik Lundh - -By obtaining, using, and/or copying this software and/or its -associated documentation, you agree that you have read, understood, -and will comply with the following terms and conditions: - -Permission to use, copy, modify, and distribute this software and its -associated documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appears in all -copies, and that both that copyright notice and this permission notice -appear in supporting documentation, and that the name of Secret Labs -AB or the author not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR -ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --------------------------------------------------------------------- - -*/ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" - -#include "unicodeobject.h" -#include "ucnhash.h" - -#ifdef MS_WINDOWS -#include <windows.h> -#endif - -/* Limit for the Unicode object free list */ - -#define MAX_UNICODE_FREELIST_SIZE 1024 - -/* Limit for the Unicode object free list stay alive optimization. - - The implementation will keep allocated Unicode memory intact for - all objects on the free list having a size less than this - limit. This reduces malloc() overhead for small Unicode objects. - - At worst this will result in MAX_UNICODE_FREELIST_SIZE * - (sizeof(PyUnicodeObject) + KEEPALIVE_SIZE_LIMIT + - malloc()-overhead) bytes of unused garbage. - - Setting the limit to 0 effectively turns the feature off. - - Note: This is an experimental feature ! If you get core dumps when - using Unicode objects, turn this feature off. - -*/ - -#define KEEPALIVE_SIZE_LIMIT 9 - -/* Endianness switches; defaults to little endian */ - -#ifdef WORDS_BIGENDIAN -# define BYTEORDER_IS_BIG_ENDIAN -#else -# define BYTEORDER_IS_LITTLE_ENDIAN -#endif - -/* --- Globals ------------------------------------------------------------ - - The globals are initialized by the _PyUnicode_Init() API and should - not be used before calling that API. - -*/ - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Free list for Unicode objects */ -static PyUnicodeObject *unicode_freelist; -static int unicode_freelist_size; - -/* The empty Unicode object is shared to improve performance. */ -static PyUnicodeObject *unicode_empty; - -/* Single character Unicode strings in the Latin-1 range are being - shared as well. */ -static PyUnicodeObject *unicode_latin1[256]; - -/* Default encoding to use and assume when NULL is passed as encoding - parameter; it is initialized by _PyUnicode_Init(). - - Always use the PyUnicode_SetDefaultEncoding() and - PyUnicode_GetDefaultEncoding() APIs to access this global. - -*/ -static char unicode_default_encoding[100]; - -Py_UNICODE -PyUnicode_GetMax(void) -{ -#ifdef Py_UNICODE_WIDE - return 0x10FFFF; -#else - /* This is actually an illegal character, so it should - not be passed to unichr. */ - return 0xFFFF; -#endif -} - -/* --- Bloom Filters ----------------------------------------------------- */ - -/* stuff to implement simple "bloom filters" for Unicode characters. - to keep things simple, we use a single bitmask, using the least 5 - bits from each unicode characters as the bit index. */ - -/* the linebreak mask is set up by Unicode_Init below */ - -#define BLOOM_MASK unsigned long - -static BLOOM_MASK bloom_linebreak; - -#define BLOOM(mask, ch) ((mask & (1 << ((ch) & 0x1F)))) - -#define BLOOM_LINEBREAK(ch)\ - (BLOOM(bloom_linebreak, (ch)) && Py_UNICODE_ISLINEBREAK((ch))) - -Py_LOCAL_INLINE(BLOOM_MASK) make_bloom_mask(Py_UNICODE* ptr, Py_ssize_t len) -{ - /* calculate simple bloom-style bitmask for a given unicode string */ - - long mask; - Py_ssize_t i; - - mask = 0; - for (i = 0; i < len; i++) - mask |= (1 << (ptr[i] & 0x1F)); - - return mask; -} - -Py_LOCAL_INLINE(int) unicode_member(Py_UNICODE chr, Py_UNICODE* set, Py_ssize_t setlen) -{ - Py_ssize_t i; - - for (i = 0; i < setlen; i++) - if (set[i] == chr) - return 1; - - return 0; -} - -#define BLOOM_MEMBER(mask, chr, set, setlen)\ - BLOOM(mask, chr) && unicode_member(chr, set, setlen) - -/* --- Unicode Object ----------------------------------------------------- */ - -static -int unicode_resize(register PyUnicodeObject *unicode, - Py_ssize_t length) -{ - void *oldstr; - - /* Shortcut if there's nothing much to do. */ - if (unicode->length == length) - goto reset; - - /* Resizing shared object (unicode_empty or single character - objects) in-place is not allowed. Use PyUnicode_Resize() - instead ! */ - - if (unicode == unicode_empty || - (unicode->length == 1 && - unicode->str[0] < 256U && - unicode_latin1[unicode->str[0]] == unicode)) { - PyErr_SetString(PyExc_SystemError, - "can't resize shared unicode objects"); - return -1; - } - - /* We allocate one more byte to make sure the string is Ux0000 terminated. - The overallocation is also used by fastsearch, which assumes that it's - safe to look at str[length] (without making any assumptions about what - it contains). */ - - oldstr = unicode->str; - PyMem_RESIZE(unicode->str, Py_UNICODE, length + 1); - if (!unicode->str) { - unicode->str = (Py_UNICODE *)oldstr; - PyErr_NoMemory(); - return -1; - } - unicode->str[length] = 0; - unicode->length = length; - - reset: - /* Reset the object caches */ - if (unicode->defenc) { - Py_DECREF(unicode->defenc); - unicode->defenc = NULL; - } - unicode->hash = -1; - - return 0; -} - -/* We allocate one more byte to make sure the string is - Ux0000 terminated -- XXX is this needed ? - - XXX This allocator could further be enhanced by assuring that the - free list never reduces its size below 1. - -*/ - -static -PyUnicodeObject *_PyUnicode_New(Py_ssize_t length) -{ - register PyUnicodeObject *unicode; - - /* Optimization for empty strings */ - if (length == 0 && unicode_empty != NULL) { - Py_INCREF(unicode_empty); - return unicode_empty; - } - - /* Unicode freelist & memory allocation */ - if (unicode_freelist) { - unicode = unicode_freelist; - unicode_freelist = *(PyUnicodeObject **)unicode; - unicode_freelist_size--; - if (unicode->str) { - /* Keep-Alive optimization: we only upsize the buffer, - never downsize it. */ - if ((unicode->length < length) && - unicode_resize(unicode, length) < 0) { - PyMem_DEL(unicode->str); - goto onError; - } - } - else { - unicode->str = PyMem_NEW(Py_UNICODE, length + 1); - } - PyObject_INIT(unicode, &PyUnicode_Type); - } - else { - unicode = PyObject_New(PyUnicodeObject, &PyUnicode_Type); - if (unicode == NULL) - return NULL; - unicode->str = PyMem_NEW(Py_UNICODE, length + 1); - } - - if (!unicode->str) { - PyErr_NoMemory(); - goto onError; - } - /* Initialize the first element to guard against cases where - * the caller fails before initializing str -- unicode_resize() - * reads str[0], and the Keep-Alive optimization can keep memory - * allocated for str alive across a call to unicode_dealloc(unicode). - * We don't want unicode_resize to read uninitialized memory in - * that case. - */ - unicode->str[0] = 0; - unicode->str[length] = 0; - unicode->length = length; - unicode->hash = -1; - unicode->defenc = NULL; - return unicode; - - onError: - _Py_ForgetReference((PyObject *)unicode); - PyObject_Del(unicode); - return NULL; -} - -static -void unicode_dealloc(register PyUnicodeObject *unicode) -{ - if (PyUnicode_CheckExact(unicode) && - unicode_freelist_size < MAX_UNICODE_FREELIST_SIZE) { - /* Keep-Alive optimization */ - if (unicode->length >= KEEPALIVE_SIZE_LIMIT) { - PyMem_DEL(unicode->str); - unicode->str = NULL; - unicode->length = 0; - } - if (unicode->defenc) { - Py_DECREF(unicode->defenc); - unicode->defenc = NULL; - } - /* Add to free list */ - *(PyUnicodeObject **)unicode = unicode_freelist; - unicode_freelist = unicode; - unicode_freelist_size++; - } - else { - PyMem_DEL(unicode->str); - Py_XDECREF(unicode->defenc); - unicode->ob_type->tp_free((PyObject *)unicode); - } -} - -int PyUnicode_Resize(PyObject **unicode, Py_ssize_t length) -{ - register PyUnicodeObject *v; - - /* Argument checks */ - if (unicode == NULL) { - PyErr_BadInternalCall(); - return -1; - } - v = (PyUnicodeObject *)*unicode; - if (v == NULL || !PyUnicode_Check(v) || v->ob_refcnt != 1 || length < 0) { - PyErr_BadInternalCall(); - return -1; - } - - /* Resizing unicode_empty and single character objects is not - possible since these are being shared. We simply return a fresh - copy with the same Unicode content. */ - if (v->length != length && - (v == unicode_empty || v->length == 1)) { - PyUnicodeObject *w = _PyUnicode_New(length); - if (w == NULL) - return -1; - Py_UNICODE_COPY(w->str, v->str, - length < v->length ? length : v->length); - Py_DECREF(*unicode); - *unicode = (PyObject *)w; - return 0; - } - - /* Note that we don't have to modify *unicode for unshared Unicode - objects, since we can modify them in-place. */ - return unicode_resize(v, length); -} - -/* Internal API for use in unicodeobject.c only ! */ -#define _PyUnicode_Resize(unicodevar, length) \ - PyUnicode_Resize(((PyObject **)(unicodevar)), length) - -PyObject *PyUnicode_FromUnicode(const Py_UNICODE *u, - Py_ssize_t size) -{ - PyUnicodeObject *unicode; - - /* If the Unicode data is known at construction time, we can apply - some optimizations which share commonly used objects. */ - if (u != NULL) { - - /* Optimization for empty strings */ - if (size == 0 && unicode_empty != NULL) { - Py_INCREF(unicode_empty); - return (PyObject *)unicode_empty; - } - - /* Single character Unicode objects in the Latin-1 range are - shared when using this constructor */ - if (size == 1 && *u < 256) { - unicode = unicode_latin1[*u]; - if (!unicode) { - unicode = _PyUnicode_New(1); - if (!unicode) - return NULL; - unicode->str[0] = *u; - unicode_latin1[*u] = unicode; - } - Py_INCREF(unicode); - return (PyObject *)unicode; - } - } - - unicode = _PyUnicode_New(size); - if (!unicode) - return NULL; - - /* Copy the Unicode data into the new object */ - if (u != NULL) - Py_UNICODE_COPY(unicode->str, u, size); - - return (PyObject *)unicode; -} - -#ifdef HAVE_WCHAR_H - -PyObject *PyUnicode_FromWideChar(register const wchar_t *w, - Py_ssize_t size) -{ - PyUnicodeObject *unicode; - - if (w == NULL) { - PyErr_BadInternalCall(); - return NULL; - } - - unicode = _PyUnicode_New(size); - if (!unicode) - return NULL; - - /* Copy the wchar_t data into the new object */ -#ifdef HAVE_USABLE_WCHAR_T - memcpy(unicode->str, w, size * sizeof(wchar_t)); -#else - { - register Py_UNICODE *u; - register Py_ssize_t i; - u = PyUnicode_AS_UNICODE(unicode); - for (i = size; i > 0; i--) - *u++ = *w++; - } -#endif - - return (PyObject *)unicode; -} - -Py_ssize_t PyUnicode_AsWideChar(PyUnicodeObject *unicode, - wchar_t *w, - Py_ssize_t size) -{ - if (unicode == NULL) { - PyErr_BadInternalCall(); - return -1; - } - - /* If possible, try to copy the 0-termination as well */ - if (size > PyUnicode_GET_SIZE(unicode)) - size = PyUnicode_GET_SIZE(unicode) + 1; - -#ifdef HAVE_USABLE_WCHAR_T - memcpy(w, unicode->str, size * sizeof(wchar_t)); -#else - { - register Py_UNICODE *u; - register Py_ssize_t i; - u = PyUnicode_AS_UNICODE(unicode); - for (i = size; i > 0; i--) - *w++ = *u++; - } -#endif - - if (size > PyUnicode_GET_SIZE(unicode)) - return PyUnicode_GET_SIZE(unicode); - else - return size; -} - -#endif - -PyObject *PyUnicode_FromOrdinal(int ordinal) -{ - Py_UNICODE s[1]; - -#ifdef Py_UNICODE_WIDE - if (ordinal < 0 || ordinal > 0x10ffff) { - PyErr_SetString(PyExc_ValueError, - "unichr() arg not in range(0x110000) " - "(wide Python build)"); - return NULL; - } -#else - if (ordinal < 0 || ordinal > 0xffff) { - PyErr_SetString(PyExc_ValueError, - "unichr() arg not in range(0x10000) " - "(narrow Python build)"); - return NULL; - } -#endif - - s[0] = (Py_UNICODE)ordinal; - return PyUnicode_FromUnicode(s, 1); -} - -PyObject *PyUnicode_FromObject(register PyObject *obj) -{ - /* XXX Perhaps we should make this API an alias of - PyObject_Unicode() instead ?! */ - if (PyUnicode_CheckExact(obj)) { - Py_INCREF(obj); - return obj; - } - if (PyUnicode_Check(obj)) { - /* For a Unicode subtype that's not a Unicode object, - return a true Unicode object with the same data. */ - return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(obj), - PyUnicode_GET_SIZE(obj)); - } - return PyUnicode_FromEncodedObject(obj, NULL, "strict"); -} - -PyObject *PyUnicode_FromEncodedObject(register PyObject *obj, - const char *encoding, - const char *errors) -{ - const char *s = NULL; - Py_ssize_t len; - PyObject *v; - - if (obj == NULL) { - PyErr_BadInternalCall(); - return NULL; - } - -#if 0 - /* For b/w compatibility we also accept Unicode objects provided - that no encodings is given and then redirect to - PyObject_Unicode() which then applies the additional logic for - Unicode subclasses. - - NOTE: This API should really only be used for object which - represent *encoded* Unicode ! - - */ - if (PyUnicode_Check(obj)) { - if (encoding) { - PyErr_SetString(PyExc_TypeError, - "decoding Unicode is not supported"); - return NULL; - } - return PyObject_Unicode(obj); - } -#else - if (PyUnicode_Check(obj)) { - PyErr_SetString(PyExc_TypeError, - "decoding Unicode is not supported"); - return NULL; - } -#endif - - /* Coerce object */ - if (PyString_Check(obj)) { - s = PyString_AS_STRING(obj); - len = PyString_GET_SIZE(obj); - } - else if (PyObject_AsCharBuffer(obj, &s, &len)) { - /* Overwrite the error message with something more useful in - case of a TypeError. */ - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_Format(PyExc_TypeError, - "coercing to Unicode: need string or buffer, " - "%.80s found", - obj->ob_type->tp_name); - goto onError; - } - - /* Convert to Unicode */ - if (len == 0) { - Py_INCREF(unicode_empty); - v = (PyObject *)unicode_empty; - } - else - v = PyUnicode_Decode(s, len, encoding, errors); - - return v; - - onError: - return NULL; -} - -PyObject *PyUnicode_Decode(const char *s, - Py_ssize_t size, - const char *encoding, - const char *errors) -{ - PyObject *buffer = NULL, *unicode; - - if (encoding == NULL) - encoding = PyUnicode_GetDefaultEncoding(); - - /* Shortcuts for common default encodings */ - if (strcmp(encoding, "utf-8") == 0) - return PyUnicode_DecodeUTF8(s, size, errors); - else if (strcmp(encoding, "latin-1") == 0) - return PyUnicode_DecodeLatin1(s, size, errors); -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) - else if (strcmp(encoding, "mbcs") == 0) - return PyUnicode_DecodeMBCS(s, size, errors); -#endif - else if (strcmp(encoding, "ascii") == 0) - return PyUnicode_DecodeASCII(s, size, errors); - - /* Decode via the codec registry */ - buffer = PyBuffer_FromMemory((void *)s, size); - if (buffer == NULL) - goto onError; - unicode = PyCodec_Decode(buffer, encoding, errors); - if (unicode == NULL) - goto onError; - if (!PyUnicode_Check(unicode)) { - PyErr_Format(PyExc_TypeError, - "decoder did not return an unicode object (type=%.400s)", - unicode->ob_type->tp_name); - Py_DECREF(unicode); - goto onError; - } - Py_DECREF(buffer); - return unicode; - - onError: - Py_XDECREF(buffer); - return NULL; -} - -PyObject *PyUnicode_AsDecodedObject(PyObject *unicode, - const char *encoding, - const char *errors) -{ - PyObject *v; - - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - goto onError; - } - - if (encoding == NULL) - encoding = PyUnicode_GetDefaultEncoding(); - - /* Decode via the codec registry */ - v = PyCodec_Decode(unicode, encoding, errors); - if (v == NULL) - goto onError; - return v; - - onError: - return NULL; -} - -PyObject *PyUnicode_Encode(const Py_UNICODE *s, - Py_ssize_t size, - const char *encoding, - const char *errors) -{ - PyObject *v, *unicode; - - unicode = PyUnicode_FromUnicode(s, size); - if (unicode == NULL) - return NULL; - v = PyUnicode_AsEncodedString(unicode, encoding, errors); - Py_DECREF(unicode); - return v; -} - -PyObject *PyUnicode_AsEncodedObject(PyObject *unicode, - const char *encoding, - const char *errors) -{ - PyObject *v; - - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - goto onError; - } - - if (encoding == NULL) - encoding = PyUnicode_GetDefaultEncoding(); - - /* Encode via the codec registry */ - v = PyCodec_Encode(unicode, encoding, errors); - if (v == NULL) - goto onError; - return v; - - onError: - return NULL; -} - -PyObject *PyUnicode_AsEncodedString(PyObject *unicode, - const char *encoding, - const char *errors) -{ - PyObject *v; - - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - goto onError; - } - - if (encoding == NULL) - encoding = PyUnicode_GetDefaultEncoding(); - - /* Shortcuts for common default encodings */ - if (errors == NULL) { - if (strcmp(encoding, "utf-8") == 0) - return PyUnicode_AsUTF8String(unicode); - else if (strcmp(encoding, "latin-1") == 0) - return PyUnicode_AsLatin1String(unicode); -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) - else if (strcmp(encoding, "mbcs") == 0) - return PyUnicode_AsMBCSString(unicode); -#endif - else if (strcmp(encoding, "ascii") == 0) - return PyUnicode_AsASCIIString(unicode); - } - - /* Encode via the codec registry */ - v = PyCodec_Encode(unicode, encoding, errors); - if (v == NULL) - goto onError; - if (!PyString_Check(v)) { - PyErr_Format(PyExc_TypeError, - "encoder did not return a string object (type=%.400s)", - v->ob_type->tp_name); - Py_DECREF(v); - goto onError; - } - return v; - - onError: - return NULL; -} - -PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode, - const char *errors) -{ - PyObject *v = ((PyUnicodeObject *)unicode)->defenc; - - if (v) - return v; - v = PyUnicode_AsEncodedString(unicode, NULL, errors); - if (v && errors == NULL) - ((PyUnicodeObject *)unicode)->defenc = v; - return v; -} - -Py_UNICODE *PyUnicode_AsUnicode(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - goto onError; - } - return PyUnicode_AS_UNICODE(unicode); - - onError: - return NULL; -} - -Py_ssize_t PyUnicode_GetSize(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - goto onError; - } - return PyUnicode_GET_SIZE(unicode); - - onError: - return -1; -} - -const char *PyUnicode_GetDefaultEncoding(void) -{ - return unicode_default_encoding; -} - -int PyUnicode_SetDefaultEncoding(const char *encoding) -{ - PyObject *v; - - /* Make sure the encoding is valid. As side effect, this also - loads the encoding into the codec registry cache. */ - v = _PyCodec_Lookup(encoding); - if (v == NULL) - goto onError; - Py_DECREF(v); - strncpy(unicode_default_encoding, - encoding, - sizeof(unicode_default_encoding)); - return 0; - - onError: - return -1; -} - -/* error handling callback helper: - build arguments, call the callback and check the arguments, - if no exception occurred, copy the replacement to the output - and adjust various state variables. - return 0 on success, -1 on error -*/ - -static -int unicode_decode_call_errorhandler(const char *errors, PyObject **errorHandler, - const char *encoding, const char *reason, - const char *input, Py_ssize_t insize, Py_ssize_t *startinpos, Py_ssize_t *endinpos, PyObject **exceptionObject, const char **inptr, - PyObject **output, Py_ssize_t *outpos, Py_UNICODE **outptr) -{ - static char *argparse = "O!n;decoding error handler must return (unicode, int) tuple"; - - PyObject *restuple = NULL; - PyObject *repunicode = NULL; - Py_ssize_t outsize = PyUnicode_GET_SIZE(*output); - Py_ssize_t requiredsize; - Py_ssize_t newpos; - Py_UNICODE *repptr; - Py_ssize_t repsize; - int res = -1; - - if (*errorHandler == NULL) { - *errorHandler = PyCodec_LookupError(errors); - if (*errorHandler == NULL) - goto onError; - } - - if (*exceptionObject == NULL) { - *exceptionObject = PyUnicodeDecodeError_Create( - encoding, input, insize, *startinpos, *endinpos, reason); - if (*exceptionObject == NULL) - goto onError; - } - else { - if (PyUnicodeDecodeError_SetStart(*exceptionObject, *startinpos)) - goto onError; - if (PyUnicodeDecodeError_SetEnd(*exceptionObject, *endinpos)) - goto onError; - if (PyUnicodeDecodeError_SetReason(*exceptionObject, reason)) - goto onError; - } - - restuple = PyObject_CallFunctionObjArgs(*errorHandler, *exceptionObject, NULL); - if (restuple == NULL) - goto onError; - if (!PyTuple_Check(restuple)) { - PyErr_Format(PyExc_TypeError, &argparse[4]); - goto onError; - } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, &repunicode, &newpos)) - goto onError; - if (newpos<0) - newpos = insize+newpos; - if (newpos<0 || newpos>insize) { - PyErr_Format(PyExc_IndexError, "position %zd from error handler out of bounds", newpos); - goto onError; - } - - /* need more space? (at least enough for what we - have+the replacement+the rest of the string (starting - at the new input position), so we won't have to check space - when there are no errors in the rest of the string) */ - repptr = PyUnicode_AS_UNICODE(repunicode); - repsize = PyUnicode_GET_SIZE(repunicode); - requiredsize = *outpos + repsize + insize-newpos; - if (requiredsize > outsize) { - if (requiredsize<2*outsize) - requiredsize = 2*outsize; - if (PyUnicode_Resize(output, requiredsize) < 0) - goto onError; - *outptr = PyUnicode_AS_UNICODE(*output) + *outpos; - } - *endinpos = newpos; - *inptr = input + newpos; - Py_UNICODE_COPY(*outptr, repptr, repsize); - *outptr += repsize; - *outpos += repsize; - /* we made it! */ - res = 0; - - onError: - Py_XDECREF(restuple); - return res; -} - -/* --- UTF-7 Codec -------------------------------------------------------- */ - -/* see RFC2152 for details */ - -static -char utf7_special[128] = { - /* indicate whether a UTF-7 character is special i.e. cannot be directly - encoded: - 0 - not special - 1 - special - 2 - whitespace (optional) - 3 - RFC2152 Set O (optional) */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 1, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, - 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 3, 3, - 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 1, 1, - -}; - -/* Note: The comparison (c) <= 0 is a trick to work-around gcc - warnings about the comparison always being false; since - utf7_special[0] is 1, we can safely make that one comparison - true */ - -#define SPECIAL(c, encodeO, encodeWS) \ - ((c) > 127 || (c) <= 0 || utf7_special[(c)] == 1 || \ - (encodeWS && (utf7_special[(c)] == 2)) || \ - (encodeO && (utf7_special[(c)] == 3))) - -#define B64(n) \ - ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(n) & 0x3f]) -#define B64CHAR(c) \ - (isalnum(c) || (c) == '+' || (c) == '/') -#define UB64(c) \ - ((c) == '+' ? 62 : (c) == '/' ? 63 : (c) >= 'a' ? \ - (c) - 71 : (c) >= 'A' ? (c) - 65 : (c) + 4 ) - -#define ENCODE(out, ch, bits) \ - while (bits >= 6) { \ - *out++ = B64(ch >> (bits-6)); \ - bits -= 6; \ - } - -#define DECODE(out, ch, bits, surrogate) \ - while (bits >= 16) { \ - Py_UNICODE outCh = (Py_UNICODE) ((ch >> (bits-16)) & 0xffff); \ - bits -= 16; \ - if (surrogate) { \ - /* We have already generated an error for the high surrogate \ - so let's not bother seeing if the low surrogate is correct or not */ \ - surrogate = 0; \ - } else if (0xDC00 <= outCh && outCh <= 0xDFFF) { \ - /* This is a surrogate pair. Unfortunately we can't represent \ - it in a 16-bit character */ \ - surrogate = 1; \ - errmsg = "code pairs are not supported"; \ - goto utf7Error; \ - } else { \ - *out++ = outCh; \ - } \ - } - -PyObject *PyUnicode_DecodeUTF7(const char *s, - Py_ssize_t size, - const char *errors) -{ - const char *starts = s; - Py_ssize_t startinpos; - Py_ssize_t endinpos; - Py_ssize_t outpos; - const char *e; - PyUnicodeObject *unicode; - Py_UNICODE *p; - const char *errmsg = ""; - int inShift = 0; - unsigned int bitsleft = 0; - unsigned long charsleft = 0; - int surrogate = 0; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - - unicode = _PyUnicode_New(size); - if (!unicode) - return NULL; - if (size == 0) - return (PyObject *)unicode; - - p = unicode->str; - e = s + size; - - while (s < e) { - Py_UNICODE ch; - restart: - ch = *s; - - if (inShift) { - if ((ch == '-') || !B64CHAR(ch)) { - inShift = 0; - s++; - - /* p, charsleft, bitsleft, surrogate = */ DECODE(p, charsleft, bitsleft, surrogate); - if (bitsleft >= 6) { - /* The shift sequence has a partial character in it. If - bitsleft < 6 then we could just classify it as padding - but that is not the case here */ - - errmsg = "partial character in shift sequence"; - goto utf7Error; - } - /* According to RFC2152 the remaining bits should be zero. We - choose to signal an error/insert a replacement character - here so indicate the potential of a misencoded character. */ - - /* On x86, a << b == a << (b%32) so make sure that bitsleft != 0 */ - if (bitsleft && charsleft << (sizeof(charsleft) * 8 - bitsleft)) { - errmsg = "non-zero padding bits in shift sequence"; - goto utf7Error; - } - - if (ch == '-') { - if ((s < e) && (*(s) == '-')) { - *p++ = '-'; - inShift = 1; - } - } else if (SPECIAL(ch,0,0)) { - errmsg = "unexpected special character"; - goto utf7Error; - } else { - *p++ = ch; - } - } else { - charsleft = (charsleft << 6) | UB64(ch); - bitsleft += 6; - s++; - /* p, charsleft, bitsleft, surrogate = */ DECODE(p, charsleft, bitsleft, surrogate); - } - } - else if ( ch == '+' ) { - startinpos = s-starts; - s++; - if (s < e && *s == '-') { - s++; - *p++ = '+'; - } else - { - inShift = 1; - bitsleft = 0; - } - } - else if (SPECIAL(ch,0,0)) { - errmsg = "unexpected special character"; - s++; - goto utf7Error; - } - else { - *p++ = ch; - s++; - } - continue; - utf7Error: - outpos = p-PyUnicode_AS_UNICODE(unicode); - endinpos = s-starts; - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "utf7", errmsg, - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&unicode, &outpos, &p)) - goto onError; - } - - if (inShift) { - outpos = p-PyUnicode_AS_UNICODE(unicode); - endinpos = size; - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "utf7", "unterminated shift sequence", - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&unicode, &outpos, &p)) - goto onError; - if (s < e) - goto restart; - } - - if (_PyUnicode_Resize(&unicode, p - PyUnicode_AS_UNICODE(unicode)) < 0) - goto onError; - - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return (PyObject *)unicode; - -onError: - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - Py_DECREF(unicode); - return NULL; -} - - -PyObject *PyUnicode_EncodeUTF7(const Py_UNICODE *s, - Py_ssize_t size, - int encodeSetO, - int encodeWhiteSpace, - const char *errors) -{ - PyObject *v; - /* It might be possible to tighten this worst case */ - Py_ssize_t cbAllocated = 5 * size; - int inShift = 0; - Py_ssize_t i = 0; - unsigned int bitsleft = 0; - unsigned long charsleft = 0; - char * out; - char * start; - - if (size == 0) - return PyString_FromStringAndSize(NULL, 0); - - v = PyString_FromStringAndSize(NULL, cbAllocated); - if (v == NULL) - return NULL; - - start = out = PyString_AS_STRING(v); - for (;i < size; ++i) { - Py_UNICODE ch = s[i]; - - if (!inShift) { - if (ch == '+') { - *out++ = '+'; - *out++ = '-'; - } else if (SPECIAL(ch, encodeSetO, encodeWhiteSpace)) { - charsleft = ch; - bitsleft = 16; - *out++ = '+'; - /* out, charsleft, bitsleft = */ ENCODE(out, charsleft, bitsleft); - inShift = bitsleft > 0; - } else { - *out++ = (char) ch; - } - } else { - if (!SPECIAL(ch, encodeSetO, encodeWhiteSpace)) { - *out++ = B64(charsleft << (6-bitsleft)); - charsleft = 0; - bitsleft = 0; - /* Characters not in the BASE64 set implicitly unshift the sequence - so no '-' is required, except if the character is itself a '-' */ - if (B64CHAR(ch) || ch == '-') { - *out++ = '-'; - } - inShift = 0; - *out++ = (char) ch; - } else { - bitsleft += 16; - charsleft = (charsleft << 16) | ch; - /* out, charsleft, bitsleft = */ ENCODE(out, charsleft, bitsleft); - - /* If the next character is special then we dont' need to terminate - the shift sequence. If the next character is not a BASE64 character - or '-' then the shift sequence will be terminated implicitly and we - don't have to insert a '-'. */ - - if (bitsleft == 0) { - if (i + 1 < size) { - Py_UNICODE ch2 = s[i+1]; - - if (SPECIAL(ch2, encodeSetO, encodeWhiteSpace)) { - - } else if (B64CHAR(ch2) || ch2 == '-') { - *out++ = '-'; - inShift = 0; - } else { - inShift = 0; - } - - } - else { - *out++ = '-'; - inShift = 0; - } - } - } - } - } - if (bitsleft) { - *out++= B64(charsleft << (6-bitsleft) ); - *out++ = '-'; - } - - _PyString_Resize(&v, out - start); - return v; -} - -#undef SPECIAL -#undef B64 -#undef B64CHAR -#undef UB64 -#undef ENCODE -#undef DECODE - -/* --- UTF-8 Codec -------------------------------------------------------- */ - -static -char utf8_code_length[256] = { - /* Map UTF-8 encoded prefix byte to sequence length. zero means - illegal prefix. see RFC 2279 for details */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 -}; - -PyObject *PyUnicode_DecodeUTF8(const char *s, - Py_ssize_t size, - const char *errors) -{ - return PyUnicode_DecodeUTF8Stateful(s, size, errors, NULL); -} - -PyObject *PyUnicode_DecodeUTF8Stateful(const char *s, - Py_ssize_t size, - const char *errors, - Py_ssize_t *consumed) -{ - const char *starts = s; - int n; - Py_ssize_t startinpos; - Py_ssize_t endinpos; - Py_ssize_t outpos; - const char *e; - PyUnicodeObject *unicode; - Py_UNICODE *p; - const char *errmsg = ""; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - - /* Note: size will always be longer than the resulting Unicode - character count */ - unicode = _PyUnicode_New(size); - if (!unicode) - return NULL; - if (size == 0) { - if (consumed) - *consumed = 0; - return (PyObject *)unicode; - } - - /* Unpack UTF-8 encoded data */ - p = unicode->str; - e = s + size; - - while (s < e) { - Py_UCS4 ch = (unsigned char)*s; - - if (ch < 0x80) { - *p++ = (Py_UNICODE)ch; - s++; - continue; - } - - n = utf8_code_length[ch]; - - if (s + n > e) { - if (consumed) - break; - else { - errmsg = "unexpected end of data"; - startinpos = s-starts; - endinpos = size; - goto utf8Error; - } - } - - switch (n) { - - case 0: - errmsg = "unexpected code byte"; - startinpos = s-starts; - endinpos = startinpos+1; - goto utf8Error; - - case 1: - errmsg = "internal error"; - startinpos = s-starts; - endinpos = startinpos+1; - goto utf8Error; - - case 2: - if ((s[1] & 0xc0) != 0x80) { - errmsg = "invalid data"; - startinpos = s-starts; - endinpos = startinpos+2; - goto utf8Error; - } - ch = ((s[0] & 0x1f) << 6) + (s[1] & 0x3f); - if (ch < 0x80) { - startinpos = s-starts; - endinpos = startinpos+2; - errmsg = "illegal encoding"; - goto utf8Error; - } - else - *p++ = (Py_UNICODE)ch; - break; - - case 3: - if ((s[1] & 0xc0) != 0x80 || - (s[2] & 0xc0) != 0x80) { - errmsg = "invalid data"; - startinpos = s-starts; - endinpos = startinpos+3; - goto utf8Error; - } - ch = ((s[0] & 0x0f) << 12) + ((s[1] & 0x3f) << 6) + (s[2] & 0x3f); - if (ch < 0x0800) { - /* Note: UTF-8 encodings of surrogates are considered - legal UTF-8 sequences; - - XXX For wide builds (UCS-4) we should probably try - to recombine the surrogates into a single code - unit. - */ - errmsg = "illegal encoding"; - startinpos = s-starts; - endinpos = startinpos+3; - goto utf8Error; - } - else - *p++ = (Py_UNICODE)ch; - break; - - case 4: - if ((s[1] & 0xc0) != 0x80 || - (s[2] & 0xc0) != 0x80 || - (s[3] & 0xc0) != 0x80) { - errmsg = "invalid data"; - startinpos = s-starts; - endinpos = startinpos+4; - goto utf8Error; - } - ch = ((s[0] & 0x7) << 18) + ((s[1] & 0x3f) << 12) + - ((s[2] & 0x3f) << 6) + (s[3] & 0x3f); - /* validate and convert to UTF-16 */ - if ((ch < 0x10000) /* minimum value allowed for 4 - byte encoding */ - || (ch > 0x10ffff)) /* maximum value allowed for - UTF-16 */ - { - errmsg = "illegal encoding"; - startinpos = s-starts; - endinpos = startinpos+4; - goto utf8Error; - } -#ifdef Py_UNICODE_WIDE - *p++ = (Py_UNICODE)ch; -#else - /* compute and append the two surrogates: */ - - /* translate from 10000..10FFFF to 0..FFFF */ - ch -= 0x10000; - - /* high surrogate = top 10 bits added to D800 */ - *p++ = (Py_UNICODE)(0xD800 + (ch >> 10)); - - /* low surrogate = bottom 10 bits added to DC00 */ - *p++ = (Py_UNICODE)(0xDC00 + (ch & 0x03FF)); -#endif - break; - - default: - /* Other sizes are only needed for UCS-4 */ - errmsg = "unsupported Unicode code range"; - startinpos = s-starts; - endinpos = startinpos+n; - goto utf8Error; - } - s += n; - continue; - - utf8Error: - outpos = p-PyUnicode_AS_UNICODE(unicode); - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "utf8", errmsg, - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&unicode, &outpos, &p)) - goto onError; - } - if (consumed) - *consumed = s-starts; - - /* Adjust length */ - if (_PyUnicode_Resize(&unicode, p - unicode->str) < 0) - goto onError; - - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return (PyObject *)unicode; - -onError: - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - Py_DECREF(unicode); - return NULL; -} - -/* Allocation strategy: if the string is short, convert into a stack buffer - and allocate exactly as much space needed at the end. Else allocate the - maximum possible needed (4 result bytes per Unicode character), and return - the excess memory at the end. -*/ -PyObject * -PyUnicode_EncodeUTF8(const Py_UNICODE *s, - Py_ssize_t size, - const char *errors) -{ -#define MAX_SHORT_UNICHARS 300 /* largest size we'll do on the stack */ - - Py_ssize_t i; /* index into s of next input byte */ - PyObject *v; /* result string object */ - char *p; /* next free byte in output buffer */ - Py_ssize_t nallocated; /* number of result bytes allocated */ - Py_ssize_t nneeded; /* number of result bytes needed */ - char stackbuf[MAX_SHORT_UNICHARS * 4]; - - assert(s != NULL); - assert(size >= 0); - - if (size <= MAX_SHORT_UNICHARS) { - /* Write into the stack buffer; nallocated can't overflow. - * At the end, we'll allocate exactly as much heap space as it - * turns out we need. - */ - nallocated = Py_SAFE_DOWNCAST(sizeof(stackbuf), size_t, int); - v = NULL; /* will allocate after we're done */ - p = stackbuf; - } - else { - /* Overallocate on the heap, and give the excess back at the end. */ - nallocated = size * 4; - if (nallocated / 4 != size) /* overflow! */ - return PyErr_NoMemory(); - v = PyString_FromStringAndSize(NULL, nallocated); - if (v == NULL) - return NULL; - p = PyString_AS_STRING(v); - } - - for (i = 0; i < size;) { - Py_UCS4 ch = s[i++]; - - if (ch < 0x80) - /* Encode ASCII */ - *p++ = (char) ch; - - else if (ch < 0x0800) { - /* Encode Latin-1 */ - *p++ = (char)(0xc0 | (ch >> 6)); - *p++ = (char)(0x80 | (ch & 0x3f)); - } - else { - /* Encode UCS2 Unicode ordinals */ - if (ch < 0x10000) { - /* Special case: check for high surrogate */ - if (0xD800 <= ch && ch <= 0xDBFF && i != size) { - Py_UCS4 ch2 = s[i]; - /* Check for low surrogate and combine the two to - form a UCS4 value */ - if (0xDC00 <= ch2 && ch2 <= 0xDFFF) { - ch = ((ch - 0xD800) << 10 | (ch2 - 0xDC00)) + 0x10000; - i++; - goto encodeUCS4; - } - /* Fall through: handles isolated high surrogates */ - } - *p++ = (char)(0xe0 | (ch >> 12)); - *p++ = (char)(0x80 | ((ch >> 6) & 0x3f)); - *p++ = (char)(0x80 | (ch & 0x3f)); - continue; - } -encodeUCS4: - /* Encode UCS4 Unicode ordinals */ - *p++ = (char)(0xf0 | (ch >> 18)); - *p++ = (char)(0x80 | ((ch >> 12) & 0x3f)); - *p++ = (char)(0x80 | ((ch >> 6) & 0x3f)); - *p++ = (char)(0x80 | (ch & 0x3f)); - } - } - - if (v == NULL) { - /* This was stack allocated. */ - nneeded = p - stackbuf; - assert(nneeded <= nallocated); - v = PyString_FromStringAndSize(stackbuf, nneeded); - } - else { - /* Cut back to size actually needed. */ - nneeded = p - PyString_AS_STRING(v); - assert(nneeded <= nallocated); - _PyString_Resize(&v, nneeded); - } - return v; - -#undef MAX_SHORT_UNICHARS -} - -PyObject *PyUnicode_AsUTF8String(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - return NULL; - } - return PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode), - NULL); -} - -/* --- UTF-16 Codec ------------------------------------------------------- */ - -PyObject * -PyUnicode_DecodeUTF16(const char *s, - Py_ssize_t size, - const char *errors, - int *byteorder) -{ - return PyUnicode_DecodeUTF16Stateful(s, size, errors, byteorder, NULL); -} - -PyObject * -PyUnicode_DecodeUTF16Stateful(const char *s, - Py_ssize_t size, - const char *errors, - int *byteorder, - Py_ssize_t *consumed) -{ - const char *starts = s; - Py_ssize_t startinpos; - Py_ssize_t endinpos; - Py_ssize_t outpos; - PyUnicodeObject *unicode; - Py_UNICODE *p; - const unsigned char *q, *e; - int bo = 0; /* assume native ordering by default */ - const char *errmsg = ""; - /* Offsets from q for retrieving byte pairs in the right order. */ -#ifdef BYTEORDER_IS_LITTLE_ENDIAN - int ihi = 1, ilo = 0; -#else - int ihi = 0, ilo = 1; -#endif - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - - /* Note: size will always be longer than the resulting Unicode - character count */ - unicode = _PyUnicode_New(size); - if (!unicode) - return NULL; - if (size == 0) - return (PyObject *)unicode; - - /* Unpack UTF-16 encoded data */ - p = unicode->str; - q = (unsigned char *)s; - e = q + size; - - if (byteorder) - bo = *byteorder; - - /* Check for BOM marks (U+FEFF) in the input and adjust current - byte order setting accordingly. In native mode, the leading BOM - mark is skipped, in all other modes, it is copied to the output - stream as-is (giving a ZWNBSP character). */ - if (bo == 0) { - if (size >= 2) { - const Py_UNICODE bom = (q[ihi] << 8) | q[ilo]; -#ifdef BYTEORDER_IS_LITTLE_ENDIAN - if (bom == 0xFEFF) { - q += 2; - bo = -1; - } - else if (bom == 0xFFFE) { - q += 2; - bo = 1; - } -#else - if (bom == 0xFEFF) { - q += 2; - bo = 1; - } - else if (bom == 0xFFFE) { - q += 2; - bo = -1; - } -#endif - } - } - - if (bo == -1) { - /* force LE */ - ihi = 1; - ilo = 0; - } - else if (bo == 1) { - /* force BE */ - ihi = 0; - ilo = 1; - } - - while (q < e) { - Py_UNICODE ch; - /* remaining bytes at the end? (size should be even) */ - if (e-q<2) { - if (consumed) - break; - errmsg = "truncated data"; - startinpos = ((const char *)q)-starts; - endinpos = ((const char *)e)-starts; - goto utf16Error; - /* The remaining input chars are ignored if the callback - chooses to skip the input */ - } - ch = (q[ihi] << 8) | q[ilo]; - - q += 2; - - if (ch < 0xD800 || ch > 0xDFFF) { - *p++ = ch; - continue; - } - - /* UTF-16 code pair: */ - if (q >= e) { - errmsg = "unexpected end of data"; - startinpos = (((const char *)q)-2)-starts; - endinpos = ((const char *)e)-starts; - goto utf16Error; - } - if (0xD800 <= ch && ch <= 0xDBFF) { - Py_UNICODE ch2 = (q[ihi] << 8) | q[ilo]; - q += 2; - if (0xDC00 <= ch2 && ch2 <= 0xDFFF) { -#ifndef Py_UNICODE_WIDE - *p++ = ch; - *p++ = ch2; -#else - *p++ = (((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x10000; -#endif - continue; - } - else { - errmsg = "illegal UTF-16 surrogate"; - startinpos = (((const char *)q)-4)-starts; - endinpos = startinpos+2; - goto utf16Error; - } - - } - errmsg = "illegal encoding"; - startinpos = (((const char *)q)-2)-starts; - endinpos = startinpos+2; - /* Fall through to report the error */ - - utf16Error: - outpos = p-PyUnicode_AS_UNICODE(unicode); - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "utf16", errmsg, - starts, size, &startinpos, &endinpos, &exc, (const char **)&q, - (PyObject **)&unicode, &outpos, &p)) - goto onError; - } - - if (byteorder) - *byteorder = bo; - - if (consumed) - *consumed = (const char *)q-starts; - - /* Adjust length */ - if (_PyUnicode_Resize(&unicode, p - unicode->str) < 0) - goto onError; - - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return (PyObject *)unicode; - -onError: - Py_DECREF(unicode); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return NULL; -} - -PyObject * -PyUnicode_EncodeUTF16(const Py_UNICODE *s, - Py_ssize_t size, - const char *errors, - int byteorder) -{ - PyObject *v; - unsigned char *p; -#ifdef Py_UNICODE_WIDE - int i, pairs; -#else - const int pairs = 0; -#endif - /* Offsets from p for storing byte pairs in the right order. */ -#ifdef BYTEORDER_IS_LITTLE_ENDIAN - int ihi = 1, ilo = 0; -#else - int ihi = 0, ilo = 1; -#endif - -#define STORECHAR(CH) \ - do { \ - p[ihi] = ((CH) >> 8) & 0xff; \ - p[ilo] = (CH) & 0xff; \ - p += 2; \ - } while(0) - -#ifdef Py_UNICODE_WIDE - for (i = pairs = 0; i < size; i++) - if (s[i] >= 0x10000) - pairs++; -#endif - v = PyString_FromStringAndSize(NULL, - 2 * (size + pairs + (byteorder == 0))); - if (v == NULL) - return NULL; - - p = (unsigned char *)PyString_AS_STRING(v); - if (byteorder == 0) - STORECHAR(0xFEFF); - if (size == 0) - return v; - - if (byteorder == -1) { - /* force LE */ - ihi = 1; - ilo = 0; - } - else if (byteorder == 1) { - /* force BE */ - ihi = 0; - ilo = 1; - } - - while (size-- > 0) { - Py_UNICODE ch = *s++; - Py_UNICODE ch2 = 0; -#ifdef Py_UNICODE_WIDE - if (ch >= 0x10000) { - ch2 = 0xDC00 | ((ch-0x10000) & 0x3FF); - ch = 0xD800 | ((ch-0x10000) >> 10); - } -#endif - STORECHAR(ch); - if (ch2) - STORECHAR(ch2); - } - return v; -#undef STORECHAR -} - -PyObject *PyUnicode_AsUTF16String(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - return NULL; - } - return PyUnicode_EncodeUTF16(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode), - NULL, - 0); -} - -/* --- Unicode Escape Codec ----------------------------------------------- */ - -static _PyUnicode_Name_CAPI *ucnhash_CAPI = NULL; - -PyObject *PyUnicode_DecodeUnicodeEscape(const char *s, - Py_ssize_t size, - const char *errors) -{ - const char *starts = s; - Py_ssize_t startinpos; - Py_ssize_t endinpos; - Py_ssize_t outpos; - int i; - PyUnicodeObject *v; - Py_UNICODE *p; - const char *end; - char* message; - Py_UCS4 chr = 0xffffffff; /* in case 'getcode' messes up */ - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - - /* Escaped strings will always be longer than the resulting - Unicode string, so we start with size here and then reduce the - length after conversion to the true value. - (but if the error callback returns a long replacement string - we'll have to allocate more space) */ - v = _PyUnicode_New(size); - if (v == NULL) - goto onError; - if (size == 0) - return (PyObject *)v; - - p = PyUnicode_AS_UNICODE(v); - end = s + size; - - while (s < end) { - unsigned char c; - Py_UNICODE x; - int digits; - - /* Non-escape characters are interpreted as Unicode ordinals */ - if (*s != '\\') { - *p++ = (unsigned char) *s++; - continue; - } - - startinpos = s-starts; - /* \ - Escapes */ - s++; - switch (*s++) { - - /* \x escapes */ - case '\n': break; - case '\\': *p++ = '\\'; break; - case '\'': *p++ = '\''; break; - case '\"': *p++ = '\"'; break; - case 'b': *p++ = '\b'; break; - case 'f': *p++ = '\014'; break; /* FF */ - case 't': *p++ = '\t'; break; - case 'n': *p++ = '\n'; break; - case 'r': *p++ = '\r'; break; - case 'v': *p++ = '\013'; break; /* VT */ - case 'a': *p++ = '\007'; break; /* BEL, not classic C */ - - /* \OOO (octal) escapes */ - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - x = s[-1] - '0'; - if ('0' <= *s && *s <= '7') { - x = (x<<3) + *s++ - '0'; - if ('0' <= *s && *s <= '7') - x = (x<<3) + *s++ - '0'; - } - *p++ = x; - break; - - /* hex escapes */ - /* \xXX */ - case 'x': - digits = 2; - message = "truncated \\xXX escape"; - goto hexescape; - - /* \uXXXX */ - case 'u': - digits = 4; - message = "truncated \\uXXXX escape"; - goto hexescape; - - /* \UXXXXXXXX */ - case 'U': - digits = 8; - message = "truncated \\UXXXXXXXX escape"; - hexescape: - chr = 0; - outpos = p-PyUnicode_AS_UNICODE(v); - if (s+digits>end) { - endinpos = size; - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "unicodeescape", "end of string in escape sequence", - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) - goto onError; - goto nextByte; - } - for (i = 0; i < digits; ++i) { - c = (unsigned char) s[i]; - if (!isxdigit(c)) { - endinpos = (s+i+1)-starts; - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "unicodeescape", message, - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) - goto onError; - goto nextByte; - } - chr = (chr<<4) & ~0xF; - if (c >= '0' && c <= '9') - chr += c - '0'; - else if (c >= 'a' && c <= 'f') - chr += 10 + c - 'a'; - else - chr += 10 + c - 'A'; - } - s += i; - if (chr == 0xffffffff && PyErr_Occurred()) - /* _decoding_error will have already written into the - target buffer. */ - break; - store: - /* when we get here, chr is a 32-bit unicode character */ - if (chr <= 0xffff) - /* UCS-2 character */ - *p++ = (Py_UNICODE) chr; - else if (chr <= 0x10ffff) { - /* UCS-4 character. Either store directly, or as - surrogate pair. */ -#ifdef Py_UNICODE_WIDE - *p++ = chr; -#else - chr -= 0x10000L; - *p++ = 0xD800 + (Py_UNICODE) (chr >> 10); - *p++ = 0xDC00 + (Py_UNICODE) (chr & 0x03FF); -#endif - } else { - endinpos = s-starts; - outpos = p-PyUnicode_AS_UNICODE(v); - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "unicodeescape", "illegal Unicode character", - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) - goto onError; - } - break; - - /* \N{name} */ - case 'N': - message = "malformed \\N character escape"; - if (ucnhash_CAPI == NULL) { - /* load the unicode data module */ - PyObject *m, *api; - m = PyImport_ImportModule("unicodedata"); - if (m == NULL) - goto ucnhashError; - api = PyObject_GetAttrString(m, "ucnhash_CAPI"); - Py_DECREF(m); - if (api == NULL) - goto ucnhashError; - ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCObject_AsVoidPtr(api); - Py_DECREF(api); - if (ucnhash_CAPI == NULL) - goto ucnhashError; - } - if (*s == '{') { - const char *start = s+1; - /* look for the closing brace */ - while (*s != '}' && s < end) - s++; - if (s > start && s < end && *s == '}') { - /* found a name. look it up in the unicode database */ - message = "unknown Unicode character name"; - s++; - if (ucnhash_CAPI->getcode(NULL, start, (int)(s-start-1), &chr)) - goto store; - } - } - endinpos = s-starts; - outpos = p-PyUnicode_AS_UNICODE(v); - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "unicodeescape", message, - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) - goto onError; - break; - - default: - if (s > end) { - message = "\\ at end of string"; - s--; - endinpos = s-starts; - outpos = p-PyUnicode_AS_UNICODE(v); - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "unicodeescape", message, - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) - goto onError; - } - else { - *p++ = '\\'; - *p++ = (unsigned char)s[-1]; - } - break; - } - nextByte: - ; - } - if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) - goto onError; - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return (PyObject *)v; - -ucnhashError: - PyErr_SetString( - PyExc_UnicodeError, - "\\N escapes not supported (can't load unicodedata module)" - ); - Py_XDECREF(v); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return NULL; - -onError: - Py_XDECREF(v); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return NULL; -} - -/* Return a Unicode-Escape string version of the Unicode object. - - If quotes is true, the string is enclosed in u"" or u'' quotes as - appropriate. - -*/ - -Py_LOCAL_INLINE(const Py_UNICODE *) findchar(const Py_UNICODE *s, - Py_ssize_t size, - Py_UNICODE ch) -{ - /* like wcschr, but doesn't stop at NULL characters */ - - while (size-- > 0) { - if (*s == ch) - return s; - s++; - } - - return NULL; -} - -static -PyObject *unicodeescape_string(const Py_UNICODE *s, - Py_ssize_t size, - int quotes) -{ - PyObject *repr; - char *p; - - static const char *hexdigit = "0123456789abcdef"; - - /* Initial allocation is based on the longest-possible unichr - escape. - - In wide (UTF-32) builds '\U00xxxxxx' is 10 chars per source - unichr, so in this case it's the longest unichr escape. In - narrow (UTF-16) builds this is five chars per source unichr - since there are two unichrs in the surrogate pair, so in narrow - (UTF-16) builds it's not the longest unichr escape. - - In wide or narrow builds '\uxxxx' is 6 chars per source unichr, - so in the narrow (UTF-16) build case it's the longest unichr - escape. - */ - - repr = PyString_FromStringAndSize(NULL, - 2 -#ifdef Py_UNICODE_WIDE - + 10*size -#else - + 6*size -#endif - + 1); - if (repr == NULL) - return NULL; - - p = PyString_AS_STRING(repr); - - if (quotes) { - *p++ = 'u'; - *p++ = (findchar(s, size, '\'') && - !findchar(s, size, '"')) ? '"' : '\''; - } - while (size-- > 0) { - Py_UNICODE ch = *s++; - - /* Escape quotes and backslashes */ - if ((quotes && - ch == (Py_UNICODE) PyString_AS_STRING(repr)[1]) || ch == '\\') { - *p++ = '\\'; - *p++ = (char) ch; - continue; - } - -#ifdef Py_UNICODE_WIDE - /* Map 21-bit characters to '\U00xxxxxx' */ - else if (ch >= 0x10000) { - *p++ = '\\'; - *p++ = 'U'; - *p++ = hexdigit[(ch >> 28) & 0x0000000F]; - *p++ = hexdigit[(ch >> 24) & 0x0000000F]; - *p++ = hexdigit[(ch >> 20) & 0x0000000F]; - *p++ = hexdigit[(ch >> 16) & 0x0000000F]; - *p++ = hexdigit[(ch >> 12) & 0x0000000F]; - *p++ = hexdigit[(ch >> 8) & 0x0000000F]; - *p++ = hexdigit[(ch >> 4) & 0x0000000F]; - *p++ = hexdigit[ch & 0x0000000F]; - continue; - } -#else - /* Map UTF-16 surrogate pairs to '\U00xxxxxx' */ - else if (ch >= 0xD800 && ch < 0xDC00) { - Py_UNICODE ch2; - Py_UCS4 ucs; - - ch2 = *s++; - size--; - if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) { - ucs = (((ch & 0x03FF) << 10) | (ch2 & 0x03FF)) + 0x00010000; - *p++ = '\\'; - *p++ = 'U'; - *p++ = hexdigit[(ucs >> 28) & 0x0000000F]; - *p++ = hexdigit[(ucs >> 24) & 0x0000000F]; - *p++ = hexdigit[(ucs >> 20) & 0x0000000F]; - *p++ = hexdigit[(ucs >> 16) & 0x0000000F]; - *p++ = hexdigit[(ucs >> 12) & 0x0000000F]; - *p++ = hexdigit[(ucs >> 8) & 0x0000000F]; - *p++ = hexdigit[(ucs >> 4) & 0x0000000F]; - *p++ = hexdigit[ucs & 0x0000000F]; - continue; - } - /* Fall through: isolated surrogates are copied as-is */ - s--; - size++; - } -#endif - - /* Map 16-bit characters to '\uxxxx' */ - if (ch >= 256) { - *p++ = '\\'; - *p++ = 'u'; - *p++ = hexdigit[(ch >> 12) & 0x000F]; - *p++ = hexdigit[(ch >> 8) & 0x000F]; - *p++ = hexdigit[(ch >> 4) & 0x000F]; - *p++ = hexdigit[ch & 0x000F]; - } - - /* Map special whitespace to '\t', \n', '\r' */ - else if (ch == '\t') { - *p++ = '\\'; - *p++ = 't'; - } - else if (ch == '\n') { - *p++ = '\\'; - *p++ = 'n'; - } - else if (ch == '\r') { - *p++ = '\\'; - *p++ = 'r'; - } - - /* Map non-printable US ASCII to '\xhh' */ - else if (ch < ' ' || ch >= 0x7F) { - *p++ = '\\'; - *p++ = 'x'; - *p++ = hexdigit[(ch >> 4) & 0x000F]; - *p++ = hexdigit[ch & 0x000F]; - } - - /* Copy everything else as-is */ - else - *p++ = (char) ch; - } - if (quotes) - *p++ = PyString_AS_STRING(repr)[1]; - - *p = '\0'; - _PyString_Resize(&repr, p - PyString_AS_STRING(repr)); - return repr; -} - -PyObject *PyUnicode_EncodeUnicodeEscape(const Py_UNICODE *s, - Py_ssize_t size) -{ - return unicodeescape_string(s, size, 0); -} - -PyObject *PyUnicode_AsUnicodeEscapeString(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - return NULL; - } - return PyUnicode_EncodeUnicodeEscape(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode)); -} - -/* --- Raw Unicode Escape Codec ------------------------------------------- */ - -PyObject *PyUnicode_DecodeRawUnicodeEscape(const char *s, - Py_ssize_t size, - const char *errors) -{ - const char *starts = s; - Py_ssize_t startinpos; - Py_ssize_t endinpos; - Py_ssize_t outpos; - PyUnicodeObject *v; - Py_UNICODE *p; - const char *end; - const char *bs; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - - /* Escaped strings will always be longer than the resulting - Unicode string, so we start with size here and then reduce the - length after conversion to the true value. (But decoding error - handler might have to resize the string) */ - v = _PyUnicode_New(size); - if (v == NULL) - goto onError; - if (size == 0) - return (PyObject *)v; - p = PyUnicode_AS_UNICODE(v); - end = s + size; - while (s < end) { - unsigned char c; - Py_UCS4 x; - int i; - int count; - - /* Non-escape characters are interpreted as Unicode ordinals */ - if (*s != '\\') { - *p++ = (unsigned char)*s++; - continue; - } - startinpos = s-starts; - - /* \u-escapes are only interpreted iff the number of leading - backslashes if odd */ - bs = s; - for (;s < end;) { - if (*s != '\\') - break; - *p++ = (unsigned char)*s++; - } - if (((s - bs) & 1) == 0 || - s >= end || - (*s != 'u' && *s != 'U')) { - continue; - } - p--; - count = *s=='u' ? 4 : 8; - s++; - - /* \uXXXX with 4 hex digits, \Uxxxxxxxx with 8 */ - outpos = p-PyUnicode_AS_UNICODE(v); - for (x = 0, i = 0; i < count; ++i, ++s) { - c = (unsigned char)*s; - if (!isxdigit(c)) { - endinpos = s-starts; - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "rawunicodeescape", "truncated \\uXXXX", - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) - goto onError; - goto nextByte; - } - x = (x<<4) & ~0xF; - if (c >= '0' && c <= '9') - x += c - '0'; - else if (c >= 'a' && c <= 'f') - x += 10 + c - 'a'; - else - x += 10 + c - 'A'; - } -#ifndef Py_UNICODE_WIDE - if (x > 0x10000) { - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "rawunicodeescape", "\\Uxxxxxxxx out of range", - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) - goto onError; - } -#endif - *p++ = x; - nextByte: - ; - } - if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) - goto onError; - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return (PyObject *)v; - - onError: - Py_XDECREF(v); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return NULL; -} - -PyObject *PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, - Py_ssize_t size) -{ - PyObject *repr; - char *p; - char *q; - - static const char *hexdigit = "0123456789abcdef"; - -#ifdef Py_UNICODE_WIDE - repr = PyString_FromStringAndSize(NULL, 10 * size); -#else - repr = PyString_FromStringAndSize(NULL, 6 * size); -#endif - if (repr == NULL) - return NULL; - if (size == 0) - return repr; - - p = q = PyString_AS_STRING(repr); - while (size-- > 0) { - Py_UNICODE ch = *s++; -#ifdef Py_UNICODE_WIDE - /* Map 32-bit characters to '\Uxxxxxxxx' */ - if (ch >= 0x10000) { - *p++ = '\\'; - *p++ = 'U'; - *p++ = hexdigit[(ch >> 28) & 0xf]; - *p++ = hexdigit[(ch >> 24) & 0xf]; - *p++ = hexdigit[(ch >> 20) & 0xf]; - *p++ = hexdigit[(ch >> 16) & 0xf]; - *p++ = hexdigit[(ch >> 12) & 0xf]; - *p++ = hexdigit[(ch >> 8) & 0xf]; - *p++ = hexdigit[(ch >> 4) & 0xf]; - *p++ = hexdigit[ch & 15]; - } - else -#endif - /* Map 16-bit characters to '\uxxxx' */ - if (ch >= 256) { - *p++ = '\\'; - *p++ = 'u'; - *p++ = hexdigit[(ch >> 12) & 0xf]; - *p++ = hexdigit[(ch >> 8) & 0xf]; - *p++ = hexdigit[(ch >> 4) & 0xf]; - *p++ = hexdigit[ch & 15]; - } - /* Copy everything else as-is */ - else - *p++ = (char) ch; - } - *p = '\0'; - _PyString_Resize(&repr, p - q); - return repr; -} - -PyObject *PyUnicode_AsRawUnicodeEscapeString(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - return NULL; - } - return PyUnicode_EncodeRawUnicodeEscape(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode)); -} - -/* --- Unicode Internal Codec ------------------------------------------- */ - -PyObject *_PyUnicode_DecodeUnicodeInternal(const char *s, - Py_ssize_t size, - const char *errors) -{ - const char *starts = s; - Py_ssize_t startinpos; - Py_ssize_t endinpos; - Py_ssize_t outpos; - PyUnicodeObject *v; - Py_UNICODE *p; - const char *end; - const char *reason; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - -#ifdef Py_UNICODE_WIDE - Py_UNICODE unimax = PyUnicode_GetMax(); -#endif - - /* XXX overflow detection missing */ - v = _PyUnicode_New((size+Py_UNICODE_SIZE-1)/ Py_UNICODE_SIZE); - if (v == NULL) - goto onError; - if (PyUnicode_GetSize((PyObject *)v) == 0) - return (PyObject *)v; - p = PyUnicode_AS_UNICODE(v); - end = s + size; - - while (s < end) { - memcpy(p, s, sizeof(Py_UNICODE)); - /* We have to sanity check the raw data, otherwise doom looms for - some malformed UCS-4 data. */ - if ( - #ifdef Py_UNICODE_WIDE - *p > unimax || *p < 0 || - #endif - end-s < Py_UNICODE_SIZE - ) - { - startinpos = s - starts; - if (end-s < Py_UNICODE_SIZE) { - endinpos = end-starts; - reason = "truncated input"; - } - else { - endinpos = s - starts + Py_UNICODE_SIZE; - reason = "illegal code point (> 0x10FFFF)"; - } - outpos = p - PyUnicode_AS_UNICODE(v); - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "unicode_internal", reason, - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) { - goto onError; - } - } - else { - p++; - s += Py_UNICODE_SIZE; - } - } - - if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) - goto onError; - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return (PyObject *)v; - - onError: - Py_XDECREF(v); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return NULL; -} - -/* --- Latin-1 Codec ------------------------------------------------------ */ - -PyObject *PyUnicode_DecodeLatin1(const char *s, - Py_ssize_t size, - const char *errors) -{ - PyUnicodeObject *v; - Py_UNICODE *p; - - /* Latin-1 is equivalent to the first 256 ordinals in Unicode. */ - if (size == 1) { - Py_UNICODE r = *(unsigned char*)s; - return PyUnicode_FromUnicode(&r, 1); - } - - v = _PyUnicode_New(size); - if (v == NULL) - goto onError; - if (size == 0) - return (PyObject *)v; - p = PyUnicode_AS_UNICODE(v); - while (size-- > 0) - *p++ = (unsigned char)*s++; - return (PyObject *)v; - - onError: - Py_XDECREF(v); - return NULL; -} - -/* create or adjust a UnicodeEncodeError */ -static void make_encode_exception(PyObject **exceptionObject, - const char *encoding, - const Py_UNICODE *unicode, Py_ssize_t size, - Py_ssize_t startpos, Py_ssize_t endpos, - const char *reason) -{ - if (*exceptionObject == NULL) { - *exceptionObject = PyUnicodeEncodeError_Create( - encoding, unicode, size, startpos, endpos, reason); - } - else { - if (PyUnicodeEncodeError_SetStart(*exceptionObject, startpos)) - goto onError; - if (PyUnicodeEncodeError_SetEnd(*exceptionObject, endpos)) - goto onError; - if (PyUnicodeEncodeError_SetReason(*exceptionObject, reason)) - goto onError; - return; - onError: - Py_DECREF(*exceptionObject); - *exceptionObject = NULL; - } -} - -/* raises a UnicodeEncodeError */ -static void raise_encode_exception(PyObject **exceptionObject, - const char *encoding, - const Py_UNICODE *unicode, Py_ssize_t size, - Py_ssize_t startpos, Py_ssize_t endpos, - const char *reason) -{ - make_encode_exception(exceptionObject, - encoding, unicode, size, startpos, endpos, reason); - if (*exceptionObject != NULL) - PyCodec_StrictErrors(*exceptionObject); -} - -/* error handling callback helper: - build arguments, call the callback and check the arguments, - put the result into newpos and return the replacement string, which - has to be freed by the caller */ -static PyObject *unicode_encode_call_errorhandler(const char *errors, - PyObject **errorHandler, - const char *encoding, const char *reason, - const Py_UNICODE *unicode, Py_ssize_t size, PyObject **exceptionObject, - Py_ssize_t startpos, Py_ssize_t endpos, - Py_ssize_t *newpos) -{ - static char *argparse = "O!n;encoding error handler must return (unicode, int) tuple"; - - PyObject *restuple; - PyObject *resunicode; - - if (*errorHandler == NULL) { - *errorHandler = PyCodec_LookupError(errors); - if (*errorHandler == NULL) - return NULL; - } - - make_encode_exception(exceptionObject, - encoding, unicode, size, startpos, endpos, reason); - if (*exceptionObject == NULL) - return NULL; - - restuple = PyObject_CallFunctionObjArgs( - *errorHandler, *exceptionObject, NULL); - if (restuple == NULL) - return NULL; - if (!PyTuple_Check(restuple)) { - PyErr_Format(PyExc_TypeError, &argparse[4]); - Py_DECREF(restuple); - return NULL; - } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, - &resunicode, newpos)) { - Py_DECREF(restuple); - return NULL; - } - if (*newpos<0) - *newpos = size+*newpos; - if (*newpos<0 || *newpos>size) { - PyErr_Format(PyExc_IndexError, "position %zd from error handler out of bounds", *newpos); - Py_DECREF(restuple); - return NULL; - } - Py_INCREF(resunicode); - Py_DECREF(restuple); - return resunicode; -} - -static PyObject *unicode_encode_ucs1(const Py_UNICODE *p, - Py_ssize_t size, - const char *errors, - int limit) -{ - /* output object */ - PyObject *res; - /* pointers to the beginning and end+1 of input */ - const Py_UNICODE *startp = p; - const Py_UNICODE *endp = p + size; - /* pointer to the beginning of the unencodable characters */ - /* const Py_UNICODE *badp = NULL; */ - /* pointer into the output */ - char *str; - /* current output position */ - Py_ssize_t respos = 0; - Py_ssize_t ressize; - const char *encoding = (limit == 256) ? "latin-1" : "ascii"; - const char *reason = (limit == 256) ? "ordinal not in range(256)" : "ordinal not in range(128)"; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - /* the following variable is used for caching string comparisons - * -1=not initialized, 0=unknown, 1=strict, 2=replace, 3=ignore, 4=xmlcharrefreplace */ - int known_errorHandler = -1; - - /* allocate enough for a simple encoding without - replacements, if we need more, we'll resize */ - res = PyString_FromStringAndSize(NULL, size); - if (res == NULL) - goto onError; - if (size == 0) - return res; - str = PyString_AS_STRING(res); - ressize = size; - - while (p<endp) { - Py_UNICODE c = *p; - - /* can we encode this? */ - if (c<limit) { - /* no overflow check, because we know that the space is enough */ - *str++ = (char)c; - ++p; - } - else { - Py_ssize_t unicodepos = p-startp; - Py_ssize_t requiredsize; - PyObject *repunicode; - Py_ssize_t repsize; - Py_ssize_t newpos; - Py_ssize_t respos; - Py_UNICODE *uni2; - /* startpos for collecting unencodable chars */ - const Py_UNICODE *collstart = p; - const Py_UNICODE *collend = p; - /* find all unecodable characters */ - while ((collend < endp) && ((*collend)>=limit)) - ++collend; - /* cache callback name lookup (if not done yet, i.e. it's the first error) */ - if (known_errorHandler==-1) { - if ((errors==NULL) || (!strcmp(errors, "strict"))) - known_errorHandler = 1; - else if (!strcmp(errors, "replace")) - known_errorHandler = 2; - else if (!strcmp(errors, "ignore")) - known_errorHandler = 3; - else if (!strcmp(errors, "xmlcharrefreplace")) - known_errorHandler = 4; - else - known_errorHandler = 0; - } - switch (known_errorHandler) { - case 1: /* strict */ - raise_encode_exception(&exc, encoding, startp, size, collstart-startp, collend-startp, reason); - goto onError; - case 2: /* replace */ - while (collstart++<collend) - *str++ = '?'; /* fall through */ - case 3: /* ignore */ - p = collend; - break; - case 4: /* xmlcharrefreplace */ - respos = str-PyString_AS_STRING(res); - /* determine replacement size (temporarily (mis)uses p) */ - for (p = collstart, repsize = 0; p < collend; ++p) { - if (*p<10) - repsize += 2+1+1; - else if (*p<100) - repsize += 2+2+1; - else if (*p<1000) - repsize += 2+3+1; - else if (*p<10000) - repsize += 2+4+1; -#ifndef Py_UNICODE_WIDE - else - repsize += 2+5+1; -#else - else if (*p<100000) - repsize += 2+5+1; - else if (*p<1000000) - repsize += 2+6+1; - else - repsize += 2+7+1; -#endif - } - requiredsize = respos+repsize+(endp-collend); - if (requiredsize > ressize) { - if (requiredsize<2*ressize) - requiredsize = 2*ressize; - if (_PyString_Resize(&res, requiredsize)) - goto onError; - str = PyString_AS_STRING(res) + respos; - ressize = requiredsize; - } - /* generate replacement (temporarily (mis)uses p) */ - for (p = collstart; p < collend; ++p) { - str += sprintf(str, "&#%d;", (int)*p); - } - p = collend; - break; - default: - repunicode = unicode_encode_call_errorhandler(errors, &errorHandler, - encoding, reason, startp, size, &exc, - collstart-startp, collend-startp, &newpos); - if (repunicode == NULL) - goto onError; - /* need more space? (at least enough for what we - have+the replacement+the rest of the string, so - we won't have to check space for encodable characters) */ - respos = str-PyString_AS_STRING(res); - repsize = PyUnicode_GET_SIZE(repunicode); - requiredsize = respos+repsize+(endp-collend); - if (requiredsize > ressize) { - if (requiredsize<2*ressize) - requiredsize = 2*ressize; - if (_PyString_Resize(&res, requiredsize)) { - Py_DECREF(repunicode); - goto onError; - } - str = PyString_AS_STRING(res) + respos; - ressize = requiredsize; - } - /* check if there is anything unencodable in the replacement - and copy it to the output */ - for (uni2 = PyUnicode_AS_UNICODE(repunicode);repsize-->0; ++uni2, ++str) { - c = *uni2; - if (c >= limit) { - raise_encode_exception(&exc, encoding, startp, size, - unicodepos, unicodepos+1, reason); - Py_DECREF(repunicode); - goto onError; - } - *str = (char)c; - } - p = startp + newpos; - Py_DECREF(repunicode); - } - } - } - /* Resize if we allocated to much */ - respos = str-PyString_AS_STRING(res); - if (respos<ressize) - /* If this falls res will be NULL */ - _PyString_Resize(&res, respos); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return res; - - onError: - Py_XDECREF(res); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return NULL; -} - -PyObject *PyUnicode_EncodeLatin1(const Py_UNICODE *p, - Py_ssize_t size, - const char *errors) -{ - return unicode_encode_ucs1(p, size, errors, 256); -} - -PyObject *PyUnicode_AsLatin1String(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - return NULL; - } - return PyUnicode_EncodeLatin1(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode), - NULL); -} - -/* --- 7-bit ASCII Codec -------------------------------------------------- */ - -PyObject *PyUnicode_DecodeASCII(const char *s, - Py_ssize_t size, - const char *errors) -{ - const char *starts = s; - PyUnicodeObject *v; - Py_UNICODE *p; - Py_ssize_t startinpos; - Py_ssize_t endinpos; - Py_ssize_t outpos; - const char *e; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - - /* ASCII is equivalent to the first 128 ordinals in Unicode. */ - if (size == 1 && *(unsigned char*)s < 128) { - Py_UNICODE r = *(unsigned char*)s; - return PyUnicode_FromUnicode(&r, 1); - } - - v = _PyUnicode_New(size); - if (v == NULL) - goto onError; - if (size == 0) - return (PyObject *)v; - p = PyUnicode_AS_UNICODE(v); - e = s + size; - while (s < e) { - register unsigned char c = (unsigned char)*s; - if (c < 128) { - *p++ = c; - ++s; - } - else { - startinpos = s-starts; - endinpos = startinpos + 1; - outpos = p - (Py_UNICODE *)PyUnicode_AS_UNICODE(v); - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "ascii", "ordinal not in range(128)", - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) - goto onError; - } - } - if (p - PyUnicode_AS_UNICODE(v) < PyString_GET_SIZE(v)) - if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) - goto onError; - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return (PyObject *)v; - - onError: - Py_XDECREF(v); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return NULL; -} - -PyObject *PyUnicode_EncodeASCII(const Py_UNICODE *p, - Py_ssize_t size, - const char *errors) -{ - return unicode_encode_ucs1(p, size, errors, 128); -} - -PyObject *PyUnicode_AsASCIIString(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - return NULL; - } - return PyUnicode_EncodeASCII(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode), - NULL); -} - -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) - -/* --- MBCS codecs for Windows -------------------------------------------- */ - -#if SIZEOF_INT < SIZEOF_SSIZE_T -#define NEED_RETRY -#endif - -/* XXX This code is limited to "true" double-byte encodings, as - a) it assumes an incomplete character consists of a single byte, and - b) IsDBCSLeadByte (probably) does not work for non-DBCS multi-byte - encodings, see IsDBCSLeadByteEx documentation. */ - -static int is_dbcs_lead_byte(const char *s, int offset) -{ - const char *curr = s + offset; - - if (IsDBCSLeadByte(*curr)) { - const char *prev = CharPrev(s, curr); - return (prev == curr) || !IsDBCSLeadByte(*prev) || (curr - prev == 2); - } - return 0; -} - -/* - * Decode MBCS string into unicode object. If 'final' is set, converts - * trailing lead-byte too. Returns consumed size if succeed, -1 otherwise. - */ -static int decode_mbcs(PyUnicodeObject **v, - const char *s, /* MBCS string */ - int size, /* sizeof MBCS string */ - int final) -{ - Py_UNICODE *p; - Py_ssize_t n = 0; - int usize = 0; - - assert(size >= 0); - - /* Skip trailing lead-byte unless 'final' is set */ - if (!final && size >= 1 && is_dbcs_lead_byte(s, size - 1)) - --size; - - /* First get the size of the result */ - if (size > 0) { - usize = MultiByteToWideChar(CP_ACP, 0, s, size, NULL, 0); - if (usize == 0) { - PyErr_SetFromWindowsErrWithFilename(0, NULL); - return -1; - } - } - - if (*v == NULL) { - /* Create unicode object */ - *v = _PyUnicode_New(usize); - if (*v == NULL) - return -1; - } - else { - /* Extend unicode object */ - n = PyUnicode_GET_SIZE(*v); - if (_PyUnicode_Resize(v, n + usize) < 0) - return -1; - } - - /* Do the conversion */ - if (size > 0) { - p = PyUnicode_AS_UNICODE(*v) + n; - if (0 == MultiByteToWideChar(CP_ACP, 0, s, size, p, usize)) { - PyErr_SetFromWindowsErrWithFilename(0, NULL); - return -1; - } - } - - return size; -} - -PyObject *PyUnicode_DecodeMBCSStateful(const char *s, - Py_ssize_t size, - const char *errors, - Py_ssize_t *consumed) -{ - PyUnicodeObject *v = NULL; - int done; - - if (consumed) - *consumed = 0; - -#ifdef NEED_RETRY - retry: - if (size > INT_MAX) - done = decode_mbcs(&v, s, INT_MAX, 0); - else -#endif - done = decode_mbcs(&v, s, (int)size, !consumed); - - if (done < 0) { - Py_XDECREF(v); - return NULL; - } - - if (consumed) - *consumed += done; - -#ifdef NEED_RETRY - if (size > INT_MAX) { - s += done; - size -= done; - goto retry; - } -#endif - - return (PyObject *)v; -} - -PyObject *PyUnicode_DecodeMBCS(const char *s, - Py_ssize_t size, - const char *errors) -{ - return PyUnicode_DecodeMBCSStateful(s, size, errors, NULL); -} - -/* - * Convert unicode into string object (MBCS). - * Returns 0 if succeed, -1 otherwise. - */ -static int encode_mbcs(PyObject **repr, - const Py_UNICODE *p, /* unicode */ - int size) /* size of unicode */ -{ - int mbcssize = 0; - Py_ssize_t n = 0; - - assert(size >= 0); - - /* First get the size of the result */ - if (size > 0) { - mbcssize = WideCharToMultiByte(CP_ACP, 0, p, size, NULL, 0, NULL, NULL); - if (mbcssize == 0) { - PyErr_SetFromWindowsErrWithFilename(0, NULL); - return -1; - } - } - - if (*repr == NULL) { - /* Create string object */ - *repr = PyString_FromStringAndSize(NULL, mbcssize); - if (*repr == NULL) - return -1; - } - else { - /* Extend string object */ - n = PyString_Size(*repr); - if (_PyString_Resize(repr, n + mbcssize) < 0) - return -1; - } - - /* Do the conversion */ - if (size > 0) { - char *s = PyString_AS_STRING(*repr) + n; - if (0 == WideCharToMultiByte(CP_ACP, 0, p, size, s, mbcssize, NULL, NULL)) { - PyErr_SetFromWindowsErrWithFilename(0, NULL); - return -1; - } - } - - return 0; -} - -PyObject *PyUnicode_EncodeMBCS(const Py_UNICODE *p, - Py_ssize_t size, - const char *errors) -{ - PyObject *repr = NULL; - int ret; - -#ifdef NEED_RETRY - retry: - if (size > INT_MAX) - ret = encode_mbcs(&repr, p, INT_MAX); - else -#endif - ret = encode_mbcs(&repr, p, (int)size); - - if (ret < 0) { - Py_XDECREF(repr); - return NULL; - } - -#ifdef NEED_RETRY - if (size > INT_MAX) { - p += INT_MAX; - size -= INT_MAX; - goto retry; - } -#endif - - return repr; -} - -PyObject *PyUnicode_AsMBCSString(PyObject *unicode) -{ - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - return NULL; - } - return PyUnicode_EncodeMBCS(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode), - NULL); -} - -#undef NEED_RETRY - -#endif /* MS_WINDOWS */ - -/* --- Character Mapping Codec -------------------------------------------- */ - -PyObject *PyUnicode_DecodeCharmap(const char *s, - Py_ssize_t size, - PyObject *mapping, - const char *errors) -{ - const char *starts = s; - Py_ssize_t startinpos; - Py_ssize_t endinpos; - Py_ssize_t outpos; - const char *e; - PyUnicodeObject *v; - Py_UNICODE *p; - Py_ssize_t extrachars = 0; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - Py_UNICODE *mapstring = NULL; - Py_ssize_t maplen = 0; - - /* Default to Latin-1 */ - if (mapping == NULL) - return PyUnicode_DecodeLatin1(s, size, errors); - - v = _PyUnicode_New(size); - if (v == NULL) - goto onError; - if (size == 0) - return (PyObject *)v; - p = PyUnicode_AS_UNICODE(v); - e = s + size; - if (PyUnicode_CheckExact(mapping)) { - mapstring = PyUnicode_AS_UNICODE(mapping); - maplen = PyUnicode_GET_SIZE(mapping); - while (s < e) { - unsigned char ch = *s; - Py_UNICODE x = 0xfffe; /* illegal value */ - - if (ch < maplen) - x = mapstring[ch]; - - if (x == 0xfffe) { - /* undefined mapping */ - outpos = p-PyUnicode_AS_UNICODE(v); - startinpos = s-starts; - endinpos = startinpos+1; - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "charmap", "character maps to <undefined>", - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) { - goto onError; - } - continue; - } - *p++ = x; - ++s; - } - } - else { - while (s < e) { - unsigned char ch = *s; - PyObject *w, *x; - - /* Get mapping (char ordinal -> integer, Unicode char or None) */ - w = PyInt_FromLong((long)ch); - if (w == NULL) - goto onError; - x = PyObject_GetItem(mapping, w); - Py_DECREF(w); - if (x == NULL) { - if (PyErr_ExceptionMatches(PyExc_LookupError)) { - /* No mapping found means: mapping is undefined. */ - PyErr_Clear(); - x = Py_None; - Py_INCREF(x); - } else - goto onError; - } - - /* Apply mapping */ - if (PyInt_Check(x)) { - long value = PyInt_AS_LONG(x); - if (value < 0 || value > 65535) { - PyErr_SetString(PyExc_TypeError, - "character mapping must be in range(65536)"); - Py_DECREF(x); - goto onError; - } - *p++ = (Py_UNICODE)value; - } - else if (x == Py_None) { - /* undefined mapping */ - outpos = p-PyUnicode_AS_UNICODE(v); - startinpos = s-starts; - endinpos = startinpos+1; - if (unicode_decode_call_errorhandler( - errors, &errorHandler, - "charmap", "character maps to <undefined>", - starts, size, &startinpos, &endinpos, &exc, &s, - (PyObject **)&v, &outpos, &p)) { - Py_DECREF(x); - goto onError; - } - Py_DECREF(x); - continue; - } - else if (PyUnicode_Check(x)) { - Py_ssize_t targetsize = PyUnicode_GET_SIZE(x); - - if (targetsize == 1) - /* 1-1 mapping */ - *p++ = *PyUnicode_AS_UNICODE(x); - - else if (targetsize > 1) { - /* 1-n mapping */ - if (targetsize > extrachars) { - /* resize first */ - Py_ssize_t oldpos = p - PyUnicode_AS_UNICODE(v); - Py_ssize_t needed = (targetsize - extrachars) + \ - (targetsize << 2); - extrachars += needed; - /* XXX overflow detection missing */ - if (_PyUnicode_Resize(&v, - PyUnicode_GET_SIZE(v) + needed) < 0) { - Py_DECREF(x); - goto onError; - } - p = PyUnicode_AS_UNICODE(v) + oldpos; - } - Py_UNICODE_COPY(p, - PyUnicode_AS_UNICODE(x), - targetsize); - p += targetsize; - extrachars -= targetsize; - } - /* 1-0 mapping: skip the character */ - } - else { - /* wrong return value */ - PyErr_SetString(PyExc_TypeError, - "character mapping must return integer, None or unicode"); - Py_DECREF(x); - goto onError; - } - Py_DECREF(x); - ++s; - } - } - if (p - PyUnicode_AS_UNICODE(v) < PyUnicode_GET_SIZE(v)) - if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) - goto onError; - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - return (PyObject *)v; - - onError: - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - Py_XDECREF(v); - return NULL; -} - -/* Charmap encoding: the lookup table */ - -struct encoding_map{ - PyObject_HEAD - unsigned char level1[32]; - int count2, count3; - unsigned char level23[1]; -}; - -static PyObject* -encoding_map_size(PyObject *obj, PyObject* args) -{ - struct encoding_map *map = (struct encoding_map*)obj; - return PyInt_FromLong(sizeof(*map) - 1 + 16*map->count2 + - 128*map->count3); -} - -static PyMethodDef encoding_map_methods[] = { - {"size", encoding_map_size, METH_NOARGS, - PyDoc_STR("Return the size (in bytes) of this object") }, - { 0 } -}; - -static void -encoding_map_dealloc(PyObject* o) -{ - PyObject_FREE(o); -} - -static PyTypeObject EncodingMapType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "EncodingMap", /*tp_name*/ - sizeof(struct encoding_map), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - encoding_map_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, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - encoding_map_methods, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*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*/ - 0, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ -}; - -PyObject* -PyUnicode_BuildEncodingMap(PyObject* string) -{ - Py_UNICODE *decode; - PyObject *result; - struct encoding_map *mresult; - int i; - int need_dict = 0; - unsigned char level1[32]; - unsigned char level2[512]; - unsigned char *mlevel1, *mlevel2, *mlevel3; - int count2 = 0, count3 = 0; - - if (!PyUnicode_Check(string) || PyUnicode_GetSize(string) != 256) { - PyErr_BadArgument(); - return NULL; - } - decode = PyUnicode_AS_UNICODE(string); - memset(level1, 0xFF, sizeof level1); - memset(level2, 0xFF, sizeof level2); - - /* If there isn't a one-to-one mapping of NULL to \0, - or if there are non-BMP characters, we need to use - a mapping dictionary. */ - if (decode[0] != 0) - need_dict = 1; - for (i = 1; i < 256; i++) { - int l1, l2; - if (decode[i] == 0 - #ifdef Py_UNICODE_WIDE - || decode[i] > 0xFFFF - #endif - ) { - need_dict = 1; - break; - } - if (decode[i] == 0xFFFE) - /* unmapped character */ - continue; - l1 = decode[i] >> 11; - l2 = decode[i] >> 7; - if (level1[l1] == 0xFF) - level1[l1] = count2++; - if (level2[l2] == 0xFF) - level2[l2] = count3++; - } - - if (count2 >= 0xFF || count3 >= 0xFF) - need_dict = 1; - - if (need_dict) { - PyObject *result = PyDict_New(); - PyObject *key, *value; - if (!result) - return NULL; - for (i = 0; i < 256; i++) { - key = value = NULL; - key = PyInt_FromLong(decode[i]); - value = PyInt_FromLong(i); - if (!key || !value) - goto failed1; - if (PyDict_SetItem(result, key, value) == -1) - goto failed1; - Py_DECREF(key); - Py_DECREF(value); - } - return result; - failed1: - Py_XDECREF(key); - Py_XDECREF(value); - Py_DECREF(result); - return NULL; - } - - /* Create a three-level trie */ - result = PyObject_MALLOC(sizeof(struct encoding_map) + - 16*count2 + 128*count3 - 1); - if (!result) - return PyErr_NoMemory(); - PyObject_Init(result, &EncodingMapType); - mresult = (struct encoding_map*)result; - mresult->count2 = count2; - mresult->count3 = count3; - mlevel1 = mresult->level1; - mlevel2 = mresult->level23; - mlevel3 = mresult->level23 + 16*count2; - memcpy(mlevel1, level1, 32); - memset(mlevel2, 0xFF, 16*count2); - memset(mlevel3, 0, 128*count3); - count3 = 0; - for (i = 1; i < 256; i++) { - int o1, o2, o3, i2, i3; - if (decode[i] == 0xFFFE) - /* unmapped character */ - continue; - o1 = decode[i]>>11; - o2 = (decode[i]>>7) & 0xF; - i2 = 16*mlevel1[o1] + o2; - if (mlevel2[i2] == 0xFF) - mlevel2[i2] = count3++; - o3 = decode[i] & 0x7F; - i3 = 128*mlevel2[i2] + o3; - mlevel3[i3] = i; - } - return result; -} - -static int -encoding_map_lookup(Py_UNICODE c, PyObject *mapping) -{ - struct encoding_map *map = (struct encoding_map*)mapping; - int l1 = c>>11; - int l2 = (c>>7) & 0xF; - int l3 = c & 0x7F; - int i; - -#ifdef Py_UNICODE_WIDE - if (c > 0xFFFF) { - return -1; - } -#endif - if (c == 0) - return 0; - /* level 1*/ - i = map->level1[l1]; - if (i == 0xFF) { - return -1; - } - /* level 2*/ - i = map->level23[16*i+l2]; - if (i == 0xFF) { - return -1; - } - /* level 3 */ - i = map->level23[16*map->count2 + 128*i + l3]; - if (i == 0) { - return -1; - } - return i; -} - -/* Lookup the character ch in the mapping. If the character - can't be found, Py_None is returned (or NULL, if another - error occurred). */ -static PyObject *charmapencode_lookup(Py_UNICODE c, PyObject *mapping) -{ - PyObject *w = PyInt_FromLong((long)c); - PyObject *x; - - if (w == NULL) - return NULL; - x = PyObject_GetItem(mapping, w); - Py_DECREF(w); - if (x == NULL) { - if (PyErr_ExceptionMatches(PyExc_LookupError)) { - /* No mapping found means: mapping is undefined. */ - PyErr_Clear(); - x = Py_None; - Py_INCREF(x); - return x; - } else - return NULL; - } - else if (x == Py_None) - return x; - else if (PyInt_Check(x)) { - long value = PyInt_AS_LONG(x); - if (value < 0 || value > 255) { - PyErr_SetString(PyExc_TypeError, - "character mapping must be in range(256)"); - Py_DECREF(x); - return NULL; - } - return x; - } - else if (PyString_Check(x)) - return x; - else { - /* wrong return value */ - PyErr_SetString(PyExc_TypeError, - "character mapping must return integer, None or str"); - Py_DECREF(x); - return NULL; - } -} - -static int -charmapencode_resize(PyObject **outobj, Py_ssize_t *outpos, Py_ssize_t requiredsize) -{ - Py_ssize_t outsize = PyString_GET_SIZE(*outobj); - /* exponentially overallocate to minimize reallocations */ - if (requiredsize < 2*outsize) - requiredsize = 2*outsize; - if (_PyString_Resize(outobj, requiredsize)) { - return 0; - } - return 1; -} - -typedef enum charmapencode_result { - enc_SUCCESS, enc_FAILED, enc_EXCEPTION -}charmapencode_result; -/* lookup the character, put the result in the output string and adjust - various state variables. Reallocate the output string if not enough - space is available. Return a new reference to the object that - was put in the output buffer, or Py_None, if the mapping was undefined - (in which case no character was written) or NULL, if a - reallocation error occurred. The caller must decref the result */ -static -charmapencode_result charmapencode_output(Py_UNICODE c, PyObject *mapping, - PyObject **outobj, Py_ssize_t *outpos) -{ - PyObject *rep; - char *outstart; - Py_ssize_t outsize = PyString_GET_SIZE(*outobj); - - if (mapping->ob_type == &EncodingMapType) { - int res = encoding_map_lookup(c, mapping); - Py_ssize_t requiredsize = *outpos+1; - if (res == -1) - return enc_FAILED; - if (outsize<requiredsize) - if (!charmapencode_resize(outobj, outpos, requiredsize)) - return enc_EXCEPTION; - outstart = PyString_AS_STRING(*outobj); - outstart[(*outpos)++] = (char)res; - return enc_SUCCESS; - } - - rep = charmapencode_lookup(c, mapping); - if (rep==NULL) - return enc_EXCEPTION; - else if (rep==Py_None) { - Py_DECREF(rep); - return enc_FAILED; - } else { - if (PyInt_Check(rep)) { - Py_ssize_t requiredsize = *outpos+1; - if (outsize<requiredsize) - if (!charmapencode_resize(outobj, outpos, requiredsize)) { - Py_DECREF(rep); - return enc_EXCEPTION; - } - outstart = PyString_AS_STRING(*outobj); - outstart[(*outpos)++] = (char)PyInt_AS_LONG(rep); - } - else { - const char *repchars = PyString_AS_STRING(rep); - Py_ssize_t repsize = PyString_GET_SIZE(rep); - Py_ssize_t requiredsize = *outpos+repsize; - if (outsize<requiredsize) - if (!charmapencode_resize(outobj, outpos, requiredsize)) { - Py_DECREF(rep); - return enc_EXCEPTION; - } - outstart = PyString_AS_STRING(*outobj); - memcpy(outstart + *outpos, repchars, repsize); - *outpos += repsize; - } - } - Py_DECREF(rep); - return enc_SUCCESS; -} - -/* handle an error in PyUnicode_EncodeCharmap - Return 0 on success, -1 on error */ -static -int charmap_encoding_error( - const Py_UNICODE *p, Py_ssize_t size, Py_ssize_t *inpos, PyObject *mapping, - PyObject **exceptionObject, - int *known_errorHandler, PyObject **errorHandler, const char *errors, - PyObject **res, Py_ssize_t *respos) -{ - PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ - Py_ssize_t repsize; - Py_ssize_t newpos; - Py_UNICODE *uni2; - /* startpos for collecting unencodable chars */ - Py_ssize_t collstartpos = *inpos; - Py_ssize_t collendpos = *inpos+1; - Py_ssize_t collpos; - char *encoding = "charmap"; - char *reason = "character maps to <undefined>"; - charmapencode_result x; - - /* find all unencodable characters */ - while (collendpos < size) { - PyObject *rep; - if (mapping->ob_type == &EncodingMapType) { - int res = encoding_map_lookup(p[collendpos], mapping); - if (res != -1) - break; - ++collendpos; - continue; - } - - rep = charmapencode_lookup(p[collendpos], mapping); - if (rep==NULL) - return -1; - else if (rep!=Py_None) { - Py_DECREF(rep); - break; - } - Py_DECREF(rep); - ++collendpos; - } - /* cache callback name lookup - * (if not done yet, i.e. it's the first error) */ - if (*known_errorHandler==-1) { - if ((errors==NULL) || (!strcmp(errors, "strict"))) - *known_errorHandler = 1; - else if (!strcmp(errors, "replace")) - *known_errorHandler = 2; - else if (!strcmp(errors, "ignore")) - *known_errorHandler = 3; - else if (!strcmp(errors, "xmlcharrefreplace")) - *known_errorHandler = 4; - else - *known_errorHandler = 0; - } - switch (*known_errorHandler) { - case 1: /* strict */ - raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); - return -1; - case 2: /* replace */ - for (collpos = collstartpos; collpos<collendpos; ++collpos) { - x = charmapencode_output('?', mapping, res, respos); - if (x==enc_EXCEPTION) { - return -1; - } - else if (x==enc_FAILED) { - raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); - return -1; - } - } - /* fall through */ - case 3: /* ignore */ - *inpos = collendpos; - break; - case 4: /* xmlcharrefreplace */ - /* generate replacement (temporarily (mis)uses p) */ - for (collpos = collstartpos; collpos < collendpos; ++collpos) { - char buffer[2+29+1+1]; - char *cp; - sprintf(buffer, "&#%d;", (int)p[collpos]); - for (cp = buffer; *cp; ++cp) { - x = charmapencode_output(*cp, mapping, res, respos); - if (x==enc_EXCEPTION) - return -1; - else if (x==enc_FAILED) { - raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); - return -1; - } - } - } - *inpos = collendpos; - break; - default: - repunicode = unicode_encode_call_errorhandler(errors, errorHandler, - encoding, reason, p, size, exceptionObject, - collstartpos, collendpos, &newpos); - if (repunicode == NULL) - return -1; - /* generate replacement */ - repsize = PyUnicode_GET_SIZE(repunicode); - for (uni2 = PyUnicode_AS_UNICODE(repunicode); repsize-->0; ++uni2) { - x = charmapencode_output(*uni2, mapping, res, respos); - if (x==enc_EXCEPTION) { - return -1; - } - else if (x==enc_FAILED) { - Py_DECREF(repunicode); - raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); - return -1; - } - } - *inpos = newpos; - Py_DECREF(repunicode); - } - return 0; -} - -PyObject *PyUnicode_EncodeCharmap(const Py_UNICODE *p, - Py_ssize_t size, - PyObject *mapping, - const char *errors) -{ - /* output object */ - PyObject *res = NULL; - /* current input position */ - Py_ssize_t inpos = 0; - /* current output position */ - Py_ssize_t respos = 0; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - /* the following variable is used for caching string comparisons - * -1=not initialized, 0=unknown, 1=strict, 2=replace, - * 3=ignore, 4=xmlcharrefreplace */ - int known_errorHandler = -1; - - /* Default to Latin-1 */ - if (mapping == NULL) - return PyUnicode_EncodeLatin1(p, size, errors); - - /* allocate enough for a simple encoding without - replacements, if we need more, we'll resize */ - res = PyString_FromStringAndSize(NULL, size); - if (res == NULL) - goto onError; - if (size == 0) - return res; - - while (inpos<size) { - /* try to encode it */ - charmapencode_result x = charmapencode_output(p[inpos], mapping, &res, &respos); - if (x==enc_EXCEPTION) /* error */ - goto onError; - if (x==enc_FAILED) { /* unencodable character */ - if (charmap_encoding_error(p, size, &inpos, mapping, - &exc, - &known_errorHandler, &errorHandler, errors, - &res, &respos)) { - goto onError; - } - } - else - /* done with this character => adjust input position */ - ++inpos; - } - - /* Resize if we allocated to much */ - if (respos<PyString_GET_SIZE(res)) { - if (_PyString_Resize(&res, respos)) - goto onError; - } - Py_XDECREF(exc); - Py_XDECREF(errorHandler); - return res; - - onError: - Py_XDECREF(res); - Py_XDECREF(exc); - Py_XDECREF(errorHandler); - return NULL; -} - -PyObject *PyUnicode_AsCharmapString(PyObject *unicode, - PyObject *mapping) -{ - if (!PyUnicode_Check(unicode) || mapping == NULL) { - PyErr_BadArgument(); - return NULL; - } - return PyUnicode_EncodeCharmap(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode), - mapping, - NULL); -} - -/* create or adjust a UnicodeTranslateError */ -static void make_translate_exception(PyObject **exceptionObject, - const Py_UNICODE *unicode, Py_ssize_t size, - Py_ssize_t startpos, Py_ssize_t endpos, - const char *reason) -{ - if (*exceptionObject == NULL) { - *exceptionObject = PyUnicodeTranslateError_Create( - unicode, size, startpos, endpos, reason); - } - else { - if (PyUnicodeTranslateError_SetStart(*exceptionObject, startpos)) - goto onError; - if (PyUnicodeTranslateError_SetEnd(*exceptionObject, endpos)) - goto onError; - if (PyUnicodeTranslateError_SetReason(*exceptionObject, reason)) - goto onError; - return; - onError: - Py_DECREF(*exceptionObject); - *exceptionObject = NULL; - } -} - -/* raises a UnicodeTranslateError */ -static void raise_translate_exception(PyObject **exceptionObject, - const Py_UNICODE *unicode, Py_ssize_t size, - Py_ssize_t startpos, Py_ssize_t endpos, - const char *reason) -{ - make_translate_exception(exceptionObject, - unicode, size, startpos, endpos, reason); - if (*exceptionObject != NULL) - PyCodec_StrictErrors(*exceptionObject); -} - -/* error handling callback helper: - build arguments, call the callback and check the arguments, - put the result into newpos and return the replacement string, which - has to be freed by the caller */ -static PyObject *unicode_translate_call_errorhandler(const char *errors, - PyObject **errorHandler, - const char *reason, - const Py_UNICODE *unicode, Py_ssize_t size, PyObject **exceptionObject, - Py_ssize_t startpos, Py_ssize_t endpos, - Py_ssize_t *newpos) -{ - static char *argparse = "O!n;translating error handler must return (unicode, int) tuple"; - - Py_ssize_t i_newpos; - PyObject *restuple; - PyObject *resunicode; - - if (*errorHandler == NULL) { - *errorHandler = PyCodec_LookupError(errors); - if (*errorHandler == NULL) - return NULL; - } - - make_translate_exception(exceptionObject, - unicode, size, startpos, endpos, reason); - if (*exceptionObject == NULL) - return NULL; - - restuple = PyObject_CallFunctionObjArgs( - *errorHandler, *exceptionObject, NULL); - if (restuple == NULL) - return NULL; - if (!PyTuple_Check(restuple)) { - PyErr_Format(PyExc_TypeError, &argparse[4]); - Py_DECREF(restuple); - return NULL; - } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, - &resunicode, &i_newpos)) { - Py_DECREF(restuple); - return NULL; - } - if (i_newpos<0) - *newpos = size+i_newpos; - else - *newpos = i_newpos; - if (*newpos<0 || *newpos>size) { - PyErr_Format(PyExc_IndexError, "position %zd from error handler out of bounds", *newpos); - Py_DECREF(restuple); - return NULL; - } - Py_INCREF(resunicode); - Py_DECREF(restuple); - return resunicode; -} - -/* Lookup the character ch in the mapping and put the result in result, - which must be decrefed by the caller. - Return 0 on success, -1 on error */ -static -int charmaptranslate_lookup(Py_UNICODE c, PyObject *mapping, PyObject **result) -{ - PyObject *w = PyInt_FromLong((long)c); - PyObject *x; - - if (w == NULL) - return -1; - x = PyObject_GetItem(mapping, w); - Py_DECREF(w); - if (x == NULL) { - if (PyErr_ExceptionMatches(PyExc_LookupError)) { - /* No mapping found means: use 1:1 mapping. */ - PyErr_Clear(); - *result = NULL; - return 0; - } else - return -1; - } - else if (x == Py_None) { - *result = x; - return 0; - } - else if (PyInt_Check(x)) { - long value = PyInt_AS_LONG(x); - long max = PyUnicode_GetMax(); - if (value < 0 || value > max) { - PyErr_Format(PyExc_TypeError, - "character mapping must be in range(0x%lx)", max+1); - Py_DECREF(x); - return -1; - } - *result = x; - return 0; - } - else if (PyUnicode_Check(x)) { - *result = x; - return 0; - } - else { - /* wrong return value */ - PyErr_SetString(PyExc_TypeError, - "character mapping must return integer, None or unicode"); - Py_DECREF(x); - return -1; - } -} -/* ensure that *outobj is at least requiredsize characters long, -if not reallocate and adjust various state variables. -Return 0 on success, -1 on error */ -static -int charmaptranslate_makespace(PyObject **outobj, Py_UNICODE **outp, - Py_ssize_t requiredsize) -{ - Py_ssize_t oldsize = PyUnicode_GET_SIZE(*outobj); - if (requiredsize > oldsize) { - /* remember old output position */ - Py_ssize_t outpos = *outp-PyUnicode_AS_UNICODE(*outobj); - /* exponentially overallocate to minimize reallocations */ - if (requiredsize < 2 * oldsize) - requiredsize = 2 * oldsize; - if (_PyUnicode_Resize(outobj, requiredsize) < 0) - return -1; - *outp = PyUnicode_AS_UNICODE(*outobj) + outpos; - } - return 0; -} -/* lookup the character, put the result in the output string and adjust - various state variables. Return a new reference to the object that - was put in the output buffer in *result, or Py_None, if the mapping was - undefined (in which case no character was written). - The called must decref result. - Return 0 on success, -1 on error. */ -static -int charmaptranslate_output(const Py_UNICODE *startinp, const Py_UNICODE *curinp, - Py_ssize_t insize, PyObject *mapping, PyObject **outobj, Py_UNICODE **outp, - PyObject **res) -{ - if (charmaptranslate_lookup(*curinp, mapping, res)) - return -1; - if (*res==NULL) { - /* not found => default to 1:1 mapping */ - *(*outp)++ = *curinp; - } - else if (*res==Py_None) - ; - else if (PyInt_Check(*res)) { - /* no overflow check, because we know that the space is enough */ - *(*outp)++ = (Py_UNICODE)PyInt_AS_LONG(*res); - } - else if (PyUnicode_Check(*res)) { - Py_ssize_t repsize = PyUnicode_GET_SIZE(*res); - if (repsize==1) { - /* no overflow check, because we know that the space is enough */ - *(*outp)++ = *PyUnicode_AS_UNICODE(*res); - } - else if (repsize!=0) { - /* more than one character */ - Py_ssize_t requiredsize = (*outp-PyUnicode_AS_UNICODE(*outobj)) + - (insize - (curinp-startinp)) + - repsize - 1; - if (charmaptranslate_makespace(outobj, outp, requiredsize)) - return -1; - memcpy(*outp, PyUnicode_AS_UNICODE(*res), sizeof(Py_UNICODE)*repsize); - *outp += repsize; - } - } - else - return -1; - return 0; -} - -PyObject *PyUnicode_TranslateCharmap(const Py_UNICODE *p, - Py_ssize_t size, - PyObject *mapping, - const char *errors) -{ - /* output object */ - PyObject *res = NULL; - /* pointers to the beginning and end+1 of input */ - const Py_UNICODE *startp = p; - const Py_UNICODE *endp = p + size; - /* pointer into the output */ - Py_UNICODE *str; - /* current output position */ - Py_ssize_t respos = 0; - char *reason = "character maps to <undefined>"; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - /* the following variable is used for caching string comparisons - * -1=not initialized, 0=unknown, 1=strict, 2=replace, - * 3=ignore, 4=xmlcharrefreplace */ - int known_errorHandler = -1; - - if (mapping == NULL) { - PyErr_BadArgument(); - return NULL; - } - - /* allocate enough for a simple 1:1 translation without - replacements, if we need more, we'll resize */ - res = PyUnicode_FromUnicode(NULL, size); - if (res == NULL) - goto onError; - if (size == 0) - return res; - str = PyUnicode_AS_UNICODE(res); - - while (p<endp) { - /* try to encode it */ - PyObject *x = NULL; - if (charmaptranslate_output(startp, p, size, mapping, &res, &str, &x)) { - Py_XDECREF(x); - goto onError; - } - Py_XDECREF(x); - if (x!=Py_None) /* it worked => adjust input pointer */ - ++p; - else { /* untranslatable character */ - PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ - Py_ssize_t repsize; - Py_ssize_t newpos; - Py_UNICODE *uni2; - /* startpos for collecting untranslatable chars */ - const Py_UNICODE *collstart = p; - const Py_UNICODE *collend = p+1; - const Py_UNICODE *coll; - - /* find all untranslatable characters */ - while (collend < endp) { - if (charmaptranslate_lookup(*collend, mapping, &x)) - goto onError; - Py_XDECREF(x); - if (x!=Py_None) - break; - ++collend; - } - /* cache callback name lookup - * (if not done yet, i.e. it's the first error) */ - if (known_errorHandler==-1) { - if ((errors==NULL) || (!strcmp(errors, "strict"))) - known_errorHandler = 1; - else if (!strcmp(errors, "replace")) - known_errorHandler = 2; - else if (!strcmp(errors, "ignore")) - known_errorHandler = 3; - else if (!strcmp(errors, "xmlcharrefreplace")) - known_errorHandler = 4; - else - known_errorHandler = 0; - } - switch (known_errorHandler) { - case 1: /* strict */ - raise_translate_exception(&exc, startp, size, collstart-startp, collend-startp, reason); - goto onError; - case 2: /* replace */ - /* No need to check for space, this is a 1:1 replacement */ - for (coll = collstart; coll<collend; ++coll) - *str++ = '?'; - /* fall through */ - case 3: /* ignore */ - p = collend; - break; - case 4: /* xmlcharrefreplace */ - /* generate replacement (temporarily (mis)uses p) */ - for (p = collstart; p < collend; ++p) { - char buffer[2+29+1+1]; - char *cp; - sprintf(buffer, "&#%d;", (int)*p); - if (charmaptranslate_makespace(&res, &str, - (str-PyUnicode_AS_UNICODE(res))+strlen(buffer)+(endp-collend))) - goto onError; - for (cp = buffer; *cp; ++cp) - *str++ = *cp; - } - p = collend; - break; - default: - repunicode = unicode_translate_call_errorhandler(errors, &errorHandler, - reason, startp, size, &exc, - collstart-startp, collend-startp, &newpos); - if (repunicode == NULL) - goto onError; - /* generate replacement */ - repsize = PyUnicode_GET_SIZE(repunicode); - if (charmaptranslate_makespace(&res, &str, - (str-PyUnicode_AS_UNICODE(res))+repsize+(endp-collend))) { - Py_DECREF(repunicode); - goto onError; - } - for (uni2 = PyUnicode_AS_UNICODE(repunicode); repsize-->0; ++uni2) - *str++ = *uni2; - p = startp + newpos; - Py_DECREF(repunicode); - } - } - } - /* Resize if we allocated to much */ - respos = str-PyUnicode_AS_UNICODE(res); - if (respos<PyUnicode_GET_SIZE(res)) { - if (_PyUnicode_Resize(&res, respos) < 0) - goto onError; - } - Py_XDECREF(exc); - Py_XDECREF(errorHandler); - return res; - - onError: - Py_XDECREF(res); - Py_XDECREF(exc); - Py_XDECREF(errorHandler); - return NULL; -} - -PyObject *PyUnicode_Translate(PyObject *str, - PyObject *mapping, - const char *errors) -{ - PyObject *result; - - str = PyUnicode_FromObject(str); - if (str == NULL) - goto onError; - result = PyUnicode_TranslateCharmap(PyUnicode_AS_UNICODE(str), - PyUnicode_GET_SIZE(str), - mapping, - errors); - Py_DECREF(str); - return result; - - onError: - Py_XDECREF(str); - return NULL; -} - -/* --- Decimal Encoder ---------------------------------------------------- */ - -int PyUnicode_EncodeDecimal(Py_UNICODE *s, - Py_ssize_t length, - char *output, - const char *errors) -{ - Py_UNICODE *p, *end; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - const char *encoding = "decimal"; - const char *reason = "invalid decimal Unicode string"; - /* the following variable is used for caching string comparisons - * -1=not initialized, 0=unknown, 1=strict, 2=replace, 3=ignore, 4=xmlcharrefreplace */ - int known_errorHandler = -1; - - if (output == NULL) { - PyErr_BadArgument(); - return -1; - } - - p = s; - end = s + length; - while (p < end) { - register Py_UNICODE ch = *p; - int decimal; - PyObject *repunicode; - Py_ssize_t repsize; - Py_ssize_t newpos; - Py_UNICODE *uni2; - Py_UNICODE *collstart; - Py_UNICODE *collend; - - if (Py_UNICODE_ISSPACE(ch)) { - *output++ = ' '; - ++p; - continue; - } - decimal = Py_UNICODE_TODECIMAL(ch); - if (decimal >= 0) { - *output++ = '0' + decimal; - ++p; - continue; - } - if (0 < ch && ch < 256) { - *output++ = (char)ch; - ++p; - continue; - } - /* All other characters are considered unencodable */ - collstart = p; - collend = p+1; - while (collend < end) { - if ((0 < *collend && *collend < 256) || - !Py_UNICODE_ISSPACE(*collend) || - Py_UNICODE_TODECIMAL(*collend)) - break; - } - /* cache callback name lookup - * (if not done yet, i.e. it's the first error) */ - if (known_errorHandler==-1) { - if ((errors==NULL) || (!strcmp(errors, "strict"))) - known_errorHandler = 1; - else if (!strcmp(errors, "replace")) - known_errorHandler = 2; - else if (!strcmp(errors, "ignore")) - known_errorHandler = 3; - else if (!strcmp(errors, "xmlcharrefreplace")) - known_errorHandler = 4; - else - known_errorHandler = 0; - } - switch (known_errorHandler) { - case 1: /* strict */ - raise_encode_exception(&exc, encoding, s, length, collstart-s, collend-s, reason); - goto onError; - case 2: /* replace */ - for (p = collstart; p < collend; ++p) - *output++ = '?'; - /* fall through */ - case 3: /* ignore */ - p = collend; - break; - case 4: /* xmlcharrefreplace */ - /* generate replacement (temporarily (mis)uses p) */ - for (p = collstart; p < collend; ++p) - output += sprintf(output, "&#%d;", (int)*p); - p = collend; - break; - default: - repunicode = unicode_encode_call_errorhandler(errors, &errorHandler, - encoding, reason, s, length, &exc, - collstart-s, collend-s, &newpos); - if (repunicode == NULL) - goto onError; - /* generate replacement */ - repsize = PyUnicode_GET_SIZE(repunicode); - for (uni2 = PyUnicode_AS_UNICODE(repunicode); repsize-->0; ++uni2) { - Py_UNICODE ch = *uni2; - if (Py_UNICODE_ISSPACE(ch)) - *output++ = ' '; - else { - decimal = Py_UNICODE_TODECIMAL(ch); - if (decimal >= 0) - *output++ = '0' + decimal; - else if (0 < ch && ch < 256) - *output++ = (char)ch; - else { - Py_DECREF(repunicode); - raise_encode_exception(&exc, encoding, - s, length, collstart-s, collend-s, reason); - goto onError; - } - } - } - p = s + newpos; - Py_DECREF(repunicode); - } - } - /* 0-terminate the output string */ - *output++ = '\0'; - Py_XDECREF(exc); - Py_XDECREF(errorHandler); - return 0; - - onError: - Py_XDECREF(exc); - Py_XDECREF(errorHandler); - return -1; -} - -/* --- Helpers ------------------------------------------------------------ */ - -#define STRINGLIB_CHAR Py_UNICODE - -#define STRINGLIB_LEN PyUnicode_GET_SIZE -#define STRINGLIB_NEW PyUnicode_FromUnicode -#define STRINGLIB_STR PyUnicode_AS_UNICODE - -Py_LOCAL_INLINE(int) -STRINGLIB_CMP(const Py_UNICODE* str, const Py_UNICODE* other, Py_ssize_t len) -{ - if (str[0] != other[0]) - return 1; - return memcmp((void*) str, (void*) other, len * sizeof(Py_UNICODE)); -} - -#define STRINGLIB_EMPTY unicode_empty - -#include "stringlib/fastsearch.h" - -#include "stringlib/count.h" -#include "stringlib/find.h" -#include "stringlib/partition.h" - -/* helper macro to fixup start/end slice values */ -#define FIX_START_END(obj) \ - if (start < 0) \ - start += (obj)->length; \ - if (start < 0) \ - start = 0; \ - if (end > (obj)->length) \ - end = (obj)->length; \ - if (end < 0) \ - end += (obj)->length; \ - if (end < 0) \ - end = 0; - -Py_ssize_t PyUnicode_Count(PyObject *str, - PyObject *substr, - Py_ssize_t start, - Py_ssize_t end) -{ - Py_ssize_t result; - PyUnicodeObject* str_obj; - PyUnicodeObject* sub_obj; - - str_obj = (PyUnicodeObject*) PyUnicode_FromObject(str); - if (!str_obj) - return -1; - sub_obj = (PyUnicodeObject*) PyUnicode_FromObject(substr); - if (!sub_obj) { - Py_DECREF(str_obj); - return -1; - } - - FIX_START_END(str_obj); - - result = stringlib_count( - str_obj->str + start, end - start, sub_obj->str, sub_obj->length - ); - - Py_DECREF(sub_obj); - Py_DECREF(str_obj); - - return result; -} - -Py_ssize_t PyUnicode_Find(PyObject *str, - PyObject *sub, - Py_ssize_t start, - Py_ssize_t end, - int direction) -{ - Py_ssize_t result; - - str = PyUnicode_FromObject(str); - if (!str) - return -2; - sub = PyUnicode_FromObject(sub); - if (!sub) { - Py_DECREF(str); - return -2; - } - - if (direction > 0) - result = stringlib_find_slice( - PyUnicode_AS_UNICODE(str), PyUnicode_GET_SIZE(str), - PyUnicode_AS_UNICODE(sub), PyUnicode_GET_SIZE(sub), - start, end - ); - else - result = stringlib_rfind_slice( - PyUnicode_AS_UNICODE(str), PyUnicode_GET_SIZE(str), - PyUnicode_AS_UNICODE(sub), PyUnicode_GET_SIZE(sub), - start, end - ); - - Py_DECREF(str); - Py_DECREF(sub); - - return result; -} - -static -int tailmatch(PyUnicodeObject *self, - PyUnicodeObject *substring, - Py_ssize_t start, - Py_ssize_t end, - int direction) -{ - if (substring->length == 0) - return 1; - - FIX_START_END(self); - - end -= substring->length; - if (end < start) - return 0; - - if (direction > 0) { - if (Py_UNICODE_MATCH(self, end, substring)) - return 1; - } else { - if (Py_UNICODE_MATCH(self, start, substring)) - return 1; - } - - return 0; -} - -Py_ssize_t PyUnicode_Tailmatch(PyObject *str, - PyObject *substr, - Py_ssize_t start, - Py_ssize_t end, - int direction) -{ - Py_ssize_t result; - - str = PyUnicode_FromObject(str); - if (str == NULL) - return -1; - substr = PyUnicode_FromObject(substr); - if (substr == NULL) { - Py_DECREF(str); - return -1; - } - - result = tailmatch((PyUnicodeObject *)str, - (PyUnicodeObject *)substr, - start, end, direction); - Py_DECREF(str); - Py_DECREF(substr); - return result; -} - -/* Apply fixfct filter to the Unicode object self and return a - reference to the modified object */ - -static -PyObject *fixup(PyUnicodeObject *self, - int (*fixfct)(PyUnicodeObject *s)) -{ - - PyUnicodeObject *u; - - u = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, self->length); - if (u == NULL) - return NULL; - - Py_UNICODE_COPY(u->str, self->str, self->length); - - if (!fixfct(u) && PyUnicode_CheckExact(self)) { - /* fixfct should return TRUE if it modified the buffer. If - FALSE, return a reference to the original buffer instead - (to save space, not time) */ - Py_INCREF(self); - Py_DECREF(u); - return (PyObject*) self; - } - return (PyObject*) u; -} - -static -int fixupper(PyUnicodeObject *self) -{ - Py_ssize_t len = self->length; - Py_UNICODE *s = self->str; - int status = 0; - - while (len-- > 0) { - register Py_UNICODE ch; - - ch = Py_UNICODE_TOUPPER(*s); - if (ch != *s) { - status = 1; - *s = ch; - } - s++; - } - - return status; -} - -static -int fixlower(PyUnicodeObject *self) -{ - Py_ssize_t len = self->length; - Py_UNICODE *s = self->str; - int status = 0; - - while (len-- > 0) { - register Py_UNICODE ch; - - ch = Py_UNICODE_TOLOWER(*s); - if (ch != *s) { - status = 1; - *s = ch; - } - s++; - } - - return status; -} - -static -int fixswapcase(PyUnicodeObject *self) -{ - Py_ssize_t len = self->length; - Py_UNICODE *s = self->str; - int status = 0; - - while (len-- > 0) { - if (Py_UNICODE_ISUPPER(*s)) { - *s = Py_UNICODE_TOLOWER(*s); - status = 1; - } else if (Py_UNICODE_ISLOWER(*s)) { - *s = Py_UNICODE_TOUPPER(*s); - status = 1; - } - s++; - } - - return status; -} - -static -int fixcapitalize(PyUnicodeObject *self) -{ - Py_ssize_t len = self->length; - Py_UNICODE *s = self->str; - int status = 0; - - if (len == 0) - return 0; - if (Py_UNICODE_ISLOWER(*s)) { - *s = Py_UNICODE_TOUPPER(*s); - status = 1; - } - s++; - while (--len > 0) { - if (Py_UNICODE_ISUPPER(*s)) { - *s = Py_UNICODE_TOLOWER(*s); - status = 1; - } - s++; - } - return status; -} - -static -int fixtitle(PyUnicodeObject *self) -{ - register Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register Py_UNICODE *e; - int previous_is_cased; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1) { - Py_UNICODE ch = Py_UNICODE_TOTITLE(*p); - if (*p != ch) { - *p = ch; - return 1; - } - else - return 0; - } - - e = p + PyUnicode_GET_SIZE(self); - previous_is_cased = 0; - for (; p < e; p++) { - register const Py_UNICODE ch = *p; - - if (previous_is_cased) - *p = Py_UNICODE_TOLOWER(ch); - else - *p = Py_UNICODE_TOTITLE(ch); - - if (Py_UNICODE_ISLOWER(ch) || - Py_UNICODE_ISUPPER(ch) || - Py_UNICODE_ISTITLE(ch)) - previous_is_cased = 1; - else - previous_is_cased = 0; - } - return 1; -} - -PyObject * -PyUnicode_Join(PyObject *separator, PyObject *seq) -{ - PyObject *internal_separator = NULL; - const Py_UNICODE blank = ' '; - const Py_UNICODE *sep = ␣ - Py_ssize_t seplen = 1; - PyUnicodeObject *res = NULL; /* the result */ - Py_ssize_t res_alloc = 100; /* # allocated bytes for string in res */ - Py_ssize_t res_used; /* # used bytes */ - Py_UNICODE *res_p; /* pointer to free byte in res's string area */ - PyObject *fseq; /* PySequence_Fast(seq) */ - Py_ssize_t seqlen; /* len(fseq) -- number of items in sequence */ - PyObject *item; - Py_ssize_t i; - - fseq = PySequence_Fast(seq, ""); - if (fseq == NULL) { - return NULL; - } - - /* Grrrr. A codec may be invoked to convert str objects to - * Unicode, and so it's possible to call back into Python code - * during PyUnicode_FromObject(), and so it's possible for a sick - * codec to change the size of fseq (if seq is a list). Therefore - * we have to keep refetching the size -- can't assume seqlen - * is invariant. - */ - seqlen = PySequence_Fast_GET_SIZE(fseq); - /* If empty sequence, return u"". */ - if (seqlen == 0) { - res = _PyUnicode_New(0); /* empty sequence; return u"" */ - goto Done; - } - /* If singleton sequence with an exact Unicode, return that. */ - if (seqlen == 1) { - item = PySequence_Fast_GET_ITEM(fseq, 0); - if (PyUnicode_CheckExact(item)) { - Py_INCREF(item); - res = (PyUnicodeObject *)item; - goto Done; - } - } - - /* At least two items to join, or one that isn't exact Unicode. */ - if (seqlen > 1) { - /* Set up sep and seplen -- they're needed. */ - if (separator == NULL) { - sep = ␣ - seplen = 1; - } - else { - internal_separator = PyUnicode_FromObject(separator); - if (internal_separator == NULL) - goto onError; - sep = PyUnicode_AS_UNICODE(internal_separator); - seplen = PyUnicode_GET_SIZE(internal_separator); - /* In case PyUnicode_FromObject() mutated seq. */ - seqlen = PySequence_Fast_GET_SIZE(fseq); - } - } - - /* Get space. */ - res = _PyUnicode_New(res_alloc); - if (res == NULL) - goto onError; - res_p = PyUnicode_AS_UNICODE(res); - res_used = 0; - - for (i = 0; i < seqlen; ++i) { - Py_ssize_t itemlen; - Py_ssize_t new_res_used; - - item = PySequence_Fast_GET_ITEM(fseq, i); - /* Convert item to Unicode. */ - if (! PyUnicode_Check(item) && ! PyString_Check(item)) { - PyErr_Format(PyExc_TypeError, - "sequence item %zd: expected string or Unicode," - " %.80s found", - i, item->ob_type->tp_name); - goto onError; - } - item = PyUnicode_FromObject(item); - if (item == NULL) - goto onError; - /* We own a reference to item from here on. */ - - /* In case PyUnicode_FromObject() mutated seq. */ - seqlen = PySequence_Fast_GET_SIZE(fseq); - - /* Make sure we have enough space for the separator and the item. */ - itemlen = PyUnicode_GET_SIZE(item); - new_res_used = res_used + itemlen; - if (new_res_used < 0) - goto Overflow; - if (i < seqlen - 1) { - new_res_used += seplen; - if (new_res_used < 0) - goto Overflow; - } - if (new_res_used > res_alloc) { - /* double allocated size until it's big enough */ - do { - res_alloc += res_alloc; - if (res_alloc <= 0) - goto Overflow; - } while (new_res_used > res_alloc); - if (_PyUnicode_Resize(&res, res_alloc) < 0) { - Py_DECREF(item); - goto onError; - } - res_p = PyUnicode_AS_UNICODE(res) + res_used; - } - - /* Copy item, and maybe the separator. */ - Py_UNICODE_COPY(res_p, PyUnicode_AS_UNICODE(item), itemlen); - res_p += itemlen; - if (i < seqlen - 1) { - Py_UNICODE_COPY(res_p, sep, seplen); - res_p += seplen; - } - Py_DECREF(item); - res_used = new_res_used; - } - - /* Shrink res to match the used area; this probably can't fail, - * but it's cheap to check. - */ - if (_PyUnicode_Resize(&res, res_used) < 0) - goto onError; - - Done: - Py_XDECREF(internal_separator); - Py_DECREF(fseq); - return (PyObject *)res; - - Overflow: - PyErr_SetString(PyExc_OverflowError, - "join() result is too long for a Python string"); - Py_DECREF(item); - /* fall through */ - - onError: - Py_XDECREF(internal_separator); - Py_DECREF(fseq); - Py_XDECREF(res); - return NULL; -} - -static -PyUnicodeObject *pad(PyUnicodeObject *self, - Py_ssize_t left, - Py_ssize_t right, - Py_UNICODE fill) -{ - PyUnicodeObject *u; - - if (left < 0) - left = 0; - if (right < 0) - right = 0; - - if (left == 0 && right == 0 && PyUnicode_CheckExact(self)) { - Py_INCREF(self); - return self; - } - - u = _PyUnicode_New(left + self->length + right); - if (u) { - if (left) - Py_UNICODE_FILL(u->str, fill, left); - Py_UNICODE_COPY(u->str + left, self->str, self->length); - if (right) - Py_UNICODE_FILL(u->str + left + self->length, fill, right); - } - - return u; -} - -#define SPLIT_APPEND(data, left, right) \ - str = PyUnicode_FromUnicode((data) + (left), (right) - (left)); \ - if (!str) \ - goto onError; \ - if (PyList_Append(list, str)) { \ - Py_DECREF(str); \ - goto onError; \ - } \ - else \ - Py_DECREF(str); - -static -PyObject *split_whitespace(PyUnicodeObject *self, - PyObject *list, - Py_ssize_t maxcount) -{ - register Py_ssize_t i; - register Py_ssize_t j; - Py_ssize_t len = self->length; - PyObject *str; - - for (i = j = 0; i < len; ) { - /* find a token */ - while (i < len && Py_UNICODE_ISSPACE(self->str[i])) - i++; - j = i; - while (i < len && !Py_UNICODE_ISSPACE(self->str[i])) - i++; - if (j < i) { - if (maxcount-- <= 0) - break; - SPLIT_APPEND(self->str, j, i); - while (i < len && Py_UNICODE_ISSPACE(self->str[i])) - i++; - j = i; - } - } - if (j < len) { - SPLIT_APPEND(self->str, j, len); - } - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -PyObject *PyUnicode_Splitlines(PyObject *string, - int keepends) -{ - register Py_ssize_t i; - register Py_ssize_t j; - Py_ssize_t len; - PyObject *list; - PyObject *str; - Py_UNICODE *data; - - string = PyUnicode_FromObject(string); - if (string == NULL) - return NULL; - data = PyUnicode_AS_UNICODE(string); - len = PyUnicode_GET_SIZE(string); - - list = PyList_New(0); - if (!list) - goto onError; - - for (i = j = 0; i < len; ) { - Py_ssize_t eol; - - /* Find a line and append it */ - while (i < len && !BLOOM_LINEBREAK(data[i])) - i++; - - /* Skip the line break reading CRLF as one line break */ - eol = i; - if (i < len) { - if (data[i] == '\r' && i + 1 < len && - data[i+1] == '\n') - i += 2; - else - i++; - if (keepends) - eol = i; - } - SPLIT_APPEND(data, j, eol); - j = i; - } - if (j < len) { - SPLIT_APPEND(data, j, len); - } - - Py_DECREF(string); - return list; - - onError: - Py_XDECREF(list); - Py_DECREF(string); - return NULL; -} - -static -PyObject *split_char(PyUnicodeObject *self, - PyObject *list, - Py_UNICODE ch, - Py_ssize_t maxcount) -{ - register Py_ssize_t i; - register Py_ssize_t j; - Py_ssize_t len = self->length; - PyObject *str; - - for (i = j = 0; i < len; ) { - if (self->str[i] == ch) { - if (maxcount-- <= 0) - break; - SPLIT_APPEND(self->str, j, i); - i = j = i + 1; - } else - i++; - } - if (j <= len) { - SPLIT_APPEND(self->str, j, len); - } - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -static -PyObject *split_substring(PyUnicodeObject *self, - PyObject *list, - PyUnicodeObject *substring, - Py_ssize_t maxcount) -{ - register Py_ssize_t i; - register Py_ssize_t j; - Py_ssize_t len = self->length; - Py_ssize_t sublen = substring->length; - PyObject *str; - - for (i = j = 0; i <= len - sublen; ) { - if (Py_UNICODE_MATCH(self, i, substring)) { - if (maxcount-- <= 0) - break; - SPLIT_APPEND(self->str, j, i); - i = j = i + sublen; - } else - i++; - } - if (j <= len) { - SPLIT_APPEND(self->str, j, len); - } - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -static -PyObject *rsplit_whitespace(PyUnicodeObject *self, - PyObject *list, - Py_ssize_t maxcount) -{ - register Py_ssize_t i; - register Py_ssize_t j; - Py_ssize_t len = self->length; - PyObject *str; - - for (i = j = len - 1; i >= 0; ) { - /* find a token */ - while (i >= 0 && Py_UNICODE_ISSPACE(self->str[i])) - i--; - j = i; - while (i >= 0 && !Py_UNICODE_ISSPACE(self->str[i])) - i--; - if (j > i) { - if (maxcount-- <= 0) - break; - SPLIT_APPEND(self->str, i + 1, j + 1); - while (i >= 0 && Py_UNICODE_ISSPACE(self->str[i])) - i--; - j = i; - } - } - if (j >= 0) { - SPLIT_APPEND(self->str, 0, j + 1); - } - if (PyList_Reverse(list) < 0) - goto onError; - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -static -PyObject *rsplit_char(PyUnicodeObject *self, - PyObject *list, - Py_UNICODE ch, - Py_ssize_t maxcount) -{ - register Py_ssize_t i; - register Py_ssize_t j; - Py_ssize_t len = self->length; - PyObject *str; - - for (i = j = len - 1; i >= 0; ) { - if (self->str[i] == ch) { - if (maxcount-- <= 0) - break; - SPLIT_APPEND(self->str, i + 1, j + 1); - j = i = i - 1; - } else - i--; - } - if (j >= -1) { - SPLIT_APPEND(self->str, 0, j + 1); - } - if (PyList_Reverse(list) < 0) - goto onError; - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -static -PyObject *rsplit_substring(PyUnicodeObject *self, - PyObject *list, - PyUnicodeObject *substring, - Py_ssize_t maxcount) -{ - register Py_ssize_t i; - register Py_ssize_t j; - Py_ssize_t len = self->length; - Py_ssize_t sublen = substring->length; - PyObject *str; - - for (i = len - sublen, j = len; i >= 0; ) { - if (Py_UNICODE_MATCH(self, i, substring)) { - if (maxcount-- <= 0) - break; - SPLIT_APPEND(self->str, i + sublen, j); - j = i; - i -= sublen; - } else - i--; - } - if (j >= 0) { - SPLIT_APPEND(self->str, 0, j); - } - if (PyList_Reverse(list) < 0) - goto onError; - return list; - - onError: - Py_DECREF(list); - return NULL; -} - -#undef SPLIT_APPEND - -static -PyObject *split(PyUnicodeObject *self, - PyUnicodeObject *substring, - Py_ssize_t maxcount) -{ - PyObject *list; - - if (maxcount < 0) - maxcount = PY_SSIZE_T_MAX; - - list = PyList_New(0); - if (!list) - return NULL; - - if (substring == NULL) - return split_whitespace(self,list,maxcount); - - else if (substring->length == 1) - return split_char(self,list,substring->str[0],maxcount); - - else if (substring->length == 0) { - Py_DECREF(list); - PyErr_SetString(PyExc_ValueError, "empty separator"); - return NULL; - } - else - return split_substring(self,list,substring,maxcount); -} - -static -PyObject *rsplit(PyUnicodeObject *self, - PyUnicodeObject *substring, - Py_ssize_t maxcount) -{ - PyObject *list; - - if (maxcount < 0) - maxcount = PY_SSIZE_T_MAX; - - list = PyList_New(0); - if (!list) - return NULL; - - if (substring == NULL) - return rsplit_whitespace(self,list,maxcount); - - else if (substring->length == 1) - return rsplit_char(self,list,substring->str[0],maxcount); - - else if (substring->length == 0) { - Py_DECREF(list); - PyErr_SetString(PyExc_ValueError, "empty separator"); - return NULL; - } - else - return rsplit_substring(self,list,substring,maxcount); -} - -static -PyObject *replace(PyUnicodeObject *self, - PyUnicodeObject *str1, - PyUnicodeObject *str2, - Py_ssize_t maxcount) -{ - PyUnicodeObject *u; - - if (maxcount < 0) - maxcount = PY_SSIZE_T_MAX; - - if (str1->length == str2->length) { - /* same length */ - Py_ssize_t i; - if (str1->length == 1) { - /* replace characters */ - Py_UNICODE u1, u2; - if (!findchar(self->str, self->length, str1->str[0])) - goto nothing; - u = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, self->length); - if (!u) - return NULL; - Py_UNICODE_COPY(u->str, self->str, self->length); - u1 = str1->str[0]; - u2 = str2->str[0]; - for (i = 0; i < u->length; i++) - if (u->str[i] == u1) { - if (--maxcount < 0) - break; - u->str[i] = u2; - } - } else { - i = fastsearch( - self->str, self->length, str1->str, str1->length, FAST_SEARCH - ); - if (i < 0) - goto nothing; - u = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, self->length); - if (!u) - return NULL; - Py_UNICODE_COPY(u->str, self->str, self->length); - while (i <= self->length - str1->length) - if (Py_UNICODE_MATCH(self, i, str1)) { - if (--maxcount < 0) - break; - Py_UNICODE_COPY(u->str+i, str2->str, str2->length); - i += str1->length; - } else - i++; - } - } else { - - Py_ssize_t n, i, j, e; - Py_ssize_t product, new_size, delta; - Py_UNICODE *p; - - /* replace strings */ - n = stringlib_count(self->str, self->length, str1->str, str1->length); - if (n > maxcount) - n = maxcount; - if (n == 0) - goto nothing; - /* new_size = self->length + n * (str2->length - str1->length)); */ - delta = (str2->length - str1->length); - if (delta == 0) { - new_size = self->length; - } else { - product = n * (str2->length - str1->length); - if ((product / (str2->length - str1->length)) != n) { - PyErr_SetString(PyExc_OverflowError, - "replace string is too long"); - return NULL; - } - new_size = self->length + product; - if (new_size < 0) { - PyErr_SetString(PyExc_OverflowError, - "replace string is too long"); - return NULL; - } - } - u = _PyUnicode_New(new_size); - if (!u) - return NULL; - i = 0; - p = u->str; - e = self->length - str1->length; - if (str1->length > 0) { - while (n-- > 0) { - /* look for next match */ - j = i; - while (j <= e) { - if (Py_UNICODE_MATCH(self, j, str1)) - break; - j++; - } - if (j > i) { - if (j > e) - break; - /* copy unchanged part [i:j] */ - Py_UNICODE_COPY(p, self->str+i, j-i); - p += j - i; - } - /* copy substitution string */ - if (str2->length > 0) { - Py_UNICODE_COPY(p, str2->str, str2->length); - p += str2->length; - } - i = j + str1->length; - } - if (i < self->length) - /* copy tail [i:] */ - Py_UNICODE_COPY(p, self->str+i, self->length-i); - } else { - /* interleave */ - while (n > 0) { - Py_UNICODE_COPY(p, str2->str, str2->length); - p += str2->length; - if (--n <= 0) - break; - *p++ = self->str[i++]; - } - Py_UNICODE_COPY(p, self->str+i, self->length-i); - } - } - return (PyObject *) u; - -nothing: - /* nothing to replace; return original string (when possible) */ - if (PyUnicode_CheckExact(self)) { - Py_INCREF(self); - return (PyObject *) self; - } - return PyUnicode_FromUnicode(self->str, self->length); -} - -/* --- Unicode Object Methods --------------------------------------------- */ - -PyDoc_STRVAR(title__doc__, -"S.title() -> unicode\n\ -\n\ -Return a titlecased version of S, i.e. words start with title case\n\ -characters, all remaining cased characters have lower case."); - -static PyObject* -unicode_title(PyUnicodeObject *self) -{ - return fixup(self, fixtitle); -} - -PyDoc_STRVAR(capitalize__doc__, -"S.capitalize() -> unicode\n\ -\n\ -Return a capitalized version of S, i.e. make the first character\n\ -have upper case."); - -static PyObject* -unicode_capitalize(PyUnicodeObject *self) -{ - return fixup(self, fixcapitalize); -} - -#if 0 -PyDoc_STRVAR(capwords__doc__, -"S.capwords() -> unicode\n\ -\n\ -Apply .capitalize() to all words in S and return the result with\n\ -normalized whitespace (all whitespace strings are replaced by ' ')."); - -static PyObject* -unicode_capwords(PyUnicodeObject *self) -{ - PyObject *list; - PyObject *item; - Py_ssize_t i; - - /* Split into words */ - list = split(self, NULL, -1); - if (!list) - return NULL; - - /* Capitalize each word */ - for (i = 0; i < PyList_GET_SIZE(list); i++) { - item = fixup((PyUnicodeObject *)PyList_GET_ITEM(list, i), - fixcapitalize); - if (item == NULL) - goto onError; - Py_DECREF(PyList_GET_ITEM(list, i)); - PyList_SET_ITEM(list, i, item); - } - - /* Join the words to form a new string */ - item = PyUnicode_Join(NULL, list); - -onError: - Py_DECREF(list); - return (PyObject *)item; -} -#endif - -/* Argument converter. Coerces to a single unicode character */ - -static int -convert_uc(PyObject *obj, void *addr) -{ - Py_UNICODE *fillcharloc = (Py_UNICODE *)addr; - PyObject *uniobj; - Py_UNICODE *unistr; - - uniobj = PyUnicode_FromObject(obj); - if (uniobj == NULL) { - PyErr_SetString(PyExc_TypeError, - "The fill character cannot be converted to Unicode"); - return 0; - } - if (PyUnicode_GET_SIZE(uniobj) != 1) { - PyErr_SetString(PyExc_TypeError, - "The fill character must be exactly one character long"); - Py_DECREF(uniobj); - return 0; - } - unistr = PyUnicode_AS_UNICODE(uniobj); - *fillcharloc = unistr[0]; - Py_DECREF(uniobj); - return 1; -} - -PyDoc_STRVAR(center__doc__, -"S.center(width[, fillchar]) -> unicode\n\ -\n\ -Return S centered in a Unicode string of length width. Padding is\n\ -done using the specified fill character (default is a space)"); - -static PyObject * -unicode_center(PyUnicodeObject *self, PyObject *args) -{ - Py_ssize_t marg, left; - Py_ssize_t width; - Py_UNICODE fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|O&:center", &width, convert_uc, &fillchar)) - return NULL; - - if (self->length >= width && PyUnicode_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*) self; - } - - marg = width - self->length; - left = marg / 2 + (marg & width & 1); - - return (PyObject*) pad(self, left, marg - left, fillchar); -} - -#if 0 - -/* This code should go into some future Unicode collation support - module. The basic comparison should compare ordinals on a naive - basis (this is what Java does and thus JPython too). */ - -/* speedy UTF-16 code point order comparison */ -/* gleaned from: */ -/* http://www-4.ibm.com/software/developer/library/utf16.html?dwzone=unicode */ - -static short utf16Fixup[32] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0x2000, -0x800, -0x800, -0x800, -0x800 -}; - -static int -unicode_compare(PyUnicodeObject *str1, PyUnicodeObject *str2) -{ - Py_ssize_t len1, len2; - - Py_UNICODE *s1 = str1->str; - Py_UNICODE *s2 = str2->str; - - len1 = str1->length; - len2 = str2->length; - - while (len1 > 0 && len2 > 0) { - Py_UNICODE c1, c2; - - c1 = *s1++; - c2 = *s2++; - - if (c1 > (1<<11) * 26) - c1 += utf16Fixup[c1>>11]; - if (c2 > (1<<11) * 26) - c2 += utf16Fixup[c2>>11]; - /* now c1 and c2 are in UTF-32-compatible order */ - - if (c1 != c2) - return (c1 < c2) ? -1 : 1; - - len1--; len2--; - } - - return (len1 < len2) ? -1 : (len1 != len2); -} - -#else - -static int -unicode_compare(PyUnicodeObject *str1, PyUnicodeObject *str2) -{ - register Py_ssize_t len1, len2; - - Py_UNICODE *s1 = str1->str; - Py_UNICODE *s2 = str2->str; - - len1 = str1->length; - len2 = str2->length; - - while (len1 > 0 && len2 > 0) { - Py_UNICODE c1, c2; - - c1 = *s1++; - c2 = *s2++; - - if (c1 != c2) - return (c1 < c2) ? -1 : 1; - - len1--; len2--; - } - - return (len1 < len2) ? -1 : (len1 != len2); -} - -#endif - -int PyUnicode_Compare(PyObject *left, - PyObject *right) -{ - PyUnicodeObject *u = NULL, *v = NULL; - int result; - - /* Coerce the two arguments */ - u = (PyUnicodeObject *)PyUnicode_FromObject(left); - if (u == NULL) - goto onError; - v = (PyUnicodeObject *)PyUnicode_FromObject(right); - if (v == NULL) - goto onError; - - /* Shortcut for empty or interned objects */ - if (v == u) { - Py_DECREF(u); - Py_DECREF(v); - return 0; - } - - result = unicode_compare(u, v); - - Py_DECREF(u); - Py_DECREF(v); - return result; - -onError: - Py_XDECREF(u); - Py_XDECREF(v); - return -1; -} - -PyObject *PyUnicode_RichCompare(PyObject *left, - PyObject *right, - int op) -{ - int result; - - result = PyUnicode_Compare(left, right); - if (result == -1 && PyErr_Occurred()) - goto onError; - - /* Convert the return value to a Boolean */ - switch (op) { - case Py_EQ: - result = (result == 0); - break; - case Py_NE: - result = (result != 0); - break; - case Py_LE: - result = (result <= 0); - break; - case Py_GE: - result = (result >= 0); - break; - case Py_LT: - result = (result == -1); - break; - case Py_GT: - result = (result == 1); - break; - } - return PyBool_FromLong(result); - - onError: - - /* Standard case - - Type errors mean that PyUnicode_FromObject() could not convert - one of the arguments (usually the right hand side) to Unicode, - ie. we can't handle the comparison request. However, it is - possible that the other object knows a comparison method, which - is why we return Py_NotImplemented to give the other object a - chance. - - */ - if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Clear(); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - if (op != Py_EQ && op != Py_NE) - return NULL; - - /* Equality comparison. - - This is a special case: we silence any PyExc_UnicodeDecodeError - and instead turn it into a PyErr_UnicodeWarning. - - */ - if (!PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) - return NULL; - PyErr_Clear(); - if (PyErr_Warn(PyExc_UnicodeWarning, - (op == Py_EQ) ? - "Unicode equal comparison " - "failed to convert both arguments to Unicode - " - "interpreting them as being unequal" : - "Unicode unequal comparison " - "failed to convert both arguments to Unicode - " - "interpreting them as being unequal" - ) < 0) - return NULL; - result = (op == Py_NE); - return PyBool_FromLong(result); -} - -int PyUnicode_Contains(PyObject *container, - PyObject *element) -{ - PyObject *str, *sub; - int result; - - /* Coerce the two arguments */ - sub = PyUnicode_FromObject(element); - if (!sub) { - PyErr_SetString(PyExc_TypeError, - "'in <string>' requires string as left operand"); - return -1; - } - - str = PyUnicode_FromObject(container); - if (!str) { - Py_DECREF(sub); - return -1; - } - - result = stringlib_contains_obj(str, sub); - - Py_DECREF(str); - Py_DECREF(sub); - - return result; -} - -/* Concat to string or Unicode object giving a new Unicode object. */ - -PyObject *PyUnicode_Concat(PyObject *left, - PyObject *right) -{ - PyUnicodeObject *u = NULL, *v = NULL, *w; - - /* Coerce the two arguments */ - u = (PyUnicodeObject *)PyUnicode_FromObject(left); - if (u == NULL) - goto onError; - v = (PyUnicodeObject *)PyUnicode_FromObject(right); - if (v == NULL) - goto onError; - - /* Shortcuts */ - if (v == unicode_empty) { - Py_DECREF(v); - return (PyObject *)u; - } - if (u == unicode_empty) { - Py_DECREF(u); - return (PyObject *)v; - } - - /* Concat the two Unicode strings */ - w = _PyUnicode_New(u->length + v->length); - if (w == NULL) - goto onError; - Py_UNICODE_COPY(w->str, u->str, u->length); - Py_UNICODE_COPY(w->str + u->length, v->str, v->length); - - Py_DECREF(u); - Py_DECREF(v); - return (PyObject *)w; - -onError: - Py_XDECREF(u); - Py_XDECREF(v); - return NULL; -} - -PyDoc_STRVAR(count__doc__, -"S.count(sub[, start[, end]]) -> int\n\ -\n\ -Return the number of non-overlapping occurrences of substring sub in\n\ -Unicode string S[start:end]. Optional arguments start and end are\n\ -interpreted as in slice notation."); - -static PyObject * -unicode_count(PyUnicodeObject *self, PyObject *args) -{ - PyUnicodeObject *substring; - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - PyObject *result; - - if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - - substring = (PyUnicodeObject *)PyUnicode_FromObject( - (PyObject *)substring); - if (substring == NULL) - return NULL; - - FIX_START_END(self); - - result = PyInt_FromSsize_t( - stringlib_count(self->str + start, end - start, - substring->str, substring->length) - ); - - Py_DECREF(substring); - - return result; -} - -PyDoc_STRVAR(encode__doc__, -"S.encode([encoding[,errors]]) -> string or unicode\n\ -\n\ -Encodes S using the codec registered for encoding. encoding defaults\n\ -to the default encoding. errors may be given to set a different error\n\ -handling scheme. Default is 'strict' meaning that encoding errors raise\n\ -a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and\n\ -'xmlcharrefreplace' as well as any other name registered with\n\ -codecs.register_error that can handle UnicodeEncodeErrors."); - -static PyObject * -unicode_encode(PyUnicodeObject *self, PyObject *args) -{ - char *encoding = NULL; - char *errors = NULL; - PyObject *v; - - if (!PyArg_ParseTuple(args, "|ss:encode", &encoding, &errors)) - return NULL; - v = PyUnicode_AsEncodedObject((PyObject *)self, encoding, errors); - if (v == NULL) - goto onError; - if (!PyString_Check(v) && !PyUnicode_Check(v)) { - PyErr_Format(PyExc_TypeError, - "encoder did not return a string/unicode object " - "(type=%.400s)", - v->ob_type->tp_name); - Py_DECREF(v); - return NULL; - } - return v; - - onError: - return NULL; -} - -PyDoc_STRVAR(decode__doc__, -"S.decode([encoding[,errors]]) -> string or unicode\n\ -\n\ -Decodes S using the codec registered for encoding. encoding defaults\n\ -to the default encoding. errors may be given to set a different error\n\ -handling scheme. Default is 'strict' meaning that encoding errors raise\n\ -a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'\n\ -as well as any other name registerd with codecs.register_error that is\n\ -able to handle UnicodeDecodeErrors."); - -static PyObject * -unicode_decode(PyUnicodeObject *self, PyObject *args) -{ - char *encoding = NULL; - char *errors = NULL; - PyObject *v; - - if (!PyArg_ParseTuple(args, "|ss:decode", &encoding, &errors)) - return NULL; - v = PyUnicode_AsDecodedObject((PyObject *)self, encoding, errors); - if (v == NULL) - goto onError; - if (!PyString_Check(v) && !PyUnicode_Check(v)) { - PyErr_Format(PyExc_TypeError, - "decoder did not return a string/unicode object " - "(type=%.400s)", - v->ob_type->tp_name); - Py_DECREF(v); - return NULL; - } - return v; - - onError: - return NULL; -} - -PyDoc_STRVAR(expandtabs__doc__, -"S.expandtabs([tabsize]) -> unicode\n\ -\n\ -Return a copy of S where all tab characters are expanded using spaces.\n\ -If tabsize is not given, a tab size of 8 characters is assumed."); - -static PyObject* -unicode_expandtabs(PyUnicodeObject *self, PyObject *args) -{ - Py_UNICODE *e; - Py_UNICODE *p; - Py_UNICODE *q; - Py_ssize_t i, j; - PyUnicodeObject *u; - int tabsize = 8; - - if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize)) - return NULL; - - /* First pass: determine size of output string */ - i = j = 0; - e = self->str + self->length; - for (p = self->str; p < e; p++) - if (*p == '\t') { - if (tabsize > 0) - j += tabsize - (j % tabsize); - } - else { - j++; - if (*p == '\n' || *p == '\r') { - i += j; - j = 0; - } - } - - /* Second pass: create output string and fill it */ - u = _PyUnicode_New(i + j); - if (!u) - return NULL; - - j = 0; - q = u->str; - - for (p = self->str; p < e; p++) - if (*p == '\t') { - if (tabsize > 0) { - i = tabsize - (j % tabsize); - j += i; - while (i--) - *q++ = ' '; - } - } - else { - j++; - *q++ = *p; - if (*p == '\n' || *p == '\r') - j = 0; - } - - return (PyObject*) u; -} - -PyDoc_STRVAR(find__doc__, -"S.find(sub [,start [,end]]) -> int\n\ -\n\ -Return the lowest index in S where substring sub is found,\n\ -such that sub is contained within s[start,end]. Optional\n\ -arguments start and end are interpreted as in slice notation.\n\ -\n\ -Return -1 on failure."); - -static PyObject * -unicode_find(PyUnicodeObject *self, PyObject *args) -{ - PyObject *substring; - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - Py_ssize_t result; - - if (!PyArg_ParseTuple(args, "O|O&O&:find", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - substring = PyUnicode_FromObject(substring); - if (!substring) - return NULL; - - result = stringlib_find_slice( - PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self), - PyUnicode_AS_UNICODE(substring), PyUnicode_GET_SIZE(substring), - start, end - ); - - Py_DECREF(substring); - - return PyInt_FromSsize_t(result); -} - -static PyObject * -unicode_getitem(PyUnicodeObject *self, Py_ssize_t index) -{ - if (index < 0 || index >= self->length) { - PyErr_SetString(PyExc_IndexError, "string index out of range"); - return NULL; - } - - return (PyObject*) PyUnicode_FromUnicode(&self->str[index], 1); -} - -static long -unicode_hash(PyUnicodeObject *self) -{ - /* Since Unicode objects compare equal to their ASCII string - counterparts, they should use the individual character values - as basis for their hash value. This is needed to assure that - strings and Unicode objects behave in the same way as - dictionary keys. */ - - register Py_ssize_t len; - register Py_UNICODE *p; - register long x; - - if (self->hash != -1) - return self->hash; - len = PyUnicode_GET_SIZE(self); - p = PyUnicode_AS_UNICODE(self); - x = *p << 7; - while (--len >= 0) - x = (1000003*x) ^ *p++; - x ^= PyUnicode_GET_SIZE(self); - if (x == -1) - x = -2; - self->hash = x; - return x; -} - -PyDoc_STRVAR(index__doc__, -"S.index(sub [,start [,end]]) -> int\n\ -\n\ -Like S.find() but raise ValueError when the substring is not found."); - -static PyObject * -unicode_index(PyUnicodeObject *self, PyObject *args) -{ - Py_ssize_t result; - PyObject *substring; - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - - if (!PyArg_ParseTuple(args, "O|O&O&:index", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - substring = PyUnicode_FromObject(substring); - if (!substring) - return NULL; - - result = stringlib_find_slice( - PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self), - PyUnicode_AS_UNICODE(substring), PyUnicode_GET_SIZE(substring), - start, end - ); - - Py_DECREF(substring); - - if (result < 0) { - PyErr_SetString(PyExc_ValueError, "substring not found"); - return NULL; - } - - return PyInt_FromSsize_t(result); -} - -PyDoc_STRVAR(islower__doc__, -"S.islower() -> bool\n\ -\n\ -Return True if all cased characters in S are lowercase and there is\n\ -at least one cased character in S, False otherwise."); - -static PyObject* -unicode_islower(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - int cased; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1) - return PyBool_FromLong(Py_UNICODE_ISLOWER(*p)); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - cased = 0; - for (; p < e; p++) { - register const Py_UNICODE ch = *p; - - if (Py_UNICODE_ISUPPER(ch) || Py_UNICODE_ISTITLE(ch)) - return PyBool_FromLong(0); - else if (!cased && Py_UNICODE_ISLOWER(ch)) - cased = 1; - } - return PyBool_FromLong(cased); -} - -PyDoc_STRVAR(isupper__doc__, -"S.isupper() -> bool\n\ -\n\ -Return True if all cased characters in S are uppercase and there is\n\ -at least one cased character in S, False otherwise."); - -static PyObject* -unicode_isupper(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - int cased; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1) - return PyBool_FromLong(Py_UNICODE_ISUPPER(*p) != 0); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - cased = 0; - for (; p < e; p++) { - register const Py_UNICODE ch = *p; - - if (Py_UNICODE_ISLOWER(ch) || Py_UNICODE_ISTITLE(ch)) - return PyBool_FromLong(0); - else if (!cased && Py_UNICODE_ISUPPER(ch)) - cased = 1; - } - return PyBool_FromLong(cased); -} - -PyDoc_STRVAR(istitle__doc__, -"S.istitle() -> bool\n\ -\n\ -Return True if S is a titlecased string and there is at least one\n\ -character in S, i.e. upper- and titlecase characters may only\n\ -follow uncased characters and lowercase characters only cased ones.\n\ -Return False otherwise."); - -static PyObject* -unicode_istitle(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - int cased, previous_is_cased; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1) - return PyBool_FromLong((Py_UNICODE_ISTITLE(*p) != 0) || - (Py_UNICODE_ISUPPER(*p) != 0)); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - cased = 0; - previous_is_cased = 0; - for (; p < e; p++) { - register const Py_UNICODE ch = *p; - - if (Py_UNICODE_ISUPPER(ch) || Py_UNICODE_ISTITLE(ch)) { - if (previous_is_cased) - return PyBool_FromLong(0); - previous_is_cased = 1; - cased = 1; - } - else if (Py_UNICODE_ISLOWER(ch)) { - if (!previous_is_cased) - return PyBool_FromLong(0); - previous_is_cased = 1; - cased = 1; - } - else - previous_is_cased = 0; - } - return PyBool_FromLong(cased); -} - -PyDoc_STRVAR(isspace__doc__, -"S.isspace() -> bool\n\ -\n\ -Return True if all characters in S are whitespace\n\ -and there is at least one character in S, False otherwise."); - -static PyObject* -unicode_isspace(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1 && - Py_UNICODE_ISSPACE(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - for (; p < e; p++) { - if (!Py_UNICODE_ISSPACE(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - -PyDoc_STRVAR(isalpha__doc__, -"S.isalpha() -> bool\n\ -\n\ -Return True if all characters in S are alphabetic\n\ -and there is at least one character in S, False otherwise."); - -static PyObject* -unicode_isalpha(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1 && - Py_UNICODE_ISALPHA(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - for (; p < e; p++) { - if (!Py_UNICODE_ISALPHA(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - -PyDoc_STRVAR(isalnum__doc__, -"S.isalnum() -> bool\n\ -\n\ -Return True if all characters in S are alphanumeric\n\ -and there is at least one character in S, False otherwise."); - -static PyObject* -unicode_isalnum(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1 && - Py_UNICODE_ISALNUM(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - for (; p < e; p++) { - if (!Py_UNICODE_ISALNUM(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - -PyDoc_STRVAR(isdecimal__doc__, -"S.isdecimal() -> bool\n\ -\n\ -Return True if there are only decimal characters in S,\n\ -False otherwise."); - -static PyObject* -unicode_isdecimal(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1 && - Py_UNICODE_ISDECIMAL(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - for (; p < e; p++) { - if (!Py_UNICODE_ISDECIMAL(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - -PyDoc_STRVAR(isdigit__doc__, -"S.isdigit() -> bool\n\ -\n\ -Return True if all characters in S are digits\n\ -and there is at least one character in S, False otherwise."); - -static PyObject* -unicode_isdigit(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1 && - Py_UNICODE_ISDIGIT(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - for (; p < e; p++) { - if (!Py_UNICODE_ISDIGIT(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - -PyDoc_STRVAR(isnumeric__doc__, -"S.isnumeric() -> bool\n\ -\n\ -Return True if there are only numeric characters in S,\n\ -False otherwise."); - -static PyObject* -unicode_isnumeric(PyUnicodeObject *self) -{ - register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); - register const Py_UNICODE *e; - - /* Shortcut for single character strings */ - if (PyUnicode_GET_SIZE(self) == 1 && - Py_UNICODE_ISNUMERIC(*p)) - return PyBool_FromLong(1); - - /* Special case for empty strings */ - if (PyUnicode_GET_SIZE(self) == 0) - return PyBool_FromLong(0); - - e = p + PyUnicode_GET_SIZE(self); - for (; p < e; p++) { - if (!Py_UNICODE_ISNUMERIC(*p)) - return PyBool_FromLong(0); - } - return PyBool_FromLong(1); -} - -PyDoc_STRVAR(join__doc__, -"S.join(sequence) -> unicode\n\ -\n\ -Return a string which is the concatenation of the strings in the\n\ -sequence. The separator between elements is S."); - -static PyObject* -unicode_join(PyObject *self, PyObject *data) -{ - return PyUnicode_Join(self, data); -} - -static Py_ssize_t -unicode_length(PyUnicodeObject *self) -{ - return self->length; -} - -PyDoc_STRVAR(ljust__doc__, -"S.ljust(width[, fillchar]) -> int\n\ -\n\ -Return S left justified in a Unicode string of length width. Padding is\n\ -done using the specified fill character (default is a space)."); - -static PyObject * -unicode_ljust(PyUnicodeObject *self, PyObject *args) -{ - Py_ssize_t width; - Py_UNICODE fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|O&:ljust", &width, convert_uc, &fillchar)) - return NULL; - - if (self->length >= width && PyUnicode_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*) self; - } - - return (PyObject*) pad(self, 0, width - self->length, fillchar); -} - -PyDoc_STRVAR(lower__doc__, -"S.lower() -> unicode\n\ -\n\ -Return a copy of the string S converted to lowercase."); - -static PyObject* -unicode_lower(PyUnicodeObject *self) -{ - return fixup(self, fixlower); -} - -#define LEFTSTRIP 0 -#define RIGHTSTRIP 1 -#define BOTHSTRIP 2 - -/* Arrays indexed by above */ -static const char *stripformat[] = {"|O:lstrip", "|O:rstrip", "|O:strip"}; - -#define STRIPNAME(i) (stripformat[i]+3) - -/* externally visible for str.strip(unicode) */ -PyObject * -_PyUnicode_XStrip(PyUnicodeObject *self, int striptype, PyObject *sepobj) -{ - Py_UNICODE *s = PyUnicode_AS_UNICODE(self); - Py_ssize_t len = PyUnicode_GET_SIZE(self); - Py_UNICODE *sep = PyUnicode_AS_UNICODE(sepobj); - Py_ssize_t seplen = PyUnicode_GET_SIZE(sepobj); - Py_ssize_t i, j; - - BLOOM_MASK sepmask = make_bloom_mask(sep, seplen); - - i = 0; - if (striptype != RIGHTSTRIP) { - while (i < len && BLOOM_MEMBER(sepmask, s[i], sep, seplen)) { - i++; - } - } - - j = len; - if (striptype != LEFTSTRIP) { - do { - j--; - } while (j >= i && BLOOM_MEMBER(sepmask, s[j], sep, seplen)); - j++; - } - - if (i == 0 && j == len && PyUnicode_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*)self; - } - else - return PyUnicode_FromUnicode(s+i, j-i); -} - - -static PyObject * -do_strip(PyUnicodeObject *self, int striptype) -{ - Py_UNICODE *s = PyUnicode_AS_UNICODE(self); - Py_ssize_t len = PyUnicode_GET_SIZE(self), i, j; - - i = 0; - if (striptype != RIGHTSTRIP) { - while (i < len && Py_UNICODE_ISSPACE(s[i])) { - i++; - } - } - - j = len; - if (striptype != LEFTSTRIP) { - do { - j--; - } while (j >= i && Py_UNICODE_ISSPACE(s[j])); - j++; - } - - if (i == 0 && j == len && PyUnicode_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*)self; - } - else - return PyUnicode_FromUnicode(s+i, j-i); -} - - -static PyObject * -do_argstrip(PyUnicodeObject *self, int striptype, PyObject *args) -{ - PyObject *sep = NULL; - - if (!PyArg_ParseTuple(args, (char *)stripformat[striptype], &sep)) - return NULL; - - if (sep != NULL && sep != Py_None) { - if (PyUnicode_Check(sep)) - return _PyUnicode_XStrip(self, striptype, sep); - else if (PyString_Check(sep)) { - PyObject *res; - sep = PyUnicode_FromObject(sep); - if (sep==NULL) - return NULL; - res = _PyUnicode_XStrip(self, striptype, sep); - Py_DECREF(sep); - return res; - } - else { - PyErr_Format(PyExc_TypeError, - "%s arg must be None, unicode or str", - STRIPNAME(striptype)); - return NULL; - } - } - - return do_strip(self, striptype); -} - - -PyDoc_STRVAR(strip__doc__, -"S.strip([chars]) -> unicode\n\ -\n\ -Return a copy of the string S with leading and trailing\n\ -whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead.\n\ -If chars is a str, it will be converted to unicode before stripping"); - -static PyObject * -unicode_strip(PyUnicodeObject *self, PyObject *args) -{ - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, BOTHSTRIP); /* Common case */ - else - return do_argstrip(self, BOTHSTRIP, args); -} - - -PyDoc_STRVAR(lstrip__doc__, -"S.lstrip([chars]) -> unicode\n\ -\n\ -Return a copy of the string S with leading whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead.\n\ -If chars is a str, it will be converted to unicode before stripping"); - -static PyObject * -unicode_lstrip(PyUnicodeObject *self, PyObject *args) -{ - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, LEFTSTRIP); /* Common case */ - else - return do_argstrip(self, LEFTSTRIP, args); -} - - -PyDoc_STRVAR(rstrip__doc__, -"S.rstrip([chars]) -> unicode\n\ -\n\ -Return a copy of the string S with trailing whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead.\n\ -If chars is a str, it will be converted to unicode before stripping"); - -static PyObject * -unicode_rstrip(PyUnicodeObject *self, PyObject *args) -{ - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, RIGHTSTRIP); /* Common case */ - else - return do_argstrip(self, RIGHTSTRIP, args); -} - - -static PyObject* -unicode_repeat(PyUnicodeObject *str, Py_ssize_t len) -{ - PyUnicodeObject *u; - Py_UNICODE *p; - Py_ssize_t nchars; - size_t nbytes; - - if (len < 0) - len = 0; - - if (len == 1 && PyUnicode_CheckExact(str)) { - /* no repeat, return original string */ - Py_INCREF(str); - return (PyObject*) str; - } - - /* ensure # of chars needed doesn't overflow int and # of bytes - * needed doesn't overflow size_t - */ - nchars = len * str->length; - if (len && nchars / len != str->length) { - PyErr_SetString(PyExc_OverflowError, - "repeated string is too long"); - return NULL; - } - nbytes = (nchars + 1) * sizeof(Py_UNICODE); - if (nbytes / sizeof(Py_UNICODE) != (size_t)(nchars + 1)) { - PyErr_SetString(PyExc_OverflowError, - "repeated string is too long"); - return NULL; - } - u = _PyUnicode_New(nchars); - if (!u) - return NULL; - - p = u->str; - - if (str->length == 1 && len > 0) { - Py_UNICODE_FILL(p, str->str[0], len); - } else { - Py_ssize_t done = 0; /* number of characters copied this far */ - if (done < nchars) { - Py_UNICODE_COPY(p, str->str, str->length); - done = str->length; - } - while (done < nchars) { - int n = (done <= nchars-done) ? done : nchars-done; - Py_UNICODE_COPY(p+done, p, n); - done += n; - } - } - - return (PyObject*) u; -} - -PyObject *PyUnicode_Replace(PyObject *obj, - PyObject *subobj, - PyObject *replobj, - Py_ssize_t maxcount) -{ - PyObject *self; - PyObject *str1; - PyObject *str2; - PyObject *result; - - self = PyUnicode_FromObject(obj); - if (self == NULL) - return NULL; - str1 = PyUnicode_FromObject(subobj); - if (str1 == NULL) { - Py_DECREF(self); - return NULL; - } - str2 = PyUnicode_FromObject(replobj); - if (str2 == NULL) { - Py_DECREF(self); - Py_DECREF(str1); - return NULL; - } - result = replace((PyUnicodeObject *)self, - (PyUnicodeObject *)str1, - (PyUnicodeObject *)str2, - maxcount); - Py_DECREF(self); - Py_DECREF(str1); - Py_DECREF(str2); - return result; -} - -PyDoc_STRVAR(replace__doc__, -"S.replace (old, new[, maxsplit]) -> unicode\n\ -\n\ -Return a copy of S with all occurrences of substring\n\ -old replaced by new. If the optional argument maxsplit is\n\ -given, only the first maxsplit occurrences are replaced."); - -static PyObject* -unicode_replace(PyUnicodeObject *self, PyObject *args) -{ - PyUnicodeObject *str1; - PyUnicodeObject *str2; - Py_ssize_t maxcount = -1; - PyObject *result; - - if (!PyArg_ParseTuple(args, "OO|n:replace", &str1, &str2, &maxcount)) - return NULL; - str1 = (PyUnicodeObject *)PyUnicode_FromObject((PyObject *)str1); - if (str1 == NULL) - return NULL; - str2 = (PyUnicodeObject *)PyUnicode_FromObject((PyObject *)str2); - if (str2 == NULL) { - Py_DECREF(str1); - return NULL; - } - - result = replace(self, str1, str2, maxcount); - - Py_DECREF(str1); - Py_DECREF(str2); - return result; -} - -static -PyObject *unicode_repr(PyObject *unicode) -{ - return unicodeescape_string(PyUnicode_AS_UNICODE(unicode), - PyUnicode_GET_SIZE(unicode), - 1); -} - -PyDoc_STRVAR(rfind__doc__, -"S.rfind(sub [,start [,end]]) -> int\n\ -\n\ -Return the highest index in S where substring sub is found,\n\ -such that sub is contained within s[start,end]. Optional\n\ -arguments start and end are interpreted as in slice notation.\n\ -\n\ -Return -1 on failure."); - -static PyObject * -unicode_rfind(PyUnicodeObject *self, PyObject *args) -{ - PyObject *substring; - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - Py_ssize_t result; - - if (!PyArg_ParseTuple(args, "O|O&O&:rfind", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - substring = PyUnicode_FromObject(substring); - if (!substring) - return NULL; - - result = stringlib_rfind_slice( - PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self), - PyUnicode_AS_UNICODE(substring), PyUnicode_GET_SIZE(substring), - start, end - ); - - Py_DECREF(substring); - - return PyInt_FromSsize_t(result); -} - -PyDoc_STRVAR(rindex__doc__, -"S.rindex(sub [,start [,end]]) -> int\n\ -\n\ -Like S.rfind() but raise ValueError when the substring is not found."); - -static PyObject * -unicode_rindex(PyUnicodeObject *self, PyObject *args) -{ - PyObject *substring; - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - Py_ssize_t result; - - if (!PyArg_ParseTuple(args, "O|O&O&:rindex", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - substring = PyUnicode_FromObject(substring); - if (!substring) - return NULL; - - result = stringlib_rfind_slice( - PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self), - PyUnicode_AS_UNICODE(substring), PyUnicode_GET_SIZE(substring), - start, end - ); - - Py_DECREF(substring); - - if (result < 0) { - PyErr_SetString(PyExc_ValueError, "substring not found"); - return NULL; - } - return PyInt_FromSsize_t(result); -} - -PyDoc_STRVAR(rjust__doc__, -"S.rjust(width[, fillchar]) -> unicode\n\ -\n\ -Return S right justified in a Unicode string of length width. Padding is\n\ -done using the specified fill character (default is a space)."); - -static PyObject * -unicode_rjust(PyUnicodeObject *self, PyObject *args) -{ - Py_ssize_t width; - Py_UNICODE fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|O&:rjust", &width, convert_uc, &fillchar)) - return NULL; - - if (self->length >= width && PyUnicode_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*) self; - } - - return (PyObject*) pad(self, width - self->length, 0, fillchar); -} - -static PyObject* -unicode_slice(PyUnicodeObject *self, Py_ssize_t start, Py_ssize_t end) -{ - /* standard clamping */ - if (start < 0) - start = 0; - if (end < 0) - end = 0; - if (end > self->length) - end = self->length; - if (start == 0 && end == self->length && PyUnicode_CheckExact(self)) { - /* full slice, return original string */ - Py_INCREF(self); - return (PyObject*) self; - } - if (start > end) - start = end; - /* copy slice */ - return (PyObject*) PyUnicode_FromUnicode(self->str + start, - end - start); -} - -PyObject *PyUnicode_Split(PyObject *s, - PyObject *sep, - Py_ssize_t maxsplit) -{ - PyObject *result; - - s = PyUnicode_FromObject(s); - if (s == NULL) - return NULL; - if (sep != NULL) { - sep = PyUnicode_FromObject(sep); - if (sep == NULL) { - Py_DECREF(s); - return NULL; - } - } - - result = split((PyUnicodeObject *)s, (PyUnicodeObject *)sep, maxsplit); - - Py_DECREF(s); - Py_XDECREF(sep); - return result; -} - -PyDoc_STRVAR(split__doc__, -"S.split([sep [,maxsplit]]) -> list of strings\n\ -\n\ -Return a list of the words in S, using sep as the\n\ -delimiter string. If maxsplit is given, at most maxsplit\n\ -splits are done. If sep is not specified or is None,\n\ -any whitespace string is a separator."); - -static PyObject* -unicode_split(PyUnicodeObject *self, PyObject *args) -{ - PyObject *substring = Py_None; - Py_ssize_t maxcount = -1; - - if (!PyArg_ParseTuple(args, "|On:split", &substring, &maxcount)) - return NULL; - - if (substring == Py_None) - return split(self, NULL, maxcount); - else if (PyUnicode_Check(substring)) - return split(self, (PyUnicodeObject *)substring, maxcount); - else - return PyUnicode_Split((PyObject *)self, substring, maxcount); -} - -PyObject * -PyUnicode_Partition(PyObject *str_in, PyObject *sep_in) -{ - PyObject* str_obj; - PyObject* sep_obj; - PyObject* out; - - str_obj = PyUnicode_FromObject(str_in); - if (!str_obj) - return NULL; - sep_obj = PyUnicode_FromObject(sep_in); - if (!sep_obj) { - Py_DECREF(str_obj); - return NULL; - } - - out = stringlib_partition( - str_obj, PyUnicode_AS_UNICODE(str_obj), PyUnicode_GET_SIZE(str_obj), - sep_obj, PyUnicode_AS_UNICODE(sep_obj), PyUnicode_GET_SIZE(sep_obj) - ); - - Py_DECREF(sep_obj); - Py_DECREF(str_obj); - - return out; -} - - -PyObject * -PyUnicode_RPartition(PyObject *str_in, PyObject *sep_in) -{ - PyObject* str_obj; - PyObject* sep_obj; - PyObject* out; - - str_obj = PyUnicode_FromObject(str_in); - if (!str_obj) - return NULL; - sep_obj = PyUnicode_FromObject(sep_in); - if (!sep_obj) { - Py_DECREF(str_obj); - return NULL; - } - - out = stringlib_rpartition( - str_obj, PyUnicode_AS_UNICODE(str_obj), PyUnicode_GET_SIZE(str_obj), - sep_obj, PyUnicode_AS_UNICODE(sep_obj), PyUnicode_GET_SIZE(sep_obj) - ); - - Py_DECREF(sep_obj); - Py_DECREF(str_obj); - - return out; -} - -PyDoc_STRVAR(partition__doc__, -"S.partition(sep) -> (head, sep, tail)\n\ -\n\ -Searches for the separator sep in S, and returns the part before it,\n\ -the separator itself, and the part after it. If the separator is not\n\ -found, returns S and two empty strings."); - -static PyObject* -unicode_partition(PyUnicodeObject *self, PyObject *separator) -{ - return PyUnicode_Partition((PyObject *)self, separator); -} - -PyDoc_STRVAR(rpartition__doc__, -"S.rpartition(sep) -> (tail, sep, head)\n\ -\n\ -Searches for the separator sep in S, starting at the end of S, and returns\n\ -the part before it, the separator itself, and the part after it. If the\n\ -separator is not found, returns two empty strings and S."); - -static PyObject* -unicode_rpartition(PyUnicodeObject *self, PyObject *separator) -{ - return PyUnicode_RPartition((PyObject *)self, separator); -} - -PyObject *PyUnicode_RSplit(PyObject *s, - PyObject *sep, - Py_ssize_t maxsplit) -{ - PyObject *result; - - s = PyUnicode_FromObject(s); - if (s == NULL) - return NULL; - if (sep != NULL) { - sep = PyUnicode_FromObject(sep); - if (sep == NULL) { - Py_DECREF(s); - return NULL; - } - } - - result = rsplit((PyUnicodeObject *)s, (PyUnicodeObject *)sep, maxsplit); - - Py_DECREF(s); - Py_XDECREF(sep); - return result; -} - -PyDoc_STRVAR(rsplit__doc__, -"S.rsplit([sep [,maxsplit]]) -> list of strings\n\ -\n\ -Return a list of the words in S, using sep as the\n\ -delimiter string, starting at the end of the string and\n\ -working to the front. If maxsplit is given, at most maxsplit\n\ -splits are done. If sep is not specified, any whitespace string\n\ -is a separator."); - -static PyObject* -unicode_rsplit(PyUnicodeObject *self, PyObject *args) -{ - PyObject *substring = Py_None; - Py_ssize_t maxcount = -1; - - if (!PyArg_ParseTuple(args, "|On:rsplit", &substring, &maxcount)) - return NULL; - - if (substring == Py_None) - return rsplit(self, NULL, maxcount); - else if (PyUnicode_Check(substring)) - return rsplit(self, (PyUnicodeObject *)substring, maxcount); - else - return PyUnicode_RSplit((PyObject *)self, substring, maxcount); -} - -PyDoc_STRVAR(splitlines__doc__, -"S.splitlines([keepends]]) -> list of strings\n\ -\n\ -Return a list of the lines in S, breaking at line boundaries.\n\ -Line breaks are not included in the resulting list unless keepends\n\ -is given and true."); - -static PyObject* -unicode_splitlines(PyUnicodeObject *self, PyObject *args) -{ - int keepends = 0; - - if (!PyArg_ParseTuple(args, "|i:splitlines", &keepends)) - return NULL; - - return PyUnicode_Splitlines((PyObject *)self, keepends); -} - -static -PyObject *unicode_str(PyUnicodeObject *self) -{ - return PyUnicode_AsEncodedString((PyObject *)self, NULL, NULL); -} - -PyDoc_STRVAR(swapcase__doc__, -"S.swapcase() -> unicode\n\ -\n\ -Return a copy of S with uppercase characters converted to lowercase\n\ -and vice versa."); - -static PyObject* -unicode_swapcase(PyUnicodeObject *self) -{ - return fixup(self, fixswapcase); -} - -PyDoc_STRVAR(translate__doc__, -"S.translate(table) -> unicode\n\ -\n\ -Return a copy of the string S, where all characters have been mapped\n\ -through the given translation table, which must be a mapping of\n\ -Unicode ordinals to Unicode ordinals, Unicode strings or None.\n\ -Unmapped characters are left untouched. Characters mapped to None\n\ -are deleted."); - -static PyObject* -unicode_translate(PyUnicodeObject *self, PyObject *table) -{ - return PyUnicode_TranslateCharmap(self->str, - self->length, - table, - "ignore"); -} - -PyDoc_STRVAR(upper__doc__, -"S.upper() -> unicode\n\ -\n\ -Return a copy of S converted to uppercase."); - -static PyObject* -unicode_upper(PyUnicodeObject *self) -{ - return fixup(self, fixupper); -} - -PyDoc_STRVAR(zfill__doc__, -"S.zfill(width) -> unicode\n\ -\n\ -Pad a numeric string x with zeros on the left, to fill a field\n\ -of the specified width. The string x is never truncated."); - -static PyObject * -unicode_zfill(PyUnicodeObject *self, PyObject *args) -{ - Py_ssize_t fill; - PyUnicodeObject *u; - - Py_ssize_t width; - if (!PyArg_ParseTuple(args, "n:zfill", &width)) - return NULL; - - if (self->length >= width) { - if (PyUnicode_CheckExact(self)) { - Py_INCREF(self); - return (PyObject*) self; - } - else - return PyUnicode_FromUnicode( - PyUnicode_AS_UNICODE(self), - PyUnicode_GET_SIZE(self) - ); - } - - fill = width - self->length; - - u = pad(self, fill, 0, '0'); - - if (u == NULL) - return NULL; - - if (u->str[fill] == '+' || u->str[fill] == '-') { - /* move sign to beginning of string */ - u->str[0] = u->str[fill]; - u->str[fill] = '0'; - } - - return (PyObject*) u; -} - -#if 0 -static PyObject* -unicode_freelistsize(PyUnicodeObject *self) -{ - return PyInt_FromLong(unicode_freelist_size); -} -#endif - -PyDoc_STRVAR(startswith__doc__, -"S.startswith(prefix[, start[, end]]) -> bool\n\ -\n\ -Return True if S starts with the specified prefix, False otherwise.\n\ -With optional start, test S beginning at that position.\n\ -With optional end, stop comparing S at that position.\n\ -prefix can also be a tuple of strings to try."); - -static PyObject * -unicode_startswith(PyUnicodeObject *self, - PyObject *args) -{ - PyObject *subobj; - PyUnicodeObject *substring; - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - int result; - - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - if (PyTuple_Check(subobj)) { - Py_ssize_t i; - for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { - substring = (PyUnicodeObject *)PyUnicode_FromObject( - PyTuple_GET_ITEM(subobj, i)); - if (substring == NULL) - return NULL; - result = tailmatch(self, substring, start, end, -1); - Py_DECREF(substring); - if (result) { - Py_RETURN_TRUE; - } - } - /* nothing matched */ - Py_RETURN_FALSE; - } - substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) - return NULL; - result = tailmatch(self, substring, start, end, -1); - Py_DECREF(substring); - return PyBool_FromLong(result); -} - - -PyDoc_STRVAR(endswith__doc__, -"S.endswith(suffix[, start[, end]]) -> bool\n\ -\n\ -Return True if S ends with the specified suffix, False otherwise.\n\ -With optional start, test S beginning at that position.\n\ -With optional end, stop comparing S at that position.\n\ -suffix can also be a tuple of strings to try."); - -static PyObject * -unicode_endswith(PyUnicodeObject *self, - PyObject *args) -{ - PyObject *subobj; - PyUnicodeObject *substring; - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - int result; - - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - if (PyTuple_Check(subobj)) { - Py_ssize_t i; - for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { - substring = (PyUnicodeObject *)PyUnicode_FromObject( - PyTuple_GET_ITEM(subobj, i)); - if (substring == NULL) - return NULL; - result = tailmatch(self, substring, start, end, +1); - Py_DECREF(substring); - if (result) { - Py_RETURN_TRUE; - } - } - Py_RETURN_FALSE; - } - substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) - return NULL; - - result = tailmatch(self, substring, start, end, +1); - Py_DECREF(substring); - return PyBool_FromLong(result); -} - - - -static PyObject * -unicode_getnewargs(PyUnicodeObject *v) -{ - return Py_BuildValue("(u#)", v->str, v->length); -} - - -static PyMethodDef unicode_methods[] = { - - /* Order is according to common usage: often used methods should - appear first, since lookup is done sequentially. */ - - {"encode", (PyCFunction) unicode_encode, METH_VARARGS, encode__doc__}, - {"replace", (PyCFunction) unicode_replace, METH_VARARGS, replace__doc__}, - {"split", (PyCFunction) unicode_split, METH_VARARGS, split__doc__}, - {"rsplit", (PyCFunction) unicode_rsplit, METH_VARARGS, rsplit__doc__}, - {"join", (PyCFunction) unicode_join, METH_O, join__doc__}, - {"capitalize", (PyCFunction) unicode_capitalize, METH_NOARGS, capitalize__doc__}, - {"title", (PyCFunction) unicode_title, METH_NOARGS, title__doc__}, - {"center", (PyCFunction) unicode_center, METH_VARARGS, center__doc__}, - {"count", (PyCFunction) unicode_count, METH_VARARGS, count__doc__}, - {"expandtabs", (PyCFunction) unicode_expandtabs, METH_VARARGS, expandtabs__doc__}, - {"find", (PyCFunction) unicode_find, METH_VARARGS, find__doc__}, - {"partition", (PyCFunction) unicode_partition, METH_O, partition__doc__}, - {"index", (PyCFunction) unicode_index, METH_VARARGS, index__doc__}, - {"ljust", (PyCFunction) unicode_ljust, METH_VARARGS, ljust__doc__}, - {"lower", (PyCFunction) unicode_lower, METH_NOARGS, lower__doc__}, - {"lstrip", (PyCFunction) unicode_lstrip, METH_VARARGS, lstrip__doc__}, - {"decode", (PyCFunction) unicode_decode, METH_VARARGS, decode__doc__}, -/* {"maketrans", (PyCFunction) unicode_maketrans, METH_VARARGS, maketrans__doc__}, */ - {"rfind", (PyCFunction) unicode_rfind, METH_VARARGS, rfind__doc__}, - {"rindex", (PyCFunction) unicode_rindex, METH_VARARGS, rindex__doc__}, - {"rjust", (PyCFunction) unicode_rjust, METH_VARARGS, rjust__doc__}, - {"rstrip", (PyCFunction) unicode_rstrip, METH_VARARGS, rstrip__doc__}, - {"rpartition", (PyCFunction) unicode_rpartition, METH_O, rpartition__doc__}, - {"splitlines", (PyCFunction) unicode_splitlines, METH_VARARGS, splitlines__doc__}, - {"strip", (PyCFunction) unicode_strip, METH_VARARGS, strip__doc__}, - {"swapcase", (PyCFunction) unicode_swapcase, METH_NOARGS, swapcase__doc__}, - {"translate", (PyCFunction) unicode_translate, METH_O, translate__doc__}, - {"upper", (PyCFunction) unicode_upper, METH_NOARGS, upper__doc__}, - {"startswith", (PyCFunction) unicode_startswith, METH_VARARGS, startswith__doc__}, - {"endswith", (PyCFunction) unicode_endswith, METH_VARARGS, endswith__doc__}, - {"islower", (PyCFunction) unicode_islower, METH_NOARGS, islower__doc__}, - {"isupper", (PyCFunction) unicode_isupper, METH_NOARGS, isupper__doc__}, - {"istitle", (PyCFunction) unicode_istitle, METH_NOARGS, istitle__doc__}, - {"isspace", (PyCFunction) unicode_isspace, METH_NOARGS, isspace__doc__}, - {"isdecimal", (PyCFunction) unicode_isdecimal, METH_NOARGS, isdecimal__doc__}, - {"isdigit", (PyCFunction) unicode_isdigit, METH_NOARGS, isdigit__doc__}, - {"isnumeric", (PyCFunction) unicode_isnumeric, METH_NOARGS, isnumeric__doc__}, - {"isalpha", (PyCFunction) unicode_isalpha, METH_NOARGS, isalpha__doc__}, - {"isalnum", (PyCFunction) unicode_isalnum, METH_NOARGS, isalnum__doc__}, - {"zfill", (PyCFunction) unicode_zfill, METH_VARARGS, zfill__doc__}, -#if 0 - {"capwords", (PyCFunction) unicode_capwords, METH_NOARGS, capwords__doc__}, -#endif - -#if 0 - /* This one is just used for debugging the implementation. */ - {"freelistsize", (PyCFunction) unicode_freelistsize, METH_NOARGS}, -#endif - - {"__getnewargs__", (PyCFunction)unicode_getnewargs, METH_NOARGS}, - {NULL, NULL} -}; - -static PyObject * -unicode_mod(PyObject *v, PyObject *w) -{ - if (!PyUnicode_Check(v)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyUnicode_Format(v, w); -} - -static PyNumberMethods unicode_as_number = { - 0, /*nb_add*/ - 0, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - unicode_mod, /*nb_remainder*/ -}; - -static PySequenceMethods unicode_as_sequence = { - (lenfunc) unicode_length, /* sq_length */ - PyUnicode_Concat, /* sq_concat */ - (ssizeargfunc) unicode_repeat, /* sq_repeat */ - (ssizeargfunc) unicode_getitem, /* sq_item */ - (ssizessizeargfunc) unicode_slice, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - PyUnicode_Contains, /* sq_contains */ -}; - -static PyObject* -unicode_subscript(PyUnicodeObject* self, PyObject* item) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += PyUnicode_GET_SIZE(self); - return unicode_getitem(self, i); - } else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength, cur, i; - Py_UNICODE* source_buf; - Py_UNICODE* result_buf; - PyObject* result; - - if (PySlice_GetIndicesEx((PySliceObject*)item, PyUnicode_GET_SIZE(self), - &start, &stop, &step, &slicelength) < 0) { - return NULL; - } - - if (slicelength <= 0) { - return PyUnicode_FromUnicode(NULL, 0); - } else { - source_buf = PyUnicode_AS_UNICODE((PyObject*)self); - result_buf = (Py_UNICODE *)PyMem_MALLOC(slicelength* - sizeof(Py_UNICODE)); - - if (result_buf == NULL) - return PyErr_NoMemory(); - - for (cur = start, i = 0; i < slicelength; cur += step, i++) { - result_buf[i] = source_buf[cur]; - } - - result = PyUnicode_FromUnicode(result_buf, slicelength); - PyMem_FREE(result_buf); - return result; - } - } else { - PyErr_SetString(PyExc_TypeError, "string indices must be integers"); - return NULL; - } -} - -static PyMappingMethods unicode_as_mapping = { - (lenfunc)unicode_length, /* mp_length */ - (binaryfunc)unicode_subscript, /* mp_subscript */ - (objobjargproc)0, /* mp_ass_subscript */ -}; - -static Py_ssize_t -unicode_buffer_getreadbuf(PyUnicodeObject *self, - Py_ssize_t index, - const void **ptr) -{ - if (index != 0) { - PyErr_SetString(PyExc_SystemError, - "accessing non-existent unicode segment"); - return -1; - } - *ptr = (void *) self->str; - return PyUnicode_GET_DATA_SIZE(self); -} - -static Py_ssize_t -unicode_buffer_getwritebuf(PyUnicodeObject *self, Py_ssize_t index, - const void **ptr) -{ - PyErr_SetString(PyExc_TypeError, - "cannot use unicode as modifiable buffer"); - return -1; -} - -static int -unicode_buffer_getsegcount(PyUnicodeObject *self, - Py_ssize_t *lenp) -{ - if (lenp) - *lenp = PyUnicode_GET_DATA_SIZE(self); - return 1; -} - -static Py_ssize_t -unicode_buffer_getcharbuf(PyUnicodeObject *self, - Py_ssize_t index, - const void **ptr) -{ - PyObject *str; - - if (index != 0) { - PyErr_SetString(PyExc_SystemError, - "accessing non-existent unicode segment"); - return -1; - } - str = _PyUnicode_AsDefaultEncodedString((PyObject *)self, NULL); - if (str == NULL) - return -1; - *ptr = (void *) PyString_AS_STRING(str); - return PyString_GET_SIZE(str); -} - -/* Helpers for PyUnicode_Format() */ - -static PyObject * -getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) -{ - Py_ssize_t argidx = *p_argidx; - if (argidx < arglen) { - (*p_argidx)++; - if (arglen < 0) - return args; - else - return PyTuple_GetItem(args, argidx); - } - PyErr_SetString(PyExc_TypeError, - "not enough arguments for format string"); - return NULL; -} - -#define F_LJUST (1<<0) -#define F_SIGN (1<<1) -#define F_BLANK (1<<2) -#define F_ALT (1<<3) -#define F_ZERO (1<<4) - -static Py_ssize_t -strtounicode(Py_UNICODE *buffer, const char *charbuffer) -{ - register Py_ssize_t i; - Py_ssize_t len = strlen(charbuffer); - for (i = len - 1; i >= 0; i--) - buffer[i] = (Py_UNICODE) charbuffer[i]; - - return len; -} - -static int -doubletounicode(Py_UNICODE *buffer, size_t len, const char *format, double x) -{ - Py_ssize_t result; - - PyOS_ascii_formatd((char *)buffer, len, format, x); - result = strtounicode(buffer, (char *)buffer); - return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); -} - -static int -longtounicode(Py_UNICODE *buffer, size_t len, const char *format, long x) -{ - Py_ssize_t result; - - PyOS_snprintf((char *)buffer, len, format, x); - result = strtounicode(buffer, (char *)buffer); - return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); -} - -/* XXX To save some code duplication, formatfloat/long/int could have been - shared with stringobject.c, converting from 8-bit to Unicode after the - formatting is done. */ - -static int -formatfloat(Py_UNICODE *buf, - size_t buflen, - int flags, - int prec, - int type, - PyObject *v) -{ - /* fmt = '%#.' + `prec` + `type` - worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/ - char fmt[20]; - double x; - - x = PyFloat_AsDouble(v); - if (x == -1.0 && PyErr_Occurred()) - return -1; - if (prec < 0) - prec = 6; - if (type == 'f' && (fabs(x) / 1e25) >= 1e25) - type = 'g'; - /* Worst case length calc to ensure no buffer overrun: - - 'g' formats: - fmt = %#.<prec>g - buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp - for any double rep.) - len = 1 + prec + 1 + 2 + 5 = 9 + prec - - 'f' formats: - buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50) - len = 1 + 50 + 1 + prec = 52 + prec - - If prec=0 the effective precision is 1 (the leading digit is - always given), therefore increase the length by one. - - */ - if ((type == 'g' && buflen <= (size_t)10 + (size_t)prec) || - (type == 'f' && buflen <= (size_t)53 + (size_t)prec)) { - PyErr_SetString(PyExc_OverflowError, - "formatted float is too long (precision too large?)"); - return -1; - } - PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c", - (flags&F_ALT) ? "#" : "", - prec, type); - return doubletounicode(buf, buflen, fmt, x); -} - -static PyObject* -formatlong(PyObject *val, int flags, int prec, int type) -{ - char *buf; - int i, len; - PyObject *str; /* temporary string object. */ - PyUnicodeObject *result; - - str = _PyString_FormatLong(val, flags, prec, type, &buf, &len); - if (!str) - return NULL; - result = _PyUnicode_New(len); - if (!result) { - Py_DECREF(str); - return NULL; - } - for (i = 0; i < len; i++) - result->str[i] = buf[i]; - result->str[len] = 0; - Py_DECREF(str); - return (PyObject*)result; -} - -static int -formatint(Py_UNICODE *buf, - size_t buflen, - int flags, - int prec, - int type, - PyObject *v) -{ - /* fmt = '%#.' + `prec` + 'l' + `type` - * worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine) - * + 1 + 1 - * = 24 - */ - char fmt[64]; /* plenty big enough! */ - char *sign; - long x; - - x = PyInt_AsLong(v); - if (x == -1 && PyErr_Occurred()) - return -1; - if (x < 0 && type == 'u') { - type = 'd'; - } - if (x < 0 && (type == 'x' || type == 'X' || type == 'o')) - sign = "-"; - else - sign = ""; - if (prec < 0) - prec = 1; - - /* buf = '+'/'-'/'' + '0'/'0x'/'' + '[0-9]'*max(prec, len(x in octal)) - * worst case buf = '-0x' + [0-9]*prec, where prec >= 11 - */ - if (buflen <= 14 || buflen <= (size_t)3 + (size_t)prec) { - PyErr_SetString(PyExc_OverflowError, - "formatted integer is too long (precision too large?)"); - return -1; - } - - if ((flags & F_ALT) && - (type == 'x' || type == 'X')) { - /* When converting under %#x or %#X, there are a number - * of issues that cause pain: - * - when 0 is being converted, the C standard leaves off - * the '0x' or '0X', which is inconsistent with other - * %#x/%#X conversions and inconsistent with Python's - * hex() function - * - there are platforms that violate the standard and - * convert 0 with the '0x' or '0X' - * (Metrowerks, Compaq Tru64) - * - there are platforms that give '0x' when converting - * under %#X, but convert 0 in accordance with the - * standard (OS/2 EMX) - * - * We can achieve the desired consistency by inserting our - * own '0x' or '0X' prefix, and substituting %x/%X in place - * of %#x/%#X. - * - * Note that this is the same approach as used in - * formatint() in stringobject.c - */ - PyOS_snprintf(fmt, sizeof(fmt), "%s0%c%%.%dl%c", - sign, type, prec, type); - } - else { - PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c", - sign, (flags&F_ALT) ? "#" : "", - prec, type); - } - if (sign[0]) - return longtounicode(buf, buflen, fmt, -x); - else - return longtounicode(buf, buflen, fmt, x); -} - -static int -formatchar(Py_UNICODE *buf, - size_t buflen, - PyObject *v) -{ - /* presume that the buffer is at least 2 characters long */ - if (PyUnicode_Check(v)) { - if (PyUnicode_GET_SIZE(v) != 1) - goto onError; - buf[0] = PyUnicode_AS_UNICODE(v)[0]; - } - - else if (PyString_Check(v)) { - if (PyString_GET_SIZE(v) != 1) - goto onError; - buf[0] = (Py_UNICODE)PyString_AS_STRING(v)[0]; - } - - else { - /* Integer input truncated to a character */ - long x; - x = PyInt_AsLong(v); - if (x == -1 && PyErr_Occurred()) - goto onError; -#ifdef Py_UNICODE_WIDE - if (x < 0 || x > 0x10ffff) { - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(0x110000) " - "(wide Python build)"); - return -1; - } -#else - if (x < 0 || x > 0xffff) { - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(0x10000) " - "(narrow Python build)"); - return -1; - } -#endif - buf[0] = (Py_UNICODE) x; - } - buf[1] = '\0'; - return 1; - - onError: - PyErr_SetString(PyExc_TypeError, - "%c requires int or char"); - return -1; -} - -/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) - - FORMATBUFLEN is the length of the buffer in which the floats, ints, & - chars are formatted. XXX This is a magic number. Each formatting - routine does bounds checking to ensure no overflow, but a better - solution may be to malloc a buffer of appropriate size for each - format. For now, the current solution is sufficient. -*/ -#define FORMATBUFLEN (size_t)120 - -PyObject *PyUnicode_Format(PyObject *format, - PyObject *args) -{ - Py_UNICODE *fmt, *res; - Py_ssize_t fmtcnt, rescnt, reslen, arglen, argidx; - int args_owned = 0; - PyUnicodeObject *result = NULL; - PyObject *dict = NULL; - PyObject *uformat; - - if (format == NULL || args == NULL) { - PyErr_BadInternalCall(); - return NULL; - } - uformat = PyUnicode_FromObject(format); - if (uformat == NULL) - return NULL; - fmt = PyUnicode_AS_UNICODE(uformat); - fmtcnt = PyUnicode_GET_SIZE(uformat); - - reslen = rescnt = fmtcnt + 100; - result = _PyUnicode_New(reslen); - if (result == NULL) - goto onError; - res = PyUnicode_AS_UNICODE(result); - - if (PyTuple_Check(args)) { - arglen = PyTuple_Size(args); - argidx = 0; - } - else { - arglen = -1; - argidx = -2; - } - if (args->ob_type->tp_as_mapping && !PyTuple_Check(args) && - !PyObject_TypeCheck(args, &PyBaseString_Type)) - dict = args; - - while (--fmtcnt >= 0) { - if (*fmt != '%') { - if (--rescnt < 0) { - rescnt = fmtcnt + 100; - reslen += rescnt; - if (_PyUnicode_Resize(&result, reslen) < 0) - goto onError; - res = PyUnicode_AS_UNICODE(result) + reslen - rescnt; - --rescnt; - } - *res++ = *fmt++; - } - else { - /* Got a format specifier */ - int flags = 0; - Py_ssize_t width = -1; - int prec = -1; - Py_UNICODE c = '\0'; - Py_UNICODE fill; - PyObject *v = NULL; - PyObject *temp = NULL; - Py_UNICODE *pbuf; - Py_UNICODE sign; - Py_ssize_t len; - Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */ - - fmt++; - if (*fmt == '(') { - Py_UNICODE *keystart; - Py_ssize_t keylen; - PyObject *key; - int pcount = 1; - - if (dict == NULL) { - PyErr_SetString(PyExc_TypeError, - "format requires a mapping"); - goto onError; - } - ++fmt; - --fmtcnt; - keystart = fmt; - /* Skip over balanced parentheses */ - while (pcount > 0 && --fmtcnt >= 0) { - if (*fmt == ')') - --pcount; - else if (*fmt == '(') - ++pcount; - fmt++; - } - keylen = fmt - keystart - 1; - if (fmtcnt < 0 || pcount > 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format key"); - goto onError; - } -#if 0 - /* keys are converted to strings using UTF-8 and - then looked up since Python uses strings to hold - variables names etc. in its namespaces and we - wouldn't want to break common idioms. */ - key = PyUnicode_EncodeUTF8(keystart, - keylen, - NULL); -#else - key = PyUnicode_FromUnicode(keystart, keylen); -#endif - if (key == NULL) - goto onError; - if (args_owned) { - Py_DECREF(args); - args_owned = 0; - } - args = PyObject_GetItem(dict, key); - Py_DECREF(key); - if (args == NULL) { - goto onError; - } - args_owned = 1; - arglen = -1; - argidx = -2; - } - while (--fmtcnt >= 0) { - switch (c = *fmt++) { - case '-': flags |= F_LJUST; continue; - case '+': flags |= F_SIGN; continue; - case ' ': flags |= F_BLANK; continue; - case '#': flags |= F_ALT; continue; - case '0': flags |= F_ZERO; continue; - } - break; - } - if (c == '*') { - v = getnextarg(args, arglen, &argidx); - if (v == NULL) - goto onError; - if (!PyInt_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "* wants int"); - goto onError; - } - width = PyInt_AsLong(v); - if (width < 0) { - flags |= F_LJUST; - width = -width; - } - if (--fmtcnt >= 0) - c = *fmt++; - } - else if (c >= '0' && c <= '9') { - width = c - '0'; - while (--fmtcnt >= 0) { - c = *fmt++; - if (c < '0' || c > '9') - break; - if ((width*10) / 10 != width) { - PyErr_SetString(PyExc_ValueError, - "width too big"); - goto onError; - } - width = width*10 + (c - '0'); - } - } - if (c == '.') { - prec = 0; - if (--fmtcnt >= 0) - c = *fmt++; - if (c == '*') { - v = getnextarg(args, arglen, &argidx); - if (v == NULL) - goto onError; - if (!PyInt_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "* wants int"); - goto onError; - } - prec = PyInt_AsLong(v); - if (prec < 0) - prec = 0; - if (--fmtcnt >= 0) - c = *fmt++; - } - else if (c >= '0' && c <= '9') { - prec = c - '0'; - while (--fmtcnt >= 0) { - c = Py_CHARMASK(*fmt++); - if (c < '0' || c > '9') - break; - if ((prec*10) / 10 != prec) { - PyErr_SetString(PyExc_ValueError, - "prec too big"); - goto onError; - } - prec = prec*10 + (c - '0'); - } - } - } /* prec */ - if (fmtcnt >= 0) { - if (c == 'h' || c == 'l' || c == 'L') { - if (--fmtcnt >= 0) - c = *fmt++; - } - } - if (fmtcnt < 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format"); - goto onError; - } - if (c != '%') { - v = getnextarg(args, arglen, &argidx); - if (v == NULL) - goto onError; - } - sign = 0; - fill = ' '; - switch (c) { - - case '%': - pbuf = formatbuf; - /* presume that buffer length is at least 1 */ - pbuf[0] = '%'; - len = 1; - break; - - case 's': - case 'r': - if (PyUnicode_Check(v) && c == 's') { - temp = v; - Py_INCREF(temp); - } - else { - PyObject *unicode; - if (c == 's') - temp = PyObject_Unicode(v); - else - temp = PyObject_Repr(v); - if (temp == NULL) - goto onError; - if (PyUnicode_Check(temp)) - /* nothing to do */; - else if (PyString_Check(temp)) { - /* convert to string to Unicode */ - unicode = PyUnicode_Decode(PyString_AS_STRING(temp), - PyString_GET_SIZE(temp), - NULL, - "strict"); - Py_DECREF(temp); - temp = unicode; - if (temp == NULL) - goto onError; - } - else { - Py_DECREF(temp); - PyErr_SetString(PyExc_TypeError, - "%s argument has non-string str()"); - goto onError; - } - } - pbuf = PyUnicode_AS_UNICODE(temp); - len = PyUnicode_GET_SIZE(temp); - if (prec >= 0 && len > prec) - len = prec; - break; - - case 'i': - case 'd': - case 'u': - case 'o': - case 'x': - case 'X': - if (c == 'i') - c = 'd'; - if (PyLong_Check(v)) { - temp = formatlong(v, flags, prec, c); - if (!temp) - goto onError; - pbuf = PyUnicode_AS_UNICODE(temp); - len = PyUnicode_GET_SIZE(temp); - sign = 1; - } - else { - pbuf = formatbuf; - len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), - flags, prec, c, v); - if (len < 0) - goto onError; - sign = 1; - } - if (flags & F_ZERO) - fill = '0'; - break; - - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - if (c == 'F') - c = 'f'; - pbuf = formatbuf; - len = formatfloat(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), - flags, prec, c, v); - if (len < 0) - goto onError; - sign = 1; - if (flags & F_ZERO) - fill = '0'; - break; - - case 'c': - pbuf = formatbuf; - len = formatchar(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), v); - if (len < 0) - goto onError; - break; - - default: - PyErr_Format(PyExc_ValueError, - "unsupported format character '%c' (0x%x) " - "at index %zd", - (31<=c && c<=126) ? (char)c : '?', - (int)c, - (Py_ssize_t)(fmt - 1 - - PyUnicode_AS_UNICODE(uformat))); - goto onError; - } - if (sign) { - if (*pbuf == '-' || *pbuf == '+') { - sign = *pbuf++; - len--; - } - else if (flags & F_SIGN) - sign = '+'; - else if (flags & F_BLANK) - sign = ' '; - else - sign = 0; - } - if (width < len) - width = len; - if (rescnt - (sign != 0) < width) { - reslen -= rescnt; - rescnt = width + fmtcnt + 100; - reslen += rescnt; - if (reslen < 0) { - Py_XDECREF(temp); - PyErr_NoMemory(); - goto onError; - } - if (_PyUnicode_Resize(&result, reslen) < 0) { - Py_XDECREF(temp); - goto onError; - } - res = PyUnicode_AS_UNICODE(result) - + reslen - rescnt; - } - if (sign) { - if (fill != ' ') - *res++ = sign; - rescnt--; - if (width > len) - width--; - } - if ((flags & F_ALT) && (c == 'x' || c == 'X')) { - assert(pbuf[0] == '0'); - assert(pbuf[1] == c); - if (fill != ' ') { - *res++ = *pbuf++; - *res++ = *pbuf++; - } - rescnt -= 2; - width -= 2; - if (width < 0) - width = 0; - len -= 2; - } - if (width > len && !(flags & F_LJUST)) { - do { - --rescnt; - *res++ = fill; - } while (--width > len); - } - if (fill == ' ') { - if (sign) - *res++ = sign; - if ((flags & F_ALT) && (c == 'x' || c == 'X')) { - assert(pbuf[0] == '0'); - assert(pbuf[1] == c); - *res++ = *pbuf++; - *res++ = *pbuf++; - } - } - Py_UNICODE_COPY(res, pbuf, len); - res += len; - rescnt -= len; - while (--width >= len) { - --rescnt; - *res++ = ' '; - } - if (dict && (argidx < arglen) && c != '%') { - PyErr_SetString(PyExc_TypeError, - "not all arguments converted during string formatting"); - Py_XDECREF(temp); - goto onError; - } - Py_XDECREF(temp); - } /* '%' */ - } /* until end */ - if (argidx < arglen && !dict) { - PyErr_SetString(PyExc_TypeError, - "not all arguments converted during string formatting"); - goto onError; - } - - if (_PyUnicode_Resize(&result, reslen - rescnt) < 0) - goto onError; - if (args_owned) { - Py_DECREF(args); - } - Py_DECREF(uformat); - return (PyObject *)result; - - onError: - Py_XDECREF(result); - Py_DECREF(uformat); - if (args_owned) { - Py_DECREF(args); - } - return NULL; -} - -static PyBufferProcs unicode_as_buffer = { - (readbufferproc) unicode_buffer_getreadbuf, - (writebufferproc) unicode_buffer_getwritebuf, - (segcountproc) unicode_buffer_getsegcount, - (charbufferproc) unicode_buffer_getcharbuf, -}; - -static PyObject * -unicode_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - -static PyObject * -unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *x = NULL; - static char *kwlist[] = {"string", "encoding", "errors", 0}; - char *encoding = NULL; - char *errors = NULL; - - if (type != &PyUnicode_Type) - return unicode_subtype_new(type, args, kwds); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:unicode", - kwlist, &x, &encoding, &errors)) - return NULL; - if (x == NULL) - return (PyObject *)_PyUnicode_New(0); - if (encoding == NULL && errors == NULL) - return PyObject_Unicode(x); - else - return PyUnicode_FromEncodedObject(x, encoding, errors); -} - -static PyObject * -unicode_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyUnicodeObject *tmp, *pnew; - Py_ssize_t n; - - assert(PyType_IsSubtype(type, &PyUnicode_Type)); - tmp = (PyUnicodeObject *)unicode_new(&PyUnicode_Type, args, kwds); - if (tmp == NULL) - return NULL; - assert(PyUnicode_Check(tmp)); - pnew = (PyUnicodeObject *) type->tp_alloc(type, n = tmp->length); - if (pnew == NULL) { - Py_DECREF(tmp); - return NULL; - } - pnew->str = PyMem_NEW(Py_UNICODE, n+1); - if (pnew->str == NULL) { - _Py_ForgetReference((PyObject *)pnew); - PyObject_Del(pnew); - Py_DECREF(tmp); - return PyErr_NoMemory(); - } - Py_UNICODE_COPY(pnew->str, tmp->str, n+1); - pnew->length = n; - pnew->hash = tmp->hash; - Py_DECREF(tmp); - return (PyObject *)pnew; -} - -PyDoc_STRVAR(unicode_doc, -"unicode(string [, encoding[, errors]]) -> object\n\ -\n\ -Create a new Unicode object from the given encoded string.\n\ -encoding defaults to the current default string encoding.\n\ -errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'."); - -PyTypeObject PyUnicode_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ - "unicode", /* tp_name */ - sizeof(PyUnicodeObject), /* tp_size */ - 0, /* tp_itemsize */ - /* Slots */ - (destructor)unicode_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - unicode_repr, /* tp_repr */ - &unicode_as_number, /* tp_as_number */ - &unicode_as_sequence, /* tp_as_sequence */ - &unicode_as_mapping, /* tp_as_mapping */ - (hashfunc) unicode_hash, /* tp_hash*/ - 0, /* tp_call*/ - (reprfunc) unicode_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - &unicode_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - unicode_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - PyUnicode_RichCompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - unicode_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &PyBaseString_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - unicode_new, /* tp_new */ - PyObject_Del, /* tp_free */ -}; - -/* Initialize the Unicode implementation */ - -void _PyUnicode_Init(void) -{ - int i; - - /* XXX - move this array to unicodectype.c ? */ - Py_UNICODE linebreak[] = { - 0x000A, /* LINE FEED */ - 0x000D, /* CARRIAGE RETURN */ - 0x001C, /* FILE SEPARATOR */ - 0x001D, /* GROUP SEPARATOR */ - 0x001E, /* RECORD SEPARATOR */ - 0x0085, /* NEXT LINE */ - 0x2028, /* LINE SEPARATOR */ - 0x2029, /* PARAGRAPH SEPARATOR */ - }; - - /* Init the implementation */ - unicode_freelist = NULL; - unicode_freelist_size = 0; - unicode_empty = _PyUnicode_New(0); - if (!unicode_empty) - return; - - strcpy(unicode_default_encoding, "ascii"); - for (i = 0; i < 256; i++) - unicode_latin1[i] = NULL; - if (PyType_Ready(&PyUnicode_Type) < 0) - Py_FatalError("Can't initialize 'unicode'"); - - /* initialize the linebreak bloom filter */ - bloom_linebreak = make_bloom_mask( - linebreak, sizeof(linebreak) / sizeof(linebreak[0]) - ); - - PyType_Ready(&EncodingMapType); -} - -/* Finalize the Unicode implementation */ - -void -_PyUnicode_Fini(void) -{ - PyUnicodeObject *u; - int i; - - Py_XDECREF(unicode_empty); - unicode_empty = NULL; - - for (i = 0; i < 256; i++) { - if (unicode_latin1[i]) { - Py_DECREF(unicode_latin1[i]); - unicode_latin1[i] = NULL; - } - } - - for (u = unicode_freelist; u != NULL;) { - PyUnicodeObject *v = u; - u = *(PyUnicodeObject **)u; - if (v->str) - PyMem_DEL(v->str); - Py_XDECREF(v->defenc); - PyObject_Del(v); - } - unicode_freelist = NULL; - unicode_freelist_size = 0; -} - -#ifdef __cplusplus -} -#endif - - -/* -Local variables: -c-basic-offset: 4 -indent-tabs-mode: nil -End: -*/ diff --git a/sys/src/cmd/python/Objects/unicodetype_db.h b/sys/src/cmd/python/Objects/unicodetype_db.h deleted file mode 100644 index 2a49a810a..000000000 --- a/sys/src/cmd/python/Objects/unicodetype_db.h +++ /dev/null @@ -1,1269 +0,0 @@ -/* this file was generated by Tools/unicode/makeunicodedata.py 2.5 */ - -/* a list of unique character type descriptors */ -const _PyUnicode_TypeRecord _PyUnicode_TypeRecords[] = { - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 32}, - {0, 0, 0, 0, 0, 48}, - {0, 0, 0, 0, 0, 6}, - {0, 0, 0, 1, 1, 6}, - {0, 0, 0, 2, 2, 6}, - {0, 0, 0, 3, 3, 6}, - {0, 0, 0, 4, 4, 6}, - {0, 0, 0, 5, 5, 6}, - {0, 0, 0, 6, 6, 6}, - {0, 0, 0, 7, 7, 6}, - {0, 0, 0, 8, 8, 6}, - {0, 0, 0, 9, 9, 6}, - {0, 32, 0, 0, 0, 129}, - {65504, 0, 65504, 0, 0, 9}, - {0, 0, 0, 0, 0, 9}, - {0, 0, 0, 0, 2, 4}, - {0, 0, 0, 0, 3, 4}, - {743, 0, 743, 0, 0, 9}, - {0, 0, 0, 0, 1, 4}, - {121, 0, 121, 0, 0, 9}, - {0, 1, 0, 0, 0, 129}, - {65535, 0, 65535, 0, 0, 9}, - {0, 65337, 0, 0, 0, 129}, - {65304, 0, 65304, 0, 0, 9}, - {0, 65415, 0, 0, 0, 129}, - {65236, 0, 65236, 0, 0, 9}, - {0, 210, 0, 0, 0, 129}, - {0, 206, 0, 0, 0, 129}, - {0, 205, 0, 0, 0, 129}, - {0, 79, 0, 0, 0, 129}, - {0, 202, 0, 0, 0, 129}, - {0, 203, 0, 0, 0, 129}, - {0, 207, 0, 0, 0, 129}, - {97, 0, 97, 0, 0, 9}, - {0, 211, 0, 0, 0, 129}, - {0, 209, 0, 0, 0, 129}, - {163, 0, 163, 0, 0, 9}, - {0, 213, 0, 0, 0, 129}, - {130, 0, 130, 0, 0, 9}, - {0, 214, 0, 0, 0, 129}, - {0, 218, 0, 0, 0, 129}, - {0, 217, 0, 0, 0, 129}, - {0, 219, 0, 0, 0, 129}, - {0, 0, 0, 0, 0, 1}, - {56, 0, 56, 0, 0, 9}, - {0, 2, 1, 0, 0, 129}, - {65535, 1, 0, 0, 0, 65}, - {65534, 0, 65535, 0, 0, 9}, - {65457, 0, 65457, 0, 0, 9}, - {0, 65439, 0, 0, 0, 129}, - {0, 65480, 0, 0, 0, 129}, - {0, 65406, 0, 0, 0, 129}, - {0, 0, 0, 0, 0, 129}, - {0, 65373, 0, 0, 0, 129}, - {0, 83, 0, 0, 0, 129}, - {65326, 0, 65326, 0, 0, 9}, - {65330, 0, 65330, 0, 0, 9}, - {65331, 0, 65331, 0, 0, 9}, - {65334, 0, 65334, 0, 0, 9}, - {65333, 0, 65333, 0, 0, 9}, - {65329, 0, 65329, 0, 0, 9}, - {65327, 0, 65327, 0, 0, 9}, - {65325, 0, 65325, 0, 0, 9}, - {65323, 0, 65323, 0, 0, 9}, - {65322, 0, 65322, 0, 0, 9}, - {65318, 0, 65318, 0, 0, 9}, - {65319, 0, 65319, 0, 0, 9}, - {65317, 0, 65317, 0, 0, 9}, - {65453, 0, 65453, 0, 0, 9}, - {84, 0, 84, 0, 0, 0}, - {0, 38, 0, 0, 0, 129}, - {0, 37, 0, 0, 0, 129}, - {0, 64, 0, 0, 0, 129}, - {0, 63, 0, 0, 0, 129}, - {65498, 0, 65498, 0, 0, 9}, - {65499, 0, 65499, 0, 0, 9}, - {65505, 0, 65505, 0, 0, 9}, - {65472, 0, 65472, 0, 0, 9}, - {65473, 0, 65473, 0, 0, 9}, - {65474, 0, 65474, 0, 0, 9}, - {65479, 0, 65479, 0, 0, 9}, - {65489, 0, 65489, 0, 0, 9}, - {65482, 0, 65482, 0, 0, 9}, - {65450, 0, 65450, 0, 0, 9}, - {65456, 0, 65456, 0, 0, 9}, - {7, 0, 7, 0, 0, 9}, - {0, 65476, 0, 0, 0, 129}, - {65440, 0, 65440, 0, 0, 9}, - {0, 65529, 0, 0, 0, 129}, - {0, 80, 0, 0, 0, 129}, - {0, 48, 0, 0, 0, 129}, - {65488, 0, 65488, 0, 0, 9}, - {0, 7264, 0, 0, 0, 129}, - {0, 0, 0, 0, 4, 4}, - {0, 0, 0, 0, 5, 4}, - {0, 0, 0, 0, 6, 4}, - {0, 0, 0, 0, 7, 4}, - {0, 0, 0, 0, 8, 4}, - {0, 0, 0, 0, 9, 4}, - {65477, 0, 65477, 0, 0, 9}, - {8, 0, 8, 0, 0, 9}, - {0, 65528, 0, 0, 0, 129}, - {74, 0, 74, 0, 0, 9}, - {86, 0, 86, 0, 0, 9}, - {100, 0, 100, 0, 0, 9}, - {128, 0, 128, 0, 0, 9}, - {112, 0, 112, 0, 0, 9}, - {126, 0, 126, 0, 0, 9}, - {0, 65528, 0, 0, 0, 65}, - {9, 0, 9, 0, 0, 9}, - {0, 65462, 0, 0, 0, 129}, - {0, 65527, 0, 0, 0, 65}, - {58331, 0, 58331, 0, 0, 9}, - {0, 65450, 0, 0, 0, 129}, - {0, 65436, 0, 0, 0, 129}, - {0, 65424, 0, 0, 0, 129}, - {0, 65408, 0, 0, 0, 129}, - {0, 65410, 0, 0, 0, 129}, - {0, 0, 0, 0, 0, 4}, - {0, 58019, 0, 0, 0, 129}, - {0, 57153, 0, 0, 0, 129}, - {0, 57274, 0, 0, 0, 129}, - {0, 16, 0, 0, 0, 0}, - {65520, 0, 65520, 0, 0, 0}, - {0, 26, 0, 0, 0, 0}, - {65510, 0, 65510, 0, 0, 0}, - {58272, 0, 58272, 0, 0, 9}, - {0, 40, 0, 0, 0, 129}, - {65496, 0, 65496, 0, 0, 9}, -}; - -/* type indexes */ -#define SHIFT 8 -static unsigned char index1[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 8, 8, 27, 28, 29, 30, 31, 32, 33, 34, 32, 35, 36, - 32, 32, 32, 37, 38, 39, 40, 41, 42, 43, 44, 32, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 45, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 46, 21, 21, 21, 21, 47, 8, 8, - 48, 49, 8, 8, 8, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 50, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 21, 51, 52, 21, 53, 54, 55, 56, 57, - 8, 58, 59, 8, 8, 8, 60, 8, 61, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 62, 63, 64, 65, 66, 67, 68, - 69, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 70, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 21, 21, 71, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 72, 73, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 74, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 74, -}; - -static unsigned char index2[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 1, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 1, 1, 1, 1, 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, - 1, 1, 1, 1, 17, 18, 1, 19, 1, 1, 1, 20, 16, 1, 1, 1, 1, 1, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 1, 14, 14, 14, 14, 14, 14, 14, 16, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 15, - 15, 15, 15, 15, 15, 15, 21, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 24, 25, 22, 23, 22, 23, 22, 23, 16, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 16, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 26, 22, 23, 22, 23, 22, 23, 27, 16, 28, 22, 23, 22, 23, 29, 22, 23, - 30, 30, 22, 23, 16, 31, 32, 33, 22, 23, 30, 34, 35, 36, 37, 22, 23, 38, - 16, 36, 39, 40, 41, 22, 23, 22, 23, 22, 23, 42, 22, 23, 42, 16, 16, 22, - 23, 42, 22, 23, 43, 43, 22, 23, 22, 23, 44, 22, 23, 16, 45, 22, 23, 16, - 46, 45, 45, 45, 45, 47, 48, 49, 47, 48, 49, 47, 48, 49, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 50, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 16, 47, 48, 49, 22, - 23, 51, 52, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 53, 16, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 16, 16, 16, 16, 16, 16, 54, 22, 23, - 55, 54, 16, 16, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, - 57, 58, 16, 59, 59, 16, 60, 16, 61, 16, 16, 16, 16, 59, 16, 16, 62, 16, - 16, 16, 16, 63, 64, 16, 16, 16, 16, 16, 64, 16, 16, 65, 16, 16, 66, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 67, 16, 16, 67, 16, 16, 16, 16, 67, - 16, 68, 68, 16, 16, 16, 16, 16, 16, 69, 16, 70, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 71, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, - 0, 45, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 72, 1, 73, 73, 73, 0, 74, 0, 75, - 75, 16, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 76, 77, 77, 77, 16, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 78, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 79, 80, 80, 0, 81, 82, 54, 54, 54, 83, 84, - 16, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 85, 86, 87, 16, 88, 89, 1, 22, 23, 90, 22, - 23, 16, 54, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, - 91, 91, 91, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 1, 1, 1, 1, 1, 0, 1, 1, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 54, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 0, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 0, 0, 0, 0, 0, 0, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, 0, 45, 1, 1, 1, 1, 1, - 1, 0, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 16, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 45, - 45, 45, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 45, 45, 1, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 45, 45, 1, 1, 1, 1, 1, 1, 1, 45, 45, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 45, 45, 45, 1, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, - 45, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 45, 1, 1, 1, 1, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, - 1, 1, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 45, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, - 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 0, 0, - 0, 45, 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, - 1, 1, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 45, 45, 0, 45, 45, 45, - 1, 1, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 45, 45, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 0, 0, 0, - 0, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, - 0, 45, 45, 0, 45, 45, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 0, 45, 0, 0, 0, - 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 45, 45, 45, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 0, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, - 45, 0, 45, 45, 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 1, 0, 1, 1, 1, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, - 45, 1, 1, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, - 0, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, - 0, 45, 45, 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, - 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 45, 45, 0, 45, 45, - 45, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 45, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 45, 0, 45, 45, 45, 45, 45, 45, 0, 0, - 0, 45, 45, 45, 0, 45, 45, 45, 45, 0, 0, 0, 45, 45, 0, 45, 0, 45, 45, 0, - 0, 0, 45, 45, 0, 0, 0, 45, 45, 45, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, - 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, - 45, 45, 45, 45, 45, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 0, 0, - 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, - 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, - 45, 45, 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 45, 0, 45, 45, - 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, - 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, - 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 45, 45, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 0, 0, 45, 45, 45, 45, - 45, 45, 45, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 1, 45, 45, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 45, 45, - 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 0, 45, 0, 0, - 45, 45, 0, 45, 0, 0, 45, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 0, 45, 45, 45, - 45, 45, 45, 45, 0, 45, 45, 45, 0, 45, 0, 45, 0, 0, 45, 45, 0, 45, 45, 45, - 45, 1, 45, 45, 1, 1, 1, 1, 1, 1, 0, 1, 1, 45, 0, 0, 45, 45, 45, 45, 45, - 0, 45, 0, 1, 1, 1, 1, 1, 1, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, - 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 0, - 45, 45, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, - 45, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, - 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 0, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 0, - 45, 0, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 0, 0, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, - 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 0, 45, 45, 45, 45, 0, 0, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 0, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 17, 18, 95, 96, 97, - 98, 99, 100, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 1, 1, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 0, 45, 45, 45, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 45, 1, 1, 1, 1, 45, 1, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 45, - 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, - 45, 45, 45, 45, 45, 45, 1, 1, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, - 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 16, 16, 16, 16, 16, 101, 0, 0, 0, 0, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, - 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 0, 0, 0, 0, 0, 0, - 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, - 103, 103, 102, 102, 102, 102, 102, 102, 0, 0, 103, 103, 103, 103, 103, - 103, 0, 0, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, - 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, - 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 0, 0, 103, - 103, 103, 103, 103, 103, 0, 0, 16, 102, 16, 102, 16, 102, 16, 102, 0, - 103, 0, 103, 0, 103, 0, 103, 102, 102, 102, 102, 102, 102, 102, 102, 103, - 103, 103, 103, 103, 103, 103, 103, 104, 104, 105, 105, 105, 105, 106, - 106, 107, 107, 108, 108, 109, 109, 0, 0, 102, 102, 102, 102, 102, 102, - 102, 102, 110, 110, 110, 110, 110, 110, 110, 110, 102, 102, 102, 102, - 102, 102, 102, 102, 110, 110, 110, 110, 110, 110, 110, 110, 102, 102, - 102, 102, 102, 102, 102, 102, 110, 110, 110, 110, 110, 110, 110, 110, - 102, 102, 16, 111, 16, 0, 16, 16, 103, 103, 112, 112, 113, 1, 114, 1, 1, - 1, 16, 111, 16, 0, 16, 16, 115, 115, 115, 115, 113, 1, 1, 1, 102, 102, - 16, 16, 0, 0, 16, 16, 103, 103, 116, 116, 0, 1, 1, 1, 102, 102, 16, 16, - 16, 87, 16, 16, 103, 103, 117, 117, 90, 1, 1, 1, 0, 0, 16, 111, 16, 0, - 16, 16, 118, 118, 119, 119, 113, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 120, 16, 0, 0, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, - 16, 120, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, 0, 45, 45, - 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 54, 1, 1, 1, 1, 54, 1, - 1, 16, 54, 54, 54, 16, 16, 54, 54, 54, 16, 1, 54, 1, 1, 1, 54, 54, 54, - 54, 54, 1, 1, 1, 1, 1, 1, 54, 1, 121, 1, 54, 1, 122, 123, 54, 54, 1, 16, - 54, 54, 1, 54, 16, 45, 45, 45, 45, 16, 1, 1, 16, 16, 54, 54, 1, 1, 1, 1, - 1, 54, 16, 16, 16, 16, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, - 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 120, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 120, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, - 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, - 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 20, 17, 18, 95, 96, 97, 98, 99, - 100, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, - 22, 23, 22, 23, 22, 23, 22, 23, 16, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, - 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, - 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, - 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 1, 1, 1, 1, 45, 45, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, - 45, 45, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 0, 0, 1, 1, 1, 1, 45, 45, 45, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 45, 45, 45, 45, 0, 0, 0, 0, 0, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 45, 45, 1, 45, 45, 45, 1, 45, 45, 45, 45, 1, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, - 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 0, 0, 0, - 0, 0, 45, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 0, 45, 0, 45, - 45, 0, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, - 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 1, 1, 1, 1, 1, 1, 1, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 1, 1, 1, 1, - 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, - 45, 45, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 0, 0, 45, 45, 45, - 45, 45, 45, 0, 0, 45, 45, 45, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 0, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 1, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, - 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 129, 129, 129, 129, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, - 129, 129, 129, 129, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 0, 0, - 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 0, 0, 0, 45, 0, 0, 45, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 45, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 45, 45, 45, 45, 0, 45, - 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 0, 1, 20, 17, 18, 95, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 0, 54, 54, 0, 0, 54, 0, 0, - 54, 54, 0, 0, 54, 54, 54, 54, 0, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, - 16, 16, 0, 16, 0, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 54, 54, 0, 54, 54, 54, 54, 0, 0, 54, 54, 54, 54, 54, 54, 54, - 54, 0, 54, 54, 54, 54, 54, 54, 54, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, - 54, 0, 54, 54, 54, 54, 0, 54, 54, 54, 54, 54, 0, 54, 0, 0, 0, 54, 54, 54, - 54, 54, 54, 54, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 0, 0, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 1, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 1, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 1, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 1, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 1, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 1, 16, 16, 16, 16, 16, 16, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 1, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 1, 16, 16, 16, 16, - 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 1, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 1, - 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, -}; - diff --git a/sys/src/cmd/python/Objects/weakrefobject.c b/sys/src/cmd/python/Objects/weakrefobject.c deleted file mode 100644 index a404f29ad..000000000 --- a/sys/src/cmd/python/Objects/weakrefobject.c +++ /dev/null @@ -1,941 +0,0 @@ -#include "Python.h" -#include "structmember.h" - - -#define GET_WEAKREFS_LISTPTR(o) \ - ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o)) - - -Py_ssize_t -_PyWeakref_GetWeakrefCount(PyWeakReference *head) -{ - Py_ssize_t count = 0; - - while (head != NULL) { - ++count; - head = head->wr_next; - } - return count; -} - - -static void -init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback) -{ - self->hash = -1; - self->wr_object = ob; - Py_XINCREF(callback); - self->wr_callback = callback; -} - -static PyWeakReference * -new_weakref(PyObject *ob, PyObject *callback) -{ - PyWeakReference *result; - - result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType); - if (result) { - init_weakref(result, ob, callback); - PyObject_GC_Track(result); - } - return result; -} - - -/* This function clears the passed-in reference and removes it from the - * list of weak references for the referent. This is the only code that - * removes an item from the doubly-linked list of weak references for an - * object; it is also responsible for clearing the callback slot. - */ -static void -clear_weakref(PyWeakReference *self) -{ - PyObject *callback = self->wr_callback; - - if (PyWeakref_GET_OBJECT(self) != Py_None) { - PyWeakReference **list = GET_WEAKREFS_LISTPTR( - PyWeakref_GET_OBJECT(self)); - - if (*list == self) - /* If 'self' is the end of the list (and thus self->wr_next == NULL) - then the weakref list itself (and thus the value of *list) will - end up being set to NULL. */ - *list = self->wr_next; - self->wr_object = Py_None; - if (self->wr_prev != NULL) - self->wr_prev->wr_next = self->wr_next; - if (self->wr_next != NULL) - self->wr_next->wr_prev = self->wr_prev; - self->wr_prev = NULL; - self->wr_next = NULL; - } - if (callback != NULL) { - Py_DECREF(callback); - self->wr_callback = NULL; - } -} - -/* Cyclic gc uses this to *just* clear the passed-in reference, leaving - * the callback intact and uncalled. It must be possible to call self's - * tp_dealloc() after calling this, so self has to be left in a sane enough - * state for that to work. We expect tp_dealloc to decref the callback - * then. The reason for not letting clear_weakref() decref the callback - * right now is that if the callback goes away, that may in turn trigger - * another callback (if a weak reference to the callback exists) -- running - * arbitrary Python code in the middle of gc is a disaster. The convolution - * here allows gc to delay triggering such callbacks until the world is in - * a sane state again. - */ -void -_PyWeakref_ClearRef(PyWeakReference *self) -{ - PyObject *callback; - - assert(self != NULL); - assert(PyWeakref_Check(self)); - /* Preserve and restore the callback around clear_weakref. */ - callback = self->wr_callback; - self->wr_callback = NULL; - clear_weakref(self); - self->wr_callback = callback; -} - -static void -weakref_dealloc(PyObject *self) -{ - PyObject_GC_UnTrack(self); - clear_weakref((PyWeakReference *) self); - self->ob_type->tp_free(self); -} - - -static int -gc_traverse(PyWeakReference *self, visitproc visit, void *arg) -{ - Py_VISIT(self->wr_callback); - return 0; -} - - -static int -gc_clear(PyWeakReference *self) -{ - clear_weakref(self); - return 0; -} - - -static PyObject * -weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw) -{ - static char *kwlist[] = {NULL}; - - if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) { - PyObject *object = PyWeakref_GET_OBJECT(self); - Py_INCREF(object); - return (object); - } - return NULL; -} - - -static long -weakref_hash(PyWeakReference *self) -{ - if (self->hash != -1) - return self->hash; - if (PyWeakref_GET_OBJECT(self) == Py_None) { - PyErr_SetString(PyExc_TypeError, "weak object has gone away"); - return -1; - } - self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self)); - return self->hash; -} - - -static PyObject * -weakref_repr(PyWeakReference *self) -{ - char buffer[256]; - if (PyWeakref_GET_OBJECT(self) == Py_None) { - PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self); - } - else { - char *name = NULL; - PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self), - "__name__"); - if (nameobj == NULL) - PyErr_Clear(); - else if (PyString_Check(nameobj)) - name = PyString_AS_STRING(nameobj); - PyOS_snprintf(buffer, sizeof(buffer), - name ? "<weakref at %p; to '%.50s' at %p (%s)>" - : "<weakref at %p; to '%.50s' at %p>", - self, - PyWeakref_GET_OBJECT(self)->ob_type->tp_name, - PyWeakref_GET_OBJECT(self), - name); - Py_XDECREF(nameobj); - } - return PyString_FromString(buffer); -} - -/* Weak references only support equality, not ordering. Two weak references - are equal if the underlying objects are equal. If the underlying object has - gone away, they are equal if they are identical. */ - -static PyObject * -weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) -{ - if (op != Py_EQ || self->ob_type != other->ob_type) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - if (PyWeakref_GET_OBJECT(self) == Py_None - || PyWeakref_GET_OBJECT(other) == Py_None) { - PyObject *res = self==other ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - return PyObject_RichCompare(PyWeakref_GET_OBJECT(self), - PyWeakref_GET_OBJECT(other), op); -} - -/* Given the head of an object's list of weak references, extract the - * two callback-less refs (ref and proxy). Used to determine if the - * shared references exist and to determine the back link for newly - * inserted references. - */ -static void -get_basic_refs(PyWeakReference *head, - PyWeakReference **refp, PyWeakReference **proxyp) -{ - *refp = NULL; - *proxyp = NULL; - - if (head != NULL && head->wr_callback == NULL) { - /* We need to be careful that the "basic refs" aren't - subclasses of the main types. That complicates this a - little. */ - if (PyWeakref_CheckRefExact(head)) { - *refp = head; - head = head->wr_next; - } - if (head != NULL - && head->wr_callback == NULL - && PyWeakref_CheckProxy(head)) { - *proxyp = head; - /* head = head->wr_next; */ - } - } -} - -/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */ -static void -insert_after(PyWeakReference *newref, PyWeakReference *prev) -{ - newref->wr_prev = prev; - newref->wr_next = prev->wr_next; - if (prev->wr_next != NULL) - prev->wr_next->wr_prev = newref; - prev->wr_next = newref; -} - -/* Insert 'newref' at the head of the list; 'list' points to the variable - * that stores the head. - */ -static void -insert_head(PyWeakReference *newref, PyWeakReference **list) -{ - PyWeakReference *next = *list; - - newref->wr_prev = NULL; - newref->wr_next = next; - if (next != NULL) - next->wr_prev = newref; - *list = newref; -} - -static int -parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs, - PyObject **obp, PyObject **callbackp) -{ - /* XXX Should check that kwargs == NULL or is empty. */ - return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp); -} - -static PyObject * -weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - PyWeakReference *self = NULL; - PyObject *ob, *callback = NULL; - - if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) { - PyWeakReference *ref, *proxy; - PyWeakReference **list; - - if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { - PyErr_Format(PyExc_TypeError, - "cannot create weak reference to '%s' object", - ob->ob_type->tp_name); - return NULL; - } - if (callback == Py_None) - callback = NULL; - list = GET_WEAKREFS_LISTPTR(ob); - get_basic_refs(*list, &ref, &proxy); - if (callback == NULL && type == &_PyWeakref_RefType) { - if (ref != NULL) { - /* We can re-use an existing reference. */ - Py_INCREF(ref); - return (PyObject *)ref; - } - } - /* We have to create a new reference. */ - /* Note: the tp_alloc() can trigger cyclic GC, so the weakref - list on ob can be mutated. This means that the ref and - proxy pointers we got back earlier may have been collected, - so we need to compute these values again before we use - them. */ - self = (PyWeakReference *) (type->tp_alloc(type, 0)); - if (self != NULL) { - init_weakref(self, ob, callback); - if (callback == NULL && type == &_PyWeakref_RefType) { - insert_head(self, list); - } - else { - PyWeakReference *prev; - - get_basic_refs(*list, &ref, &proxy); - prev = (proxy == NULL) ? ref : proxy; - if (prev == NULL) - insert_head(self, list); - else - insert_after(self, prev); - } - } - } - return (PyObject *)self; -} - -static int -weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs) -{ - PyObject *tmp; - - if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp)) - return 0; - else - return 1; -} - - -PyTypeObject -_PyWeakref_RefType = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "weakref", - sizeof(PyWeakReference), - 0, - weakref_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)weakref_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - (hashfunc)weakref_hash, /*tp_hash*/ - (ternaryfunc)weakref_call, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE - | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - 0, /*tp_doc*/ - (traverseproc)gc_traverse, /*tp_traverse*/ - (inquiry)gc_clear, /*tp_clear*/ - (richcmpfunc)weakref_richcompare, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - weakref___init__, /*tp_init*/ - PyType_GenericAlloc, /*tp_alloc*/ - weakref___new__, /*tp_new*/ - PyObject_GC_Del, /*tp_free*/ -}; - - -static int -proxy_checkref(PyWeakReference *proxy) -{ - if (PyWeakref_GET_OBJECT(proxy) == Py_None) { - PyErr_SetString(PyExc_ReferenceError, - "weakly-referenced object no longer exists"); - return 0; - } - return 1; -} - - -/* If a parameter is a proxy, check that it is still "live" and wrap it, - * replacing the original value with the raw object. Raises ReferenceError - * if the param is a dead proxy. - */ -#define UNWRAP(o) \ - if (PyWeakref_CheckProxy(o)) { \ - if (!proxy_checkref((PyWeakReference *)o)) \ - return NULL; \ - o = PyWeakref_GET_OBJECT(o); \ - } - -#define UNWRAP_I(o) \ - if (PyWeakref_CheckProxy(o)) { \ - if (!proxy_checkref((PyWeakReference *)o)) \ - return -1; \ - o = PyWeakref_GET_OBJECT(o); \ - } - -#define WRAP_UNARY(method, generic) \ - static PyObject * \ - method(PyObject *proxy) { \ - UNWRAP(proxy); \ - return generic(proxy); \ - } - -#define WRAP_BINARY(method, generic) \ - static PyObject * \ - method(PyObject *x, PyObject *y) { \ - UNWRAP(x); \ - UNWRAP(y); \ - return generic(x, y); \ - } - -/* Note that the third arg needs to be checked for NULL since the tp_call - * slot can receive NULL for this arg. - */ -#define WRAP_TERNARY(method, generic) \ - static PyObject * \ - method(PyObject *proxy, PyObject *v, PyObject *w) { \ - UNWRAP(proxy); \ - UNWRAP(v); \ - if (w != NULL) \ - UNWRAP(w); \ - return generic(proxy, v, w); \ - } - - -/* direct slots */ - -WRAP_BINARY(proxy_getattr, PyObject_GetAttr) -WRAP_UNARY(proxy_str, PyObject_Str) -WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords) - -static PyObject * -proxy_repr(PyWeakReference *proxy) -{ - char buf[160]; - PyOS_snprintf(buf, sizeof(buf), - "<weakproxy at %p to %.100s at %p>", proxy, - PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name, - PyWeakref_GET_OBJECT(proxy)); - return PyString_FromString(buf); -} - - -static int -proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value) -{ - if (!proxy_checkref(proxy)) - return -1; - return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value); -} - -static int -proxy_compare(PyObject *proxy, PyObject *v) -{ - UNWRAP_I(proxy); - UNWRAP_I(v); - return PyObject_Compare(proxy, v); -} - -/* number slots */ -WRAP_BINARY(proxy_add, PyNumber_Add) -WRAP_BINARY(proxy_sub, PyNumber_Subtract) -WRAP_BINARY(proxy_mul, PyNumber_Multiply) -WRAP_BINARY(proxy_div, PyNumber_Divide) -WRAP_BINARY(proxy_mod, PyNumber_Remainder) -WRAP_BINARY(proxy_divmod, PyNumber_Divmod) -WRAP_TERNARY(proxy_pow, PyNumber_Power) -WRAP_UNARY(proxy_neg, PyNumber_Negative) -WRAP_UNARY(proxy_pos, PyNumber_Positive) -WRAP_UNARY(proxy_abs, PyNumber_Absolute) -WRAP_UNARY(proxy_invert, PyNumber_Invert) -WRAP_BINARY(proxy_lshift, PyNumber_Lshift) -WRAP_BINARY(proxy_rshift, PyNumber_Rshift) -WRAP_BINARY(proxy_and, PyNumber_And) -WRAP_BINARY(proxy_xor, PyNumber_Xor) -WRAP_BINARY(proxy_or, PyNumber_Or) -WRAP_UNARY(proxy_int, PyNumber_Int) -WRAP_UNARY(proxy_long, PyNumber_Long) -WRAP_UNARY(proxy_float, PyNumber_Float) -WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd) -WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract) -WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply) -WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide) -WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder) -WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower) -WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift) -WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift) -WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd) -WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor) -WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr) - -static int -proxy_nonzero(PyWeakReference *proxy) -{ - PyObject *o = PyWeakref_GET_OBJECT(proxy); - if (!proxy_checkref(proxy)) - return -1; - return PyObject_IsTrue(o); -} - -static void -proxy_dealloc(PyWeakReference *self) -{ - if (self->wr_callback != NULL) - PyObject_GC_UnTrack((PyObject *)self); - clear_weakref(self); - PyObject_GC_Del(self); -} - -/* sequence slots */ - -static PyObject * -proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j) -{ - if (!proxy_checkref(proxy)) - return NULL; - return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j); -} - -static int -proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value) -{ - if (!proxy_checkref(proxy)) - return -1; - return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value); -} - -static int -proxy_contains(PyWeakReference *proxy, PyObject *value) -{ - if (!proxy_checkref(proxy)) - return -1; - return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value); -} - - -/* mapping slots */ - -static Py_ssize_t -proxy_length(PyWeakReference *proxy) -{ - if (!proxy_checkref(proxy)) - return -1; - return PyObject_Length(PyWeakref_GET_OBJECT(proxy)); -} - -WRAP_BINARY(proxy_getitem, PyObject_GetItem) - -static int -proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value) -{ - if (!proxy_checkref(proxy)) - return -1; - - if (value == NULL) - return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key); - else - return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value); -} - -/* iterator slots */ - -static PyObject * -proxy_iter(PyWeakReference *proxy) -{ - if (!proxy_checkref(proxy)) - return NULL; - return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy)); -} - -static PyObject * -proxy_iternext(PyWeakReference *proxy) -{ - if (!proxy_checkref(proxy)) - return NULL; - return PyIter_Next(PyWeakref_GET_OBJECT(proxy)); -} - - -static PyNumberMethods proxy_as_number = { - proxy_add, /*nb_add*/ - proxy_sub, /*nb_subtract*/ - proxy_mul, /*nb_multiply*/ - proxy_div, /*nb_divide*/ - proxy_mod, /*nb_remainder*/ - proxy_divmod, /*nb_divmod*/ - proxy_pow, /*nb_power*/ - proxy_neg, /*nb_negative*/ - proxy_pos, /*nb_positive*/ - proxy_abs, /*nb_absolute*/ - (inquiry)proxy_nonzero, /*nb_nonzero*/ - proxy_invert, /*nb_invert*/ - proxy_lshift, /*nb_lshift*/ - proxy_rshift, /*nb_rshift*/ - proxy_and, /*nb_and*/ - proxy_xor, /*nb_xor*/ - proxy_or, /*nb_or*/ - 0, /*nb_coerce*/ - proxy_int, /*nb_int*/ - proxy_long, /*nb_long*/ - proxy_float, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ - proxy_iadd, /*nb_inplace_add*/ - proxy_isub, /*nb_inplace_subtract*/ - proxy_imul, /*nb_inplace_multiply*/ - proxy_idiv, /*nb_inplace_divide*/ - proxy_imod, /*nb_inplace_remainder*/ - proxy_ipow, /*nb_inplace_power*/ - proxy_ilshift, /*nb_inplace_lshift*/ - proxy_irshift, /*nb_inplace_rshift*/ - proxy_iand, /*nb_inplace_and*/ - proxy_ixor, /*nb_inplace_xor*/ - proxy_ior, /*nb_inplace_or*/ -}; - -static PySequenceMethods proxy_as_sequence = { - (lenfunc)proxy_length, /*sq_length*/ - 0, /*sq_concat*/ - 0, /*sq_repeat*/ - 0, /*sq_item*/ - (ssizessizeargfunc)proxy_slice, /*sq_slice*/ - 0, /*sq_ass_item*/ - (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/ - (objobjproc)proxy_contains, /* sq_contains */ -}; - -static PyMappingMethods proxy_as_mapping = { - (lenfunc)proxy_length, /*mp_length*/ - proxy_getitem, /*mp_subscript*/ - (objobjargproc)proxy_setitem, /*mp_ass_subscript*/ -}; - - -PyTypeObject -_PyWeakref_ProxyType = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "weakproxy", - sizeof(PyWeakReference), - 0, - /* methods */ - (destructor)proxy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - proxy_compare, /* tp_compare */ - (reprfunc)proxy_repr, /* tp_repr */ - &proxy_as_number, /* tp_as_number */ - &proxy_as_sequence, /* tp_as_sequence */ - &proxy_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - proxy_str, /* tp_str */ - proxy_getattr, /* tp_getattro */ - (setattrofunc)proxy_setattr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)gc_traverse, /* tp_traverse */ - (inquiry)gc_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)proxy_iter, /* tp_iter */ - (iternextfunc)proxy_iternext, /* tp_iternext */ -}; - - -PyTypeObject -_PyWeakref_CallableProxyType = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "weakcallableproxy", - sizeof(PyWeakReference), - 0, - /* methods */ - (destructor)proxy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - proxy_compare, /* tp_compare */ - (unaryfunc)proxy_repr, /* tp_repr */ - &proxy_as_number, /* tp_as_number */ - &proxy_as_sequence, /* tp_as_sequence */ - &proxy_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - proxy_call, /* tp_call */ - proxy_str, /* tp_str */ - proxy_getattr, /* tp_getattro */ - (setattrofunc)proxy_setattr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)gc_traverse, /* tp_traverse */ - (inquiry)gc_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)proxy_iter, /* tp_iter */ - (iternextfunc)proxy_iternext, /* tp_iternext */ -}; - - - -PyObject * -PyWeakref_NewRef(PyObject *ob, PyObject *callback) -{ - PyWeakReference *result = NULL; - PyWeakReference **list; - PyWeakReference *ref, *proxy; - - if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { - PyErr_Format(PyExc_TypeError, - "cannot create weak reference to '%s' object", - ob->ob_type->tp_name); - return NULL; - } - list = GET_WEAKREFS_LISTPTR(ob); - get_basic_refs(*list, &ref, &proxy); - if (callback == Py_None) - callback = NULL; - if (callback == NULL) - /* return existing weak reference if it exists */ - result = ref; - if (result != NULL) - Py_INCREF(result); - else { - /* Note: new_weakref() can trigger cyclic GC, so the weakref - list on ob can be mutated. This means that the ref and - proxy pointers we got back earlier may have been collected, - so we need to compute these values again before we use - them. */ - result = new_weakref(ob, callback); - if (result != NULL) { - get_basic_refs(*list, &ref, &proxy); - if (callback == NULL) { - if (ref == NULL) - insert_head(result, list); - else { - /* Someone else added a ref without a callback - during GC. Return that one instead of this one - to avoid violating the invariants of the list - of weakrefs for ob. */ - Py_DECREF(result); - Py_INCREF(ref); - result = ref; - } - } - else { - PyWeakReference *prev; - - prev = (proxy == NULL) ? ref : proxy; - if (prev == NULL) - insert_head(result, list); - else - insert_after(result, prev); - } - } - } - return (PyObject *) result; -} - - -PyObject * -PyWeakref_NewProxy(PyObject *ob, PyObject *callback) -{ - PyWeakReference *result = NULL; - PyWeakReference **list; - PyWeakReference *ref, *proxy; - - if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { - PyErr_Format(PyExc_TypeError, - "cannot create weak reference to '%s' object", - ob->ob_type->tp_name); - return NULL; - } - list = GET_WEAKREFS_LISTPTR(ob); - get_basic_refs(*list, &ref, &proxy); - if (callback == Py_None) - callback = NULL; - if (callback == NULL) - /* attempt to return an existing weak reference if it exists */ - result = proxy; - if (result != NULL) - Py_INCREF(result); - else { - /* Note: new_weakref() can trigger cyclic GC, so the weakref - list on ob can be mutated. This means that the ref and - proxy pointers we got back earlier may have been collected, - so we need to compute these values again before we use - them. */ - result = new_weakref(ob, callback); - if (result != NULL) { - PyWeakReference *prev; - - if (PyCallable_Check(ob)) - result->ob_type = &_PyWeakref_CallableProxyType; - else - result->ob_type = &_PyWeakref_ProxyType; - get_basic_refs(*list, &ref, &proxy); - if (callback == NULL) { - if (proxy != NULL) { - /* Someone else added a proxy without a callback - during GC. Return that one instead of this one - to avoid violating the invariants of the list - of weakrefs for ob. */ - Py_DECREF(result); - Py_INCREF(result = proxy); - goto skip_insert; - } - prev = ref; - } - else - prev = (proxy == NULL) ? ref : proxy; - - if (prev == NULL) - insert_head(result, list); - else - insert_after(result, prev); - skip_insert: - ; - } - } - return (PyObject *) result; -} - - -PyObject * -PyWeakref_GetObject(PyObject *ref) -{ - if (ref == NULL || !PyWeakref_Check(ref)) { - PyErr_BadInternalCall(); - return NULL; - } - return PyWeakref_GET_OBJECT(ref); -} - -/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's - * handle_weakrefs(). - */ -static void -handle_callback(PyWeakReference *ref, PyObject *callback) -{ - PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL); - - if (cbresult == NULL) - PyErr_WriteUnraisable(callback); - else - Py_DECREF(cbresult); -} - -/* This function is called by the tp_dealloc handler to clear weak references. - * - * This iterates through the weak references for 'object' and calls callbacks - * for those references which have one. It returns when all callbacks have - * been attempted. - */ -void -PyObject_ClearWeakRefs(PyObject *object) -{ - PyWeakReference **list; - - if (object == NULL - || !PyType_SUPPORTS_WEAKREFS(object->ob_type) - || object->ob_refcnt != 0) { - PyErr_BadInternalCall(); - return; - } - list = GET_WEAKREFS_LISTPTR(object); - /* Remove the callback-less basic and proxy references */ - if (*list != NULL && (*list)->wr_callback == NULL) { - clear_weakref(*list); - if (*list != NULL && (*list)->wr_callback == NULL) - clear_weakref(*list); - } - if (*list != NULL) { - PyWeakReference *current = *list; - Py_ssize_t count = _PyWeakref_GetWeakrefCount(current); - int restore_error = PyErr_Occurred() ? 1 : 0; - PyObject *err_type, *err_value, *err_tb; - - if (restore_error) - PyErr_Fetch(&err_type, &err_value, &err_tb); - if (count == 1) { - PyObject *callback = current->wr_callback; - - current->wr_callback = NULL; - clear_weakref(current); - if (callback != NULL) { - handle_callback(current, callback); - Py_DECREF(callback); - } - } - else { - PyObject *tuple; - Py_ssize_t i = 0; - - tuple = PyTuple_New(count * 2); - if (tuple == NULL) { - if (restore_error) - PyErr_Fetch(&err_type, &err_value, &err_tb); - return; - } - - for (i = 0; i < count; ++i) { - PyWeakReference *next = current->wr_next; - - Py_INCREF(current); - PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current); - PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback); - current->wr_callback = NULL; - clear_weakref(current); - current = next; - } - for (i = 0; i < count; ++i) { - PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1); - - if (callback != NULL) { - PyObject *item = PyTuple_GET_ITEM(tuple, i * 2); - handle_callback((PyWeakReference *)item, callback); - } - } - Py_DECREF(tuple); - } - if (restore_error) - PyErr_Restore(err_type, err_value, err_tb); - } -} |