chiark / gitweb /
Initial import.
[mLib-python] / atom.pyx
1 # -*-pyrex-*-
2 #
3 # $Id$
4 #
5 # Atom tables
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 cdef extern from 'atom.h':
29   ctypedef struct atom:
30     pass
31   ctypedef struct atom_iter:
32     pass
33   ctypedef struct atom_table:
34     pass
35   atom_table *ATOM_GLOBAL
36   void atom_mkiter(atom_iter *i, atom_table *t)
37   atom *atom_next(atom_iter *)
38   atom_pystartup()
39   atom_pywrap(atom *a)
40   atom_pyintern(obj)
41   atom *ATOM_A(obj)
42
43 cdef extern from 'mLib/assoc.h':
44   ctypedef struct assoc_table:
45     pass
46   ctypedef struct assoc_base:
47     pass
48   ctypedef struct assoc_iter:
49     pass
50   void assoc_create(assoc_table *t)
51   void assoc_destroy(assoc_table *t)
52   void *assoc_find(assoc_table *t, atom *a, int sz, unsigned *f)
53   void assoc_remove(assoc_table *t, void *b)
54   atom *ASSOC_ATOM(void *b)
55   void assoc_mkiter(assoc_iter *i, assoc_table *t)
56   void *assoc_next(assoc_iter *i)
57
58 cdef extern from 'grim.h':
59   int PSIZEOF(void *p)
60
61 cdef extern from 'Python.h':
62   int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1
63   PyString_FromStringAndSize(char *p, int n)
64   ctypedef struct PyObject:
65     pass
66   void Py_INCREF(PyObject *obj)
67   void Py_DECREF(PyObject *obj)
68
69 cdef class AtomIter:
70   cdef atom_iter _i
71   def __new__(me):
72     atom_mkiter(&me._i, ATOM_GLOBAL)
73   def __next__(me):
74     cdef atom *a
75     a = atom_next(&me._i)
76     if not a:
77       raise StopIteration
78     return atom_pywrap(a)
79   def __iter__(me):
80     return me
81
82 def atoms():
83   return AtomIter()
84
85 cdef struct entry:
86   assoc_base _b
87   PyObject *v
88
89 cdef entry *_find(assoc_table *t, object key, unsigned *f) except ?NULL:
90   cdef void *p
91   cdef int n
92   cdef entry *e
93   cdef atom *a
94   a = ATOM_A(atom_pyintern(key))
95   if f:
96     f[0] = 0
97     e = <entry *>assoc_find(t, a, PSIZEOF(e), f)
98     if not f[0]:
99       e.v = NULL
100   else:
101     e = <entry *>assoc_find(t, a, 0, NULL)
102   return e
103
104 cdef _key(entry *e):
105   return atom_pywrap(ASSOC_ATOM(<void *>e))
106
107 cdef _eget(entry *e):
108   Py_INCREF(e.v)
109   return <object>e.v
110
111 cdef void _eset(entry *e, v):
112   if e.v:
113     Py_DECREF(e.v)
114   e.v = <PyObject *>v
115   Py_INCREF(e.v)
116
117 cdef void _edel(assoc_table *t, entry *e):
118   if e.v:
119     Py_DECREF(e.v)
120   assoc_remove(t, <void *>e)
121
122 cdef class Table:
123   cdef assoc_table _t
124   def __new__(me, *hunoz, **hukairz):
125     assoc_create(&me._t)
126   def __init__(me, stuff = None, **kw):
127     me.update(stuff, **kw)
128   def __getitem__(me, key):
129     cdef entry *e
130     e = _find(&me._t, key, NULL)
131     if not e:
132       raise KeyError, key
133     return _eget(e)
134   def __setitem__(me, key, value):
135     cdef unsigned f
136     _eset(_find(&me._t, key, &f), value)
137   def __delitem__(me, key):
138     cdef entry *e
139     cdef unsigned f
140     e = _find(&me._t, key, &f)
141     if not e:
142       raise KeyError, key
143     _edel(&me._t, e)
144   def get(me, key, default = None):
145     cdef entry *e
146     e = _find(&me._t, key, NULL)
147     if not e:
148       return default
149     return _eget(e)
150   def setdefault(me, key, default = None):
151     cdef entry *e
152     cdef unsigned f
153     e = _find(&me._t, key, &f)
154     if f:
155       return _eget(e)
156     else:
157       _eset(e, default)
158       return default
159   def pop(me, key, default = None):
160     cdef entry *e
161     e = _find(&me._t, key, NULL)
162     if not e:
163       return default
164     rc = _eget(e)
165     _edel(&me._t, e)
166     return rc
167   def popitem(me):
168     cdef entry *e
169     cdef assoc_iter i
170     assoc_mkiter(&i, &me._t)
171     e = <entry *>assoc_next(&i)
172     if not e:
173       raise ValueError, 'popitem(): table is empty'
174     return _key(e), _eget(e)
175   def keys(me):
176     cdef assoc_iter i
177     cdef entry *e
178     l = []
179     assoc_mkiter(&i, &me._t)
180     while 1:
181       e = <entry *>assoc_next(&i)
182       if not e:
183         break
184       l.append(_key(e))
185     return l
186   def values(me):
187     cdef assoc_iter i
188     cdef entry *e
189     l = []
190     assoc_mkiter(&i, &me._t)
191     while 1:
192       e = <entry *>assoc_next(&i)
193       if not e:
194         break
195       l.append(_eget(e))
196     return l
197   def items(me):
198     cdef assoc_iter i
199     cdef entry *e
200     l = []
201     assoc_mkiter(&i, &me._t)
202     while 1:
203       e = <entry *>assoc_next(&i)
204       if not e:
205         break
206       l.append((_key(e), _eget(e)))
207     return l
208   def clear(me):
209     cdef assoc_iter i
210     cdef entry *e
211     assoc_mkiter(&i, &me._t)
212     while 1:
213       e = <entry *>assoc_next(&i)
214       if not e:
215         break
216       _edel(&me._t, e)
217     return me
218   def __dealloc__(me):
219     cdef assoc_iter i
220     cdef entry *e
221     assoc_mkiter(&i, &me._t)
222     while 1:
223       e = <entry *>assoc_next(&i)
224       if not e:
225         break
226       _edel(&me._t, e)
227     assoc_destroy(&me._t)
228   def iterkeys(me):
229     return KeyIter(me)
230   def __iter__(me):
231     return KeyIter(me)
232   def itervalues(me):
233     return ValueIter(me)
234   def iteritems(me):
235     return ItemIter(me)
236   def update(me, stuff = None, **kw):
237     if stuff is None:
238       pass
239     elif hasattr(stuff, 'keys'):
240       for k in stuff:
241         me[k] = stuff[k]
242     else:
243       for k, v in stuff:
244         me[k] = v
245     for k, v in kw.iteritems():
246       me[k] = kw[k]
247     return me
248
249 cdef class KeyIter:
250   cdef Table _t
251   cdef assoc_iter _i
252   def __new__(me, Table t):
253     me._t = t
254     assoc_mkiter(&me._i, &t._t)
255   def __iter__(me):
256     return me
257   def __next__(me):
258     cdef entry *e
259     e = <entry *>assoc_next(&me._i)
260     if not e:
261       raise StopIteration
262     return _key(e)
263
264 cdef class ValueIter:
265   cdef Table _t
266   cdef assoc_iter _i
267   def __new__(me, Table t):
268     me._t = t
269     assoc_mkiter(&me._i, &t._t)
270   def __iter__(me):
271     return me
272   def __next__(me):
273     cdef entry *e
274     e = <entry *>assoc_next(&me._i)
275     if not e:
276       raise StopIteration
277     return _eget(e)
278
279 cdef class ItemIter:
280   cdef Table _t
281   cdef assoc_iter _i
282   def __new__(me, Table t):
283     me._t = t
284     assoc_mkiter(&me._i, &t._t)
285   def __iter__(me):
286     return me
287   def __next__(me):
288     cdef entry *e
289     e = <entry *>assoc_next(&me._i)
290     if not e:
291       raise StopIteration
292     return _key(e), _eget(e)
293
294 Atom = atom_pystartup()
295
296 #----- That's all, folks ----------------------------------------------------