7 * (c) 2005 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of the Python interface to mLib.
14 * mLib/Python is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * mLib/Python is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with mLib/Python; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Header files ------------------------------------------------------*/
35 #include <mLib/darray.h>
36 #include <mLib/dstr.h>
41 /*----- Data structures ---------------------------------------------------*/
43 DA_DECL(obj_v, PyObject *);
45 typedef struct da_pyobj {
49 #define DA_PYCHECK(o) PyObject_TypeCheck((o), &da_pytype)
50 #define DA_V(o) (&((da_pyobj *)(o))->v)
52 typedef struct daiter_pyobj {
57 #define DAITER_DA(obj) (((daiter_pyobj *)(obj))->da)
58 #define DAITER_V(obj) DA_V(DAITER_DA(obj))
59 #define DAITER_I(obj) (((daiter_pyobj *)(obj))->i)
61 static PyTypeObject da_pytype, daiter_pytype;
63 static int getseq(PyObject **pseq, PyObject ***v, size_t *n)
65 PyObject *seq = *pseq;
67 if (!seq || seq == Py_None) {
71 } else if (DA_PYCHECK(seq)) {
73 *n = DA_LEN(DA_V(seq));
75 } else if ((seq = PySequence_Fast(seq, "expected iterable")) == 0)
79 *v = PySequence_Fast_ITEMS(seq);
80 *n = PySequence_Fast_GET_SIZE(seq);
85 static void range_inc(PyObject **v, PyObject **vl)
86 { while (v < vl) { Py_INCREF(*v); v++; } }
87 static void range_dec(PyObject **v, PyObject **vl)
88 { if (v) { while (v < vl) { Py_DECREF(*v); v++; } } }
89 static void range_copy(PyObject ***gv, PyObject ***gvl)
91 size_t n = *gvl - *gv;
92 size_t sz = sizeof(PyObject *) * n;
94 if (!n) { *gv = *gvl = 0; return; }
101 static PyObject *abstract_pynew(PyTypeObject *ty,
102 PyObject *hunoz, PyObject *hukairz)
104 PyErr_SetString(PyExc_TypeError, "can't instantiate this type");
108 /*----- Iterator ----------------------------------------------------------*/
110 static PyObject *daiter_pynext(PyObject *me)
114 if (DAITER_I(me) >= DA_LEN(DAITER_V(me))) return (0);
115 x = DA(DAITER_V(me))[DAITER_I(me)]; DAITER_I(me)++; RETURN_OBJ(x);
118 static void daiter_pydealloc(PyObject *me)
119 { Py_DECREF(DAITER_DA(me)); PyObject_DEL(me); }
121 static PyTypeObject daiter_pytype = {
122 PyObject_HEAD_INIT(0) 0, /* Header */
123 "array.ArrayIter", /* @tp_name@ */
124 sizeof(daiter_pyobj), /* @tp_basicsize@ */
125 0, /* @tp_itemsize@ */
127 daiter_pydealloc, /* @tp_dealloc@ */
129 0, /* @tp_getattr@ */
130 0, /* @tp_setattr@ */
131 0, /* @tp_compare@ */
133 0, /* @tp_as_number@ */
134 0, /* @tp_as_sequence@ */
135 0, /* @tp_as_mapping@ */
139 0, /* @tp_getattro@ */
140 0, /* @tp_setattro@ */
141 0, /* @tp_as_buffer@ */
142 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
148 0, /* @tp_traverse@ */
150 0, /* @tp_richcompare@ */
151 0, /* @tp_weaklistoffset@ */
152 PyObject_SelfIter, /* @tp_iter@ */
153 daiter_pynext, /* @tp_iternexr@ */
154 0, /* @tp_methods@ */
155 0, /* @tp_members@ */
159 0, /* @tp_descr_get@ */
160 0, /* @tp_descr_set@ */
161 0, /* @tp_dictoffset@ */
163 PyType_GenericAlloc, /* @tp_alloc@ */
164 abstract_pynew, /* @tp_new@ */
169 /*----- Main array code ---------------------------------------------------*/
171 static void da_doinsert(PyObject *me, PyObject **items, size_t n,
172 size_t start, size_t end)
174 PyObject **v, **gv, **gvl;
175 obj_v *da = DA_V(me);
180 gv = v + start; gvl = v + end; range_copy(&gv, &gvl);
181 if (start < DA_LEN(da) - end) {
185 DA_UNSAFE_SLIDE(da, off);
186 memmove(v, v + off, sizeof(PyObject *) * start);
189 memmove(v + off, v, sizeof(PyObject *) * start);
190 DA_UNSAFE_UNSLIDE(da, off);
196 memmove(v + end + off, v + end,
197 sizeof(PyObject *) * (DA_LEN(da) - end));
200 memmove(v + end - off, v + end,
201 sizeof(PyObject *) * (DA_LEN(da) - end));
202 DA_UNSAFE_SHRINK(da, off);
204 DA_UNSAFE_EXTEND(da, off);
209 memcpy(v, items, sizeof(PyObject *) * n);
218 static int da_insert(PyObject *me, PyObject *seq, int start, int end)
223 if (0 > start || start > end || end > DA_LEN(DA_V(me))) {
224 PyErr_SetString(PyExc_IndexError, "bad slice");
227 if (getseq(&seq, &items, &n)) return (-1);
228 da_doinsert(me, items, n, start, end);
233 static PyObject *da_new(PyTypeObject *ty)
235 da_pyobj *me = (da_pyobj *)ty->tp_alloc(ty, 0);
237 return ((PyObject *)me);
240 static PyObject *da_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
241 { return (da_new(ty)); }
242 static int da_pyinit(PyObject *me, PyObject *arg, PyObject *kw)
245 static char *kwlist[] = { "sequence", 0 };
247 if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", kwlist, &init) ||
248 (init && da_insert((PyObject *)me, init, 0, 0)))
253 static void da_pydealloc(PyObject *me)
256 PyObject **v = DA(DA_V(me));
257 size_t n = DA_LEN(DA_V(me));
259 for (i = 0; i < n; i++) Py_DECREF(v[i]);
260 DA_DESTROY(DA_V(me));
263 static int da_pylength(PyObject *me)
264 { return (DA_LEN(DA_V(me))); }
266 static int da_pytraverse(PyObject *me, visitproc proc, void *arg)
269 PyObject **v = DA(DA_V(me));
270 size_t n = DA_LEN(DA_V(me));
273 for (i = 0; i < n; i++) {
274 if ((err = proc(v[i], arg)) != 0)
280 static int da_pyclear(PyObject *me)
282 range_dec(DA(DA_V(me)), DA(DA_V(me)) + DA_LEN(DA_V(me)));
287 static PyObject *da_pyconcat(PyObject *me, PyObject *other)
289 PyObject *x = da_new(&da_pytype);
290 PyObject **items = DA(DA_V(me));
291 size_t n = DA_LEN(DA_V(me));
293 da_doinsert(x, items, n, 0, 0);
294 if (da_insert(x, other, n, n)) {
301 static PyObject *da_pyrepeat(PyObject *me, int times)
303 PyObject *x = da_new(&da_pytype);
304 PyObject **items = DA(DA_V(me)), **dest;
305 size_t n = DA_LEN(DA_V(me));
308 DA_ENSURE(DA_V(x), n * times);
309 DA_UNSAFE_EXTEND(DA_V(x), n * times);
310 for (i = 0, dest = DA(DA_V(x)); i < times; i++, dest += n)
311 memcpy(dest, items, n * sizeof(PyObject *));
312 range_inc(DA(DA_V(x)), DA(DA_V(x)) + n * times);
316 static PyObject *da_pygetitem(PyObject *me, int i)
320 if (i < 0 || i >= DA_LEN(DA_V(me))) {
321 PyErr_SetString(PyExc_IndexError, "index out of range");
329 static PyObject *da_pygetslice(PyObject *me, int i, int j)
333 if (i < 0 || j < i || DA_LEN(DA_V(me)) < j) {
334 PyErr_SetString(PyExc_IndexError, "bad slice");
337 x = da_new(&da_pytype);
338 da_doinsert(x, DA(DA_V(me)) + i, j - i, 0, 0);
342 static int da_pyputitem(PyObject *me, int i, PyObject *x)
346 if (i < 0 || i >= DA_LEN(DA_V(me))) {
347 PyErr_SetString(PyExc_IndexError, "index out of range");
350 p = DA(DA_V(me)) + i;
357 static int da_pyputslice(PyObject *me, int i, int j, PyObject *x)
358 { return (da_insert(me, x, i, j)); }
360 static int da_pycontainsp(PyObject *me, PyObject *x)
362 PyObject **items = DA(DA_V(me));
363 size_t n = DA_LEN(DA_V(me));
367 for (i = 0; i < n; i++) {
368 if (PyObject_Cmp(items[i], x, &rc))
376 static PyObject *da_pyrepr(PyObject *me)
379 PyObject *s, *rc = 0;
384 dstr_puts(&d, "Array([");
385 for (i = 0; i < DA_LEN(DA_V(me)); i++) {
386 if ((s = PyObject_Repr(DA(DA_V(me))[i])) == 0 ||
387 PyString_AsStringAndSize(s, &p, &n)) {
391 if (i) dstr_puts(&d, ", ");
396 rc = PyString_FromStringAndSize(d.buf, d.len);
402 static PyObject *da_pyappend(PyObject *me, PyObject *seq)
404 size_t n = DA_LEN(DA_V(me));
405 if (da_insert(me, seq, n, n)) return (0);
409 static PyObject *da_pyiprepeat(PyObject *me, int times)
411 PyObject **items, **dest;
412 size_t n = DA_LEN(DA_V(me));
416 PyErr_SetString(PyExc_ValueError, "multiplier must be nonnegative");
420 items = DA(DA_V(me));
421 range_dec(items, items + n);
426 DA_ENSURE(DA_V(me), n * times);
427 items = DA(DA_V(me));
428 for (i = 0, dest = items + n; i < times; i++, dest += n)
429 memcpy(dest, items, n * sizeof(PyObject *));
430 range_inc(items + n, dest);
431 DA_UNSAFE_EXTEND(DA_V(me), n * times);
435 static PyObject *da_pyget(PyObject *me, PyObject *index)
437 if (PySlice_Check(index)) {
438 int start, stop, step, len;
443 if (PySlice_GetIndicesEx((PySliceObject *)index, DA_LEN(DA_V(me)),
444 &start, &stop, &step, &len))
446 if (step == 1) return (da_pygetslice(me, start, stop));
447 v = da_new(&da_pytype);
448 DA_ENSURE(DA_V(v), len);
450 ww = DA(DA_V(me)) + start;
451 DA_UNSAFE_EXTEND(DA_V(v), len);
455 vv++; ww += step; len--;
457 return ((PyObject *)v);
461 if ((i = PyInt_AsLong(index)) == -1 && PyErr_Occurred()) return (0);
462 return (da_pygetitem(me, i));
466 static int da_pyput(PyObject *me, PyObject *index, PyObject *x)
468 if (PySlice_Check(index)) {
469 int start, stop, step, len;
475 if (PySlice_GetIndicesEx((PySliceObject *)index, DA_LEN(DA_V(me)),
476 &start, &stop, &step, &len))
478 if (step == 1) return (da_insert(me, x, start, stop));
479 if (getseq(&x, &vv, &n)) return (-1);
481 PyErr_SetString(PyExc_ValueError, "wrong number of items");
485 g = gg = xmalloc(len * sizeof(PyObject *));
486 ww = DA(DA_V(me)) + start;
488 *gg++ = *ww; *ww = *vv++;
499 if ((i = PyInt_AsLong(index)) == -1 && PyErr_Occurred()) return (-1);
500 return (da_pyputitem(me, i, x));
504 static PyObject *da_pyiter(PyObject *me)
506 daiter_pyobj *i = PyObject_NEW(daiter_pyobj, &daiter_pytype);
507 i->da = me; Py_INCREF(me);
509 return ((PyObject *)i);
512 static PyObject *dameth_push(PyObject *me, PyObject *arg)
516 if (!PyArg_ParseTuple(arg, "O:push", &x)) return (0);
518 DA_PUSH(DA_V(me), x);
522 static PyObject *dameth_pop(PyObject *me, PyObject *arg)
526 if (!PyArg_ParseTuple(arg, ":pop")) return (0);
528 x = DA_POP(DA_V(me));
529 CATCH switch (exc_type) {
531 PyErr_SetString(PyExc_ValueError, "stack underflow");
539 static PyObject *dameth_unshift(PyObject *me, PyObject *arg)
543 if (!PyArg_ParseTuple(arg, "O:unshift", &x)) return (0);
545 DA_UNSHIFT(DA_V(me), x);
549 static PyObject *dameth_shift(PyObject *me, PyObject *arg)
553 if (!PyArg_ParseTuple(arg, ":shift")) return (0);
555 x = DA_SHIFT(DA_V(me));
556 CATCH switch (exc_type) {
558 PyErr_SetString(PyExc_ValueError, "stack underflow");
566 static PyObject *dameth_tidy(PyObject *me, PyObject *arg)
568 if (!PyArg_ParseTuple(arg, ":tidy")) return (0);
573 static PyMethodDef da_pymethods[] = {
574 #define METHNAME(func) dameth_##func
575 METH (push, "A.push(X): [A, B, ..., W], X -> [A, B, ..., W, X]")
576 METH (pop, "A.pop() -> X: [A, B, ..., W, X] -> [A, B, ..., W]")
577 METH (unshift, "A.unshift(X): [A, B, ..., W], X -> [X, A, ..., W]")
578 METH (shift, "A.shift() -> X: [X, A, ..., W] -> [A, ..., W], X")
579 METH (tidy, "A.tidy()")
584 static PySequenceMethods da_pysequence = {
585 da_pylength, /* @sq_length@ */
586 da_pyconcat, /* @sq_concat@ */
587 da_pyrepeat, /* @sq_repeat@ */
588 da_pygetitem, /* @sq_item@ */
589 da_pygetslice, /* @sq_slice@ */
590 da_pyputitem, /* @sq_ass_item@ */
591 da_pyputslice, /* @sq_ass_slice@ */
592 da_pycontainsp, /* @sq_contains@ */
593 da_pyappend, /* @sq_inplace_concat@ */
594 da_pyiprepeat /* @sq_inplace_repeat@ */
597 static PyMappingMethods da_pymapping = {
598 da_pylength, /* @mp_length@ */
599 da_pyget, /* @mp_subscript@ */
600 da_pyput /* @mp_ass_subscript@ */
603 static PyTypeObject da_pytype = {
604 PyObject_HEAD_INIT(0) 0, /* Header */
605 "array.Array", /* @tp_name@ */
606 sizeof(da_pyobj), /* @tp_basicsize@ */
607 0, /* @tp_itemsize@ */
609 da_pydealloc, /* @tp_dealloc@ */
611 0, /* @tp_getattr@ */
612 0, /* @tp_setattr@ */
613 0, /* @tp_compare@ */
614 da_pyrepr, /* @tp_repr@ */
615 0, /* @tp_as_number@ */
616 &da_pysequence, /* @tp_as_sequence@ */
617 &da_pymapping, /* @tp_as_mapping@ */
620 &da_pyrepr, /* @tp_str@ */
621 0, /* @tp_getattro@ */
622 0, /* @tp_setattro@ */
623 0, /* @tp_as_buffer@ */
624 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
628 "Double-ended array type.",
630 da_pytraverse, /* @tp_traverse@ */
631 da_pyclear, /* @tp_clear@ */
632 0, /* @tp_richcompare@ */
633 0, /* @tp_weaklistoffset@ */
634 da_pyiter, /* @tp_iter@ */
635 0, /* @tp_iternext@ */
636 da_pymethods, /* @tp_methods@ */
637 0, /* @tp_members@ */
641 0, /* @tp_descr_get@ */
642 0, /* @tp_descr_set@ */
643 0, /* @tp_dictoffset@ */
644 da_pyinit, /* @tp_init@ */
645 PyType_GenericAlloc, /* @tp_alloc@ */
646 da_pynew, /* @tp_new@ */
651 /*----- Initialization ----------------------------------------------------*/
653 static PyMethodDef emptymethods[] = { { 0 } };
657 PyObject *mod = Py_InitModule("array", emptymethods);
658 PyType_Ready(&da_pytype); PyType_Ready(&daiter_pytype);
659 PyModule_AddObject(mod, "Array", (PyObject *)&da_pytype);
660 PyModule_AddObject(mod, "ArrayIter", (PyObject *)&daiter_pytype);
663 /*----- That's all, folks -------------------------------------------------*/