hashcommon.nim 2.7 KB

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