Skip to content

Commit

Permalink
Add proc find to heapqueue (#14628)
Browse files Browse the repository at this point in the history
* 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
#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:
  #13393
  #13418
  #13440
  #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.
  • Loading branch information
c-blake authored Jun 10, 2020
1 parent 8bbdb8f commit 6aa971d
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 4 deletions.
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
17 changes: 13 additions & 4 deletions lib/pure/collections/heapqueue.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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]
Expand Down

0 comments on commit 6aa971d

Please sign in to comment.