thashes.nim 6.3 KB

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