hashindex.pyx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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, capacity=0):
  32. index = hashindex_create(<bytes>os.fsencode(path), capacity, 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):
  86. cdef const void *key
  87. iter = NSKeyIterator()
  88. iter.idx = self
  89. iter.index = self.index
  90. if marker:
  91. key = hashindex_get(self.index, <char *>marker)
  92. if marker is None:
  93. raise IndexError
  94. iter.key = key - 32
  95. return iter
  96. cdef class NSKeyIterator:
  97. cdef NSIndex idx
  98. cdef HashIndex *index
  99. cdef const void *key
  100. def __cinit__(self):
  101. self.key = NULL
  102. def __iter__(self):
  103. return self
  104. def __next__(self):
  105. self.key = hashindex_next_key(self.index, <char *>self.key)
  106. if not self.key:
  107. raise StopIteration
  108. cdef int *value = <int *>(self.key + 32)
  109. return (<char *>self.key)[:32], (_le32toh(value[0]), _le32toh(value[1]))
  110. cdef class ChunkIndex(IndexBase):
  111. value_size = 12
  112. def __getitem__(self, key):
  113. assert len(key) == 32
  114. data = <int *>hashindex_get(self.index, <char *>key)
  115. if not data:
  116. raise KeyError
  117. return _le32toh(data[0]), _le32toh(data[1]), _le32toh(data[2])
  118. def __setitem__(self, key, value):
  119. assert len(key) == 32
  120. cdef int[3] data
  121. data[0] = _htole32(value[0])
  122. data[1] = _htole32(value[1])
  123. data[2] = _htole32(value[2])
  124. if not hashindex_set(self.index, <char *>key, data):
  125. raise Exception('hashindex_set failed')
  126. def __contains__(self, key):
  127. assert len(key) == 32
  128. data = <int *>hashindex_get(self.index, <char *>key)
  129. return data != NULL
  130. def iteritems(self, marker=None):
  131. cdef const void *key
  132. iter = ChunkKeyIterator()
  133. iter.idx = self
  134. iter.index = self.index
  135. if marker:
  136. key = hashindex_get(self.index, <char *>marker)
  137. if marker is None:
  138. raise IndexError
  139. iter.key = key - 32
  140. return iter
  141. cdef class ChunkKeyIterator:
  142. cdef ChunkIndex idx
  143. cdef HashIndex *index
  144. cdef const void *key
  145. def __cinit__(self):
  146. self.key = NULL
  147. def __iter__(self):
  148. return self
  149. def __next__(self):
  150. self.key = hashindex_next_key(self.index, <char *>self.key)
  151. if not self.key:
  152. raise StopIteration
  153. cdef int *value = <int *>(self.key + 32)
  154. return (<char *>self.key)[:32], (_le32toh(value[0]), _le32toh(value[1]), _le32toh(value[2]))