2014-09-13 05:14:43 +04:00
|
|
|
# cython: profile=True
|
|
|
|
from libc.stdlib cimport calloc, free
|
|
|
|
cimport cython
|
|
|
|
|
|
|
|
|
2014-09-13 04:02:41 +04:00
|
|
|
cdef class PointerHash:
|
|
|
|
def __cinit__(self, size_t initial_size=8):
|
|
|
|
self.size = initial_size
|
|
|
|
self.filled = 0
|
2014-09-13 18:43:42 +04:00
|
|
|
self._last = NULL
|
2014-09-13 04:02:41 +04:00
|
|
|
# Size must be power of two
|
|
|
|
assert self.size & (self.size - 1) == 0
|
|
|
|
self.cells = <Cell*>calloc(self.size, sizeof(Cell))
|
|
|
|
|
|
|
|
def __dealloc__(self):
|
|
|
|
free(self.cells)
|
|
|
|
|
|
|
|
def __getitem__(self, key_t key):
|
2014-09-13 05:14:43 +04:00
|
|
|
assert key != 0
|
2014-09-13 19:02:06 +04:00
|
|
|
cdef val_t value = self.get(key)
|
|
|
|
return <size_t>value if value != NULL else None
|
2014-09-13 04:02:41 +04:00
|
|
|
|
2014-09-13 19:02:06 +04:00
|
|
|
def __setitem__(self, key_t key, size_t value):
|
|
|
|
assert key != 0 and value != 0
|
|
|
|
self.set(key, <val_t>value)
|
2014-09-13 04:02:41 +04:00
|
|
|
|
2014-09-13 19:02:06 +04:00
|
|
|
cdef val_t get(self, key_t key):
|
2014-09-13 18:43:42 +04:00
|
|
|
cell = _find_cell(self.cells, self.size, key)
|
|
|
|
self._last = cell
|
|
|
|
return cell.value
|
2014-09-13 04:02:41 +04:00
|
|
|
|
2014-09-13 19:02:06 +04:00
|
|
|
cdef void set(self, key_t key, val_t value) except *:
|
2014-09-13 18:43:42 +04:00
|
|
|
cdef Cell* cell
|
|
|
|
if self._last != NULL and key == self._last.key:
|
|
|
|
cell = self._last
|
|
|
|
else:
|
|
|
|
cell = _find_cell(self.cells, self.size, key)
|
|
|
|
self._last = NULL
|
|
|
|
if cell.key == 0:
|
|
|
|
cell.key = key
|
2014-09-13 04:02:41 +04:00
|
|
|
self.filled += 1
|
2014-09-13 18:43:42 +04:00
|
|
|
cell.value = value
|
2014-09-13 04:02:41 +04:00
|
|
|
if (self.filled + 1) * 4 >= (self.size * 3):
|
|
|
|
self.resize(self.size * 2)
|
|
|
|
|
2014-09-13 18:43:42 +04:00
|
|
|
cdef void resize(self, size_t new_size) except *:
|
2014-09-13 05:14:43 +04:00
|
|
|
assert (new_size & (new_size - 1)) == 0 # Must be a power of 2
|
2014-09-13 04:02:41 +04:00
|
|
|
assert self.filled * 4 <= new_size * 3
|
|
|
|
|
|
|
|
cdef Cell* old_cells = self.cells
|
|
|
|
cdef size_t old_size = self.size
|
|
|
|
|
|
|
|
self.size = new_size
|
|
|
|
self.cells = <Cell*>calloc(new_size, sizeof(Cell))
|
2014-09-13 05:14:43 +04:00
|
|
|
|
|
|
|
self.filled = 0
|
|
|
|
cdef size_t i
|
2014-09-13 18:43:42 +04:00
|
|
|
cdef size_t slot
|
2014-09-13 04:02:41 +04:00
|
|
|
for i in range(old_size):
|
2014-09-13 18:43:42 +04:00
|
|
|
if old_cells[i].key != 0:
|
2014-09-13 19:02:06 +04:00
|
|
|
assert old_cells[i].value != NULL, i
|
|
|
|
self.set(old_cells[i].key, old_cells[i].value)
|
2014-09-13 18:43:42 +04:00
|
|
|
free(old_cells)
|
|
|
|
|
|
|
|
|
|
|
|
@cython.cdivision
|
|
|
|
cdef inline Cell* _find_cell(Cell* cells, size_t size, key_t key) nogil:
|
|
|
|
cdef size_t i = (key % size)
|
|
|
|
while cells[i].key != 0 and cells[i].key != key:
|
|
|
|
i = (i + 1) % size
|
|
|
|
return &cells[i]
|