From 6aa971d39f1339a27a953972cd329f9cbe791f98 Mon Sep 17 00:00:00 2001 From: c-blake Date: Wed, 10 Jun 2020 14:53:18 -0400 Subject: [PATCH] Add `proc find` to `heapqueue` (#14628) * Unwind just the "pseudorandom probing" (whole hash-code-keyed variable stride double hashing) part of recent sets & tables changes (which has still been causing bugs over a month later (e.g., two days ago https://github.com/nim-lang/Nim/issues/13794) as well as still having several "figure this out" implementation question comments in them (see just diffs of this PR). This topic has been discussed in many places: https://github.com/nim-lang/Nim/issues/13393 https://github.com/nim-lang/Nim/pull/13418 https://github.com/nim-lang/Nim/pull/13440 https://github.com/nim-lang/Nim/issues/13794 Alternative/non-mandatory stronger integer hashes (or vice-versa opt-in identity hashes) are a better solution that is more general (no illusion of one hard-coded sequence solving all problems) while retaining the virtues of linear probing such as cache obliviousness and age-less tables under delete-heavy workloads (still untested after a month of this change). The only real solution for truly adversarial keys is a hash keyed off of data unobservable to attackers. That all fits better with a few families of user-pluggable/define-switchable hashes which can be provided in a separate PR more about `hashes.nim`. This PR carefully preserves the better (but still hard coded!) probing of the `intsets` and other recent fixes like `move` annotations, hash order invariant tests, `intsets.missingOrExcl` fixing, and the move of `rightSize` into `hashcommon.nim`. * Fix `data.len` -> `dataLen` problem. * Add neglected API call `find` to heapqueue. * Add a changelog.md entry, `since` annotation and rename parameter to be `heap` like all the other procs for consistency. * Add missing import. --- changelog.md | 2 ++ lib/pure/collections/heapqueue.nim | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 8e06d30f196e..e86e42b339c6 100644 --- a/changelog.md +++ b/changelog.md @@ -110,6 +110,8 @@ - new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` for json serialization/deserialization of custom types. +- new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``. + ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index f958a5b0accb..b0789593ad51 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -50,6 +50,7 @@ assert jobs[0].priority == 1 ]## +import std/private/since type HeapQueue*[T] = object ## A heap queue, commonly known as a priority queue. @@ -125,6 +126,12 @@ proc pop*[T](heap: var HeapQueue[T]): T = else: result = lastelt +proc find*[T](heap: HeapQueue[T], x: T): int {.since: (1, 3).} = + ## Linear scan to find index of item ``x`` or -1 if not found. + result = -1 + for i in 0 ..< heap.len: + if heap[i] == x: return i + proc del*[T](heap: var HeapQueue[T], index: Natural) = ## Removes the element at `index` from `heap`, maintaining the heap invariant. swap(heap.data[^1], heap.data[index]) @@ -207,18 +214,20 @@ when isMainModule: heap.del(0) doAssert(heap[0] == 1) - heap.del(heap.data.find(7)) + heap.del(heap.find(7)) doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) - heap.del(heap.data.find(5)) + heap.del(heap.find(5)) doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) - heap.del(heap.data.find(6)) + heap.del(heap.find(6)) doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) - heap.del(heap.data.find(2)) + heap.del(heap.find(2)) doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9]) + doAssert(heap.find(2) == -1) + block: # Test del last var heap = initHeapQueue[int]() let data = [1, 2, 3]