std/lists: Various changes to lists (RFC #303) (#16536)

* Various changes to `lists` (RFC #303)

* Removing a non-element is no-op; better tests

* Remove preserves cycles; add appendMove alias; tests.

* Return value for (singly linked) `lists.remove`

* More test for lists.remove

* Moved `lists.append` to the end of the file to see all `add` definitions

* Disable testing js for now

* Use workaround for swap js bug

* Smaller diff

* Undo "silent" deprecation of append

* Correct typo in changelog

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>

* Remove `appendMoved`

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>

* Don't remove appendMoved

Co-authored-by: Clyybber <darkmine956@gmail.com>
Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
This commit is contained in:
Peter Salvi 2021-02-08 22:24:16 +01:00 • committed by GitHub
commit e211a2a9f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 349 additions and 161 deletions

View file

@ -111,6 +111,9 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
- Added `math.signbit`. - Added `math.signbit`.
- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably)
- In `lists`: renamed `append` to `add` and retained `append` as an alias;
added `prepend` and `prependMoved` analogously to `add` and `addMoved`;
added `remove` for `SinglyLinkedList`s.
- Added optional `options` argument to `copyFile`, `copyFileToDir`, and - Added optional `options` argument to `copyFile`, `copyFileToDir`, and

View file

@ -22,50 +22,43 @@
## ##
## Lists ## Lists
## ----- ## -----
## runnableExamples:
## .. code-block:: var
## import lists l = initDoublyLinkedList[int]()
## a = newDoublyLinkedNode[int](3)
## var b = newDoublyLinkedNode[int](7)
## l = initDoublyLinkedList[int]() c = newDoublyLinkedNode[int](9)
## a = newDoublyLinkedNode[int](3)
## b = newDoublyLinkedNode[int](7) l.add(a)
## c = newDoublyLinkedNode[int](9) l.add(b)
## l.prepend(c)
## l.append(a)
## l.append(b) assert a.next == b
## l.prepend(c) assert a.prev == c
## assert c.next == a
## assert a.next == b assert c.next.next == b
## assert a.prev == c assert c.prev == nil
## assert c.next == a assert b.next == nil
## assert c.next.next == b
## assert c.prev == nil
## assert b.next == nil
##
##
## Rings ## Rings
## ----- ## -----
## runnableExamples:
## .. code-block:: var
## import lists l = initSinglyLinkedRing[int]()
## a = newSinglyLinkedNode[int](3)
## var b = newSinglyLinkedNode[int](7)
## l = initSinglyLinkedRing[int]() c = newSinglyLinkedNode[int](9)
## a = newSinglyLinkedNode[int](3)
## b = newSinglyLinkedNode[int](7) l.add(a)
## c = newSinglyLinkedNode[int](9) l.add(b)
## l.prepend(c)
## l.append(a)
## l.append(b) assert c.next == a
## l.prepend(c) assert a.next == b
## assert c.next.next == b
## assert c.next == a assert b.next == c
## assert a.next == b assert c.next.next.next == c
## assert c.next.next == b
## assert b.next == c
## assert c.next.next.next == c
##
## See also ## See also
## ======== ## ========
## ##
@ -187,7 +180,7 @@ func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (
assert a.toSeq == [1, 2, 3, 4, 5] assert a.toSeq == [1, 2, 3, 4, 5]
result = initSinglyLinkedList[T]() result = initSinglyLinkedList[T]()
for elem in elems.items: for elem in elems.items:
result.append(elem) result.add(elem)
func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} =
## Creates a new `DoublyLinkedList` from members of `elems`. ## Creates a new `DoublyLinkedList` from members of `elems`.
@ -197,7 +190,7 @@ func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (
assert a.toSeq == [1, 2, 3, 4, 5] assert a.toSeq == [1, 2, 3, 4, 5]
result = initDoublyLinkedList[T]() result = initDoublyLinkedList[T]()
for elem in elems.items: for elem in elems.items:
result.append(elem) result.add(elem)
template itemsListImpl() {.dirty.} = template itemsListImpl() {.dirty.} =
var it = L.head var it = L.head
@ -219,20 +212,13 @@ iterator items*[T](L: SomeLinkedList[T]): T =
## See also: ## See also:
## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_ ## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_
## * `nodes iterator <#nodes.i,SomeLinkedList[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedList[T]>`_
## runnableExamples:
## **Examples:** from std/sugar import collect
## from std/sequtils import toSeq
## .. code-block:: let a = collect(initSinglyLinkedList):
## var a = initSinglyLinkedList[int]() for i in 1..3: 10*i
## for i in 1 .. 3: doAssert toSeq(items(a)) == toSeq(a)
## a.append(10*i) doAssert toSeq(a) == @[10, 20, 30]
##
## for x in a: # the same as: for x in items(a):
## echo x
##
## # 10
## # 20
## # 30
itemsListImpl() itemsListImpl()
iterator items*[T](L: SomeLinkedRing[T]): T = iterator items*[T](L: SomeLinkedRing[T]): T =
@ -241,20 +227,13 @@ iterator items*[T](L: SomeLinkedRing[T]): T =
## See also: ## See also:
## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_ ## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_
## * `nodes iterator <#nodes.i,SomeLinkedRing[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedRing[T]>`_
## runnableExamples:
## **Examples:** from std/sugar import collect
## from std/sequtils import toSeq
## .. code-block:: let a = collect(initSinglyLinkedRing):
## var a = initSinglyLinkedRing[int]() for i in 1..3: 10*i
## for i in 1 .. 3: doAssert toSeq(items(a)) == toSeq(a)
## a.append(10*i) doAssert toSeq(a) == @[10, 20, 30]
##
## for x in a: # the same as: for x in items(a):
## echo x
##
## # 10
## # 20
## # 30
itemsRingImpl() itemsRingImpl()
iterator mitems*[T](L: var SomeLinkedList[T]): var T = iterator mitems*[T](L: var SomeLinkedList[T]): var T =
@ -266,7 +245,7 @@ iterator mitems*[T](L: var SomeLinkedList[T]): var T =
runnableExamples: runnableExamples:
var a = initSinglyLinkedList[int]() var a = initSinglyLinkedList[int]()
for i in 1 .. 5: for i in 1 .. 5:
a.append(10*i) a.add(10*i)
assert $a == "[10, 20, 30, 40, 50]" assert $a == "[10, 20, 30, 40, 50]"
for x in mitems(a): for x in mitems(a):
x = 5*x - 1 x = 5*x - 1
@ -282,7 +261,7 @@ iterator mitems*[T](L: var SomeLinkedRing[T]): var T =
runnableExamples: runnableExamples:
var a = initSinglyLinkedRing[int]() var a = initSinglyLinkedRing[int]()
for i in 1 .. 5: for i in 1 .. 5:
a.append(10*i) a.add(10*i)
assert $a == "[10, 20, 30, 40, 50]" assert $a == "[10, 20, 30, 40, 50]"
for x in mitems(a): for x in mitems(a):
x = 5*x - 1 x = 5*x - 1
@ -299,7 +278,7 @@ iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] =
runnableExamples: runnableExamples:
var a = initDoublyLinkedList[int]() var a = initDoublyLinkedList[int]()
for i in 1 .. 5: for i in 1 .. 5:
a.append(10*i) a.add(10*i)
assert $a == "[10, 20, 30, 40, 50]" assert $a == "[10, 20, 30, 40, 50]"
for x in nodes(a): for x in nodes(a):
if x.value == 30: if x.value == 30:
@ -324,7 +303,7 @@ iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] =
runnableExamples: runnableExamples:
var a = initDoublyLinkedRing[int]() var a = initDoublyLinkedRing[int]()
for i in 1 .. 5: for i in 1 .. 5:
a.append(10*i) a.add(10*i)
assert $a == "[10, 20, 30, 40, 50]" assert $a == "[10, 20, 30, 40, 50]"
for x in nodes(a): for x in nodes(a):
if x.value == 30: if x.value == 30:
@ -357,8 +336,8 @@ proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] =
## * `contains proc <#contains,SomeLinkedCollection[T],T>`_ ## * `contains proc <#contains,SomeLinkedCollection[T],T>`_
runnableExamples: runnableExamples:
var a = initSinglyLinkedList[int]() var a = initSinglyLinkedList[int]()
a.append(9) a.add(9)
a.append(8) a.add(8)
assert a.find(9).value == 9 assert a.find(9).value == 9
assert a.find(1) == nil assert a.find(1) == nil
@ -373,8 +352,8 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} =
## * `find proc <#find,SomeLinkedCollection[T],T>`_ ## * `find proc <#find,SomeLinkedCollection[T],T>`_
runnableExamples: runnableExamples:
var a = initSinglyLinkedList[int]() var a = initSinglyLinkedList[int]()
a.append(9) a.add(9)
a.append(8) a.add(8)
assert a.contains(9) assert a.contains(9)
assert 8 in a assert 8 in a
assert(not a.contains(1)) assert(not a.contains(1))
@ -382,12 +361,60 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} =
result = find(L, value) != nil result = find(L, value) != nil
proc append*[T](L: var SinglyLinkedList[T], proc prepend*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} =
n: SinglyLinkedNode[T]) {.inline.} = ## Prepends a shallow copy of `b` to the beginning of `a`.
##
## See also:
## * `prependMoved proc <#prependMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_
## * `prependMoved proc <#prependMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_
## for moving the second list instead of copying
runnableExamples:
import sequtils
var a = [4, 5].toSinglyLinkedList
let b = [1, 2, 3].toSinglyLinkedList
a.prepend b
assert a.toSeq == [1, 2, 3, 4, 5]
assert b.toSeq == [1, 2, 3]
a.prepend a
assert a.toSeq == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
var tmp = b.copy
tmp.addMoved a
a = tmp
proc prependMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} =
## Moves `b` before the head of `a`. Efficiency: O(1).
## Note that `b` becomes empty after the operation unless it has the same address as `a`.
## Self-prepending results in a cycle.
##
## See also:
## * `prepend proc <#prepend,T,T>`_
## for prepending a copy of a list
runnableExamples:
import std/[sequtils, enumerate, sugar]
var
a = [4, 5].toSinglyLinkedList
b = [1, 2, 3].toSinglyLinkedList
c = [0, 1].toSinglyLinkedList
a.prependMoved b
assert a.toSeq == [1, 2, 3, 4, 5]
assert b.toSeq == []
c.prependMoved c
let s = collect:
for i, ci in enumerate(c):
if i == 6: break
ci
assert s == [0, 1, 0, 1, 0, 1]
b.addMoved a
when defined(js): # XXX: swap broken in js; bug #16771
(b, a) = (a, b)
else: swap a, b
proc add*[T](L: var SinglyLinkedList[T],
n: SinglyLinkedNode[T]) {.inline.} =
## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value
## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value
@ -395,7 +422,7 @@ proc append*[T](L: var SinglyLinkedList[T],
var var
a = initSinglyLinkedList[int]() a = initSinglyLinkedList[int]()
n = newSinglyLinkedNode[int](9) n = newSinglyLinkedNode[int](9)
a.append(n) a.add(n)
assert a.contains(9) assert a.contains(9)
n.next = nil n.next = nil
@ -405,29 +432,29 @@ proc append*[T](L: var SinglyLinkedList[T],
L.tail = n L.tail = n
if L.head == nil: L.head = n if L.head == nil: L.head = n
proc append*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = proc add*[T](L: var SinglyLinkedList[T], value: T) {.inline.} =
## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## Appends (adds to the end) a value to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value
## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value
runnableExamples: runnableExamples:
var a = initSinglyLinkedList[int]() var a = initSinglyLinkedList[int]()
a.append(9) a.add(9)
a.append(8) a.add(8)
assert a.contains(9) assert a.contains(9)
append(L, newSinglyLinkedNode(value)) add(L, newSinglyLinkedNode(value))
proc prepend*[T](L: var SinglyLinkedList[T], proc prepend*[T](L: var SinglyLinkedList[T],
n: SinglyLinkedNode[T]) {.inline.} = n: SinglyLinkedNode[T]) {.inline.} =
## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value
## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value
runnableExamples: runnableExamples:
var var
@ -444,9 +471,9 @@ proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} =
## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value
## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
runnableExamples: runnableExamples:
@ -477,7 +504,7 @@ func copy*[T](a: SinglyLinkedList[T]): SinglyLinkedList[T] {.since: (1, 5, 1).}
assert $c == $c.copy assert $c == $c.copy
result = initSinglyLinkedList[T]() result = initSinglyLinkedList[T]()
for x in a.items: for x in a.items:
result.append(x) result.add(x)
proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} =
## Moves `b` to the end of `a`. Efficiency: O(1). ## Moves `b` to the end of `a`. Efficiency: O(1).
@ -488,7 +515,7 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} =
## * `add proc <#add,T,T>`_ ## * `add proc <#add,T,T>`_
## for adding a copy of a list ## for adding a copy of a list
runnableExamples: runnableExamples:
import sequtils, std/enumerate, std/sugar import std/[sequtils, enumerate, sugar]
var var
a = [1, 2, 3].toSinglyLinkedList a = [1, 2, 3].toSinglyLinkedList
b = [4, 5].toSinglyLinkedList b = [4, 5].toSinglyLinkedList
@ -511,11 +538,11 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} =
b.head = nil b.head = nil
b.tail = nil b.tail = nil
proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = proc add*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value ## * `add proc <#add,DoublyLinkedList[T],T>`_ for appending a value
## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value ## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value
@ -525,7 +552,7 @@ proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
var var
a = initDoublyLinkedList[int]() a = initDoublyLinkedList[int]()
n = newDoublyLinkedNode[int](9) n = newDoublyLinkedNode[int](9)
a.append(n) a.add(n)
assert a.contains(9) assert a.contains(9)
n.next = nil n.next = nil
@ -536,11 +563,11 @@ proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
L.tail = n L.tail = n
if L.head == nil: L.head = n if L.head == nil: L.head = n
proc append*[T](L: var DoublyLinkedList[T], value: T) = proc add*[T](L: var DoublyLinkedList[T], value: T) =
## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## Appends (adds to the end) a value to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
@ -549,18 +576,18 @@ proc append*[T](L: var DoublyLinkedList[T], value: T) =
## for removing a node ## for removing a node
runnableExamples: runnableExamples:
var a = initDoublyLinkedList[int]() var a = initDoublyLinkedList[int]()
a.append(9) a.add(9)
a.append(8) a.add(8)
assert a.contains(9) assert a.contains(9)
append(L, newDoublyLinkedNode(value)) add(L, newDoublyLinkedNode(value))
proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value ## * `add proc <#add,DoublyLinkedList[T],T>`_ for appending a value
## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value ## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value
## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
## for removing a node ## for removing a node
@ -583,9 +610,9 @@ proc prepend*[T](L: var DoublyLinkedList[T], value: T) =
## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value ## * `add proc <#add,DoublyLinkedList[T],T>`_ for appending a value
## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
@ -614,7 +641,7 @@ func copy*[T](a: DoublyLinkedList[T]): DoublyLinkedList[T] {.since: (1, 5, 1).}
assert $c == $c.copy assert $c == $c.copy
result = initDoublyLinkedList[T]() result = initDoublyLinkedList[T]()
for x in a.items: for x in a.items:
result.append(x) result.add(x)
proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} = proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} =
## Moves `b` to the end of `a`. Efficiency: O(1). ## Moves `b` to the end of `a`. Efficiency: O(1).
@ -625,7 +652,7 @@ proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} =
## * `add proc <#add,T,T>`_ ## * `add proc <#add,T,T>`_
## for adding a copy of a list ## for adding a copy of a list
runnableExamples: runnableExamples:
import sequtils, std/enumerate, std/sugar import std/[sequtils, enumerate, sugar]
var var
a = [1, 2, 3].toDoublyLinkedList a = [1, 2, 3].toDoublyLinkedList
b = [4, 5].toDoublyLinkedList b = [4, 5].toDoublyLinkedList
@ -669,16 +696,63 @@ proc add*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} =
var tmp = b.copy var tmp = b.copy
a.addMoved tmp a.addMoved tmp
proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.discardable.} =
## Removes a node `n` from `L`.
## Returns `true` if `n` was found in `L`.
## Efficiency: O(n); the list is traversed until `n` is found.
## Attempting to remove an element not contained in the list is a no-op.
## When the list is cyclic, the cycle is preserved after removal.
runnableExamples:
import std/[sequtils, enumerate, sugar]
var a = [0, 1, 2].toSinglyLinkedList
let n = a.head.next
doAssert n.value == 1
doAssert a.remove(n) == true
doAssert a.toSeq == [0, 2]
doAssert a.remove(n) == false
doAssert a.toSeq == [0, 2]
a.addMoved a # cycle: [0, 2, 0, 2, ...]
a.remove a.head
let s = collect:
for i, ai in enumerate(a):
if i == 4: break
ai
doAssert s == [2, 2, 2, 2]
if n == L.head:
L.head = n.next
if L.tail.next == n:
L.tail.next = L.head # restore cycle
else:
var prev = L.head
while prev.next != n and prev.next != nil:
prev = prev.next
if prev.next == nil:
return false
prev.next = n.next
true
proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
## Removes a node `n` from `L`. Efficiency: O(1). ## Removes a node `n` from `L`. Efficiency: O(1).
## This function assumes, for the sake of efficiency, that `n` is contained in `L`,
## otherwise the effects are undefined.
## When the list is cyclic, the cycle is preserved after removal.
runnableExamples: runnableExamples:
var import std/[sequtils, enumerate, sugar]
a = initDoublyLinkedList[int]() var a = [0, 1, 2].toSinglyLinkedList
n = newDoublyLinkedNode[int](5) let n = a.head.next
a.append(n) doAssert n.value == 1
assert 5 in a a.remove n
a.remove(n) doAssert a.toSeq == [0, 2]
assert 5 notin a a.remove n
doAssert a.toSeq == [0, 2]
a.addMoved a # cycle: [0, 2, 0, 2, ...]
a.remove a.head
let s = collect:
for i, ai in enumerate(a):
if i == 4: break
ai
doAssert s == [2, 2, 2, 2]
if n == L.tail: L.tail = n.prev if n == L.tail: L.tail = n.prev
if n == L.head: L.head = n.next if n == L.head: L.head = n.next
@ -687,11 +761,11 @@ proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = proc add*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value
## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value
@ -699,7 +773,7 @@ proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
var var
a = initSinglyLinkedRing[int]() a = initSinglyLinkedRing[int]()
n = newSinglyLinkedNode[int](9) n = newSinglyLinkedNode[int](9)
a.append(n) a.add(n)
assert a.contains(9) assert a.contains(9)
if L.head != nil: if L.head != nil:
@ -712,29 +786,29 @@ proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
L.head = n L.head = n
L.tail = n L.tail = n
proc append*[T](L: var SinglyLinkedRing[T], value: T) = proc add*[T](L: var SinglyLinkedRing[T], value: T) =
## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## Appends (adds to the end) a value to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value
runnableExamples: runnableExamples:
var a = initSinglyLinkedRing[int]() var a = initSinglyLinkedRing[int]()
a.append(9) a.add(9)
a.append(8) a.add(8)
assert a.contains(9) assert a.contains(9)
append(L, newSinglyLinkedNode(value)) add(L, newSinglyLinkedNode(value))
proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value
## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value
runnableExamples: runnableExamples:
var var
@ -756,9 +830,9 @@ proc prepend*[T](L: var SinglyLinkedRing[T], value: T) =
## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value
## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
runnableExamples: runnableExamples:
@ -770,11 +844,11 @@ proc prepend*[T](L: var SinglyLinkedRing[T], value: T) =
proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = proc add*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value ## * `add proc <#add,DoublyLinkedRing[T],T>`_ for appending a value
## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value ## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value
@ -784,7 +858,7 @@ proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
var var
a = initDoublyLinkedRing[int]() a = initDoublyLinkedRing[int]()
n = newDoublyLinkedNode[int](9) n = newDoublyLinkedNode[int](9)
a.append(n) a.add(n)
assert a.contains(9) assert a.contains(9)
if L.head != nil: if L.head != nil:
@ -797,11 +871,11 @@ proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
n.next = n n.next = n
L.head = n L.head = n
proc append*[T](L: var DoublyLinkedRing[T], value: T) = proc add*[T](L: var DoublyLinkedRing[T], value: T) =
## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## Appends (adds to the end) a value to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
@ -810,18 +884,18 @@ proc append*[T](L: var DoublyLinkedRing[T], value: T) =
## for removing a node ## for removing a node
runnableExamples: runnableExamples:
var a = initDoublyLinkedRing[int]() var a = initDoublyLinkedRing[int]()
a.append(9) a.add(9)
a.append(8) a.add(8)
assert a.contains(9) assert a.contains(9)
append(L, newDoublyLinkedNode(value)) add(L, newDoublyLinkedNode(value))
proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value ## * `add proc <#add,DoublyLinkedRing[T],T>`_ for appending a value
## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value ## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value
## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
## for removing a node ## for removing a node
@ -846,9 +920,9 @@ proc prepend*[T](L: var DoublyLinkedRing[T], value: T) =
## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1).
## ##
## See also: ## See also:
## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
## for appending a node ## for appending a node
## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value ## * `add proc <#add,DoublyLinkedRing[T],T>`_ for appending a value
## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
## for prepending a node ## for prepending a node
## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_
@ -866,7 +940,7 @@ proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
var var
a = initDoublyLinkedRing[int]() a = initDoublyLinkedRing[int]()
n = newDoublyLinkedNode[int](5) n = newDoublyLinkedNode[int](5)
a.append(n) a.add(n)
assert 5 in a assert 5 in a
a.remove(n) a.remove(n)
assert 5 notin a assert 5 notin a
@ -880,3 +954,31 @@ proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) =
L.head = nil L.head = nil
else: else:
L.head = L.head.prev L.head = L.head.prev
proc append*[T](a: var (SinglyLinkedList[T] | SinglyLinkedRing[T]),
b: SinglyLinkedList[T] | SinglyLinkedNode[T] | T) =
## Alias for `a.add(b)`.
##
## See also:
## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_
## * `add proc <#add,SinglyLinkedList[T],T>`_
## * `add proc <#add,T,T>`_
a.add b
proc append*[T](a: var (DoublyLinkedList[T] | DoublyLinkedRing[T]),
b: DoublyLinkedList[T] | DoublyLinkedNode[T] | T) =
## Alias for `a.add(b)`.
##
## See also:
## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_
## * `add proc <#add,DoublyLinkedList[T],T>`_
## * `add proc <#add,T,T>`_
a.add b
proc appendMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} =
## Alias for `a.addMoved(b)`.
##
## See also:
## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_
## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_
a.addMoved b

View file

@ -2,7 +2,7 @@ discard """
targets: "c js" targets: "c js"
""" """
import lists, sequtils, std/enumerate, std/sugar import lists, sequtils
const const
data = [1, 2, 3, 4, 5, 6] data = [1, 2, 3, 4, 5, 6]
@ -10,7 +10,7 @@ const
block SinglyLinkedListTest1: block SinglyLinkedListTest1:
var L: SinglyLinkedList[int] var L: SinglyLinkedList[int]
for d in items(data): L.prepend(d) for d in items(data): L.prepend(d)
for d in items(data): L.append(d) for d in items(data): L.add(d)
doAssert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]") doAssert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]")
doAssert(4 in L) doAssert(4 in L)
@ -26,7 +26,7 @@ block SinglyLinkedListTest2:
block DoublyLinkedListTest1: block DoublyLinkedListTest1:
var L: DoublyLinkedList[int] var L: DoublyLinkedList[int]
for d in items(data): L.prepend(d) for d in items(data): L.prepend(d)
for d in items(data): L.append(d) for d in items(data): L.add(d)
L.remove(L.find(1)) L.remove(L.find(1))
doAssert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]") doAssert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]")
@ -51,8 +51,8 @@ block DoublyLinkedRingTest1:
doAssert($L == "[4, 4]") doAssert($L == "[4, 4]")
doAssert(4 in L) doAssert(4 in L)
L.append(3) L.add(3)
L.append(5) L.add(5)
doAssert($L == "[4, 4, 3, 5]") doAssert($L == "[4, 4, 3, 5]")
L.remove(L.find(3)) L.remove(L.find(3))
@ -65,23 +65,35 @@ block DoublyLinkedRingTest1:
block tlistsToString: block tlistsToString:
block: block:
var l = initDoublyLinkedList[int]() var l = initDoublyLinkedList[int]()
l.append(1) l.add(1)
l.append(2) l.add(2)
l.append(3) l.add(3)
doAssert $l == "[1, 2, 3]" doAssert $l == "[1, 2, 3]"
block: block:
var l = initDoublyLinkedList[string]() var l = initDoublyLinkedList[string]()
l.append("1") l.add("1")
l.append("2") l.add("2")
l.append("3") l.add("3")
doAssert $l == """["1", "2", "3"]""" doAssert $l == """["1", "2", "3"]"""
block: block:
var l = initDoublyLinkedList[char]() var l = initDoublyLinkedList[char]()
l.append('1') l.add('1')
l.append('2') l.add('2')
l.append('3') l.add('3')
doAssert $l == """['1', '2', '3']""" doAssert $l == """['1', '2', '3']"""
# Copied here until it is merged into sequtils
template take(a: untyped, max: int): untyped =
type T = typeof(block: (for ai in a: ai))
var ret: seq[T]
var i = 0
if max > 0:
for ai in a:
ret.add ai
i.inc
if i >= max: break
ret
template testCommon(initList, toList) = template testCommon(initList, toList) =
block: # toSinglyLinkedList, toDoublyLinkedList block: # toSinglyLinkedList, toDoublyLinkedList
@ -101,7 +113,7 @@ template testCommon(initList, toList) =
let f1 = Foo(x: 1) let f1 = Foo(x: 1)
var a = [f0].toList var a = [f0].toList
var b = a.copy var b = a.copy
b.append f1 b.add f1
doAssert a.toSeq == [f0] doAssert a.toSeq == [f0]
doAssert b.toSeq == [f0, f1] doAssert b.toSeq == [f0, f1]
f0.x = 42 f0.x = 42
@ -140,11 +152,82 @@ template testCommon(initList, toList) =
block: block:
var c = [0, 1].toList var c = [0, 1].toList
c.addMoved c c.addMoved c
let s = collect: doAssert c.take(6) == [0, 1, 0, 1, 0, 1]
for i, ci in enumerate(c):
if i == 6: break block: # prepend, prependMoved
ci block:
doAssert s == [0, 1, 0, 1, 0, 1] var
l0 = initList[int]()
l1 = [1].toList
l2 = [2, 3].toList
l3 = [4, 5, 6].toList
l0.prepend l3
l1.prepend l3
doAssert l3.toSeq == [4, 5, 6]
l2.prependMoved l3
doAssert l0.toSeq == [4, 5, 6]
doAssert l1.toSeq == [4, 5, 6, 1]
doAssert l2.toSeq == [4, 5, 6, 2, 3]
doAssert l3.toSeq == []
l2.prepend l3 # re-prepending l3 that was destroyed is now a no-op
doAssert l2.toSeq == [4, 5, 6, 2, 3]
doAssert l3.toSeq == []
block:
var
l0 = initList[int]()
l1 = [1].toList
l2 = [2, 3].toList
l3 = [4, 5, 6].toList
l3.prependMoved l0
l2.prependMoved l1
doAssert l3.toSeq == [4, 5, 6]
doAssert l2.toSeq == [1, 2, 3]
l3.prepend l0
doAssert l3.toSeq == [4, 5, 6]
block:
var c = [0, 1].toList
c.prependMoved c
doAssert c.take(6) == [0, 1, 0, 1, 0, 1]
block remove:
var l = [0, 1, 2, 3].toList
let
l0 = l.head
l1 = l0.next
l2 = l1.next
l3 = l2.next
l.remove l0
doAssert l.toSeq == [1, 2, 3]
l.remove l2
doAssert l.toSeq == [1, 3]
l.remove l2
doAssert l.toSeq == [1, 3]
l.remove l3
doAssert l.toSeq == [1]
l.remove l1
doAssert l.toSeq == []
# Cycle preservation
var a = [10, 11, 12].toList
a.addMoved a
doAssert a.take(6) == @[10, 11, 12, 10, 11, 12]
a.remove a.head.next
doAssert a.take(6) == @[10, 12, 10, 12, 10, 12]
a.remove a.head
doAssert a.take(6) == @[12, 12, 12, 12, 12, 12]
testCommon initSinglyLinkedList, toSinglyLinkedList testCommon initSinglyLinkedList, toSinglyLinkedList
testCommon initDoublyLinkedList, toDoublyLinkedList testCommon initDoublyLinkedList, toDoublyLinkedList
block remove: # return value check
var l = [0, 1, 2, 3].toSinglyLinkedList
let n = l.head.next.next
doAssert l.remove(n) == true
doAssert l.toSeq == [0, 1, 3]
doAssert l.remove(n) == false
doAssert l.toSeq == [0, 1, 3]
doAssert l.remove(l.head) == true
doAssert l.toSeq == [1, 3]
doAssert l.remove(l.head.next) == true
doAssert l.toSeq == [1]
doAssert l.remove(l.head) == true
doAssert l.toSeq == []