Commit f677127a authored by Marius Wachtler's avatar Marius Wachtler

Add dictproxy and use it for type.__dict__

parent e95f4bef
......@@ -390,6 +390,7 @@ STDOBJECT_SRCS := \
iterobject.c \
bufferobject.c \
cobject.c \
dictproxy.c \
$(EXTRA_STDOBJECT_SRCS)
STDPYTHON_SRCS := \
......
......@@ -78,6 +78,7 @@ file(GLOB_RECURSE STDOBJECT_SRCS Objects
bytes_methods.c
capsule.c
cobject.c
dictproxy.c
exceptions.c
floatobject.c
iterobject.c
......
......@@ -80,6 +80,8 @@ PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type;
PyAPI_DATA(PyTypeObject) PyDictProxy_Type;
PyAPI_DATA(PyTypeObject) PyGetSetDescr_Type;
PyAPI_DATA(PyTypeObject) PyMemberDescr_Type;
#else
PyAPI_DATA(PyTypeObject) PyDictProxy_Type;
#endif
// (Pyston TODO: add #defines to our names)
PyAPI_DATA(PyTypeObject*) wrapperdescr_cls;
......
// This file is originally from CPython 2.7, with modifications for Pyston
// The code is normally part of descrobject.c
#include "Python.h"
/* --- 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 PyObject *
proxy_repr(proxyobject *pp)
{
PyObject *dictrepr;
PyObject *result;
dictrepr = PyObject_Repr(pp->dict);
if (dictrepr == NULL)
return NULL;
result = PyString_FromFormat("dict_proxy(%s)", PyString_AS_STRING(dictrepr));
Py_DECREF(dictrepr);
return result;
}
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);
}
PyTypeObject PyDictProxy_Type = {
// Pyston change:
// PyVarObject_HEAD_INIT(&PyType_Type, 0)
PyVarObject_HEAD_INIT(NULL, 0)
"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 */
(reprfunc)proxy_repr, /* 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, &PyDictProxy_Type);
if (pp != NULL) {
Py_INCREF(dict);
pp->dict = dict;
_PyObject_GC_TRACK(pp);
}
return (PyObject *)pp;
}
......@@ -439,8 +439,17 @@ Box* dictContains(BoxedDict* self, Box* k) {
/* Return 1 if `key` is in dict `op`, 0 if not, and -1 on error. */
extern "C" int PyDict_Contains(PyObject* op, PyObject* key) noexcept {
BoxedDict* mp = (BoxedDict*)op;
try {
if (op->cls == attrwrapper_cls) {
Box* rtn = PyObject_CallMethod(op, "__contains__", "O", key);
if (!rtn)
return -1;
return rtn == True;
}
BoxedDict* mp = (BoxedDict*)op;
assert(isSubclass(mp->cls, dict_cls));
return mp->getOrNull(key) ? 1 : 0;
} catch (ExcInfo e) {
setCAPIException(e);
......
......@@ -4391,8 +4391,8 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
base_heap_cls->nslots() * sizeof(BoxedHeapClass::SlotOffset));
}
if (!made->getattr("__dict__") && (made->instancesHaveHCAttrs() || made->instancesHaveDictAttrs()))
made->giveAttr("__dict__", dict_descr);
if (made->instancesHaveHCAttrs() || made->instancesHaveDictAttrs())
made->setattr("__dict__", dict_descr, NULL);
for (const auto& p : attr_dict->d) {
auto k = coerceUnicodeToStr(p.first);
......
......@@ -495,6 +495,12 @@ extern "C" void typeGCHandler(GCVisitor* v, Box* b) {
}
static Box* typeDict(Box* obj, void* context) {
if (obj->cls->instancesHaveHCAttrs())
return PyDictProxy_New(obj->getAttrWrapper());
abort();
}
static Box* typeSubDict(Box* obj, void* context) {
if (obj->cls->instancesHaveHCAttrs())
return obj->getAttrWrapper();
if (obj->cls->instancesHaveDictAttrs())
......@@ -502,7 +508,7 @@ static Box* typeDict(Box* obj, void* context) {
abort();
}
static void typeSetDict(Box* obj, Box* val, void* context) {
static void typeSubSetDict(Box* obj, Box* val, void* context) {
if (obj->cls->instancesHaveDictAttrs()) {
RELEASE_ASSERT(val->cls == dict_cls, "");
obj->setDict(static_cast<BoxedDict*>(val));
......@@ -1635,6 +1641,20 @@ public:
return new AttrWrapperIter(self);
}
static Box* eq(Box* _self, Box* _other) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
// In order to not have to reimplement dict cmp: just create a real dict for now and us it.
BoxedDict* dict = (BoxedDict*)AttrWrapper::copy(_self);
assert(dict->cls == dict_cls);
const std::string eq_str = "__eq__";
return callattrInternal(dict, &eq_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(1), _other, NULL, NULL, NULL,
NULL);
}
static Box* ne(Box* _self, Box* _other) { return eq(_self, _other) == True ? False : True; }
friend class AttrWrapperIter;
};
......@@ -2437,9 +2457,9 @@ void setupRuntime() {
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
dict_descr = new (pyston_getset_cls) BoxedGetsetDescriptor(typeDict, typeSetDict, NULL);
dict_descr = new (pyston_getset_cls) BoxedGetsetDescriptor(typeSubDict, typeSubSetDict, NULL);
gc::registerPermanentRoot(dict_descr);
type_cls->giveAttr("__dict__", dict_descr);
type_cls->giveAttr("__dict__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeDict, NULL, NULL));
instancemethod_cls = BoxedHeapClass::create(type_cls, object_cls, &instancemethodGCHandler, 0,
......@@ -2619,6 +2639,8 @@ void setupRuntime() {
attrwrapper_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::str, UNKNOWN, 1)));
attrwrapper_cls->giveAttr("__contains__",
new BoxedFunction(boxRTFunction((void*)AttrWrapper::contains, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::eq, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::ne, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("keys", new BoxedFunction(boxRTFunction((void*)AttrWrapper::keys, LIST, 1)));
attrwrapper_cls->giveAttr("values", new BoxedFunction(boxRTFunction((void*)AttrWrapper::values, LIST, 1)));
attrwrapper_cls->giveAttr("items", new BoxedFunction(boxRTFunction((void*)AttrWrapper::items, LIST, 1)));
......@@ -2652,6 +2674,7 @@ void setupRuntime() {
PyCallIter_AddHasNext();
PyType_Ready(&PyCallIter_Type);
PyType_Ready(&PyCObject_Type);
PyType_Ready(&PyDictProxy_Type);
initerrno();
init_sha();
......
......@@ -31,9 +31,8 @@ print 'C.dd is %s' % str(C.dd)
print 'C.ndd is %s' % str(C.ndd)
C.dd = 6
C.ndd = 7
#TODO it would be nice to print these out (once __dict__ is implemented)
#print C.__dict__['dd']
#print C.__dict__['ndd']
print C.__dict__['dd']
print C.__dict__['ndd']
print C.dd
print C.ndd
......@@ -62,8 +61,8 @@ print 'D.dd is %s' % str(D.dd)
print 'D.ndd is %s' % str(D.ndd)
D.dd = 6
D.ndd = 7
#print D.__dict__['dd']
#print D.__dict__['ndd']
print D.__dict__['dd']
print D.__dict__['ndd']
class DataDescriptor(object):
def __get__(self, obj, type): return 1
......@@ -82,7 +81,7 @@ print d1.a
print 'D1.a is %s' % str(D1.a)
D1.a = 6
#print D1.__dict__['a']
print D1.__dict__['a']
class C2(object):
a = 4
......@@ -93,7 +92,7 @@ print d2.a
print 'D2.a is %s' % str(D2.a)
D2.a = 6
#print D2.__dict__['a']
print D2.__dict__['a']
class C3(object):
a = NonDataDescriptor()
......@@ -104,15 +103,15 @@ print d3.a
print 'D3.a is %s' % str(D3.a)
D3.a = 6
#print D3.__dict__['a']
print D3.__dict__['a']
class C4(object):
a = 6
class D4(C4):
a = NonDataDescriptor()
d4 = D4()
#print d4.a
print d4.a
print 'D4.a is %s' % str(D4.a)
D4.a = 6
#print D4.__dict__['a']
print D4.__dict__['a']
......@@ -49,3 +49,14 @@ d1.clear()
print hasattr(c, "attr")
print hasattr(c, "foo")
print c.__dict__ is d1
dictproxy = C.__dict__
print type(dictproxy)
print "foo" in dictproxy
print "foo" in dictproxy.keys()
print type(dictproxy["foo"])
print dictproxy == dict(C.__dict__)
try:
dictproxy["test"] = "val"
except Exception as e:
print e
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