111
116
def __len__(self):
114
cdef PyObject **_lookup(self, key, long hash) except NULL:
115
"""Find the slot where 'key' would fit.
117
This is the same as a dicts 'lookup' function
119
:param key: An object we are looking up
120
:param hash: The hash for key
121
:return: The location in self.table where key should be put
122
should never be NULL, but may reference a NULL (PyObject*)
124
cdef size_t i, perturb
127
cdef PyObject **table, **cur, **free_slot, *py_key
133
py_key = <PyObject *>key
135
# Found a blank spot, or found the exact key
142
if _is_equal(py_key, hash, cur[0]):
143
# Both py_key and cur[0] belong in this slot, return it
146
# size_t is unsigned, hash is signed...
149
i = (i << 2) + i + perturb + 1
150
cur = &table[i & mask]
151
if cur[0] == NULL: # Found an empty spot
152
if free_slot: # Did we find a _dummy earlier?
156
if (cur[0] == py_key # exact match
157
or _is_equal(py_key, hash, cur[0])): # Equivalent match
159
if (cur[0] == _dummy and free_slot == NULL):
161
perturb >>= PERTURB_SHIFT
162
raise AssertionError('should never get here')
164
119
def _test_lookup(self, key):
165
120
cdef PyObject **slot
167
slot = self._lookup(key, hash(key))
122
slot = _StaticTupleInterner_Lookup(self, key, hash(key))
168
123
if slot[0] == NULL:
170
125
elif slot[0] == _dummy:
176
131
def __contains__(self, key):
177
132
cdef PyObject **slot
179
slot = self._lookup(key, hash(key))
134
slot = _StaticTupleInterner_Lookup(self, key, hash(key))
180
135
if slot[0] == NULL or slot[0] == _dummy:
184
139
def __getitem__(self, key):
140
"""Return a stored item that is equivalent to key."""
185
141
cdef PyObject **slot
186
slot = self._lookup(key, hash(key))
142
slot = _StaticTupleInterner_Lookup(self, key, hash(key))
187
143
if slot[0] == NULL or slot[0] == _dummy:
188
144
raise KeyError("Key %s is not present" % key)
189
145
val = <object>(slot[0])
192
def __setitem__(self, key, value):
193
cdef PyObject **slot, *py_key
196
slot = self._lookup(key, hash(key))
197
if (slot[0] == NULL or slot[0] == _dummy):
198
py_key = <PyObject *>key
148
# def __setitem__(self, key, value):
149
# assert key == value
153
"""Similar to set.add(), start tracking this key.
155
There is one small difference, which is that we return the object that
156
is stored at the given location. (which is closer to the
157
dict.setdefault() functionality.)
159
return StaticTupleInterner_Add(self, key)
161
def discard(self, key):
162
"""Remove key from the dict, whether it exists or not.
164
:return: 0 if the item did not exist, 1 if it did
166
return StaticTupleInterner_Discard(self, key)
202
169
def __delitem__(self, key):
203
cdef PyObject **slot, *py_key
205
slot = self._lookup(key, hash(key))
206
if (slot[0] == NULL or slot[0] == _dummy):
207
pass # Raise KeyError
210
# TODO: Check refcounts
170
"""Remove the given item from the dict.
172
Raise a KeyError if the key was not present.
175
exists = StaticTupleInterner_Discard(self, key)
177
raise KeyError('Key %s not present' % (key,))
180
cdef api inline PyObject **_StaticTupleInterner_Lookup(
181
StaticTupleInterner self, key, long hash) except NULL:
182
"""Find the slot where 'key' would fit.
184
This is the same as a dicts 'lookup' function.
186
:param key: An object we are looking up
187
:param hash: The hash for key
188
:return: The location in self.table where key should be put
189
should never be NULL, but may reference a NULL (PyObject*)
191
cdef size_t i, perturb
194
cdef PyObject **table, **cur, **free_slot, *py_key
200
py_key = <PyObject *>key
202
# Found a blank spot, or found the exact key
209
if _is_equal(py_key, hash, cur[0]):
210
# Both py_key and cur[0] belong in this slot, return it
213
# size_t is unsigned, hash is signed...
216
i = (i << 2) + i + perturb + 1
217
cur = &table[i & mask]
218
if cur[0] == NULL: # Found an empty spot
219
if free_slot: # Did we find a _dummy earlier?
223
if (cur[0] == py_key # exact match
224
or _is_equal(py_key, hash, cur[0])): # Equivalent match
226
if (cur[0] == _dummy and free_slot == NULL):
228
perturb >>= PERTURB_SHIFT
229
raise AssertionError('should never get here')
232
cdef api object StaticTupleInterner_Add(StaticTupleInterner self, object key):
233
"""Add a key to the StaticTupleInterner (set).
235
:param self: The StaticTupleInterner to add the key to.
236
:param key: The key to be added. If the key is already present,
237
self will not be modified
238
:return: The current key stored at the location defined by 'key'.
239
This may be the same object, or it may be an equivalent object.
240
(consider dict.setdefault(key, key))
242
cdef PyObject **slot, *py_key
244
slot = _StaticTupleInterner_Lookup(self, key, hash(key))
245
py_key = <PyObject *>key
246
if (slot[0] == NULL):
251
elif (slot[0] == _dummy):
255
# No else: clause. If _StaticTupleInterner_Lookup returns a pointer to
256
# a live object, then we already have a value at this location.
257
return <object>(slot[0])
260
cdef api int StaticTupleInterner_Discard(StaticTupleInterner self,
261
object key) except -1:
262
"""Remove the object referenced at location 'key'.
264
:param self: The StaticTupleInterner being modified
265
:param key: The key we are checking on
266
:return: 1 if there was an object present, 0 if there was not, and -1 on
269
cdef PyObject **slot, *py_key
271
slot = _StaticTupleInterner_Lookup(self, key, hash(key))
272
if slot[0] == NULL or slot[0] == _dummy: