hashcommon.nim 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2019 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # An `include` file which contains common code for
  10. # hash sets and tables.
  11. const
  12. growthFactor = 2
  13. # hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These
  14. # two procs retain clarity of that encoding without the space cost of an enum.
  15. proc isEmpty(hcode: Hash): bool {.inline.} =
  16. result = hcode == 0
  17. proc isFilled(hcode: Hash): bool {.inline.} =
  18. result = hcode != 0
  19. proc nextTry(h, maxHash: Hash): Hash {.inline.} =
  20. result = (h + 1) and maxHash
  21. proc mustRehash[T](t: T): bool {.inline.} =
  22. # If this is changed, make sure to synchronize it with `slotsNeeded` below
  23. assert(t.dataLen > t.counter)
  24. result = (t.dataLen * 2 < t.counter * 3) or (t.dataLen - t.counter < 4)
  25. proc slotsNeeded(count: Natural): int {.inline.} =
  26. # Make sure to synchronize with `mustRehash` above
  27. result = nextPowerOfTwo(count * 3 div 2 + 4)
  28. proc rightSize*(count: Natural): int {.inline, deprecated: "Deprecated since 1.4.0".} =
  29. ## It is not needed anymore because
  30. ## picking the correct size is done internally.
  31. ##
  32. ## Returns the value of `initialSize` to support `count` items.
  33. ##
  34. ## If more items are expected to be added, simply add that
  35. ## expected extra amount to the parameter before calling this.
  36. result = count
  37. template rawGetKnownHCImpl() {.dirty.} =
  38. if t.dataLen == 0:
  39. return -1
  40. var h: Hash = hc and maxHash(t) # start with real hash value
  41. while isFilled(t.data[h].hcode):
  42. # Compare hc THEN key with boolean short circuit. This makes the common case
  43. # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
  44. # It does slow down succeeding lookups by one extra Hash cmp&and..usually
  45. # just a few clock cycles, generally worth it for any non-integer-like A.
  46. if t.data[h].hcode == hc and t.data[h].key == key:
  47. return h
  48. h = nextTry(h, maxHash(t))
  49. result = -1 - h # < 0 => MISSING; insert idx = -1 - result
  50. proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} =
  51. rawGetKnownHCImpl()
  52. template genHashImpl(key, hc: typed) =
  53. hc = hash(key)
  54. if hc == 0: # This almost never taken branch should be very predictable.
  55. hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine.
  56. template genHash(key: typed): Hash =
  57. var res: Hash
  58. genHashImpl(key, res)
  59. res
  60. template rawGetImpl() {.dirty.} =
  61. genHashImpl(key, hc)
  62. rawGetKnownHCImpl()
  63. proc rawGet[X, A](t: X, key: A, hc: var Hash): int {.inline.} =
  64. rawGetImpl()