5 * (c) 2005 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the Python interface to mLib.
12 * mLib/Python is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * mLib/Python is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with mLib/Python; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /*----- Header files ------------------------------------------------------*/
33 #include <mLib/darray.h>
34 #include <mLib/dstr.h>
40 /*----- Data structures ---------------------------------------------------*/
42 DA_DECL(obj_v
, PyObject
*);
44 typedef struct da_pyobj
{
48 #define DA_PYCHECK(o) PyObject_TypeCheck((o), &da_pytype)
49 #define DA_V(o) (&((da_pyobj *)(o))->v)
51 typedef struct daiter_pyobj
{
56 #define DAITER_DA(obj) (((daiter_pyobj *)(obj))->da)
57 #define DAITER_V(obj) DA_V(DAITER_DA(obj))
58 #define DAITER_I(obj) (((daiter_pyobj *)(obj))->i)
60 static int getseq(PyObject
**pseq
, PyObject
***v
, size_t *n
)
62 PyObject
*seq
= *pseq
;
64 if (!seq
|| seq
== Py_None
) {
68 } else if (DA_PYCHECK(seq
)) {
70 *n
= DA_LEN(DA_V(seq
));
72 } else if ((seq
= PySequence_Fast(seq
, "expected iterable")) == 0)
76 *v
= PySequence_Fast_ITEMS(seq
);
77 *n
= PySequence_Fast_GET_SIZE(seq
);
82 static void range_inc(PyObject
**v
, PyObject
**vl
)
83 { while (v
< vl
) { Py_INCREF(*v
); v
++; } }
84 static void range_dec(PyObject
**v
, PyObject
**vl
)
85 { if (v
) { while (v
< vl
) { Py_DECREF(*v
); v
++; } } }
86 static void range_copy(PyObject
***gv
, PyObject
***gvl
)
88 size_t n
= *gvl
- *gv
;
89 size_t sz
= sizeof(PyObject
*) * n
;
91 if (!n
) { *gv
= *gvl
= 0; return; }
98 static PyObject
*abstract_pynew(PyTypeObject
*ty
,
99 PyObject
*hunoz
, PyObject
*hukairz
)
101 PyErr_SetString(PyExc_TypeError
, "can't instantiate this type");
105 /*----- Iterator ----------------------------------------------------------*/
107 static PyObject
*daiter_pynext(PyObject
*me
)
111 if (DAITER_I(me
) >= DA_LEN(DAITER_V(me
))) return (0);
112 x
= DA(DAITER_V(me
))[DAITER_I(me
)]; DAITER_I(me
)++; RETURN_OBJ(x
);
115 static void daiter_pydealloc(PyObject
*me
)
116 { Py_DECREF(DAITER_DA(me
)); PyObject_DEL(me
); }
118 PyTypeObject daiter_pytype
= {
119 PyObject_HEAD_INIT(0) 0, /* Header */
120 "mLib.ArrayIter", /* @tp_name@ */
121 sizeof(daiter_pyobj
), /* @tp_basicsize@ */
122 0, /* @tp_itemsize@ */
124 daiter_pydealloc
, /* @tp_dealloc@ */
126 0, /* @tp_getattr@ */
127 0, /* @tp_setattr@ */
128 0, /* @tp_compare@ */
130 0, /* @tp_as_number@ */
131 0, /* @tp_as_sequence@ */
132 0, /* @tp_as_mapping@ */
136 0, /* @tp_getattro@ */
137 0, /* @tp_setattro@ */
138 0, /* @tp_as_buffer@ */
139 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
145 0, /* @tp_traverse@ */
147 0, /* @tp_richcompare@ */
148 0, /* @tp_weaklistoffset@ */
149 PyObject_SelfIter
, /* @tp_iter@ */
150 daiter_pynext
, /* @tp_iternexr@ */
151 0, /* @tp_methods@ */
152 0, /* @tp_members@ */
156 0, /* @tp_descr_get@ */
157 0, /* @tp_descr_set@ */
158 0, /* @tp_dictoffset@ */
160 PyType_GenericAlloc
, /* @tp_alloc@ */
161 abstract_pynew
, /* @tp_new@ */
166 /*----- Main array code ---------------------------------------------------*/
168 static void da_doinsert(PyObject
*me
, PyObject
**items
, size_t n
,
169 size_t start
, size_t end
)
171 PyObject
**v
, **gv
, **gvl
;
172 obj_v
*da
= DA_V(me
);
177 gv
= v
+ start
; gvl
= v
+ end
; range_copy(&gv
, &gvl
);
178 if (start
< DA_LEN(da
) - end
) {
182 DA_UNSAFE_SLIDE(da
, off
);
183 memmove(v
, v
+ off
, sizeof(PyObject
*) * start
);
186 memmove(v
+ off
, v
, sizeof(PyObject
*) * start
);
187 DA_UNSAFE_UNSLIDE(da
, off
);
193 memmove(v
+ end
+ off
, v
+ end
,
194 sizeof(PyObject
*) * (DA_LEN(da
) - end
));
197 memmove(v
+ end
- off
, v
+ end
,
198 sizeof(PyObject
*) * (DA_LEN(da
) - end
));
199 DA_UNSAFE_SHRINK(da
, off
);
201 DA_UNSAFE_EXTEND(da
, off
);
206 memcpy(v
, items
, sizeof(PyObject
*) * n
);
215 static int da_insert(PyObject
*me
, PyObject
*seq
, int start
, int end
)
220 if (0 > start
|| start
> end
|| end
> DA_LEN(DA_V(me
))) {
221 PyErr_SetString(PyExc_IndexError
, "bad slice");
224 if (getseq(&seq
, &items
, &n
)) return (-1);
225 da_doinsert(me
, items
, n
, start
, end
);
230 static PyObject
*da_new(PyTypeObject
*ty
)
232 da_pyobj
*me
= (da_pyobj
*)ty
->tp_alloc(ty
, 0);
234 return ((PyObject
*)me
);
237 static PyObject
*da_pynew(PyTypeObject
*ty
, PyObject
*arg
, PyObject
*kw
)
238 { return (da_new(ty
)); }
239 static int da_pyinit(PyObject
*me
, PyObject
*arg
, PyObject
*kw
)
242 static char *kwlist
[] = { "sequence", 0 };
244 if (!PyArg_ParseTupleAndKeywords(arg
, kw
, "|O:new", kwlist
, &init
) ||
245 (init
&& da_insert((PyObject
*)me
, init
, 0, 0)))
250 static void da_pydealloc(PyObject
*me
)
253 PyObject
**v
= DA(DA_V(me
));
254 size_t n
= DA_LEN(DA_V(me
));
256 for (i
= 0; i
< n
; i
++) Py_DECREF(v
[i
]);
257 DA_DESTROY(DA_V(me
));
260 static int da_pylength(PyObject
*me
)
261 { return (DA_LEN(DA_V(me
))); }
263 static int da_pytraverse(PyObject
*me
, visitproc proc
, void *arg
)
266 PyObject
**v
= DA(DA_V(me
));
267 size_t n
= DA_LEN(DA_V(me
));
270 for (i
= 0; i
< n
; i
++) {
271 if ((err
= proc(v
[i
], arg
)) != 0)
277 static int da_pyclear(PyObject
*me
)
279 range_dec(DA(DA_V(me
)), DA(DA_V(me
)) + DA_LEN(DA_V(me
)));
284 static PyObject
*da_pyconcat(PyObject
*me
, PyObject
*other
)
286 PyObject
*x
= da_new(&da_pytype
);
287 PyObject
**items
= DA(DA_V(me
));
288 size_t n
= DA_LEN(DA_V(me
));
290 da_doinsert(x
, items
, n
, 0, 0);
291 if (da_insert(x
, other
, n
, n
)) {
298 static PyObject
*da_pyrepeat(PyObject
*me
, int times
)
300 PyObject
*x
= da_new(&da_pytype
);
301 PyObject
**items
= DA(DA_V(me
)), **dest
;
302 size_t n
= DA_LEN(DA_V(me
));
305 DA_ENSURE(DA_V(x
), n
* times
);
306 DA_UNSAFE_EXTEND(DA_V(x
), n
* times
);
307 for (i
= 0, dest
= DA(DA_V(x
)); i
< times
; i
++, dest
+= n
)
308 memcpy(dest
, items
, n
* sizeof(PyObject
*));
309 range_inc(DA(DA_V(x
)), DA(DA_V(x
)) + n
* times
);
313 static PyObject
*da_pygetitem(PyObject
*me
, int i
)
317 if (i
< 0 || i
>= DA_LEN(DA_V(me
))) {
318 PyErr_SetString(PyExc_IndexError
, "index out of range");
326 static PyObject
*da_pygetslice(PyObject
*me
, int i
, int j
)
330 if (i
< 0 || j
< i
|| DA_LEN(DA_V(me
)) < j
) {
331 PyErr_SetString(PyExc_IndexError
, "bad slice");
334 x
= da_new(&da_pytype
);
335 da_doinsert(x
, DA(DA_V(me
)) + i
, j
- i
, 0, 0);
339 static int da_pyputitem(PyObject
*me
, int i
, PyObject
*x
)
343 if (i
< 0 || i
>= DA_LEN(DA_V(me
))) {
344 PyErr_SetString(PyExc_IndexError
, "index out of range");
347 p
= DA(DA_V(me
)) + i
;
354 static int da_pyputslice(PyObject
*me
, int i
, int j
, PyObject
*x
)
355 { return (da_insert(me
, x
, i
, j
)); }
357 static int da_pycontainsp(PyObject
*me
, PyObject
*x
)
359 PyObject
**items
= DA(DA_V(me
));
360 size_t n
= DA_LEN(DA_V(me
));
364 for (i
= 0; i
< n
; i
++) {
365 if (PyObject_Cmp(items
[i
], x
, &rc
))
373 static PyObject
*da_pyrepr(PyObject
*me
)
376 PyObject
*s
, *rc
= 0;
381 dstr_puts(&d
, "Array([");
382 for (i
= 0; i
< DA_LEN(DA_V(me
)); i
++) {
383 if ((s
= PyObject_Repr(DA(DA_V(me
))[i
])) == 0 ||
384 PyString_AsStringAndSize(s
, &p
, &n
)) {
388 if (i
) dstr_puts(&d
, ", ");
393 rc
= PyString_FromStringAndSize(d
.buf
, d
.len
);
399 static PyObject
*da_pyappend(PyObject
*me
, PyObject
*seq
)
401 size_t n
= DA_LEN(DA_V(me
));
402 if (da_insert(me
, seq
, n
, n
)) return (0);
406 static PyObject
*da_pyiprepeat(PyObject
*me
, int times
)
408 PyObject
**items
, **dest
;
409 size_t n
= DA_LEN(DA_V(me
));
413 PyErr_SetString(PyExc_ValueError
, "multiplier must be nonnegative");
417 items
= DA(DA_V(me
));
418 range_dec(items
, items
+ n
);
423 DA_ENSURE(DA_V(me
), n
* times
);
424 items
= DA(DA_V(me
));
425 for (i
= 0, dest
= items
+ n
; i
< times
; i
++, dest
+= n
)
426 memcpy(dest
, items
, n
* sizeof(PyObject
*));
427 range_inc(items
+ n
, dest
);
428 DA_UNSAFE_EXTEND(DA_V(me
), n
* times
);
432 static PyObject
*da_pyget(PyObject
*me
, PyObject
*index
)
434 if (PySlice_Check(index
)) {
435 int start
, stop
, step
, len
;
440 if (PySlice_GetIndicesEx((PySliceObject
*)index
, DA_LEN(DA_V(me
)),
441 &start
, &stop
, &step
, &len
))
443 if (step
== 1) return (da_pygetslice(me
, start
, stop
));
444 v
= da_new(&da_pytype
);
445 DA_ENSURE(DA_V(v
), len
);
447 ww
= DA(DA_V(me
)) + start
;
448 DA_UNSAFE_EXTEND(DA_V(v
), len
);
452 vv
++; ww
+= step
; len
--;
454 return ((PyObject
*)v
);
458 if ((i
= PyInt_AsLong(index
)) == -1 && PyErr_Occurred()) return (0);
459 return (da_pygetitem(me
, i
));
463 static int da_pyput(PyObject
*me
, PyObject
*index
, PyObject
*x
)
465 if (PySlice_Check(index
)) {
466 int start
, stop
, step
, len
;
472 if (PySlice_GetIndicesEx((PySliceObject
*)index
, DA_LEN(DA_V(me
)),
473 &start
, &stop
, &step
, &len
))
475 if (step
== 1) return (da_insert(me
, x
, start
, stop
));
476 if (getseq(&x
, &vv
, &n
)) return (-1);
478 PyErr_SetString(PyExc_ValueError
, "wrong number of items");
482 g
= gg
= xmalloc(len
* sizeof(PyObject
*));
483 ww
= DA(DA_V(me
)) + start
;
485 *gg
++ = *ww
; *ww
= *vv
++;
496 if ((i
= PyInt_AsLong(index
)) == -1 && PyErr_Occurred()) return (-1);
497 return (da_pyputitem(me
, i
, x
));
501 static PyObject
*da_pyiter(PyObject
*me
)
503 daiter_pyobj
*i
= PyObject_NEW(daiter_pyobj
, &daiter_pytype
);
504 i
->da
= me
; Py_INCREF(me
);
506 return ((PyObject
*)i
);
509 static PyObject
*dameth_push(PyObject
*me
, PyObject
*arg
)
513 if (!PyArg_ParseTuple(arg
, "O:push", &x
)) return (0);
515 DA_PUSH(DA_V(me
), x
);
519 static PyObject
*dameth_pop(PyObject
*me
, PyObject
*arg
)
521 PyObject
*x
= Py_None
;
523 if (!PyArg_ParseTuple(arg
, ":pop")) return (0);
525 x
= DA_POP(DA_V(me
));
526 CATCH
switch (exc_type
) {
528 PyErr_SetString(PyExc_ValueError
, "stack underflow");
536 static PyObject
*dameth_unshift(PyObject
*me
, PyObject
*arg
)
540 if (!PyArg_ParseTuple(arg
, "O:unshift", &x
)) return (0);
542 DA_UNSHIFT(DA_V(me
), x
);
546 static PyObject
*dameth_shift(PyObject
*me
, PyObject
*arg
)
548 PyObject
*x
= Py_None
;
550 if (!PyArg_ParseTuple(arg
, ":shift")) return (0);
552 x
= DA_SHIFT(DA_V(me
));
553 CATCH
switch (exc_type
) {
555 PyErr_SetString(PyExc_ValueError
, "stack underflow");
563 static PyObject
*dameth_tidy(PyObject
*me
, PyObject
*arg
)
565 if (!PyArg_ParseTuple(arg
, ":tidy")) return (0);
570 static PyMethodDef da_pymethods
[] = {
571 #define METHNAME(func) dameth_##func
572 METH (push
, "A.push(X): [A, B, ..., W], X -> [A, B, ..., W, X]")
573 METH (pop
, "A.pop() -> X: [A, B, ..., W, X] -> [A, B, ..., W]")
574 METH (unshift
, "A.unshift(X): [A, B, ..., W], X -> [X, A, ..., W]")
575 METH (shift
, "A.shift() -> X: [X, A, ..., W] -> [A, ..., W], X")
576 METH (tidy
, "A.tidy()")
581 static PySequenceMethods da_pysequence
= {
582 da_pylength
, /* @sq_length@ */
583 da_pyconcat
, /* @sq_concat@ */
584 da_pyrepeat
, /* @sq_repeat@ */
585 da_pygetitem
, /* @sq_item@ */
586 da_pygetslice
, /* @sq_slice@ */
587 da_pyputitem
, /* @sq_ass_item@ */
588 da_pyputslice
, /* @sq_ass_slice@ */
589 da_pycontainsp
, /* @sq_contains@ */
590 da_pyappend
, /* @sq_inplace_concat@ */
591 da_pyiprepeat
/* @sq_inplace_repeat@ */
594 static PyMappingMethods da_pymapping
= {
595 da_pylength
, /* @mp_length@ */
596 da_pyget
, /* @mp_subscript@ */
597 da_pyput
/* @mp_ass_subscript@ */
600 PyTypeObject da_pytype
= {
601 PyObject_HEAD_INIT(0) 0, /* Header */
602 "mLib.Array", /* @tp_name@ */
603 sizeof(da_pyobj
), /* @tp_basicsize@ */
604 0, /* @tp_itemsize@ */
606 da_pydealloc
, /* @tp_dealloc@ */
608 0, /* @tp_getattr@ */
609 0, /* @tp_setattr@ */
610 0, /* @tp_compare@ */
611 da_pyrepr
, /* @tp_repr@ */
612 0, /* @tp_as_number@ */
613 &da_pysequence
, /* @tp_as_sequence@ */
614 &da_pymapping
, /* @tp_as_mapping@ */
617 &da_pyrepr
, /* @tp_str@ */
618 0, /* @tp_getattro@ */
619 0, /* @tp_setattro@ */
620 0, /* @tp_as_buffer@ */
621 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
625 "Double-ended array type.",
627 da_pytraverse
, /* @tp_traverse@ */
628 da_pyclear
, /* @tp_clear@ */
629 0, /* @tp_richcompare@ */
630 0, /* @tp_weaklistoffset@ */
631 da_pyiter
, /* @tp_iter@ */
632 0, /* @tp_iternext@ */
633 da_pymethods
, /* @tp_methods@ */
634 0, /* @tp_members@ */
638 0, /* @tp_descr_get@ */
639 0, /* @tp_descr_set@ */
640 0, /* @tp_dictoffset@ */
641 da_pyinit
, /* @tp_init@ */
642 PyType_GenericAlloc
, /* @tp_alloc@ */
643 da_pynew
, /* @tp_new@ */
648 /*----- Initialization ----------------------------------------------------*/
650 void da_pysetup(void)
651 { PyType_Ready(&da_pytype
); PyType_Ready(&daiter_pytype
); }
653 /*----- That's all, folks -------------------------------------------------*/