bitabs.nim 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. ## A BiTable is a table that can be seen as an optimized pair
  2. ## of (Table[Id, Val], Table[Val, Id]).
  3. import hashes
  4. type
  5. Id* = distinct uint32
  6. BiTable*[T] = object
  7. vals: seq[T] # indexed by Id
  8. keys: seq[Id] # indexed by hash(val)
  9. proc nextTry(h, maxHash: Hash): Hash {.inline.} =
  10. result = (h + 1) and maxHash
  11. template maxHash(t): untyped = high(t.keys)
  12. template isFilled(x: Id): bool = x.uint32 > 0'u32
  13. const
  14. NullId* = Id(0)
  15. proc `$`*(x: Id): string {.borrow.}
  16. proc hash*(x: Id): Hash {.borrow.}
  17. proc `==`*(x, y: Id): bool {.borrow.}
  18. proc mustRehash(length, counter: int): bool {.inline.} =
  19. assert(length > counter)
  20. result = (length * 2 < counter * 3) or (length - counter < 4)
  21. const
  22. idStart = 256 # Ids do not start with 0 but with this value. The IR needs it.
  23. proc isBuiltin*(x: Id): bool {.inline.} = uint32(x) < idStart
  24. template idToIdx(x: Id): int = x.int - idStart
  25. proc enlarge[T](t: var BiTable[T]) =
  26. var n: seq[Id]
  27. newSeq(n, len(t.keys) * 2)
  28. swap(t.keys, n)
  29. for i in 0..high(n):
  30. let eh = n[i]
  31. if isFilled(eh):
  32. var j = hash(t.vals[idToIdx eh]) and maxHash(t)
  33. while isFilled(t.keys[j]):
  34. j = nextTry(j, maxHash(t))
  35. t.keys[j] = move n[i]
  36. proc getOrIncl*[T](t: var BiTable[T]; v: T): Id =
  37. let origH = hash(v)
  38. var h = origH and maxHash(t)
  39. if t.keys.len != 0:
  40. while true:
  41. let id = t.keys[h]
  42. if not isFilled(id): break
  43. if t.vals[idToIdx t.keys[h]] == v: return id
  44. h = nextTry(h, maxHash(t))
  45. # not found, we need to insert it:
  46. if mustRehash(t.keys.len, t.vals.len):
  47. enlarge(t)
  48. # recompute where to insert:
  49. h = origH and maxHash(t)
  50. while true:
  51. let id = t.keys[h]
  52. if not isFilled(id): break
  53. h = nextTry(h, maxHash(t))
  54. else:
  55. setLen(t.keys, 16)
  56. h = origH and maxHash(t)
  57. result = Id(t.vals.len + idStart)
  58. t.keys[h] = result
  59. t.vals.add v
  60. proc `[]`*[T](t: var BiTable[T]; id: Id): var T {.inline.} =
  61. let idx = idToIdx id
  62. assert idx < t.vals.len
  63. result = t.vals[idx]
  64. proc `[]`*[T](t: BiTable[T]; id: Id): lent T {.inline.} =
  65. let idx = idToIdx id
  66. assert idx < t.vals.len
  67. result = t.vals[idx]
  68. when isMainModule:
  69. var t: BiTable[string]
  70. echo getOrIncl(t, "hello")
  71. echo getOrIncl(t, "hello")
  72. echo getOrIncl(t, "hello3")
  73. echo getOrIncl(t, "hello4")
  74. echo getOrIncl(t, "helloasfasdfdsa")
  75. echo getOrIncl(t, "hello")
  76. for i in 0 ..< 100_000:
  77. discard t.getOrIncl($i & "___" & $i)
  78. for i in 0 ..< 100_000:
  79. assert t.getOrIncl($i & "___" & $i).idToIdx == i + 4
  80. echo t.vals.len
  81. echo t.vals[0]
  82. echo t.vals[1004]