debian/control: Add Build-Depends for `dh-python'.
[mLib-python] / mapping.pyx
1 ### -*-pyrex-*-
2 ###
3 ### Common mapping stuff
4 ###
5 ### (c) 2005 Straylight/Edgeware
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This file is part of the Python interface to mLib.
11 ###
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.
16 ###
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.
21 ###
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.
25
26 cdef class Mapping
27
28 cdef class _MapIterator:
29 cdef void *_next(me):
30 return NULL
31
32 cdef class Mapping:
33
34 ## Subclasses must implement these
35 cdef int _init(me) except -1:
36 raise TypeError, 'abstract class'
37 cdef void *_find(me, object key, unsigned *f) except NULL:
38 raise SystemError, 'unimplemented _find'
39 cdef object _key(me, void *e):
40 return None
41 cdef object _value(me, void *e):
42 return None
43 cdef void _setval(me, void *e, object val):
44 pass
45 cdef void _del(me, void *e):
46 pass
47 cdef _MapIterator _iter(me):
48 raise SystemError, 'unimplemented _iter'
49
50 ## Initialization
51 def __cinit__(me, *hunoz, **hukairz):
52 me._init()
53 def __init__(me, stuff = None, **kw):
54 me.update(stuff, kw)
55
56 ## Bulk update
57 def update(me, stuff = None, **kw):
58 """D.update([MAP], **KW): insert mappings from MAP and KW"""
59 cdef unsigned f
60 if stuff is None:
61 pass
62 elif hasattr(stuff, 'itemiter'):
63 for k, v in stuff.itemiter:
64 me._setval(me._find(k, &f), v)
65 elif hasattr(stuff, 'keys'):
66 for k in stuff.keys():
67 me._setval(me._find( k, &f), stuff[k])
68 else:
69 for k, v in stuff:
70 me._setval(me._find(k, &f), v)
71 for k, v in kw.iteritems():
72 me._setval(me._find(k, &f), v)
73 return me
74
75 ## Item access
76 def __getitem__(me, key):
77 cdef void *e
78 e = me._find(key, NULL)
79 if not e:
80 raise KeyError, key
81 return me._value(e)
82 def __setitem__(me, key, value):
83 cdef unsigned f
84 me._setval(me._find(key, &f), value)
85 def __delitem__(me, key):
86 cdef void *e
87 cdef unsigned f
88 e = me._find(key, &f)
89 if not e:
90 raise KeyError, key
91 me._del(e)
92 def get(me, key, default = None):
93 """D.get(KEY, [default = None]) -> VALUE: value at KEY, or DEFAULT"""
94 cdef void *e
95 e = me._find(key, NULL)
96 if not e:
97 return default
98 return me._value(e)
99 def setdefault(me, key, default = None):
100 """
101 D.setdefault(KEY, [default = None]) -> VALUE:
102 return value at key, or store DEFAULT at key and return that"""
103 cdef void *e
104 cdef unsigned f
105 e = me._find(key, &f)
106 if f:
107 return me._value(e)
108 else:
109 me._setval(e, default)
110 return default
111 def pop(me, key, default = None):
112 """
113 D.pop(KEY, [default = None]) -> VALUE:
114 return value at key or DEFAULT, and remove KEY"""
115 cdef void *e
116 e = me._find(key, NULL)
117 if not e:
118 return default
119 rc = me._value(e)
120 me._del(e)
121 return rc
122 def popitem(me):
123 """D.popitem() -> KEY, VALUE: return and remove an association pair"""
124 cdef _MapIterator i
125 cdef void *e
126 i = me._iter()
127 e = i._next()
128 if not e:
129 raise ValueError, 'popitem(): table is empty'
130 return me._key(e), me._value(e)
131
132 ## Lists of items
133 cdef object _list(me, object (*func)(Mapping m, void *e)):
134 cdef _MapIterator i
135 cdef void *e
136 i = me._iter()
137 l = []
138 while 1:
139 e = i._next()
140 if not e:
141 break
142 l.append(func(me, e))
143 return l
144
145 def keys(me):
146 """D.keys() -> LIST: return a list of known keys"""
147 return me._list(_map_key)
148 def values(me):
149 """D.values() -> LIST: return a list of known values"""
150 return me._list(_map_value)
151 def items(me):
152 """D.values() -> LIST: return a list of known (KEY, VALUE) pairs"""
153 return me._list(_map_item)
154
155 def clear(me):
156 """D.clear(): remove all mappings"""
157 cdef _MapIterator i
158 cdef void *e
159 i = me._iter()
160 while 1:
161 e = i._next()
162 if not e:
163 break
164 me._del(e)
165 return me
166
167 ## Iteration
168 def __iter__(me):
169 return MapKeyIter(me)
170 def iterkeys(me):
171 """D.iterkeys() -> ITER: return iterator over keys"""
172 return MapKeyIter(me)
173 def itervalues(me):
174 """D.itervalues() -> ITER: return iterator over values"""
175 return MapValueIter(me)
176 def iteritems(me):
177 """D.iteritems() -> ITER: return iterator over (KEY, VALUE) pairs"""
178 return MapItemIter(me)
179
180 cdef class MapIterBase:
181 cdef Mapping m
182 cdef object (*func)(Mapping m, void *e)
183 cdef _MapIterator i
184 cdef int _init(me) except -1:
185 raise TypeError, 'abstract class'
186 def __cinit__(me):
187 me.i = m._iter()
188 me._init()
189 def __iter__(me):
190 return me
191 def __next__(me):
192 cdef void *e
193 e = me.i._next()
194 if not e:
195 raise StopIteration
196 return me.func(me.m, e)
197 cdef class MapKeyIter (MapIterBase):
198 cdef int _init(me) except -1:
199 me.func = _map_key
200 return 0
201 cdef class MapValueIter (MapIterBase):
202 cdef int _init(me) except -1:
203 me.func = _map_value
204 return 0
205 cdef class MapItemIter (MapIterBase):
206 cdef int _init(me) except -1:
207 me.func = _map_item
208 return 0
209
210 cdef object _map_key(Mapping m, void *e):
211 return m._key(e)
212 cdef object _map_value(Mapping m, void *e):
213 return m._value(e)
214 cdef object _map_item(Mapping m, void *e):
215 return m._key(e), m._value(e)
216
217 ###----- That's all, folks --------------------------------------------------