Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Apr 15, 2021
1 parent 73227ce commit e1f99c7
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 36 deletions.
84 changes: 48 additions & 36 deletions lib/pure/hashes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,22 @@ proc hashData*(data: pointer, size: int): Hash =
dec(s)
result = !$h

proc hashIdentity*[T: Ordinal|enum](x: T): Hash {.inline, since: (1, 3).} =
## The identity hash, i.e. `hashIdentity(x) = x`.
cast[Hash](ord(x))

when defined(nimIntHash1):
proc hash*[T: Ordinal|enum](x: T): Hash {.inline.} =
## Efficient hashing of integers.
cast[Hash](ord(x))
else:
proc hash*[T: Ordinal|enum](x: T): Hash {.inline.} =
## Efficient hashing of integers.
hashWangYi1(uint64(ord(x)))

when defined(js):
var objectID = 0

proc hash*(x: pointer): Hash {.inline.} =
## Efficient hashing of pointers.
when defined(js):
proc getObjectId(x: pointer): int =
asm """
if (typeof `x` == "object") {
if ("_NimID" in `x`)
Expand All @@ -209,29 +219,43 @@ proc hash*(x: pointer): Hash {.inline.} =
}
}
"""

proc hash*(x: pointer | ref | ptr): Hash {.inline.} =
## Efficient `hash` overload.
runnableExamples:
var a: array[10, uint8]
assert a[0].addr.hash != a[1].addr.hash
assert cast[pointer](a[0].addr).hash == a[0].addr.hash
runnableExamples:
type A = ref object
x: int
let a = A(x: 3)
let ha = a.hash
assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`.
a.x = 4
assert ha == a.hash # the hash only depends on the address
runnableExamples:
# you can overload `hash` if you want to customize semantics
type A[T] = ref object
x, y: T
proc hash(a: A): Hash = hash(a.x)
assert A[int](x: 3, y: 4).hash == A[int](x: 3, y: 5).hash

when defined(js):
let id = getObjectId(cast[pointer](x))
result = hash(id)
# consistent with c backend and code expecting scrambled
# hashes depending on `nimIntHash1`.
else:
result = cast[Hash](cast[uint](x) shr 3) # skip the alignment
result = hash(cast[int](x))

proc hash*[T: proc](x: T): Hash {.inline.} =
## Efficient hashing of proc vars. Closures are supported too.
when T is "closure":
result = hash(rawProc(x)) !& hash(rawEnv(x))
result = hash((rawProc(x), rawEnv(x)))
else:
result = hash(pointer(x))

proc hashIdentity*[T: Ordinal|enum](x: T): Hash {.inline, since: (1, 3).} =
## The identity hash, i.e. `hashIdentity(x) = x`.
cast[Hash](ord(x))

when defined(nimIntHash1):
proc hash*[T: Ordinal|enum](x: T): Hash {.inline.} =
## Efficient hashing of integers.
cast[Hash](ord(x))
else:
proc hash*[T: Ordinal|enum](x: T): Hash {.inline.} =
## Efficient hashing of integers.
hashWangYi1(uint64(ord(x)))

proc hash*(x: float): Hash {.inline.} =
## Efficient hashing of floats.
let y = x + 0.0 # for denormalization
Expand Down Expand Up @@ -484,10 +508,10 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
h = h !& ord(c)
result = !$h

proc hash*[T: tuple | object | ref | ptr](x: T): Hash =
proc hash*[T: tuple | object](x: T): Hash =
## Efficient hashing overload.
## `hash` must be defined for each component of `x`.
runnableExamples:
# For tuple | object, `hash` should be defined for each of the field types.
type Obj = object
x: int
y: string
Expand All @@ -498,21 +522,9 @@ proc hash*[T: tuple | object | ref | ptr](x: T): Hash =
# you can define custom hashes for objects (even if they're generic):
proc hash(a: Obj2): Hash = hash((a.x))
assert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2"))
runnableExamples:
# For ref | ptr, `hash(cast[int](x))` is used.
discard
when T is tuple | object:
for f in fields(x):
result = result !& hash(f)
result = !$result
elif T is ref: result = hash(cast[int](x))
elif T is ptr:
when defined(nimLegacyHashPtr):
result = hash(cast[cstring](x))
else:
result = hash(cast[int](x))
else:
static: doAssert(false, $T)
for f in fields(x):
result = result !& hash(f)
result = !$result

proc hash*[A](x: openArray[A]): Hash =
## Efficient hashing of arrays and sequences.
Expand Down
12 changes: 12 additions & 0 deletions tests/collections/ttables.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ And we get here
3
'''
joinable: false
targets: "c cpp js"
"""

import hashes, sequtils, tables, algorithm

proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
Expand Down Expand Up @@ -444,3 +446,13 @@ block emptyOrdered:
var t2: OrderedTable[int, string]
doAssert t1 == t2

block: # Table[ref, int]
type A = ref object
x: int
var t: OrderedTable[A, int]
let a1 = A(x: 3)
let a2 = A(x: 3)
t[a1] = 10
t[a2] = 11
doAssert t[a1] == 10
doAssert t[a2] == 11

0 comments on commit e1f99c7

Please sign in to comment.