[cdatapack] implement iteritems()

Summary: `iteritems()` differs from `__iter__()` slightly in that it yields the delta base and delta.

Test Plan:
run this toy program

```
#!/usr/bin/env python

import cdatapack

a = cdatapack.datapack('d864669a5651d04505ec6e5e9dba1319cde71f7b')
for x in a.iterentries():
    print x[0], repr(x[1]), repr(x[2]), len(x[3])
for x in a:
    print x[0], repr(x[1])
```

Reviewers: #fastmanifest, durham

Reviewed By: durham

Subscribers: mitrandir

Differential Revision: https://phabricator.intern.facebook.com/D3659133

Signature: t1:3659133:1470339839:dbdce5990a30ffe019ccc44fce97925b64524acd
This commit is contained in:
Tony Tung 2016-08-04 13:48:21 -07:00
parent a28137668e
commit 113f23b65e

View File

@ -17,6 +17,7 @@
// ==== Forward declarations ====
static PyTypeObject cdatapack_iterator_type;
static PyTypeObject cdatapack_deltas_iterator_type;
// ==== py_cdatapack PyObject declaration ====
@ -95,9 +96,36 @@ static py_cdatapack_iterator *cdatapack_getiter(py_cdatapack *self) {
return iterator;
}
/**
* Returns a delta iterator for a cdatapack.
*/
static py_cdatapack_iterator *cdatapack_getiterentries(py_cdatapack *self) {
py_cdatapack_iterator *iterator;
iterator = PyObject_New(
py_cdatapack_iterator,
&cdatapack_deltas_iterator_type);
if (iterator == NULL) {
return NULL;
}
iterator->datapack = self;
Py_INCREF(iterator->datapack);
/* TODO: should have a data_version type and use sizeof(..) */
iterator->ptr = ((uint8_t *) self->handle->data_mmap) + 1;
iterator->end = ((uint8_t *) self->handle->data_mmap) +
self->handle->data_file_sz;
return iterator;
}
// ==== cdatapack ctype declaration ====
static PyMethodDef cdatapack_methods[] = {
{"iterentries", (PyCFunction)cdatapack_getiterentries,
METH_NOARGS,
"Iterate over (path, nodeid, deltabasenode, delta) tuples in this "
"datapack."},
{NULL, NULL}
};
@ -215,6 +243,86 @@ static PyTypeObject cdatapack_iterator_type = {
(iternextfunc) cdatapack_iterator_iternext, /* tp_iternext: next() method */
};
// ==== cdatapack_deltas_iterator class methods ====
/**
* Deallocates a cdatapack deltas iterator
*/
static void cdatapack_deltas_iterator_dealloc(py_cdatapack_iterator *self) {
Py_XDECREF(self->datapack);
PyObject_Del(self);
}
/**
* Yields the next item from the iterator.
*/
static PyObject *cdatapack_deltas_iterator_iternext(
py_cdatapack_iterator *iterator) {
delta_chain_link_t link;
if (iterator->ptr >= iterator->end) {
return NULL;
}
iterator->ptr = getdeltachainlink(iterator->ptr, &link);
PyObject *tuple = NULL, *fn = NULL, *node = NULL, *deltabasenode, *delta;
fn = PyString_FromStringAndSize(link.filename, link.filename_sz);
node = PyString_FromStringAndSize((const char *) link.node, NODE_SZ);
deltabasenode = PyString_FromStringAndSize((const char *) link.deltabase_node,
NODE_SZ);
delta = PyString_FromStringAndSize((const char *) link.delta, link.delta_sz);
if (fn == NULL || node == NULL || deltabasenode == NULL || delta == NULL) {
goto cleanup;
}
tuple = PyTuple_Pack(4, fn, node, deltabasenode, delta);
cleanup:
Py_XDECREF(fn);
Py_XDECREF(node);
Py_XDECREF(deltabasenode);
Py_XDECREF(delta);
return tuple;
}
// ==== cdatapack_deltas_iterator ctype declaration ====
static PyTypeObject cdatapack_deltas_iterator_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"cdatapack.datapack.iterentries", /* tp_name */
sizeof(py_cdatapack_iterator), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)cdatapack_deltas_iterator_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 - length/contains */
0, /* tp_as_mapping - getitem/setitem*/
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Iterator for delta chains in a datapack.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter: __iter__() method */
(iternextfunc) cdatapack_deltas_iterator_iternext, /* tp_iternext: next()
* method */
};
static PyMethodDef mod_methods[] = {
{NULL, NULL}
};