Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Lib/test/test_xml_etree_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class SizeofTest(unittest.TestCase):
def setUp(self):
self.elementsize = support.calcobjsize('5P')
# extra
self.extra = struct.calcsize('PnnP4P')
self.extra = struct.calcsize('PnnP4PNN')

check_sizeof = support.check_sizeof

Expand Down
20 changes: 20 additions & 0 deletions Modules/_elementtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ typedef struct {

PyObject* _children[STATIC_CHILDREN];

/* incremented whenever 'attrib' is externally mutated */
size_t attrs_version;
/* incremented whenever children are externally mutated */
size_t nodes_version;
} ElementObjectExtra;

typedef struct {
Expand Down Expand Up @@ -279,6 +283,9 @@ create_extra(ElementObject* self, PyObject* attrib)
self->extra->allocated = STATIC_CHILDREN;
self->extra->children = self->extra->_children;

self->extra->attrs_version = 0;
self->extra->nodes_version = 0;

return 0;
}

Expand Down Expand Up @@ -506,6 +513,7 @@ element_resize(ElementObject* self, Py_ssize_t extra)
}
self->extra->children = children;
self->extra->allocated = size;
self->extra->nodes_version++;
}

return 0;
Expand Down Expand Up @@ -539,6 +547,7 @@ element_add_subelement(elementtreestate *st, ElementObject *self,
self->extra->children[self->extra->length] = Py_NewRef(element);

self->extra->length++;
self->extra->nodes_version++;

return 0;
}
Expand Down Expand Up @@ -780,6 +789,7 @@ _elementtree_Element___copy___impl(ElementObject *self, PyTypeObject *cls)

assert(!element->extra->length);
element->extra->length = self->extra->length;
element->extra->nodes_version = self->extra->nodes_version;
}

return (PyObject*) element;
Expand Down Expand Up @@ -847,6 +857,7 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)
if (element_resize(element, self->extra->length) < 0)
goto error;

// TODO(picnixz): check for an evil child's __deepcopy__ on 'self'
for (i = 0; i < self->extra->length; i++) {
PyObject* child = deepcopy(st, self->extra->children[i], memo);
if (!child || !Element_Check(st, child)) {
Expand All @@ -862,6 +873,7 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)

assert(!element->extra->length);
element->extra->length = self->extra->length;
element->extra->nodes_version = 0;
}

/* add object to memo dictionary (so deepcopy won't visit it again) */
Expand Down Expand Up @@ -1548,6 +1560,7 @@ _elementtree_Element_insert_impl(ElementObject *self, Py_ssize_t index,
self->extra->children[index] = Py_NewRef(subelement);

self->extra->length++;
self->extra->nodes_version++;

Py_RETURN_NONE;
}
Expand Down Expand Up @@ -1645,6 +1658,7 @@ _elementtree_Element_remove_impl(ElementObject *self, PyObject *subelement)
return NULL;
}

// TODO(picnixz): check against evil __eq__
for (i = 0; i < self->extra->length; i++) {
if (self->extra->children[i] == subelement)
break;
Expand All @@ -1669,6 +1683,7 @@ _elementtree_Element_remove_impl(ElementObject *self, PyObject *subelement)
self->extra->length--;
for (; i < self->extra->length; i++)
self->extra->children[i] = self->extra->children[i+1];
self->extra->nodes_version++;

Py_DECREF(found);
Py_RETURN_NONE;
Expand Down Expand Up @@ -1724,6 +1739,7 @@ _elementtree_Element_set_impl(ElementObject *self, PyObject *key,
if (PyDict_SetItem(attrib, key, value) < 0)
return NULL;

self->extra->attrs_version++;
Py_RETURN_NONE;
}

Expand Down Expand Up @@ -1757,6 +1773,7 @@ element_setitem(PyObject* self_, Py_ssize_t index, PyObject* item)
self->extra->children[i] = self->extra->children[i+1];
}

self->extra->nodes_version++;
Py_DECREF(old);

return 0;
Expand Down Expand Up @@ -1907,6 +1924,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
}

self->extra->length -= slicelen;
self->extra->nodes_version++;

/* Discard the recycle list with all the deleted sub-elements */
Py_DECREF(recycle);
Expand Down Expand Up @@ -1982,6 +2000,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
}

self->extra->length += newlen - slicelen;
self->extra->nodes_version++;

Py_DECREF(seq);

Expand Down Expand Up @@ -2078,6 +2097,7 @@ element_attrib_setter(ElementObject *self, PyObject *value, void *closure)
return -1;
}
Py_XSETREF(self->extra->attrib, Py_NewRef(value));
self->extra->attrs_version++;
return 0;
}

Expand Down
Loading