hashset.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. package tamias
  2. // HashSet uses a chained hashtable implementation.
  3. // Other than the transformation functions, there is nothing fancy going on.
  4. type HashValue int64
  5. type HashElement interface {
  6. Equals(interface {}) (bool)
  7. /*
  8. Iter() (*HashElement)
  9. Filter() (bool)
  10. */
  11. }
  12. // cpHashSetBin's form the linked lists in the chained hash table.
  13. type HashSetBin struct {
  14. // Pointer to the element.
  15. elt HashElement
  16. // Hash value of the element.
  17. hash HashValue
  18. // Next element in the chain.
  19. next * HashSetBin
  20. }
  21. /*
  22. // Equality function. Returns true if ptr is equal to elt.
  23. typedef int (*cpHashSetEqlFunc)(void *ptr, void *elt);
  24. // Used by cpHashSetInsert(). Called to transform the ptr into an element.
  25. typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);
  26. // Iterator function for a hashset.
  27. typedef void (*cpHashSetIterFunc)(void *elt, void *data);
  28. // Filter function. Returns false if elt should be dropped.
  29. typedef int (*cpHashSetFilterFunc)(void *elt, void *data);
  30. */
  31. type HashSet struct {
  32. // Number of elements stored in the table.
  33. entries int;
  34. // Number of cells in the table.
  35. size int;
  36. /*
  37. cpHashSetEqlFunc eql;
  38. cpHashSetTransFunc trans;
  39. (*HashElement) Iterate(*HashElement) (bool)
  40. */
  41. // Default value returned by cpHashSetFind() when no element is found.
  42. // Defaults to NULL.
  43. default_value HashElement;
  44. // The table and recycled bins
  45. table []*HashSetBin
  46. pooledbins *HashSetBin
  47. // Will use Go's array for this in stead.
  48. // cpArray *allocatedBuffers;
  49. }
  50. // Used for resizing hash tables.
  51. // Values approximately double.
  52. // http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
  53. var primes = [30]int{ 5, 13, 23, 47, 97, 193, 389, 769, 1543, 3079,
  54. 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433,
  55. 1572869, 3145739, 6291469, 12582917, 25165843, 50331653,
  56. 100663319, 201326611, 402653189, 805306457, 1610612741, 0 }
  57. func next_prime(n int) (int) {
  58. i := 0
  59. for n > primes[i] {
  60. i++
  61. Assert(primes[i] > 0,
  62. "Tried to resize a hash table to a size greater than 1610612741 O_o");
  63. // realistically this should never happen
  64. }
  65. return primes[i]
  66. }
  67. func (set * HashSet) Destroy() {
  68. set.table = nil
  69. set.pooledbins = nil
  70. }
  71. func (set * HashSet) Free() {
  72. }
  73. func HashSetAlloc() (* HashSet) {
  74. return &HashSet{}
  75. }
  76. func (set * HashSet) Init(size int) (* HashSet) {
  77. set.size = next_prime(size)
  78. set.entries = 0
  79. set.default_value = nil
  80. set.table = make([]*HashSetBin, 0, set.size)
  81. set.pooledbins = nil
  82. return set
  83. // set.buffers = nil
  84. }
  85. func HashSetNew(size int) (* HashSet) {
  86. return HashSetAlloc().Init(size)
  87. }
  88. func (set * HashSet) IsFull() bool {
  89. return (set.entries >= set.size);
  90. }
  91. func (set * HashSet) Resize() {
  92. // Get the next approximate doubled prime.
  93. newsize := next_prime(set.size + 1)
  94. // Allocate a new table.
  95. newtable := make([]*HashSetBin, set.size, newsize)
  96. // Iterate over the chains.
  97. for i:=0 ; i < set.size ; i++ {
  98. // Rehash the bins into the new table.
  99. bin := set.table[i];
  100. var next *HashSetBin
  101. var idx int
  102. for bin != nil {
  103. next = bin.next
  104. idx = int(bin.hash) % newsize;
  105. bin.next = newtable[idx]
  106. newtable[idx] = bin;
  107. bin = next;
  108. }
  109. }
  110. set.table = newtable
  111. set.size = newsize
  112. }
  113. func (set * HashSet) recycleBin(bin * HashSetBin) {
  114. bin.next = set.pooledbins
  115. set.pooledbins = bin
  116. bin.elt = nil
  117. }
  118. func (set * HashSet) getUnusedBin() (* HashSetBin) {
  119. bin := set.pooledbins
  120. if bin != nil {
  121. set.pooledbins = bin.next
  122. return bin
  123. }
  124. // Pool is exhausted, make 100 more
  125. count := 100
  126. newbins := make([]HashSetBin, count)
  127. // push all but the first one, return the first instead
  128. for i:=1; i<count; i++ {
  129. set.recycleBin(&newbins[i])
  130. }
  131. return &newbins[0]
  132. }
  133. func (set *HashSet) hashIndex(hash HashValue) (HashValue) {
  134. return hash % HashValue(set.size)
  135. }
  136. // Find the correct has bin for this element, or nil if not found
  137. func (set *HashSet) findBin(hash HashValue, ptr HashElement) (*HashSetBin) {
  138. idx := set.hashIndex(hash)
  139. bin := set.table[idx]
  140. // Follow the chained elements in the bin until the element is equal
  141. for bin != nil && !ptr.Equals(bin.elt) {
  142. bin = bin.next
  143. }
  144. return bin;
  145. }
  146. // Find the correct has bin for this element, or nil if not found
  147. // Also returns the bin before the current bin
  148. func (set *HashSet) findBinPrev(hash HashValue, ptr HashElement) (
  149. bin *HashSetBin, prev *HashSetBin) {
  150. idx := set.hashIndex(hash)
  151. prev = nil
  152. bin = set.table[idx]
  153. // Follow the chained elements in the bin until the element is equal
  154. for bin != nil && !ptr.Equals(bin.elt) {
  155. prev = bin
  156. bin = bin.next
  157. }
  158. return bin, prev;
  159. }
  160. func (set * HashSet) Insert(hash HashValue, ptr HashElement) (HashElement) {
  161. idx := set.hashIndex(hash)
  162. // Find the bin with the matching element.
  163. bin := set.findBin(hash, ptr)
  164. // Create it if necessary.
  165. if bin == nil {
  166. bin = set.getUnusedBin()
  167. bin.hash = hash
  168. bin.elt = ptr //XXX Transformation not called here. Is it needed?
  169. bin.next = set.table[idx]
  170. set.table[idx] = bin
  171. set.entries++
  172. // Resize the set if it's full.
  173. if set.IsFull() {
  174. set.Resize()
  175. }
  176. } else {
  177. // this is not in Chipmunk original but seems like a bug not to do it
  178. bin.elt = ptr
  179. }
  180. return bin.elt
  181. }
  182. func (set * HashSet) Remove(hash HashValue, ptr HashElement) (HashElement) {
  183. bin, prev := set.findBinPrev(hash, ptr)
  184. // Remove it if it exists.
  185. if bin != nil {
  186. // Update the previous bin next pointer to point to the next bin.
  187. if prev != nil {
  188. prev.next = bin.next
  189. }
  190. set.entries--
  191. return_value := bin.elt
  192. set.recycleBin(bin)
  193. return return_value
  194. }
  195. return nil;
  196. }
  197. func (set * HashSet) Find(hash HashValue, ptr HashElement) (HashElement) {
  198. bin := set.findBin(hash, ptr)
  199. if bin != nil {
  200. return bin.elt
  201. }
  202. return set.default_value
  203. }
  204. type HashSetIterFunc func(bin, data HashElement)
  205. func (set * HashSet) Each(fun HashSetIterFunc, data HashElement) {
  206. for i:=0 ; i<set.size ; i++ {
  207. bin := set.table[i];
  208. for bin != nil {
  209. next := bin.next;
  210. fun(bin.elt, data);
  211. bin = next;
  212. }
  213. }
  214. }
  215. type HashSetFilterFunc func(bin, data HashElement) (bool)
  216. /*
  217. XXX: how to iterate and filter?
  218. void
  219. cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data)
  220. {
  221. for(int i=0; i<set.size; i++){
  222. cpHashSetBin *bin = set.table[i];
  223. while(bin){
  224. cpHashSetBin *next = bin.next;
  225. func(bin.elt, data);
  226. bin = next;
  227. }
  228. }
  229. }
  230. void
  231. cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data)
  232. {
  233. // Iterate over all the chains.
  234. for(int i=0; i<set.size; i++){
  235. // The rest works similarly to cpHashSetRemove() above.
  236. cpHashSetBin **prev_ptr = &set.table[i];
  237. cpHashSetBin *bin = set.table[i];
  238. while(bin){
  239. cpHashSetBin *next = bin.next;
  240. if(func(bin.elt, data)){
  241. prev_ptr = &bin.next;
  242. } else {
  243. (*prev_ptr) = next;
  244. set.entries--;
  245. recycleBin(set, bin);
  246. }
  247. bin = next;
  248. }
  249. }
  250. }
  251. */