hashes: support object default hash (#17175)

This commit is contained in:
Timothee Cour 2021-02-25 23:45:37 -08:00 • committed by GitHub
commit 63f1c38f4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 18 deletions

View file

@ -173,14 +173,16 @@ provided by the operating system.
dumping (on select signals) and notifying the parent process about the cause dumping (on select signals) and notifying the parent process about the cause
of termination. of termination.
- Added `strip` and `setSlice` to `std/strbasics`. - `hashes.hash` now supports `object`, but can be overloaded.
- Added `strip` and `setSlice` to `std/strbasics`.
- Added to `wrapnils` an option-like API via `??.`, `isSome`, `get`. - Added to `wrapnils` an option-like API via `??.`, `isSome`, `get`.
- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` - `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"`
and `$none(int)` to `"none(int)"` instead of `"None[int]"`. and `$none(int)` to `"none(int)"` instead of `"None[int]"`.
## Language changes ## Language changes
- `nimscript` now handles `except Exception as e`. - `nimscript` now handles `except Exception as e`.

View file

@ -54,20 +54,6 @@ runnableExamples:
## **Note:** If the type has a `==` operator, the following must hold: ## **Note:** If the type has a `==` operator, the following must hold:
## If two values compare equal, their hashes must also be equal. ## If two values compare equal, their hashes must also be equal.
## ##
## You can hash an object by all of its fields with the `fields` iterator:
runnableExamples:
proc hash(x: object): Hash =
for f in fields(x):
result = result !& hash(f)
result = !$result
type
Obj = object
x: int
y: string
doAssert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2"))
## See also ## See also
## ======== ## ========
## * `md5 module <md5.html>`_ for the MD5 checksum algorithm ## * `md5 module <md5.html>`_ for the MD5 checksum algorithm
@ -499,14 +485,24 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
result = !$h result = !$h
proc hash*[T: tuple](x: T): Hash = proc hash*[T: tuple | object](x: T): Hash =
## Efficient hashing of tuples. ## Efficient hashing of tuples and objects.
## There must be a `hash` proc defined for each of the field types. ## There must be a `hash` proc defined for each of the field types.
runnableExamples:
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"))
for f in fields(x): for f in fields(x):
result = result !& hash(f) result = result !& hash(f)
result = !$result result = !$result
proc hash*[A](x: openArray[A]): Hash = proc hash*[A](x: openArray[A]): Hash =
## Efficient hashing of arrays and sequences. ## Efficient hashing of arrays and sequences.
## There must be a `hash` proc defined for the element type `A`. ## There must be a `hash` proc defined for the element type `A`.

View file

@ -130,5 +130,51 @@ proc main() =
# run at CT, expecting c semantics. # run at CT, expecting c semantics.
discard discard
block: # hash(object)
type
Obj = object
x: int
y: string
Obj2[T] = object
x: int
y: string
Obj3 = object
x: int
y: string
Obj4 = object
case t: bool
of false:
x: int
of true:
y: int
z: int
Obj5 = object
case t: bool
of false:
x: int
of true:
y: int
z: int
proc hash(a: Obj2): Hash = hash(a.x)
proc hash(a: Obj3): Hash = hash((a.x,))
proc hash(a: Obj5): Hash =
case a.t
of false: hash(a.x)
of true: hash(a.y)
doAssert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2"))
doAssert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2"))
doAssert hash(Obj2[float](x: 520, y: "Nim")) != hash(Obj2[float](x: 521, y: "Nim2"))
doAssert hash(Obj3(x: 520, y: "Nim")) == hash(Obj3(x: 520, y: "Nim2"))
doAssert hash(Obj4(t: false, x: 1)) == hash(Obj4(t: false, x: 1))
doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: false, x: 2))
doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: true, y: 1))
doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: false, x: 2))
doAssert hash(Obj5(t: false, x: 1)) == hash(Obj5(t: true, y: 1))
doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: true, y: 2))
static: main() static: main()
main() main()