hashcommon.nim 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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. when not defined(nimHasDefault):
  14. template default[T](t: typedesc[T]): T =
  15. var v: T
  16. v
  17. # hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These
  18. # two procs retain clarity of that encoding without the space cost of an enum.
  19. proc isEmpty(hcode: Hash): bool {.inline.} =
  20. result = hcode == 0
  21. proc isFilled(hcode: Hash): bool {.inline.} =
  22. result = hcode != 0
  23. proc nextTry(h, maxHash: Hash): Hash {.inline.} =
  24. result = (h + 1) and maxHash
  25. proc mustRehash(length, counter: int): bool {.inline.} =
  26. assert(length > counter)
  27. result = (length * 2 < counter * 3) or (length - counter < 4)
  28. template rawGetKnownHCImpl() {.dirty.} =
  29. if t.dataLen == 0:
  30. return -1
  31. var h: Hash = hc and maxHash(t) # start with real hash value
  32. while isFilled(t.data[h].hcode):
  33. # Compare hc THEN key with boolean short circuit. This makes the common case
  34. # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
  35. # It does slow down succeeding lookups by one extra Hash cmp&and..usually
  36. # just a few clock cycles, generally worth it for any non-integer-like A.
  37. if t.data[h].hcode == hc and t.data[h].key == key:
  38. return h
  39. h = nextTry(h, maxHash(t))
  40. result = -1 - h # < 0 => MISSING; insert idx = -1 - result
  41. proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} =
  42. rawGetKnownHCImpl()
  43. template genHashImpl(key, hc: typed) =
  44. hc = hash(key)
  45. if hc == 0: # This almost never taken branch should be very predictable.
  46. hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine.
  47. template genHash(key: typed): Hash =
  48. var res: Hash
  49. genHashImpl(key, res)
  50. res
  51. template rawGetImpl() {.dirty.} =
  52. genHashImpl(key, hc)
  53. rawGetKnownHCImpl()
  54. proc rawGet[X, A](t: X, key: A, hc: var Hash): int {.inline.} =
  55. rawGetImpl()