hashindex.pyx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # -*- coding: utf-8 -*-
  2. import os
  3. cdef extern from "_hashindex.c":
  4. ctypedef struct HashIndex:
  5. pass
  6. HashIndex *hashindex_open(char *path, int readonly)
  7. HashIndex *hashindex_create(char *path, int capacity, int key_size, int value_size)
  8. int hashindex_get_size(HashIndex *index)
  9. int hashindex_clear(HashIndex *index)
  10. int hashindex_close(HashIndex *index)
  11. int hashindex_flush(HashIndex *index)
  12. void *hashindex_get(HashIndex *index, void *key)
  13. void *hashindex_next_key(HashIndex *index, void *key)
  14. int hashindex_delete(HashIndex *index, void *key)
  15. int hashindex_set(HashIndex *index, void *key, void *value)
  16. int _htole32(int v)
  17. int _le32toh(int v)
  18. _NoDefault = object()
  19. cdef class IndexBase:
  20. cdef HashIndex *index
  21. key_size = 32
  22. def __cinit__(self, path, readonly=False):
  23. self.index = hashindex_open(<bytes>os.fsencode(path), readonly)
  24. if not self.index:
  25. raise Exception('Failed to open %s' % path)
  26. def __dealloc__(self):
  27. if self.index:
  28. if not hashindex_close(self.index):
  29. raise Exception('hashindex_close failed')
  30. @classmethod
  31. def create(cls, path):
  32. index = hashindex_create(<bytes>os.fsencode(path), 0, cls.key_size, cls.value_size)
  33. if not index:
  34. raise Exception('Failed to create %s' % path)
  35. hashindex_close(index)
  36. return cls(path)
  37. def clear(self):
  38. if not hashindex_clear(self.index):
  39. raise Exception('hashindex_clear failed')
  40. def flush(self):
  41. if not hashindex_flush(self.index):
  42. raise Exception('hashindex_flush failed')
  43. def setdefault(self, key, value):
  44. if not key in self:
  45. self[key] = value
  46. def __delitem__(self, key):
  47. assert len(key) == 32
  48. if not hashindex_delete(self.index, <char *>key):
  49. raise Exception('hashindex_delete failed')
  50. def get(self, key, default=None):
  51. try:
  52. return self[key]
  53. except KeyError:
  54. return default
  55. def pop(self, key, default=_NoDefault):
  56. try:
  57. value = self[key]
  58. del self[key]
  59. return value
  60. except KeyError:
  61. if default != _NoDefault:
  62. return default
  63. raise
  64. def __len__(self):
  65. return hashindex_get_size(self.index)
  66. cdef class NSIndex(IndexBase):
  67. value_size = 8
  68. def __getitem__(self, key):
  69. assert len(key) == 32
  70. data = <int *>hashindex_get(self.index, <char *>key)
  71. if not data:
  72. raise KeyError
  73. return _le32toh(data[0]), _le32toh(data[1])
  74. def __setitem__(self, key, value):
  75. assert len(key) == 32
  76. cdef int[2] data
  77. data[0] = _htole32(value[0])
  78. data[1] = _htole32(value[1])
  79. if not hashindex_set(self.index, <char *>key, data):
  80. raise Exception('hashindex_set failed')
  81. def __contains__(self, key):
  82. assert len(key) == 32
  83. data = <int *>hashindex_get(self.index, <char *>key)
  84. return data != NULL
  85. def iteritems(self, marker=None, limit=0):
  86. iter = NSKeyIterator()
  87. iter.idx = self
  88. iter.index = self.index
  89. return iter
  90. cdef class NSKeyIterator:
  91. cdef NSIndex idx
  92. cdef HashIndex *index
  93. cdef char *key
  94. def __cinit__(self):
  95. self.key = NULL
  96. def __iter__(self):
  97. return self
  98. def __next__(self):
  99. self.key = <char *>hashindex_next_key(self.index, <char *>self.key)
  100. if not self.key:
  101. raise StopIteration
  102. cdef int *value = <int *>(self.key + 32)
  103. return self.key[:32], (_le32toh(value[0]), _le32toh(value[1]))
  104. cdef class ChunkIndex(IndexBase):
  105. value_size = 12
  106. def __getitem__(self, key):
  107. assert len(key) == 32
  108. data = <int *>hashindex_get(self.index, <char *>key)
  109. if not data:
  110. raise KeyError
  111. return _le32toh(data[0]), _le32toh(data[1]), _le32toh(data[2])
  112. def __setitem__(self, key, value):
  113. assert len(key) == 32
  114. cdef int[3] data
  115. data[0] = _htole32(value[0])
  116. data[1] = _htole32(value[1])
  117. data[2] = _htole32(value[2])
  118. if not hashindex_set(self.index, <char *>key, data):
  119. raise Exception('hashindex_set failed')
  120. def __contains__(self, key):
  121. assert len(key) == 32
  122. data = <int *>hashindex_get(self.index, <char *>key)
  123. return data != NULL
  124. def iteritems(self, marker=None, limit=0):
  125. iter = ChunkKeyIterator()
  126. iter.idx = self
  127. iter.index = self.index
  128. return iter
  129. cdef class ChunkKeyIterator:
  130. cdef ChunkIndex idx
  131. cdef HashIndex *index
  132. cdef char *key
  133. def __cinit__(self):
  134. self.key = NULL
  135. def __iter__(self):
  136. return self
  137. def __next__(self):
  138. self.key = <char *>hashindex_next_key(self.index, <char *>self.key)
  139. if not self.key:
  140. raise StopIteration
  141. cdef int *value = <int *>(self.key + 32)
  142. return self.key[:32], (_le32toh(value[0]), _le32toh(value[1]), _le32toh(value[2]))