thashes.nim 6.5 KB

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