Commit 40f3a650 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add mapping methods and corresponding test

parent 4e5e1dba
...@@ -97,46 +97,48 @@ static PyObject* wrap_sq_item(PyObject* self, PyObject* args, void* wrapped) noe ...@@ -97,46 +97,48 @@ static PyObject* wrap_sq_item(PyObject* self, PyObject* args, void* wrapped) noe
return NULL; return NULL;
} }
PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept { static PyObject* wrap_lenfunc(PyObject* self, PyObject* args, void* wrapped) {
try { lenfunc func = (lenfunc)wrapped;
// TODO: runtime ICs? Py_ssize_t res;
Box* new_attr = typeLookup(self, _new_str, NULL);
assert(new_attr);
new_attr = processDescriptor(new_attr, None, self);
return runtimeCall(new_attr, ArgPassSpec(1, 0, true, true), self, args, kwds, NULL, NULL); if (!check_num_args(args, 0))
} catch (Box* e) { return NULL;
abort(); res = (*func)(self);
} if (res == -1 && PyErr_Occurred())
return NULL;
return PyInt_FromLong((long)res);
} }
PyObject* slot_tp_call(PyObject* self, PyObject* args, PyObject* kwds) noexcept { static PyObject* wrap_objobjargproc(PyObject* self, PyObject* args, void* wrapped) {
try { objobjargproc func = (objobjargproc)wrapped;
Py_FatalError("this function is untested"); int res;
PyObject* key, *value;
// TODO: runtime ICs? if (!PyArg_UnpackTuple(args, "", 2, 2, &key, &value))
return runtimeCall(self, ArgPassSpec(0, 0, true, true), args, kwds, NULL, NULL, NULL); return NULL;
} catch (Box* e) { res = (*func)(self, key, value);
abort(); if (res == -1 && PyErr_Occurred())
} return NULL;
Py_INCREF(Py_None);
return Py_None;
} }
PyObject* slot_tp_repr(PyObject* self) noexcept { static PyObject* wrap_delitem(PyObject* self, PyObject* args, void* wrapped) {
try { objobjargproc func = (objobjargproc)wrapped;
return repr(self); int res;
} catch (Box* e) { PyObject* key;
abort();
}
}
PyObject* slot_sq_item(PyObject* self, Py_ssize_t i) noexcept { if (!check_num_args(args, 1))
try { return NULL;
return getitem(self, boxInt(i)); key = PyTuple_GET_ITEM(args, 0);
} catch (Box* e) { res = (*func)(self, key, NULL);
abort(); if (res == -1 && PyErr_Occurred())
} return NULL;
Py_INCREF(Py_None);
return Py_None;
} }
static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** attrobj) { static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** attrobj) {
PyObject* res; PyObject* res;
...@@ -180,6 +182,64 @@ static PyObject* call_method(PyObject* o, const char* name, PyObject** nameobj, ...@@ -180,6 +182,64 @@ static PyObject* call_method(PyObject* o, const char* name, PyObject** nameobj,
return retval; return retval;
} }
PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept {
try {
// TODO: runtime ICs?
Box* new_attr = typeLookup(self, _new_str, NULL);
assert(new_attr);
new_attr = processDescriptor(new_attr, None, self);
return runtimeCall(new_attr, ArgPassSpec(1, 0, true, true), self, args, kwds, NULL, NULL);
} catch (Box* e) {
abort();
}
}
PyObject* slot_tp_call(PyObject* self, PyObject* args, PyObject* kwds) noexcept {
try {
Py_FatalError("this function is untested");
// TODO: runtime ICs?
return runtimeCall(self, ArgPassSpec(0, 0, true, true), args, kwds, NULL, NULL, NULL);
} catch (Box* e) {
abort();
}
}
PyObject* slot_tp_repr(PyObject* self) noexcept {
try {
return repr(self);
} catch (Box* e) {
abort();
}
}
PyObject* slot_sq_item(PyObject* self, Py_ssize_t i) noexcept {
try {
return getitem(self, boxInt(i));
} catch (Box* e) {
abort();
}
}
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;
}
// Copied from CPython: // Copied from CPython:
#define SLOT0(FUNCNAME, OPSTR) \ #define SLOT0(FUNCNAME, OPSTR) \
static PyObject* FUNCNAME(PyObject* self) noexcept { \ static PyObject* FUNCNAME(PyObject* self) noexcept { \
...@@ -193,8 +253,25 @@ static PyObject* call_method(PyObject* o, const char* name, PyObject** nameobj, ...@@ -193,8 +253,25 @@ static PyObject* call_method(PyObject* o, const char* name, PyObject** nameobj,
return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \ return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \
} }
#define slot_mp_length slot_sq_length
SLOT1(slot_mp_subscript, "__getitem__", PyObject*, "O") 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;
}
typedef wrapper_def slotdef; typedef wrapper_def slotdef;
static void** slotptr(BoxedClass* type, int offset) { static void** slotptr(BoxedClass* type, int offset) {
...@@ -266,7 +343,11 @@ static slotdef slotdefs[] = { ...@@ -266,7 +343,11 @@ static slotdef slotdefs[] = {
PyWrapperFlag_KEYWORDS), PyWrapperFlag_KEYWORDS),
TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""), TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
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("__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]"),
// SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, "x.__len__() <==> len(x)"), // SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, "x.__len__() <==> len(x)"),
/* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL. /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
...@@ -400,7 +481,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) { ...@@ -400,7 +481,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) {
RELEASE_ASSERT(cls->tp_setattr == NULL, ""); RELEASE_ASSERT(cls->tp_setattr == NULL, "");
RELEASE_ASSERT(cls->tp_compare == NULL, ""); RELEASE_ASSERT(cls->tp_compare == NULL, "");
RELEASE_ASSERT(cls->tp_as_number == NULL, ""); RELEASE_ASSERT(cls->tp_as_number == NULL, "");
RELEASE_ASSERT(cls->tp_as_mapping == NULL, "");
RELEASE_ASSERT(cls->tp_hash == NULL, ""); RELEASE_ASSERT(cls->tp_hash == NULL, "");
RELEASE_ASSERT(cls->tp_str == NULL, ""); RELEASE_ASSERT(cls->tp_str == NULL, "");
RELEASE_ASSERT(cls->tp_getattro == NULL || cls->tp_getattro == PyObject_GenericGetAttr, ""); RELEASE_ASSERT(cls->tp_getattro == NULL || cls->tp_getattro == PyObject_GenericGetAttr, "");
......
...@@ -29,7 +29,7 @@ slots_tester_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -29,7 +29,7 @@ slots_tester_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
} }
static PyObject * static PyObject *
slots_tester_repr(slots_tester_object *obj) slots_tester_seq_repr(slots_tester_object *obj)
{ {
char buf[80]; char buf[80];
snprintf(buf, sizeof(buf), "<my custom repr: %d>", obj->n); snprintf(buf, sizeof(buf), "<my custom repr: %d>", obj->n);
...@@ -37,7 +37,7 @@ slots_tester_repr(slots_tester_object *obj) ...@@ -37,7 +37,7 @@ slots_tester_repr(slots_tester_object *obj)
} }
static PyObject * static PyObject *
slots_tester_call(slots_tester_object *obj, PyObject *args, PyObject *kw) slots_tester_seq_call(slots_tester_object *obj, PyObject *args, PyObject *kw)
{ {
if (!PyArg_ParseTuple(args, "")) if (!PyArg_ParseTuple(args, ""))
return NULL; return NULL;
...@@ -46,7 +46,7 @@ slots_tester_call(slots_tester_object *obj, PyObject *args, PyObject *kw) ...@@ -46,7 +46,7 @@ slots_tester_call(slots_tester_object *obj, PyObject *args, PyObject *kw)
} }
static PyObject* static PyObject*
slots_tester_item(slots_tester_object *obj, Py_ssize_t i) slots_tester_seq_item(slots_tester_object *obj, Py_ssize_t i)
{ {
if (i < 0 || i >= 5) { if (i < 0 || i >= 5) {
PyErr_SetString(PyExc_IndexError, "tuple index out of range"); PyErr_SetString(PyExc_IndexError, "tuple index out of range");
...@@ -55,13 +55,13 @@ slots_tester_item(slots_tester_object *obj, Py_ssize_t i) ...@@ -55,13 +55,13 @@ slots_tester_item(slots_tester_object *obj, Py_ssize_t i)
return PyInt_FromLong(i + obj->n); return PyInt_FromLong(i + obj->n);
} }
PyDoc_STRVAR(slots_tester_doc, "slots_tester doc"); PyDoc_STRVAR(slots_tester_seq_doc, "slots_tester_seq doc");
static PySequenceMethods slots_tester_as_sequence = { static PySequenceMethods slots_tester_seq_as_sequence = {
(lenfunc)0, (lenfunc)0,
(binaryfunc)0, /* sq_concat */ (binaryfunc)0, /* sq_concat */
(ssizeargfunc)0, /* sq_repeat */ (ssizeargfunc)0, /* sq_repeat */
(ssizeargfunc)slots_tester_item, /* sq_item */ (ssizeargfunc)slots_tester_seq_item, /* sq_item */
(ssizessizeargfunc)0, /* sq_slice */ (ssizessizeargfunc)0, /* sq_slice */
0, /* sq_ass_item */ 0, /* sq_ass_item */
0, /* sq_ass_slice */ 0, /* sq_ass_slice */
...@@ -69,9 +69,9 @@ static PySequenceMethods slots_tester_as_sequence = { ...@@ -69,9 +69,9 @@ static PySequenceMethods slots_tester_as_sequence = {
}; };
static PyTypeObject slots_tester = { static PyTypeObject slots_tester_seq = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"slots_test.slots_tester", /* tp_name */ "slots_test.slots_tester_seq", /* tp_name */
sizeof(slots_tester_object), /* tp_basicsize */ sizeof(slots_tester_object), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
/* methods */ /* methods */
...@@ -80,18 +80,83 @@ static PyTypeObject slots_tester = { ...@@ -80,18 +80,83 @@ static PyTypeObject slots_tester = {
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_compare */ 0, /* tp_compare */
(reprfunc)slots_tester_repr, /* tp_repr */ (reprfunc)slots_tester_seq_repr, /* tp_repr */
0, /* tp_as_number */ 0, /* tp_as_number */
&slots_tester_as_sequence, /* tp_as_sequence */ &slots_tester_seq_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */ 0, /* tp_as_mapping */
0, /* tp_hash */ 0, /* tp_hash */
(ternaryfunc)slots_tester_call, /* tp_call */ (ternaryfunc)slots_tester_seq_call, /* tp_call */
0, /* tp_str */ 0, /* tp_str */
0, /* tp_getattro */ 0, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */ Py_TPFLAGS_DEFAULT, /* tp_flags */
slots_tester_doc, /* tp_doc */ slots_tester_seq_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 */
slots_tester_new, /* tp_new */
0, /* tp_free */
};
static Py_ssize_t slots_tester_map_length(slots_tester_object* obj) {
return obj->n;
}
static PyObject* slots_tester_map_subscript(slots_tester_object* obj, PyObject* key) {
int n2 = PyInt_AsLong(key);
return PyInt_FromLong(n2 + obj->n);
}
static int slots_tester_map_ass_sub(slots_tester_object* obj, PyObject* key, PyObject* value) {
int n2 = PyInt_AsLong(key);
printf("Assigning to subscript for object with n=%d, key=%d, set/delete=%d\n", obj->n, n2, !!value);
return 0;
}
static PyMappingMethods slots_tester_map_asmapping = {
(lenfunc)slots_tester_map_length, /*mp_length*/
(binaryfunc)slots_tester_map_subscript, /*mp_subscript*/
(objobjargproc)slots_tester_map_ass_sub, /*mp_ass_subscript*/
};
static PyTypeObject slots_tester_map= {
PyVarObject_HEAD_INIT(NULL, 0)
"slots_test.slots_tester_map", /* tp_name */
sizeof(slots_tester_object), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
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 */
&slots_tester_map_asmapping, /* 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_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
...@@ -185,12 +250,17 @@ initslots_test(void) ...@@ -185,12 +250,17 @@ initslots_test(void)
if (m == NULL) if (m == NULL)
return; return;
int res = PyType_Ready(&slots_tester); int res = PyType_Ready(&slots_tester_seq);
if (res < 0)
return;
res = PyType_Ready(&slots_tester_map);
if (res < 0) if (res < 0)
return; return;
// Not sure if the result of PyInt_FromLong needs to be decref'd // Not sure if the result of PyInt_FromLong needs to be decref'd
PyDict_SetItemString(slots_tester.tp_dict, "set_through_tpdict", PyInt_FromLong(123)); PyDict_SetItemString(slots_tester_seq.tp_dict, "set_through_tpdict", PyInt_FromLong(123));
PyModule_AddObject(m, "SlotsTester", (PyObject *)&slots_tester); PyModule_AddObject(m, "SlotsTesterSeq", (PyObject *)&slots_tester_seq);
PyModule_AddObject(m, "SlotsTesterMap", (PyObject *)&slots_tester_map);
} }
...@@ -4,10 +4,17 @@ ...@@ -4,10 +4,17 @@
import slots_test import slots_test
for i in xrange(3): for i in xrange(3):
t = slots_test.SlotsTester(i + 5) t = slots_test.SlotsTesterSeq(i + 5)
print t, repr(t), t(), t[2] print t, repr(t), t(), t[2]
print slots_test.SlotsTester.set_through_tpdict, slots_test.SlotsTester(5).set_through_tpdict # print slots_test.SlotsTesterSeq.__doc__
print slots_test.SlotsTesterSeq.set_through_tpdict, slots_test.SlotsTesterSeq(5).set_through_tpdict
for i in xrange(3):
t = slots_test.SlotsTesterMap(i + 5)
print len(t), t[2]
t[1] = 5
del t[2]
class C(object): class C(object):
def __repr__(self): def __repr__(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment