thashes.nim 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. discard """
  2. matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:on; --backend:c -d:nimStringHash2; --backend:cpp -d:nimStringHash2; --backend:js -d:nimStringHash2"
  3. """
  4. import std/hashes
  5. from stdtest/testutils import disableVm, whenVMorJs
  6. import std/assertions
  7. when not defined(js) and not defined(cpp):
  8. block:
  9. var x = 12
  10. iterator hello(): int {.closure.} =
  11. yield x
  12. discard hash(hello)
  13. block hashes:
  14. block hashing:
  15. var dummy = 0.0
  16. doAssert hash(dummy) == hash(-dummy)
  17. # "VM and runtime should make the same hash value (hashIdentity)"
  18. block:
  19. const hi123 = hashIdentity(123)
  20. doAssert hashIdentity(123) == hi123
  21. # "VM and runtime should make the same hash value (hashWangYi1)"
  22. block:
  23. const wy123 = hashWangYi1(123)
  24. doAssert wy123 != 0
  25. doAssert hashWangYi1(123) == wy123
  26. const wyNeg123 = hashWangYi1(-123)
  27. doAssert wyNeg123 != 0
  28. when not defined(js): # TODO: fixme it doesn't work for JS
  29. doAssert hashWangYi1(-123) == wyNeg123
  30. # "hashIdentity value incorrect at 456"
  31. block:
  32. doAssert hashIdentity(456) == 456
  33. # "hashWangYi1 value incorrect at 456"
  34. block:
  35. when Hash.sizeof < 8:
  36. doAssert hashWangYi1(456) == 1293320666
  37. else:
  38. doAssert hashWangYi1(456) == -6421749900419628582
  39. template jsNoInt64: untyped =
  40. when defined js:
  41. when compiles(compileOption("jsbigint64")):
  42. when not compileOption("jsbigint64"): true
  43. else: false
  44. else: false
  45. else: false
  46. const sHash2 = (when defined(nimStringHash2) or jsNoInt64(): true else: false)
  47. block empty:
  48. const emptyStrHash = # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash]
  49. when sHash2: 0 else: cast[Hash](-7286425919675154353i64)
  50. var
  51. a = ""
  52. b = newSeq[char]()
  53. c = newSeq[int]()
  54. d = cstring""
  55. e = "abcd"
  56. doAssert hash(a) == emptyStrHash
  57. doAssert hash(b) == emptyStrHash
  58. doAssert hash(c) == 0
  59. doAssert hash(d) == emptyStrHash
  60. doAssert hashIgnoreCase(a) == 0
  61. doAssert hashIgnoreStyle(a) == 0
  62. doAssert hash(e, 3, 2) == emptyStrHash
  63. block sameButDifferent:
  64. doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13)
  65. doAssert hash("aa bb aaaa1234") == hash(cstring"aa bb aaaa1234")
  66. doAssert hashIgnoreCase("aA bb aAAa1234") == hashIgnoreCase("aa bb aaaa1234")
  67. doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234")
  68. block smallSize: # no multibyte hashing
  69. let
  70. xx = @['H', 'i']
  71. ii = @[72'u8, 105]
  72. ss = "Hi"
  73. doAssert hash(xx) == hash(ii)
  74. doAssert hash(xx) == hash(ss)
  75. doAssert hash(xx) == hash(xx, 0, xx.high)
  76. doAssert hash(ss) == hash(ss, 0, ss.high)
  77. block largeSize: # longer than 4 characters
  78. let
  79. xx = @['H', 'e', 'l', 'l', 'o']
  80. xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's']
  81. ssl = "Helloweens"
  82. doAssert hash(xxl) == hash(ssl)
  83. doAssert hash(xxl) == hash(xxl, 0, xxl.high)
  84. doAssert hash(ssl) == hash(ssl, 0, ssl.high)
  85. doAssert hash(xx) == hash(xxl, 0, 4)
  86. doAssert hash(xx) == hash(ssl, 0, 4)
  87. doAssert hash(xx, 0, 3) == hash(xxl, 0, 3)
  88. doAssert hash(xx, 0, 3) == hash(ssl, 0, 3)
  89. proc main() =
  90. doAssert hash(0.0) == hash(0)
  91. # bug #16061
  92. when not sHash2: # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash]
  93. doAssert hash(cstring"abracadabra") == cast[Hash](-1119910118870047694i64)
  94. else:
  95. doAssert hash(cstring"abracadabra") == 97309975
  96. doAssert hash(cstring"abracadabra") == hash("abracadabra")
  97. when sizeof(int) == 8 or defined(js):
  98. block:
  99. var s: seq[Hash] = @[]
  100. for a in [0.0, 1.0, -1.0, 1000.0, -1000.0]:
  101. let b = hash(a)
  102. doAssert b notin s
  103. s.add b
  104. when defined(js):
  105. doAssert hash(0.345602) == 2035867618
  106. doAssert hash(234567.45) == -20468103
  107. doAssert hash(-9999.283456) == -43247422
  108. doAssert hash(84375674.0) == 707542256
  109. else:
  110. doAssert hash(0.345602) == 387936373221941218
  111. doAssert hash(234567.45) == -8179139172229468551
  112. doAssert hash(-9999.283456) == 5876943921626224834
  113. doAssert hash(84375674.0) == 1964453089107524848
  114. else:
  115. doAssert hash(0.345602) != 0
  116. doAssert hash(234567.45) != 0
  117. doAssert hash(-9999.283456) != 0
  118. doAssert hash(84375674.0) != 0
  119. block: # bug #16555
  120. proc fn(): auto =
  121. # avoids hardcoding values
  122. var a = "abc\0def"
  123. var b = a.cstring
  124. result = (hash(a), hash(b))
  125. doAssert result[0] != result[1]
  126. when not defined(js):
  127. doAssert fn() == static(fn())
  128. else:
  129. # xxx this is a tricky case; consistency of hashes for cstring's containing
  130. # '\0\' matters for c backend but less for js backend since such strings
  131. # are much less common in js backend; we make vm for js backend consistent
  132. # with c backend instead of js backend because FFI code (or other) could
  133. # run at CT, expecting c semantics.
  134. discard
  135. block: # hash(object)
  136. type
  137. Obj = object
  138. x: int
  139. y: string
  140. Obj2[T] = object
  141. x: int
  142. y: string
  143. Obj3 = object
  144. x: int
  145. y: string
  146. Obj4 = object
  147. case t: bool
  148. of false:
  149. x: int
  150. of true:
  151. y: int
  152. z: int
  153. Obj5 = object
  154. case t: bool
  155. of false:
  156. x: int
  157. of true:
  158. y: int
  159. z: int
  160. proc hash(a: Obj2): Hash = hash(a.x)
  161. proc hash(a: Obj3): Hash = hash((a.x,))
  162. proc hash(a: Obj5): Hash =
  163. case a.t
  164. of false: hash(a.x)
  165. of true: hash(a.y)
  166. doAssert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2"))
  167. doAssert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2"))
  168. doAssert hash(Obj2[float](x: 520, y: "Nim")) != hash(Obj2[float](x: 521, y: "Nim2"))
  169. doAssert hash(Obj3(x: 520, y: "Nim")) == hash(Obj3(x: 520, y: "Nim2"))
  170. doAssert hash(Obj4(t: false, x: 1)) == hash(Obj4(t: false, x: 1))
  171. doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: false, x: 2))
  172. doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: true, y: 1))
  173. doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: false, x: 2))
  174. doAssert hash(Obj5(t: false, x: 1)) == hash(Obj5(t: true, y: 1))
  175. doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: true, y: 2))
  176. block: # hash(ref|ptr|pointer)
  177. var a: array[10, uint8] = default(array[10, uint8])
  178. # disableVm:
  179. whenVMorJs:
  180. # pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417
  181. discard
  182. do:
  183. doAssert a[0].addr.hash != a[1].addr.hash
  184. doAssert cast[pointer](a[0].addr).hash == a[0].addr.hash
  185. block: # hash(ref)
  186. type A = ref object
  187. x: int
  188. let a = A(x: 3)
  189. disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer
  190. let ha = a.hash
  191. doAssert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`.
  192. a.x = 4
  193. doAssert ha == a.hash # the hash only depends on the address
  194. block: # hash(proc)
  195. proc fn(a: int): auto = a*2
  196. doAssert fn isnot "closure"
  197. doAssert fn is (proc)
  198. const fn2 = fn
  199. let fn3 = fn
  200. whenVMorJs: discard
  201. do:
  202. doAssert hash(fn2) == hash(fn)
  203. doAssert hash(fn3) == hash(fn)
  204. block: # hash(closure)
  205. proc outer() =
  206. var a = 0
  207. proc inner() = a.inc
  208. doAssert inner is "closure"
  209. let inner2 = inner
  210. whenVMorJs: discard
  211. do:
  212. doAssert hash(inner2) == hash(inner)
  213. outer()
  214. static: main()
  215. main()