chiark / gitweb /
37850d937635e2ca9f8665bc6b96d1030ad9cf2e
[mLib-python] / array.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Double-ended arrays
6  *
7  * (c) 2005 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the Python interface to mLib.
13  *
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.
18  * 
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.
23  * 
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.
27  */
28
29 /*----- Header files ------------------------------------------------------*/
30
31 #include <Python.h>
32
33 #include <string.h>
34
35 #include <mLib/darray.h>
36 #include <mLib/dstr.h>
37 #include <mLib/exc.h>
38
39 #include "grim.h"
40
41 /*----- Data structures ---------------------------------------------------*/
42
43 DA_DECL(obj_v, PyObject *);
44
45 typedef struct da_pyobj {
46   PyObject_HEAD
47   obj_v v;
48 } da_pyobj;
49 #define DA_PYCHECK(o) PyObject_TypeCheck((o), &da_pytype)
50 #define DA_V(o) (&((da_pyobj *)(o))->v)
51
52 typedef struct daiter_pyobj {
53   PyObject_HEAD
54   PyObject *da;
55   size_t i;
56 } 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)
60
61 static PyTypeObject da_pytype, daiter_pytype;
62
63 static int getseq(PyObject **pseq, PyObject ***v, size_t *n)
64 {
65   PyObject *seq = *pseq;
66
67   if (!seq || seq == Py_None) {
68     *v = 0;
69     *n = 0;
70     *pseq = 0;
71   } else if (DA_PYCHECK(seq)) {
72     *v = DA(DA_V(seq));
73     *n = DA_LEN(DA_V(seq));
74     Py_INCREF(seq);
75   } else if ((seq = PySequence_Fast(seq, "expected iterable")) == 0)
76     return (-1);
77   else {
78     *pseq = seq;
79     *v = PySequence_Fast_ITEMS(seq);
80     *n = PySequence_Fast_GET_SIZE(seq);
81   }
82   return (0);
83 }
84
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)
90 {
91   size_t n = *gvl - *gv;
92   size_t sz = sizeof(PyObject *) * n;
93   PyObject **v;
94   if (!n) { *gv = *gvl = 0; return; }
95   v = xmalloc(sz);
96   memcpy(v, *gv, sz);
97   *gv = v;
98   *gvl = v + n;
99 }
100
101 static PyObject *abstract_pynew(PyTypeObject *ty,
102                                 PyObject *hunoz, PyObject *hukairz)
103 {
104   PyErr_SetString(PyExc_TypeError, "can't instantiate this type");
105   return (0);
106 }
107
108 /*----- Iterator ----------------------------------------------------------*/
109
110 static PyObject *daiter_pynext(PyObject *me)
111 {
112   PyObject *x;
113
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);
116 }
117
118 static void daiter_pydealloc(PyObject *me)
119   { Py_DECREF(DAITER_DA(me)); PyObject_DEL(me); }
120
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@ */
126
127   daiter_pydealloc,                     /* @tp_dealloc@ */
128   0,                                    /* @tp_print@ */
129   0,                                    /* @tp_getattr@ */
130   0,                                    /* @tp_setattr@ */
131   0,                                    /* @tp_compare@ */
132   0,                                    /* @tp_repr@ */
133   0,                                    /* @tp_as_number@ */
134   0,                                    /* @tp_as_sequence@ */
135   0,                                    /* @tp_as_mapping@ */
136   0,                                    /* @tp_hash@ */
137   0,                                    /* @tp_call@ */
138   0,                                    /* @tp_str@ */
139   0,                                    /* @tp_getattro@ */
140   0,                                    /* @tp_setattro@ */
141   0,                                    /* @tp_as_buffer@ */
142   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
143     Py_TPFLAGS_BASETYPE,
144
145   /* @tp_doc@ */
146 "Array iterator.",
147
148   0,                                    /* @tp_traverse@ */
149   0,                                    /* @tp_clear@ */
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@ */
156   0,                                    /* @tp_getset@ */
157   0,                                    /* @tp_base@ */
158   0,                                    /* @tp_dict@ */
159   0,                                    /* @tp_descr_get@ */
160   0,                                    /* @tp_descr_set@ */
161   0,                                    /* @tp_dictoffset@ */
162   0,                                    /* @tp_init@ */
163   PyType_GenericAlloc,                  /* @tp_alloc@ */
164   abstract_pynew,                       /* @tp_new@ */
165   0,                                    /* @tp_free@ */
166   0                                     /* @tp_is_gc@ */
167 };
168
169 /*----- Main array code ---------------------------------------------------*/
170
171 static void da_doinsert(PyObject *me, PyObject **items, size_t n,
172                         size_t start, size_t end)
173 {
174   PyObject **v, **gv, **gvl;
175   obj_v *da = DA_V(me);
176   size_t off, ne;
177
178   ne = end - start;
179   v = DA(da);
180   gv = v + start; gvl = v + end; range_copy(&gv, &gvl);
181   if (start < DA_LEN(da) - end) {
182     if (n > ne) {
183       off = n - ne;
184       DA_SHUNT(da, off);
185       DA_UNSAFE_SLIDE(da, off);
186       memmove(v, v + off, sizeof(PyObject *) * start);
187     } else {
188       off = ne - n;
189       memmove(v + off, v, sizeof(PyObject *) * start);
190       DA_UNSAFE_UNSLIDE(da, off);
191     }
192   } else {
193     if (n > ne) {
194       off = n - ne;
195       DA_ENSURE(da, off);
196       memmove(v + end + off, v + end,
197               sizeof(PyObject *) * (DA_LEN(da) - end));
198     } else {
199       off = ne - n;
200       memmove(v + end - off, v + end,
201               sizeof(PyObject *) * (DA_LEN(da) - end));
202       DA_UNSAFE_SHRINK(da, off);
203     }
204     DA_UNSAFE_EXTEND(da, off);
205   }
206
207   if (n) {
208     v = DA(da) + start;
209     memcpy(v, items, sizeof(PyObject *) * n);
210     range_inc(v, v + n);
211   }
212   if (gv) {
213     range_dec(gv, gvl);
214     xfree(gv);
215   }
216 }
217
218 static int da_insert(PyObject *me, PyObject *seq, int start, int end)
219 {
220   PyObject **items;
221   size_t n;
222   
223   if (0 > start || start > end || end > DA_LEN(DA_V(me))) {
224     PyErr_SetString(PyExc_IndexError, "bad slice");
225     return (-1);
226   }
227   if (getseq(&seq, &items, &n)) return (-1);
228   da_doinsert(me, items, n, start, end);
229   Py_XDECREF(seq);
230   return (0);
231 }
232
233 static PyObject *da_new(PyTypeObject *ty)
234 {
235   da_pyobj *me = (da_pyobj *)ty->tp_alloc(ty, 0);
236   DA_CREATE(&me->v);
237   return ((PyObject *)me);
238 }
239
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)
243 {
244   PyObject *init = 0;
245   static char *kwlist[] = { "sequence", 0 };
246
247   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", kwlist, &init) ||
248       (init && da_insert((PyObject *)me, init, 0, 0)))
249     return (-1);
250   return (0);
251 }
252
253 static void da_pydealloc(PyObject *me)
254 {
255   size_t i;
256   PyObject **v = DA(DA_V(me));
257   size_t n = DA_LEN(DA_V(me));
258
259   for (i = 0; i < n; i++) Py_DECREF(v[i]);
260   DA_DESTROY(DA_V(me));
261 }
262
263 static int da_pylength(PyObject *me)
264   { return (DA_LEN(DA_V(me))); }
265
266 static int da_pytraverse(PyObject *me, visitproc proc, void *arg)
267 {
268   size_t i;
269   PyObject **v = DA(DA_V(me));
270   size_t n = DA_LEN(DA_V(me));
271   int err;
272
273   for (i = 0; i < n; i++) {
274     if ((err = proc(v[i], arg)) != 0)
275       return (err);
276   }
277   return (0);
278 }
279
280 static int da_pyclear(PyObject *me)
281 {
282   range_dec(DA(DA_V(me)), DA(DA_V(me)) + DA_LEN(DA_V(me)));
283   DA_RESET(DA_V(me));
284   return (0);
285 }
286
287 static PyObject *da_pyconcat(PyObject *me, PyObject *other)
288 {
289   PyObject *x = da_new(&da_pytype);
290   PyObject **items = DA(DA_V(me));
291   size_t n = DA_LEN(DA_V(me));
292
293   da_doinsert(x, items, n, 0, 0);
294   if (da_insert(x, other, n, n)) {
295     Py_DECREF(x);
296     return (0);
297   }
298   return (x);
299 }
300
301 static PyObject *da_pyrepeat(PyObject *me, int times)
302 {
303   PyObject *x = da_new(&da_pytype);
304   PyObject **items = DA(DA_V(me)), **dest;
305   size_t n = DA_LEN(DA_V(me));
306   int i;
307
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);
313   return (x);
314 }
315
316 static PyObject *da_pygetitem(PyObject *me, int i)
317 {
318   PyObject *o;
319
320   if (i < 0 || i >= DA_LEN(DA_V(me))) {
321     PyErr_SetString(PyExc_IndexError, "index out of range");
322     return (0);
323   }
324   o = DA(DA_V(me))[i];
325   Py_INCREF(o);
326   return (o);
327 }
328
329 static PyObject *da_pygetslice(PyObject *me, int i, int j)
330 {
331   PyObject *x;
332
333   if (i < 0 || j < i || DA_LEN(DA_V(me)) < j) {
334     PyErr_SetString(PyExc_IndexError, "bad slice");
335     return (0);
336   }
337   x = da_new(&da_pytype);
338   da_doinsert(x, DA(DA_V(me)) + i, j - i, 0, 0);
339   return (x);
340 }
341
342 static int da_pyputitem(PyObject *me, int i, PyObject *x)
343 {
344   PyObject **p;
345   
346   if (i < 0 || i >= DA_LEN(DA_V(me))) {
347     PyErr_SetString(PyExc_IndexError, "index out of range");
348     return (-1);
349   }
350   p = DA(DA_V(me)) + i;
351   Py_DECREF(*p);
352   *p = x;
353   Py_INCREF(*p);
354   return (0);
355 }
356
357 static int da_pyputslice(PyObject *me, int i, int j, PyObject *x)
358   { return (da_insert(me, x, i, j)); }
359
360 static int da_pycontainsp(PyObject *me, PyObject *x)
361 {
362   PyObject **items = DA(DA_V(me));
363   size_t n = DA_LEN(DA_V(me));
364   size_t i;
365   int rc;
366
367   for (i = 0; i < n; i++) {
368     if (PyObject_Cmp(items[i], x, &rc))
369       return (-1);
370     if (rc)
371       return (1);
372   }
373   return (0);
374 }
375
376 static PyObject *da_pyrepr(PyObject *me)
377 {
378   dstr d = DSTR_INIT;
379   PyObject *s, *rc = 0;
380   char *p;
381   int n;
382   size_t i;
383
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)) {
388       Py_XDECREF(s);
389       goto done;
390     }
391     if (i) dstr_puts(&d, ", ");
392     dstr_putm(&d, p, n);
393     Py_DECREF(s);
394   }
395   dstr_puts(&d, "])");
396   rc = PyString_FromStringAndSize(d.buf, d.len);
397 done:
398   dstr_destroy(&d);
399   return (rc);
400 }
401
402 static PyObject *da_pyappend(PyObject *me, PyObject *seq)
403 {
404   size_t n = DA_LEN(DA_V(me));
405   if (da_insert(me, seq, n, n)) return (0);
406   RETURN_ME;
407 }
408
409 static PyObject *da_pyiprepeat(PyObject *me, int times)
410 {
411   PyObject **items, **dest;
412   size_t n = DA_LEN(DA_V(me));
413   int i;
414
415   if (times < 0) {
416     PyErr_SetString(PyExc_ValueError, "multiplier must be nonnegative");
417     return (0);
418   }
419   if (!times) {
420     items = DA(DA_V(me));
421     range_dec(items, items + n);
422     DA_RESET(DA_V(me));
423     RETURN_ME;
424   }
425   times--;
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);
432   RETURN_ME;
433 }
434
435 static PyObject *da_pyget(PyObject *me, PyObject *index)
436 {
437   if (PySlice_Check(index)) {
438     int start, stop, step, len;
439     PyObject *v;
440     PyObject **ww;
441     PyObject **vv;
442
443     if (PySlice_GetIndicesEx((PySliceObject *)index, DA_LEN(DA_V(me)),
444                              &start, &stop, &step, &len))
445       return (0);
446     if (step == 1) return (da_pygetslice(me, start, stop));
447     v = da_new(&da_pytype);
448     DA_ENSURE(DA_V(v), len);
449     vv = DA(DA_V(v));
450     ww = DA(DA_V(me)) + start;
451     DA_UNSAFE_EXTEND(DA_V(v), len);
452     while (len) {
453       *vv = *ww;
454       Py_INCREF(*vv);
455       vv++; ww += step; len--;
456     }
457     return ((PyObject *)v);
458   } else {
459     int i;
460
461     if ((i = PyInt_AsLong(index)) == -1 && PyErr_Occurred()) return (0);
462     return (da_pygetitem(me, i));
463   }
464 }
465
466 static int da_pyput(PyObject *me, PyObject *index, PyObject *x)
467 {
468   if (PySlice_Check(index)) {
469     int start, stop, step, len;
470     size_t n;
471     PyObject **ww;
472     PyObject **vv;
473     PyObject **g, **gg;
474
475     if (PySlice_GetIndicesEx((PySliceObject *)index, DA_LEN(DA_V(me)),
476                              &start, &stop, &step, &len))
477       return (-1);
478     if (step == 1) return (da_insert(me, x, start, stop));
479     if (getseq(&x, &vv, &n)) return (-1);
480     if (n != len) {
481       PyErr_SetString(PyExc_ValueError, "wrong number of items");
482       Py_XDECREF(x);
483       return (-1);
484     }
485     g = gg = xmalloc(len * sizeof(PyObject *));
486     ww = DA(DA_V(me)) + start;
487     while (len) {
488       *gg++ = *ww; *ww = *vv++;
489       Py_INCREF(*ww);
490       ww += step; len--;
491     }
492     range_dec(g, gg);
493     xfree(g);
494     Py_XDECREF(x);
495     return (0);
496   } else {
497     int i;
498
499     if ((i = PyInt_AsLong(index)) == -1 && PyErr_Occurred()) return (-1);
500     return (da_pyputitem(me, i, x));
501   }
502 }
503
504 static PyObject *da_pyiter(PyObject *me)
505 {
506   daiter_pyobj *i = PyObject_NEW(daiter_pyobj, &daiter_pytype);
507   i->da = me; Py_INCREF(me);
508   i->i = 0;
509   return ((PyObject *)i);
510 }
511
512 static PyObject *dameth_push(PyObject *me, PyObject *arg)
513 {
514   PyObject *x;
515
516   if (!PyArg_ParseTuple(arg, "O:push", &x)) return (0);
517   Py_INCREF(x);
518   DA_PUSH(DA_V(me), x);
519   RETURN_ME;
520 }
521
522 static PyObject *dameth_pop(PyObject *me, PyObject *arg)
523 {
524   PyObject *x;
525
526   if (!PyArg_ParseTuple(arg, ":pop")) return (0);
527   TRY
528     x = DA_POP(DA_V(me));
529   CATCH switch (exc_type) {
530     case DAEXC_UFLOW:
531       PyErr_SetString(PyExc_ValueError, "stack underflow");
532       return (0);
533     default:
534       RETHROW;
535   } END_TRY;
536   RETURN_OBJ(x);
537 }
538
539 static PyObject *dameth_unshift(PyObject *me, PyObject *arg)
540 {
541   PyObject *x;
542
543   if (!PyArg_ParseTuple(arg, "O:unshift", &x)) return (0);
544   Py_INCREF(x);
545   DA_UNSHIFT(DA_V(me), x);
546   RETURN_ME;
547 }
548
549 static PyObject *dameth_shift(PyObject *me, PyObject *arg)
550 {
551   PyObject *x;
552
553   if (!PyArg_ParseTuple(arg, ":shift")) return (0);
554   TRY
555     x = DA_SHIFT(DA_V(me));
556   CATCH switch (exc_type) {
557     case DAEXC_UFLOW:
558       PyErr_SetString(PyExc_ValueError, "stack underflow");
559       return (0);
560     default:
561       RETHROW;
562   } END_TRY;
563   RETURN_OBJ(x);
564 }
565
566 static PyObject *dameth_tidy(PyObject *me, PyObject *arg)
567 {
568   if (!PyArg_ParseTuple(arg, ":tidy")) return (0);
569   DA_TIDY(DA_V(me));
570   RETURN_ME;
571 }
572
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()")
580 #undef METHNAME
581   { 0 }
582 };
583
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@ */
595 };
596
597 static PyMappingMethods da_pymapping = {
598   da_pylength,                          /* @mp_length@ */
599   da_pyget,                             /* @mp_subscript@ */
600   da_pyput                              /* @mp_ass_subscript@ */
601 };
602
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@ */
608
609   da_pydealloc,                         /* @tp_dealloc@ */
610   0,                                    /* @tp_print@ */
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@ */
618   0,                                    /* @tp_hash@ */
619   0,                                    /* @tp_call@ */
620   &da_pyrepr,                           /* @tp_str@ */
621   0,                                    /* @tp_getattro@ */
622   0,                                    /* @tp_setattro@ */
623   0,                                    /* @tp_as_buffer@ */
624   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
625     Py_TPFLAGS_HAVE_GC,
626
627   /* @tp_doc@ */
628 "Double-ended array type.",
629
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@ */
638   0,                                    /* @tp_getset@ */
639   0,                                    /* @tp_base@ */
640   0,                                    /* @tp_dict@ */
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@ */
647   0,                                    /* @tp_free@ */
648   0                                     /* @tp_is_gc@ */
649 };
650
651 /*----- Initialization ----------------------------------------------------*/
652
653 static PyMethodDef emptymethods[] = { { 0 } };
654
655 void initarray(void)
656 {
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);
661 }
662
663 /*----- That's all, folks -------------------------------------------------*/