This module implements efficient computations of hash values for diverse Nim types. All the procs are based on these two building blocks:
If you want to implement hash procs for your custom types, you will end up writing the following kind of skeleton of code:
Example:
import pure/hashes type Something = object foo: int bar: string iterator items(x: Something): Hash = yield hash(x.foo) yield hash(x.bar) proc hash(x: Something): Hash = ## Computes a Hash from `x`. var h: Hash = 0 # Iterate over parts of `x`. for xAtom in x: # Mix the atom with the partial hash. h = h !& xAtom # Finish the hash. result = !$hIf your custom types contain fields for which there already is a hash proc, you can simply hash together the hash values of the individual fields:
Example:
import pure/hashes type Something = object foo: int bar: string proc hash(x: Something): Hash = ## Computes a Hash from `x`. var h: Hash = 0 h = h !& hash(x.foo) h = h !& hash(x.bar) result = !$h
See also
- md5 module for the MD5 checksum algorithm
- base64 module for a Base64 encoder and decoder
- std/sha1 module for the SHA-1 checksum algorithm
- tables module for hash tables
Procs
proc `!$`(h: Hash): Hash {.inline, ...raises: [], tags: [].}
-
Finishes the computation of the hash value.
This is only needed if you need to implement a hash proc for a new datatype.
Source Edit proc `!&`(h: Hash; val: int): Hash {.inline, ...raises: [], tags: [].}
-
Mixes a hash value h with val to produce a new hash value.
This is only needed if you need to implement a hash proc for a new datatype.
Source Edit proc hash(sBuf: string; sPos, ePos: int): Hash {....raises: [], tags: [].}
-
Efficient hashing of a string buffer, from starting position sPos to ending position ePos (included).
hash(myStr, 0, myStr.high) is equivalent to hash(myStr).
Example:
var a = "abracadabra" doAssert hash(a, 0, 3) == hash(a, 7, 10)
Source Edit proc hash(x: cstring): Hash {....raises: [], tags: [].}
-
Efficient hashing of null-terminated strings.
Example:
doAssert hash(cstring"abracadabra") == hash("abracadabra") doAssert hash(cstring"AbracadabrA") == hash("AbracadabrA") doAssert hash(cstring"abracadabra") != hash(cstring"AbracadabrA")
Source Edit proc hash(x: float): Hash {.inline, ...raises: [], tags: [].}
- Efficient hashing of floats. Source Edit
proc hash(x: pointer): Hash {.inline, ...raises: [], tags: [].}
- Efficient hash overload. Source Edit
proc hash(x: string): Hash {....raises: [], tags: [].}
-
Efficient hashing of strings.
See also:
Example:
doAssert hash("abracadabra") != hash("AbracadabrA")
Source Edit proc hash[A](aBuf: openArray[A]; sPos, ePos: int): Hash
-
Efficient hashing of portions of arrays and sequences, from starting position sPos to ending position ePos (included). There must be a hash proc defined for the element type A.
hash(myBuf, 0, myBuf.high) is equivalent to hash(myBuf).
Example:
let a = [1, 2, 5, 1, 2, 6] doAssert hash(a, 0, 1) == hash(a, 3, 4)
Source Edit proc hash[A](x: openArray[A]): Hash
- Efficient hashing of arrays and sequences. There must be a hash proc defined for the element type A. Source Edit
proc hash[A](x: set[A]): Hash
- Efficient hashing of sets. There must be a hash proc defined for the element type A. Source Edit
proc hash[T: tuple | object | proc](x: T): Hash
-
Efficient hash overload.
Example:
# for `tuple|object`, `hash` must be defined for each component of `x`. type Obj = object x: int y: string type Obj2[T] = object x: int y: string assert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2")) # 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"))
Example:
# proc proc fn1() = discard const fn1b = fn1 assert hash(fn1b) == hash(fn1) # closure proc outer = var a = 0 proc fn2() = a.inc assert fn2 is "closure" let fn2b = fn2 assert hash(fn2b) == hash(fn2) assert hash(fn2) != hash(fn1) outer()
Source Edit proc hash[T](x: ptr [T]): Hash {.inline.}
-
Efficient hash overload.
Example:
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
Source Edit proc hash[T](x: ref [T]): Hash {.inline.}
-
Efficient hash overload.Important: Use -d:nimPreviewHashRef to enable hashing refs. It is expected that this behavior becomes the new default in upcoming versions.
Example: cmd: -d:nimPreviewHashRef
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
Example: cmd: -d:nimPreviewHashRef
# 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
Source Edit proc hashData(data: pointer; size: int): Hash {....raises: [], tags: [].}
- Hashes an array of bytes of size size. Source Edit
proc hashIdentity[T: Ordinal | enum](x: T): Hash {.inline.}
- The identity hash, i.e. hashIdentity(x) = x. Source Edit
proc hashIgnoreCase(sBuf: string; sPos, ePos: int): Hash {....raises: [], tags: [].}
-
Efficient hashing of a string buffer, from starting position sPos to ending position ePos (included); case is ignored.
Note: This uses a different hashing algorithm than hash(string).
hashIgnoreCase(myBuf, 0, myBuf.high) is equivalent to hashIgnoreCase(myBuf).
Example:
var a = "ABracadabRA" doAssert hashIgnoreCase(a, 0, 3) == hashIgnoreCase(a, 7, 10)
Source Edit proc hashIgnoreCase(x: string): Hash {....raises: [], tags: [].}
-
Efficient hashing of strings; case is ignored.
Note: This uses a different hashing algorithm than hash(string).
See also:
Example:
doAssert hashIgnoreCase("ABRAcaDABRA") == hashIgnoreCase("abRACAdabra") doAssert hashIgnoreCase("abcdefghi") != hash("abcdefghi")
Source Edit proc hashIgnoreStyle(sBuf: string; sPos, ePos: int): Hash {....raises: [], tags: [].}
-
Efficient hashing of a string buffer, from starting position sPos to ending position ePos (included); style is ignored.
Note: This uses a different hashing algorithm than hash(string).
hashIgnoreStyle(myBuf, 0, myBuf.high) is equivalent to hashIgnoreStyle(myBuf).
Example:
var a = "ABracada_b_r_a" doAssert hashIgnoreStyle(a, 0, 3) == hashIgnoreStyle(a, 7, a.high)
Source Edit proc hashIgnoreStyle(x: string): Hash {....raises: [], tags: [].}
-
Efficient hashing of strings; style is ignored.
Note: This uses a different hashing algorithm than hash(string).
See also:
Example:
doAssert hashIgnoreStyle("aBr_aCa_dAB_ra") == hashIgnoreStyle("abracadabra") doAssert hashIgnoreStyle("abcdefghi") != hash("abcdefghi")
Source Edit proc hashWangYi1(x: int64 | uint64 | Hash): Hash {.inline.}
-
Wang Yi's hash_v1 for 64-bit ints (see https://github.com/rurban/smhasher for more details). This passed all scrambling tests in Spring 2019 and is simple.
Note: It's ok to define proc(x: int16): Hash = hashWangYi1(Hash(x)).
Source Edit