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>
42 /*----- Data structures ---------------------------------------------------*/
44 DA_DECL(obj_v
, PyObject
*);
46 typedef struct da_pyobj
{
50 #define DA_PYCHECK(o) PyObject_TypeCheck((o), &da_pytype)
51 #define DA_V(o) (&((da_pyobj *)(o))->v)
53 typedef struct daiter_pyobj
{
58 #define DAITER_DA(obj) (((daiter_pyobj *)(obj))->da)
59 #define DAITER_V(obj) DA_V(DAITER_DA(obj))
60 #define DAITER_I(obj) (((daiter_pyobj *)(obj))->i)
62 static int getseq(PyObject
**pseq
, PyObject
***v
, size_t *n
)
64 PyObject
*seq
= *pseq
;
66 if (!seq
|| seq
== Py_None
) {
70 } else if (DA_PYCHECK(seq
)) {
72 *n
= DA_LEN(DA_V(seq
));
74 } else if ((seq
= PySequence_Fast(seq
, "expected iterable")) == 0)
78 *v
= PySequence_Fast_ITEMS(seq
);
79 *n
= PySequence_Fast_GET_SIZE(seq
);
84 static void range_inc(PyObject
**v
, PyObject
**vl
)
85 { while (v
< vl
) { Py_INCREF(*v
); v
++; } }
86 static void range_dec(PyObject
**v
, PyObject
**vl
)
87 { if (v
) { while (v
< vl
) { Py_DECREF(*v
); v
++; } } }
88 static void range_copy(PyObject
***gv
, PyObject
***gvl
)
90 size_t n
= *gvl
- *gv
;
91 size_t sz
= sizeof(PyObject
*) * n
;
93 if (!n
) { *gv
= *gvl
= 0; return; }
100 static PyObject
*abstract_pynew(PyTypeObject
*ty
,
101 PyObject
*hunoz
, PyObject
*hukairz
)
103 PyErr_SetString(PyExc_TypeError
, "can't instantiate this type");
107 /*----- Iterator ----------------------------------------------------------*/
109 static PyObject
*daiter_pynext(PyObject
*me
)
113 if (DAITER_I(me
) >= DA_LEN(DAITER_V(me
))) return (0);
114 x
= DA(DAITER_V(me
))[DAITER_I(me
)]; DAITER_I(me
)++; RETURN_OBJ(x
);
117 static void daiter_pydealloc(PyObject
*me
)
118 { Py_DECREF(DAITER_DA(me
)); PyObject_DEL(me
); }
120 PyTypeObject daiter_pytype
= {
121 PyObject_HEAD_INIT(0) 0, /* Header */
122 "array.ArrayIter", /* @tp_name@ */
123 sizeof(daiter_pyobj
), /* @tp_basicsize@ */
124 0, /* @tp_itemsize@ */
126 daiter_pydealloc
, /* @tp_dealloc@ */
128 0, /* @tp_getattr@ */
129 0, /* @tp_setattr@ */
130 0, /* @tp_compare@ */
132 0, /* @tp_as_number@ */
133 0, /* @tp_as_sequence@ */
134 0, /* @tp_as_mapping@ */
138 0, /* @tp_getattro@ */
139 0, /* @tp_setattro@ */
140 0, /* @tp_as_buffer@ */
141 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
147 0, /* @tp_traverse@ */
149 0, /* @tp_richcompare@ */
150 0, /* @tp_weaklistoffset@ */
151 PyObject_SelfIter
, /* @tp_iter@ */
152 daiter_pynext
, /* @tp_iternexr@ */
153 0, /* @tp_methods@ */
154 0, /* @tp_members@ */
158 0, /* @tp_descr_get@ */
159 0, /* @tp_descr_set@ */
160 0, /* @tp_dictoffset@ */
162 PyType_GenericAlloc
, /* @tp_alloc@ */
163 abstract_pynew
, /* @tp_new@ */
168 /*----- Main array code ---------------------------------------------------*/
170 static void da_doinsert(PyObject
*me
, PyObject
**items
, size_t n
,
171 size_t start
, size_t end
)
173 PyObject
**v
, **gv
, **gvl
;
174 obj_v
*da
= DA_V(me
);
179 gv
= v
+ start
; gvl
= v
+ end
; range_copy(&gv
, &gvl
);
180 if (start
< DA_LEN(da
) - end
) {
184 DA_UNSAFE_SLIDE(da
, off
);
185 memmove(v
, v
+ off
, sizeof(PyObject
*) * start
);
188 memmove(v
+ off
, v
, sizeof(PyObject
*) * start
);
189 DA_UNSAFE_UNSLIDE(da
, off
);
195 memmove(v
+ end
+ off
, v
+ end
,
196 sizeof(PyObject
*) * (DA_LEN(da
) - end
));
199 memmove(v
+ end
- off
, v
+ end
,
200 sizeof(PyObject
*) * (DA_LEN(da
) - end
));
201 DA_UNSAFE_SHRINK(da
, off
);
203 DA_UNSAFE_EXTEND(da
, off
);
208 memcpy(v
, items
, sizeof(PyObject
*) * n
);
217 static int da_insert(PyObject
*me
, PyObject
*seq
, int start
, int end
)
222 if (0 > start
|| start
> end
|| end
> DA_LEN(DA_V(me
))) {
223 PyErr_SetString(PyExc_IndexError
, "bad slice");
226 if (getseq(&seq
, &items
, &n
)) return (-1);
227 da_doinsert(me
, items
, n
, start
, end
);
232 static PyObject
*da_new(PyTypeObject
*ty
)
234 da_pyobj
*me
= (da_pyobj
*)ty
->tp_alloc(ty
, 0);
236 return ((PyObject
*)me
);
239 static PyObject
*da_pynew(PyTypeObject
*ty
, PyObject
*arg
, PyObject
*kw
)
240 { return (da_new(ty
)); }
241 static int da_pyinit(PyObject
*me
, PyObject
*arg
, PyObject
*kw
)
244 static char *kwlist
[] = { "sequence", 0 };
246 if (!PyArg_ParseTupleAndKeywords(arg
, kw
, "|O:new", kwlist
, &init
) ||
247 (init
&& da_insert((PyObject
*)me
, init
, 0, 0)))
252 static void da_pydealloc(PyObject
*me
)
255 PyObject
**v
= DA(DA_V(me
));
256 size_t n
= DA_LEN(DA_V(me
));
258 for (i
= 0; i
< n
; i
++) Py_DECREF(v
[i
]);
259 DA_DESTROY(DA_V(me
));
262 static int da_pylength(PyObject
*me
)
263 { return (DA_LEN(DA_V(me
))); }
265 static int da_pytraverse(PyObject
*me
, visitproc proc
, void *arg
)
268 PyObject
**v
= DA(DA_V(me
));
269 size_t n
= DA_LEN(DA_V(me
));
272 for (i
= 0; i
< n
; i
++) {
273 if ((err
= proc(v
[i
], arg
)) != 0)
279 static int da_pyclear(PyObject
*me
)
281 range_dec(DA(DA_V(me
)), DA(DA_V(me
)) + DA_LEN(DA_V(me
)));
286 static PyObject
*da_pyconcat(PyObject
*me
, PyObject
*other
)
288 PyObject
*x
= da_new(&da_pytype
);
289 PyObject
**items
= DA(DA_V(me
));
290 size_t n
= DA_LEN(DA_V(me
));
292 da_doinsert(x
, items
, n
, 0, 0);
293 if (da_insert(x
, other
, n
, n
)) {
300 static PyObject
*da_pyrepeat(PyObject
*me
, int times
)
302 PyObject
*x
= da_new(&da_pytype
);
303 PyObject
**items
= DA(DA_V(me
)), **dest
;
304 size_t n
= DA_LEN(DA_V(me
));
307 DA_ENSURE(DA_V(x
), n
* times
);
308 DA_UNSAFE_EXTEND(DA_V(x
), n
* times
);
309 for (i
= 0, dest
= DA(DA_V(x
)); i
< times
; i
++, dest
+= n
)
310 memcpy(dest
, items
, n
* sizeof(PyObject
*));
311 range_inc(DA(DA_V(x
)), DA(DA_V(x
)) + n
* times
);
315 static PyObject
*da_pygetitem(PyObject
*me
, int i
)
319 if (i
< 0 || i
>= DA_LEN(DA_V(me
))) {
320 PyErr_SetString(PyExc_IndexError
, "index out of range");
328 static PyObject
*da_pygetslice(PyObject
*me
, int i
, int j
)
332 if (i
< 0 || j
< i
|| DA_LEN(DA_V(me
)) < j
) {
333 PyErr_SetString(PyExc_IndexError
, "bad slice");
336 x
= da_new(&da_pytype
);
337 da_doinsert(x
, DA(DA_V(me
)) + i
, j
- i
, 0, 0);
341 static int da_pyputitem(PyObject
*me
, int i
, PyObject
*x
)
345 if (i
< 0 || i
>= DA_LEN(DA_V(me
))) {
346 PyErr_SetString(PyExc_IndexError
, "index out of range");
349 p
= DA(DA_V(me
)) + i
;
356 static int da_pyputslice(PyObject
*me
, int i
, int j
, PyObject
*x
)
357 { return (da_insert(me
, x
, i
, j
)); }
359 static int da_pycontainsp(PyObject
*me
, PyObject
*x
)
361 PyObject
**items
= DA(DA_V(me
));
362 size_t n
= DA_LEN(DA_V(me
));
366 for (i
= 0; i
< n
; i
++) {
367 if (PyObject_Cmp(items
[i
], x
, &rc
))
375 static PyObject
*da_pyrepr(PyObject
*me
)
378 PyObject
*s
, *rc
= 0;
383 dstr_puts(&d
, "Array([");
384 for (i
= 0; i
< DA_LEN(DA_V(me
)); i
++) {
385 if ((s
= PyObject_Repr(DA(DA_V(me
))[i
])) == 0 ||
386 PyString_AsStringAndSize(s
, &p
, &n
)) {
390 if (i
) dstr_puts(&d
, ", ");
395 rc
= PyString_FromStringAndSize(d
.buf
, d
.len
);
401 static PyObject
*da_pyappend(PyObject
*me
, PyObject
*seq
)
403 size_t n
= DA_LEN(DA_V(me
));
404 if (da_insert(me
, seq
, n
, n
)) return (0);
408 static PyObject
*da_pyiprepeat(PyObject
*me
, int times
)
410 PyObject
**items
, **dest
;
411 size_t n
= DA_LEN(DA_V(me
));
415 PyErr_SetString(PyExc_ValueError
, "multiplier must be nonnegative");
419 items
= DA(DA_V(me
));
420 range_dec(items
, items
+ n
);
425 DA_ENSURE(DA_V(me
), n
* times
);
426 items
= DA(DA_V(me
));
427 for (i
= 0, dest
= items
+ n
; i
< times
; i
++, dest
+= n
)
428 memcpy(dest
, items
, n
* sizeof(PyObject
*));
429 range_inc(items
+ n
, dest
);
430 DA_UNSAFE_EXTEND(DA_V(me
), n
* times
);
434 static PyObject
*da_pyget(PyObject
*me
, PyObject
*index
)
436 if (PySlice_Check(index
)) {
437 int start
, stop
, step
, len
;
442 if (PySlice_GetIndicesEx((PySliceObject
*)index
, DA_LEN(DA_V(me
)),
443 &start
, &stop
, &step
, &len
))
445 if (step
== 1) return (da_pygetslice(me
, start
, stop
));
446 v
= da_new(&da_pytype
);
447 DA_ENSURE(DA_V(v
), len
);
449 ww
= DA(DA_V(me
)) + start
;
450 DA_UNSAFE_EXTEND(DA_V(v
), len
);
454 vv
++; ww
+= step
; len
--;
456 return ((PyObject
*)v
);
460 if ((i
= PyInt_AsLong(index
)) == -1 && PyErr_Occurred()) return (0);
461 return (da_pygetitem(me
, i
));
465 static int da_pyput(PyObject
*me
, PyObject
*index
, PyObject
*x
)
467 if (PySlice_Check(index
)) {
468 int start
, stop
, step
, len
;
474 if (PySlice_GetIndicesEx((PySliceObject
*)index
, DA_LEN(DA_V(me
)),
475 &start
, &stop
, &step
, &len
))
477 if (step
== 1) return (da_insert(me
, x
, start
, stop
));
478 if (getseq(&x
, &vv
, &n
)) return (-1);
480 PyErr_SetString(PyExc_ValueError
, "wrong number of items");
484 g
= gg
= xmalloc(len
* sizeof(PyObject
*));
485 ww
= DA(DA_V(me
)) + start
;
487 *gg
++ = *ww
; *ww
= *vv
++;
498 if ((i
= PyInt_AsLong(index
)) == -1 && PyErr_Occurred()) return (-1);
499 return (da_pyputitem(me
, i
, x
));
503 static PyObject
*da_pyiter(PyObject
*me
)
505 daiter_pyobj
*i
= PyObject_NEW(daiter_pyobj
, &daiter_pytype
);
506 i
->da
= me
; Py_INCREF(me
);
508 return ((PyObject
*)i
);
511 static PyObject
*dameth_push(PyObject
*me
, PyObject
*arg
)
515 if (!PyArg_ParseTuple(arg
, "O:push", &x
)) return (0);
517 DA_PUSH(DA_V(me
), x
);
521 static PyObject
*dameth_pop(PyObject
*me
, PyObject
*arg
)
525 if (!PyArg_ParseTuple(arg
, ":pop")) return (0);
527 x
= DA_POP(DA_V(me
));
528 CATCH
switch (exc_type
) {
530 PyErr_SetString(PyExc_ValueError
, "stack underflow");
538 static PyObject
*dameth_unshift(PyObject
*me
, PyObject
*arg
)
542 if (!PyArg_ParseTuple(arg
, "O:unshift", &x
)) return (0);
544 DA_UNSHIFT(DA_V(me
), x
);
548 static PyObject
*dameth_shift(PyObject
*me
, PyObject
*arg
)
552 if (!PyArg_ParseTuple(arg
, ":shift")) return (0);
554 x
= DA_SHIFT(DA_V(me
));
555 CATCH
switch (exc_type
) {
557 PyErr_SetString(PyExc_ValueError
, "stack underflow");
565 static PyObject
*dameth_tidy(PyObject
*me
, PyObject
*arg
)
567 if (!PyArg_ParseTuple(arg
, ":tidy")) return (0);
572 static PyMethodDef da_pymethods
[] = {
573 #define METHNAME(func) dameth_##func
574 METH (push
, "A.push(X): [A, B, ..., W], X -> [A, B, ..., W, X]")
575 METH (pop
, "A.pop() -> X: [A, B, ..., W, X] -> [A, B, ..., W]")
576 METH (unshift
, "A.unshift(X): [A, B, ..., W], X -> [X, A, ..., W]")
577 METH (shift
, "A.shift() -> X: [X, A, ..., W] -> [A, ..., W], X")
578 METH (tidy
, "A.tidy()")
583 static PySequenceMethods da_pysequence
= {
584 da_pylength
, /* @sq_length@ */
585 da_pyconcat
, /* @sq_concat@ */
586 da_pyrepeat
, /* @sq_repeat@ */
587 da_pygetitem
, /* @sq_item@ */
588 da_pygetslice
, /* @sq_slice@ */
589 da_pyputitem
, /* @sq_ass_item@ */
590 da_pyputslice
, /* @sq_ass_slice@ */
591 da_pycontainsp
, /* @sq_contains@ */
592 da_pyappend
, /* @sq_inplace_concat@ */
593 da_pyiprepeat
/* @sq_inplace_repeat@ */
596 static PyMappingMethods da_pymapping
= {
597 da_pylength
, /* @mp_length@ */
598 da_pyget
, /* @mp_subscript@ */
599 da_pyput
/* @mp_ass_subscript@ */
602 PyTypeObject da_pytype
= {
603 PyObject_HEAD_INIT(0) 0, /* Header */
604 "array.Array", /* @tp_name@ */
605 sizeof(da_pyobj
), /* @tp_basicsize@ */
606 0, /* @tp_itemsize@ */
608 da_pydealloc
, /* @tp_dealloc@ */
610 0, /* @tp_getattr@ */
611 0, /* @tp_setattr@ */
612 0, /* @tp_compare@ */
613 da_pyrepr
, /* @tp_repr@ */
614 0, /* @tp_as_number@ */
615 &da_pysequence
, /* @tp_as_sequence@ */
616 &da_pymapping
, /* @tp_as_mapping@ */
619 &da_pyrepr
, /* @tp_str@ */
620 0, /* @tp_getattro@ */
621 0, /* @tp_setattro@ */
622 0, /* @tp_as_buffer@ */
623 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
627 "Double-ended array type.",
629 da_pytraverse
, /* @tp_traverse@ */
630 da_pyclear
, /* @tp_clear@ */
631 0, /* @tp_richcompare@ */
632 0, /* @tp_weaklistoffset@ */
633 da_pyiter
, /* @tp_iter@ */
634 0, /* @tp_iternext@ */
635 da_pymethods
, /* @tp_methods@ */
636 0, /* @tp_members@ */
640 0, /* @tp_descr_get@ */
641 0, /* @tp_descr_set@ */
642 0, /* @tp_dictoffset@ */
643 da_pyinit
, /* @tp_init@ */
644 PyType_GenericAlloc
, /* @tp_alloc@ */
645 da_pynew
, /* @tp_new@ */
650 /*----- Initialization ----------------------------------------------------*/
652 void da_pysetup(void)
653 { PyType_Ready(&da_pytype
); PyType_Ready(&daiter_pytype
); }
655 /*----- That's all, folks -------------------------------------------------*/