hashindex.pyx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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.index = self.index
  88. return iter
  89. cdef class NSKeyIterator:
  90. cdef HashIndex *index
  91. cdef char *key
  92. def __cinit__(self):
  93. self.key = NULL
  94. def __iter__(self):
  95. return self
  96. def __next__(self):
  97. self.key = <char *>hashindex_next_key(self.index, <char *>self.key)
  98. if not self.key:
  99. raise StopIteration
  100. cdef int *value = <int *>(self.key + 32)
  101. return self.key[:32], (_le32toh(value[0]), _le32toh(value[1]))
  102. cdef class ChunkIndex(IndexBase):
  103. value_size = 12
  104. def __getitem__(self, key):
  105. assert len(key) == 32
  106. data = <int *>hashindex_get(self.index, <char *>key)
  107. if not data:
  108. raise KeyError
  109. return _le32toh(data[0]), _le32toh(data[1]), _le32toh(data[2])
  110. def __setitem__(self, key, value):
  111. assert len(key) == 32
  112. cdef int[3] data
  113. data[0] = _htole32(value[0])
  114. data[1] = _htole32(value[1])
  115. data[2] = _htole32(value[2])
  116. if not hashindex_set(self.index, <char *>key, data):
  117. raise Exception('hashindex_set failed')
  118. def __contains__(self, key):
  119. assert len(key) == 32
  120. data = <int *>hashindex_get(self.index, <char *>key)
  121. return data != NULL
  122. def iteritems(self, marker=None, limit=0):
  123. iter = ChunkKeyIterator()
  124. iter.index = self.index
  125. return iter
  126. cdef class ChunkKeyIterator:
  127. cdef HashIndex *index
  128. cdef char *key
  129. def __cinit__(self):
  130. self.key = NULL
  131. def __iter__(self):
  132. return self
  133. def __next__(self):
  134. self.key = <char *>hashindex_next_key(self.index, <char *>self.key)
  135. if not self.key:
  136. raise StopIteration
  137. cdef int *value = <int *>(self.key + 32)
  138. return self.key[:32], (_le32toh(value[0]), _le32toh(value[1]), _le32toh(value[2]))