14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Definition of a class that is used to intern StaticTuple objects."""
17
"""Definition of a class that is similar to Set with some small changes."""
19
19
cdef extern from "Python.h":
20
20
ctypedef unsigned long size_t
57
# Only handled for now because we are testing with stuff like tuples versus
58
# StaticTuple objects. If we decide to limit StaticTupleInterner to
59
# strictly only allowing StaticTuple objects, then this is no longer
60
# required, and Py_NotImplemented => not equal
61
57
if res == Py_NotImplemented:
63
59
res = Py_TYPE(other).tp_richcompare(other, this, Py_EQ)
71
cdef public api class StaticTupleInterner [object StaticTupleInternerObject,
72
type StaticTupleInterner_type]:
73
"""This class tracks the canonical forms for StaticTuples.
67
cdef public api class SimpleSet [object SimpleSetObject, type SimpleSet_Type]:
68
"""This class can be used to track canonical forms for objects.
75
70
It is similar in function to the interned dictionary that is used by
87
82
DEF DEFAULT_SIZE=1024
88
83
DEF PERTURB_SHIFT=5
90
# Note that most of the members on this class are just thunks over to the C
91
# api. However, this provides a nice Python/Pyrex api, as well as making it
92
# easy to test the C api from pure python.
94
85
def __init__(self):
95
86
cdef Py_ssize_t size, n_bytes
125
116
return <int>(slot - self.table), res
127
118
def __contains__(self, key):
128
"""Is key present in this StaticTupleInterner."""
119
"""Is key present in this SimpleSet."""
129
120
cdef PyObject **slot
131
122
slot = _lookup(self, key)
209
196
# TODO: Test this
210
197
# if new_size < self.used:
211
# raise RuntimeError('cannot shrink StaticTupleInterner to something'
198
# raise RuntimeError('cannot shrink SimpleSet to something'
212
199
# ' smaller than the number of used slots.')
213
200
n_bytes = sizeof(PyObject*) * new_size;
214
201
new_table = <PyObject **>PyMem_Malloc(n_bytes)
313
300
raise KeyError('Key %s not present' % (key,))
315
302
def __iter__(self):
316
return _StaticTupleInterner_iterator(self)
319
cdef class _StaticTupleInterner_iterator:
320
"""Iterator over the StaticTupleInterner structure."""
303
return _SimpleSet_iterator(self)
306
cdef class _SimpleSet_iterator:
307
"""Iterator over the SimpleSet structure."""
322
309
cdef Py_ssize_t pos
323
cdef StaticTupleInterner table
324
311
cdef Py_ssize_t used # track if things have been mutated while iterating
325
312
cdef Py_ssize_t len # number of entries left
327
314
def __init__(self, obj):
330
self.used = self.table.used
331
self.len = self.table.used
317
self.used = self.set.used
318
self.len = self.set.used
333
320
def __iter__(self):
337
324
cdef Py_ssize_t mask, i
338
325
cdef PyObject **table
340
if self.table is None:
341
328
raise StopIteration
342
if self.table.used != self.used:
329
if self.set.used != self.used:
343
330
# Force this exception to continue to be raised
345
332
raise RuntimeError("Set size changed during iteration")
347
mask = self.table.mask
348
table = self.table.table
335
table = self.set.table
350
337
while i <= mask and (table[i] == NULL or table[i] == _dummy):
354
341
# we walked to the end
356
343
raise StopIteration
357
344
# We must have found one
358
345
key = <object>(table[i])
362
349
def __length_hint__(self):
363
if self.table is not None and self.used == self.table.used:
350
if self.set is not None and self.used == self.set.used:
369
cdef api StaticTupleInterner StaticTupleInterner_New():
370
"""Create a new StaticTupleInterner object."""
371
return StaticTupleInterner()
356
cdef api SimpleSet SimpleSet_New():
357
"""Create a new SimpleSet object."""
374
361
cdef inline int _check_self_not_none(object self) except -1:
383
370
raise TypeError('self must not be None')
386
cdef inline PyObject **_lookup(StaticTupleInterner self,
373
cdef inline PyObject **_lookup(SimpleSet self,
387
374
object key) except NULL:
388
375
"""Find the slot where 'key' would fit.
439
426
raise AssertionError('should never get here')
442
cdef api PyObject **_StaticTupleInterner_Lookup(object self,
429
cdef api PyObject **_SimpleSet_Lookup(object self,
443
430
object key) except NULL:
444
431
"""Find the slot where 'key' would fit.
456
443
return _lookup(self, key)
459
cdef api object StaticTupleInterner_Add(object self, object key):
460
"""Add a key to the StaticTupleInterner (set).
446
cdef api object SimpleSet_Add(object self, object key):
447
"""Add a key to the SimpleSet (set).
462
:param self: The StaticTupleInterner to add the key to.
449
:param self: The SimpleSet to add the key to.
463
450
:param key: The key to be added. If the key is already present,
464
451
self will not be modified
465
452
:return: The current key stored at the location defined by 'key'.
466
453
This may be the same object, or it may be an equivalent object.
467
454
(consider dict.setdefault(key, key))
469
cdef StaticTupleInterner true_self
456
cdef SimpleSet true_self
470
457
_check_self_not_none(self)
472
459
return true_self.add(key)
475
cdef api bint StaticTupleInterner_Contains(object self, object key) except -1:
462
cdef api bint SimpleSet_Contains(object self, object key) except -1:
476
463
"""Is key present in self?"""
477
cdef StaticTupleInterner true_self
464
cdef SimpleSet true_self
478
465
_check_self_not_none(self)
480
467
return key in true_self
483
cdef api int StaticTupleInterner_Discard(object self, object key) except -1:
470
cdef api int SimpleSet_Discard(object self, object key) except -1:
484
471
"""Remove the object referenced at location 'key'.
486
:param self: The StaticTupleInterner being modified
473
:param self: The SimpleSet being modified
487
474
:param key: The key we are checking on
488
475
:return: 1 if there was an object present, 0 if there was not, and -1 on
491
cdef StaticTupleInterner true_self
478
cdef SimpleSet true_self
492
479
_check_self_not_none(self)
494
481
return true_self.discard(key)
497
cdef api PyObject *StaticTupleInterner_Get(StaticTupleInterner self,
484
cdef api PyObject *SimpleSet_Get(SimpleSet self,
498
485
object key) except? NULL:
499
486
"""Get a pointer to the object present at location 'key'.
505
492
:param key: The value we are looking for
506
493
:return: The object present at that location
508
cdef StaticTupleInterner true_self
495
cdef SimpleSet true_self
509
496
_check_self_not_none(self)
511
498
return true_self._get(key)
514
cdef api Py_ssize_t StaticTupleInterner_Size(object self) except -1:
501
cdef api Py_ssize_t SimpleSet_Size(object self) except -1:
515
502
"""Get the number of active entries in 'self'"""
516
cdef StaticTupleInterner true_self = self
503
cdef SimpleSet true_self = self
517
504
_check_self_not_none(self)
518
505
return true_self.used
521
508
# TODO: this should probably have direct tests, since it isn't used by __iter__
522
cdef api int StaticTupleInterner_Next(object self, Py_ssize_t *pos,
509
cdef api int SimpleSet_Next(object self, Py_ssize_t *pos,
524
"""Walk over items in a StaticTupleInterner.
511
"""Walk over items in a SimpleSet.
526
513
:param pos: should be initialized to 0 by the caller, and will be updated