hashcommon.nim 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  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. template rawGetKnownHCImpl() {.dirty.} =
  32. if t.dataLen == 0:
  33. return -1
  34. var h: Hash = hc and maxHash(t) # start with real hash value
  35. while isFilled(t.data[h].hcode):
  36. # Compare hc THEN key with boolean short circuit. This makes the common case
  37. # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
  38. # It does slow down succeeding lookups by one extra Hash cmp&and..usually
  39. # just a few clock cycles, generally worth it for any non-integer-like A.
  40. if t.data[h].hcode == hc and t.data[h].key == key:
  41. return h
  42. h = nextTry(h, maxHash(t))
  43. result = -1 - h # < 0 => MISSING; insert idx = -1 - result
  44. proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} =
  45. rawGetKnownHCImpl()
  46. template genHashImpl(key, hc: typed) =
  47. hc = hash(key)
  48. if hc == 0: # This almost never taken branch should be very predictable.
  49. hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine.
  50. template genHash(key: typed): Hash =
  51. var res: Hash
  52. genHashImpl(key, res)
  53. res
  54. template rawGetImpl() {.dirty.} =
  55. genHashImpl(key, hc)
  56. rawGetKnownHCImpl()
  57. proc rawGet[X, A](t: X, key: A, hc: var Hash): int {.inline, outParamsAt: [3].} =
  58. rawGetImpl()