From da6e8caa1ddf84275c8d1c81dcb59ec5de02dbef Mon Sep 17 00:00:00 2001 From: Peter Salvi Date: Thu, 31 Dec 2020 22:48:32 +0100 Subject: [PATCH 01/13] Various changes to `lists` (RFC #303) --- changelog.md | 3 + lib/pure/collections/lists.nim | 208 ++++++++++++++++++++++----------- tests/stdlib/tlists.nim | 82 ++++++++++--- 3 files changed, 210 insertions(+), 83 deletions(-) diff --git a/changelog.md b/changelog.md index 8bdbc74169804..050871ee5a180 100644 --- a/changelog.md +++ b/changelog.md @@ -109,6 +109,9 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. - Added `math.signbit`. - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) +- In `lists`: renamed `append` to `add` and added a deprecated `append`; + added `prepend` and `prependMoved` analogously to `add` and `andMoved`; + added `remove` for `SinglyLinkedList`s. ## Language changes diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 8af0ed826d6d9..0582d9e70cb71 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -32,8 +32,8 @@ ## b = newDoublyLinkedNode[int](7) ## c = newDoublyLinkedNode[int](9) ## -## l.append(a) -## l.append(b) +## l.add(a) +## l.add(b) ## l.prepend(c) ## ## assert a.next == b @@ -56,8 +56,8 @@ ## b = newSinglyLinkedNode[int](7) ## c = newSinglyLinkedNode[int](9) ## -## l.append(a) -## l.append(b) +## l.add(a) +## l.add(b) ## l.prepend(c) ## ## assert c.next == a @@ -187,7 +187,7 @@ func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: ( assert a.toSeq == [1, 2, 3, 4, 5] result = initSinglyLinkedList[T]() for elem in elems.items: - result.append(elem) + result.add(elem) func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = ## Creates a new `DoublyLinkedList` from members of `elems`. @@ -197,7 +197,7 @@ func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: ( assert a.toSeq == [1, 2, 3, 4, 5] result = initDoublyLinkedList[T]() for elem in elems.items: - result.append(elem) + result.add(elem) template itemsListImpl() {.dirty.} = var it = L.head @@ -225,7 +225,7 @@ iterator items*[T](L: SomeLinkedList[T]): T = ## .. code-block:: ## var a = initSinglyLinkedList[int]() ## for i in 1 .. 3: - ## a.append(10*i) + ## a.add(10*i) ## ## for x in a: # the same as: for x in items(a): ## echo x @@ -247,7 +247,7 @@ iterator items*[T](L: SomeLinkedRing[T]): T = ## .. code-block:: ## var a = initSinglyLinkedRing[int]() ## for i in 1 .. 3: - ## a.append(10*i) + ## a.add(10*i) ## ## for x in a: # the same as: for x in items(a): ## echo x @@ -266,7 +266,7 @@ iterator mitems*[T](L: var SomeLinkedList[T]): var T = runnableExamples: var a = initSinglyLinkedList[int]() for i in 1 .. 5: - a.append(10*i) + a.add(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in mitems(a): x = 5*x - 1 @@ -282,7 +282,7 @@ iterator mitems*[T](L: var SomeLinkedRing[T]): var T = runnableExamples: var a = initSinglyLinkedRing[int]() for i in 1 .. 5: - a.append(10*i) + a.add(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in mitems(a): x = 5*x - 1 @@ -299,7 +299,7 @@ iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] = runnableExamples: var a = initDoublyLinkedList[int]() for i in 1 .. 5: - a.append(10*i) + a.add(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in nodes(a): if x.value == 30: @@ -324,7 +324,7 @@ iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] = runnableExamples: var a = initDoublyLinkedRing[int]() for i in 1 .. 5: - a.append(10*i) + a.add(10*i) assert $a == "[10, 20, 30, 40, 50]" for x in nodes(a): if x.value == 30: @@ -357,8 +357,8 @@ proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] = ## * `contains proc <#contains,SomeLinkedCollection[T],T>`_ runnableExamples: var a = initSinglyLinkedList[int]() - a.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.find(9).value == 9 assert a.find(1) == nil @@ -373,8 +373,8 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = ## * `find proc <#find,SomeLinkedCollection[T],T>`_ runnableExamples: var a = initSinglyLinkedList[int]() - a.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.contains(9) assert 8 in a assert(not a.contains(1)) @@ -382,12 +382,62 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = result = find(L, value) != nil -proc append*[T](L: var SinglyLinkedList[T], - n: SinglyLinkedNode[T]) {.inline.} = +proc append*[T](L: var SomeLinkedCollection[T], n: SomeLinkedNode[T] | T) + {.deprecated: "Deprecated since v1.6; use `add`".} = + add(L, n) + +proc prepend*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = + ## 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 sequtils, std/enumerate, std/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 + 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). ## ## 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]>`_ ## for prepending a node ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value @@ -395,7 +445,7 @@ proc append*[T](L: var SinglyLinkedList[T], var a = initSinglyLinkedList[int]() n = newSinglyLinkedNode[int](9) - a.append(n) + a.add(n) assert a.contains(9) n.next = nil @@ -405,29 +455,29 @@ proc append*[T](L: var SinglyLinkedList[T], L.tail = 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). ## ## 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]>`_ ## for prepending a node ## * `prepend proc <#prepend,SinglyLinkedList[T],T>`_ for prepending a value runnableExamples: var a = initSinglyLinkedList[int]() - a.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.contains(9) - append(L, newSinglyLinkedNode(value)) + add(L, newSinglyLinkedNode(value)) proc prepend*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). ## ## See also: - ## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ + ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## 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 runnableExamples: var @@ -444,9 +494,9 @@ proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). ## ## See also: - ## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ + ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## 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]>`_ ## for prepending a node runnableExamples: @@ -477,7 +527,7 @@ func copy*[T](a: SinglyLinkedList[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} assert $c == $c.copy result = initSinglyLinkedList[T]() for x in a.items: - result.append(x) + result.add(x) proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = ## Moves `b` to the end of `a`. Efficiency: O(1). @@ -511,11 +561,11 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = b.head = 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). ## ## 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]>`_ ## for prepending a node ## * `prepend proc <#prepend,DoublyLinkedList[T],T>`_ for prepending a value @@ -525,7 +575,7 @@ proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = var a = initDoublyLinkedList[int]() n = newDoublyLinkedNode[int](9) - a.append(n) + a.add(n) assert a.contains(9) n.next = nil @@ -536,11 +586,11 @@ proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = L.tail = 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). ## ## See also: - ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for appending a node ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for prepending a node @@ -549,18 +599,18 @@ proc append*[T](L: var DoublyLinkedList[T], value: T) = ## for removing a node runnableExamples: var a = initDoublyLinkedList[int]() - a.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.contains(9) - append(L, newDoublyLinkedNode(value)) + add(L, newDoublyLinkedNode(value)) proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## ## See also: - ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## 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 ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for removing a node @@ -583,9 +633,9 @@ proc prepend*[T](L: var DoublyLinkedList[T], value: T) = ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## ## See also: - ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## 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]>`_ ## for prepending a node ## * `remove proc <#remove,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ @@ -614,7 +664,7 @@ func copy*[T](a: DoublyLinkedList[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} assert $c == $c.copy result = initDoublyLinkedList[T]() for x in a.items: - result.append(x) + result.add(x) proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} = ## Moves `b` to the end of `a`. Efficiency: O(1). @@ -669,13 +719,33 @@ proc add*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = var tmp = b.copy a.addMoved tmp +proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) = + ## Removes a node `n` from `L`. + ## Efficiency: O(n), unless `n` is the head element. + runnableExamples: + var + a = initSinglyLinkedList[int]() + n = newSinglyLinkedNode[int](5) + a.add(n) + assert 5 in a + a.remove(n) + assert 5 notin a + + if n == L.head: + L.head = n.next + else: + var prev = L.head + while prev.next != n: + prev = prev.next + prev.next = n.next + proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Removes a node `n` from `L`. Efficiency: O(1). runnableExamples: var a = initDoublyLinkedList[int]() n = newDoublyLinkedNode[int](5) - a.append(n) + a.add(n) assert 5 in a a.remove(n) assert 5 notin a @@ -687,11 +757,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). ## ## 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]>`_ ## for prepending a node ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value @@ -699,7 +769,7 @@ proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = var a = initSinglyLinkedRing[int]() n = newSinglyLinkedNode[int](9) - a.append(n) + a.add(n) assert a.contains(9) if L.head != nil: @@ -712,29 +782,29 @@ proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = L.head = 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). ## ## See also: - ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for appending a node ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for prepending a node ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value runnableExamples: var a = initSinglyLinkedRing[int]() - a.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.contains(9) - append(L, newSinglyLinkedNode(value)) + add(L, newSinglyLinkedNode(value)) proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## ## See also: - ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## 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 runnableExamples: var @@ -756,9 +826,9 @@ proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## ## See also: - ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## 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]>`_ ## for prepending a node runnableExamples: @@ -770,11 +840,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). ## ## 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]>`_ ## for prepending a node ## * `prepend proc <#prepend,DoublyLinkedRing[T],T>`_ for prepending a value @@ -784,7 +854,7 @@ proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = var a = initDoublyLinkedRing[int]() n = newDoublyLinkedNode[int](9) - a.append(n) + a.add(n) assert a.contains(9) if L.head != nil: @@ -797,11 +867,11 @@ proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = n.next = 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). ## ## See also: - ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for appending a node ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for prepending a node @@ -810,18 +880,18 @@ proc append*[T](L: var DoublyLinkedRing[T], value: T) = ## for removing a node runnableExamples: var a = initDoublyLinkedRing[int]() - a.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.contains(9) - append(L, newDoublyLinkedNode(value)) + add(L, newDoublyLinkedNode(value)) proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## ## See also: - ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## 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 ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for removing a node @@ -846,9 +916,9 @@ proc prepend*[T](L: var DoublyLinkedRing[T], value: T) = ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## ## See also: - ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## 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]>`_ ## for prepending a node ## * `remove proc <#remove,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ @@ -866,7 +936,7 @@ proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = var a = initDoublyLinkedRing[int]() n = newDoublyLinkedNode[int](5) - a.append(n) + a.add(n) assert 5 in a a.remove(n) assert 5 notin a diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index b5a3d3f7e3a1f..781e58832a4ca 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -10,7 +10,7 @@ const block SinglyLinkedListTest1: var L: SinglyLinkedList[int] 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(4 in L) @@ -26,7 +26,7 @@ block SinglyLinkedListTest2: block DoublyLinkedListTest1: var L: DoublyLinkedList[int] 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)) doAssert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]") @@ -51,8 +51,8 @@ block DoublyLinkedRingTest1: doAssert($L == "[4, 4]") doAssert(4 in L) - L.append(3) - L.append(5) + L.add(3) + L.add(5) doAssert($L == "[4, 4, 3, 5]") L.remove(L.find(3)) @@ -65,21 +65,21 @@ block DoublyLinkedRingTest1: block tlistsToString: block: var l = initDoublyLinkedList[int]() - l.append(1) - l.append(2) - l.append(3) + l.add(1) + l.add(2) + l.add(3) doAssert $l == "[1, 2, 3]" block: var l = initDoublyLinkedList[string]() - l.append("1") - l.append("2") - l.append("3") + l.add("1") + l.add("2") + l.add("3") doAssert $l == """["1", "2", "3"]""" block: var l = initDoublyLinkedList[char]() - l.append('1') - l.append('2') - l.append('3') + l.add('1') + l.add('2') + l.add('3') doAssert $l == """['1', '2', '3']""" template testCommon(initList, toList) = @@ -101,7 +101,7 @@ template testCommon(initList, toList) = let f1 = Foo(x: 1) var a = [f0].toList var b = a.copy - b.append f1 + b.add f1 doAssert a.toSeq == [f0] doAssert b.toSeq == [f0, f1] f0.x = 42 @@ -146,5 +146,59 @@ template testCommon(initList, toList) = ci doAssert s == [0, 1, 0, 1, 0, 1] + block: # prepend, prependMoved + block: + var + l0 = initList[int]() + l1 = [1].toList + l2 = [2, 3].toList + l3 = [4, 5, 6].toList + l0.prepend l3 + l1.prepend l3 + 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 + let s = collect: + for i, ci in enumerate(c): + if i == 6: break + ci + doAssert s == [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 l3 + doAssert l.toSeq == [1] + l.remove l1 + doAssert l.toSeq == [] + testCommon initSinglyLinkedList, toSinglyLinkedList testCommon initDoublyLinkedList, toDoublyLinkedList From ab2ba9a5457306ca9b52689a8236971935d6ae6a Mon Sep 17 00:00:00 2001 From: Peter Salvi Date: Fri, 1 Jan 2021 22:21:22 +0100 Subject: [PATCH 02/13] Removing a non-element is no-op; better tests --- changelog.md | 1 + lib/pure/collections/lists.nim | 82 ++++++++++++++++------------------ tests/stdlib/tlists.nim | 3 ++ 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/changelog.md b/changelog.md index 050871ee5a180..696e58ba81211 100644 --- a/changelog.md +++ b/changelog.md @@ -110,6 +110,7 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) - In `lists`: renamed `append` to `add` and added a deprecated `append`; +- In `lists`: renamed `append` to `add` and retained `append` as an alias; added `prepend` and `prependMoved` analogously to `add` and `andMoved`; added `remove` for `SinglyLinkedList`s. diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 0582d9e70cb71..6838a6aec0f06 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -219,20 +219,13 @@ iterator items*[T](L: SomeLinkedList[T]): T = ## See also: ## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedList[T]>`_ - ## - ## **Examples:** - ## - ## .. code-block:: - ## var a = initSinglyLinkedList[int]() - ## for i in 1 .. 3: - ## a.add(10*i) - ## - ## for x in a: # the same as: for x in items(a): - ## echo x - ## - ## # 10 - ## # 20 - ## # 30 + runnableExamples: + from std/sugar import collect + from std/sequtils import toSeq + let a = collect(initSinglyLinkedList): + for i in 1..3: 10*i + doAssert toSeq(items(a)) == toSeq(a) + doAssert toSeq(a) == @[10, 20, 30] itemsListImpl() iterator items*[T](L: SomeLinkedRing[T]): T = @@ -241,20 +234,13 @@ iterator items*[T](L: SomeLinkedRing[T]): T = ## See also: ## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedRing[T]>`_ - ## - ## **Examples:** - ## - ## .. code-block:: - ## var a = initSinglyLinkedRing[int]() - ## for i in 1 .. 3: - ## a.add(10*i) - ## - ## for x in a: # the same as: for x in items(a): - ## echo x - ## - ## # 10 - ## # 20 - ## # 30 + runnableExamples: + from std/sugar import collect + from std/sequtils import toSeq + let a = collect(initSinglyLinkedRing): + for i in 1..3: 10*i + doAssert toSeq(items(a)) == toSeq(a) + doAssert toSeq(a) == @[10, 20, 30] itemsRingImpl() iterator mitems*[T](L: var SomeLinkedList[T]): var T = @@ -382,9 +368,16 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = result = find(L, value) != nil -proc append*[T](L: var SomeLinkedCollection[T], n: SomeLinkedNode[T] | T) - {.deprecated: "Deprecated since v1.6; use `add`".} = - add(L, n) +proc append*[T](a: var SomeLinkedCollection[T], b: SomeLinkedNode[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,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## * `add proc <#add,DoublyLinkedList[T],T>`_ + ## * `add proc <#add,T,T>`_ + a.add b proc prepend*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = ## Prepends a shallow copy of `b` to the beginning of `a`. @@ -415,7 +408,7 @@ proc prependMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} = ## * `prepend proc <#prepend,T,T>`_ ## for prepending a copy of a list runnableExamples: - import sequtils, std/enumerate, std/sugar + import std/[sequtils, enumerate, sugar] var a = [4, 5].toSinglyLinkedList b = [1, 2, 3].toSinglyLinkedList @@ -538,7 +531,7 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = ## * `add proc <#add,T,T>`_ ## for adding a copy of a list runnableExamples: - import sequtils, std/enumerate, std/sugar + import std/[sequtils, enumerate, sugar] var a = [1, 2, 3].toSinglyLinkedList b = [4, 5].toSinglyLinkedList @@ -675,7 +668,7 @@ proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} = ## * `add proc <#add,T,T>`_ ## for adding a copy of a list runnableExamples: - import sequtils, std/enumerate, std/sugar + import std/[sequtils, enumerate, sugar] var a = [1, 2, 3].toDoublyLinkedList b = [4, 5].toDoublyLinkedList @@ -722,22 +715,25 @@ proc add*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) = ## Removes a node `n` from `L`. ## Efficiency: O(n), unless `n` is the head element. + ## Attempting to remove an element not contained in the list is a no-op. runnableExamples: - var - a = initSinglyLinkedList[int]() - n = newSinglyLinkedNode[int](5) - a.add(n) - assert 5 in a - a.remove(n) - assert 5 notin a + from sequtils import toSeq + var a = [0, 1, 2].toSinglyLinkedList + let n = a.head.next + doAssert n.value == 1 + a.remove n + doAssert a.toSeq == [0, 2] + a.remove n + doAssert a.toSeq == [0, 2] if n == L.head: L.head = n.next else: var prev = L.head - while prev.next != n: + while prev.next != n and prev.next != nil: prev = prev.next - prev.next = n.next + if prev.next != nil: + prev.next = n.next proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Removes a node `n` from `L`. Efficiency: O(1). diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 781e58832a4ca..726df06460182 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -155,6 +155,7 @@ template testCommon(initList, 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] @@ -195,6 +196,8 @@ template testCommon(initList, toList) = 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 From 9753b6b9fa5f9a1feb8334cb032c1e9561d03e2c Mon Sep 17 00:00:00 2001 From: Peter Salvi Date: Sun, 3 Jan 2021 11:23:06 +0100 Subject: [PATCH 03/13] Remove preserves cycles; add appendMove alias; tests. --- changelog.md | 1 + lib/pure/collections/lists.nim | 113 +++++++++++++++++++-------------- tests/stdlib/tlists.nim | 34 ++++++---- 3 files changed, 91 insertions(+), 57 deletions(-) diff --git a/changelog.md b/changelog.md index 696e58ba81211..35151cb5867fb 100644 --- a/changelog.md +++ b/changelog.md @@ -111,6 +111,7 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) - In `lists`: renamed `append` to `add` and added a deprecated `append`; - In `lists`: renamed `append` to `add` and retained `append` as an alias; +- In `lists`: renamed `append` to `add` and retained `append` (and added `appendMoved`) as an alias; added `prepend` and `prependMoved` analogously to `add` and `andMoved`; added `remove` for `SinglyLinkedList`s. diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 6838a6aec0f06..a50cce316c9a4 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -22,50 +22,43 @@ ## ## Lists ## ----- -## -## .. code-block:: -## import lists -## -## var -## l = initDoublyLinkedList[int]() -## a = newDoublyLinkedNode[int](3) -## b = newDoublyLinkedNode[int](7) -## c = newDoublyLinkedNode[int](9) -## -## l.add(a) -## l.add(b) -## l.prepend(c) -## -## assert a.next == b -## assert a.prev == c -## assert c.next == a -## assert c.next.next == b -## assert c.prev == nil -## assert b.next == nil -## -## +runnableExamples: + var + l = initDoublyLinkedList[int]() + a = newDoublyLinkedNode[int](3) + b = newDoublyLinkedNode[int](7) + c = newDoublyLinkedNode[int](9) + + l.add(a) + l.add(b) + l.prepend(c) + + assert a.next == b + assert a.prev == c + assert c.next == a + assert c.next.next == b + assert c.prev == nil + assert b.next == nil + ## Rings ## ----- -## -## .. code-block:: -## import lists -## -## var -## l = initSinglyLinkedRing[int]() -## a = newSinglyLinkedNode[int](3) -## b = newSinglyLinkedNode[int](7) -## c = newSinglyLinkedNode[int](9) -## -## l.add(a) -## l.add(b) -## l.prepend(c) -## -## assert c.next == a -## assert a.next == b -## assert c.next.next == b -## assert b.next == c -## assert c.next.next.next == c -## +runnableExamples: + var + l = initSinglyLinkedRing[int]() + a = newSinglyLinkedNode[int](3) + b = newSinglyLinkedNode[int](7) + c = newSinglyLinkedNode[int](9) + + l.add(a) + l.add(b) + l.prepend(c) + + assert c.next == a + assert a.next == b + assert c.next.next == b + assert b.next == c + assert c.next.next.next == c + ## See also ## ======== ## @@ -368,17 +361,34 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = result = find(L, value) != nil -proc append*[T](a: var SomeLinkedCollection[T], b: SomeLinkedNode[T] | T) = - ## Alias for `a.add(b)`. +proc append*[T](a: var (SinglyLinkedList[T] | SinglyLinkedRing[T]), + b: SinglyLinkedList[T] | SinglyLinkedNode[T] | T) = + ## Deprecated 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) = + ## Deprecated 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).} = + ## Deprecated alias for `a.addMoved(b)`. + ## + ## See also: + ## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_ + ## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_ + a.addMoved b + proc prepend*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = ## Prepends a shallow copy of `b` to the beginning of `a`. ## @@ -714,10 +724,11 @@ proc add*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) = ## Removes a node `n` from `L`. - ## Efficiency: O(n), unless `n` is the head element. + ## 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: - from sequtils import toSeq + import std/[sequtils, enumerate, sugar] var a = [0, 1, 2].toSinglyLinkedList let n = a.head.next doAssert n.value == 1 @@ -725,9 +736,18 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) = doAssert a.toSeq == [0, 2] 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.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: @@ -737,6 +757,7 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) = proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Removes a node `n` from `L`. Efficiency: O(1). + ## When the list is cyclic, the cycle is preserved after removal. runnableExamples: var a = initDoublyLinkedList[int]() diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 726df06460182..9723d42f60384 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -2,7 +2,7 @@ discard """ targets: "c js" """ -import lists, sequtils, std/enumerate, std/sugar +import lists, sequtils const data = [1, 2, 3, 4, 5, 6] @@ -82,6 +82,18 @@ block tlistsToString: l.add('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) = block: # toSinglyLinkedList, toDoublyLinkedList @@ -140,11 +152,7 @@ template testCommon(initList, toList) = block: var c = [0, 1].toList c.addMoved c - let s = collect: - for i, ci in enumerate(c): - if i == 6: break - ci - doAssert s == [0, 1, 0, 1, 0, 1] + doAssert c.take(6) == [0, 1, 0, 1, 0, 1] block: # prepend, prependMoved block: @@ -179,11 +187,7 @@ template testCommon(initList, toList) = block: var c = [0, 1].toList c.prependMoved c - let s = collect: - for i, ci in enumerate(c): - if i == 6: break - ci - doAssert s == [0, 1, 0, 1, 0, 1] + doAssert c.take(6) == [0, 1, 0, 1, 0, 1] block remove: var l = [0, 1, 2, 3].toList @@ -202,6 +206,14 @@ template testCommon(initList, toList) = 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 initDoublyLinkedList, toDoublyLinkedList From 45a47f7a53c1a178bc42ee46b53384e9c489376d Mon Sep 17 00:00:00 2001 From: Peter Salvi Date: Wed, 13 Jan 2021 10:05:18 +0100 Subject: [PATCH 04/13] Return value for (singly linked) `lists.remove` --- changelog.md | 2 -- lib/pure/collections/lists.nim | 19 +++++++++++++------ tests/stdlib/tlists.nim | 10 ++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/changelog.md b/changelog.md index 35151cb5867fb..d95c47903a186 100644 --- a/changelog.md +++ b/changelog.md @@ -109,8 +109,6 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. - Added `math.signbit`. - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) -- In `lists`: renamed `append` to `add` and added a deprecated `append`; -- In `lists`: renamed `append` to `add` and retained `append` as an alias; - In `lists`: renamed `append` to `add` and retained `append` (and added `appendMoved`) as an alias; added `prepend` and `prependMoved` analogously to `add` and `andMoved`; added `remove` for `SinglyLinkedList`s. diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index a50cce316c9a4..632fa1c8b267f 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -722,8 +722,9 @@ proc add*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = var tmp = b.copy a.addMoved tmp -proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) = +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. @@ -732,9 +733,9 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) = var a = [0, 1, 2].toSinglyLinkedList let n = a.head.next doAssert n.value == 1 - a.remove n + doAssert a.remove(n) == true doAssert a.toSeq == [0, 2] - a.remove n + doAssert a.remove(n) == false doAssert a.toSeq == [0, 2] a.addMoved a # cycle: [0, 2, 0, 2, ...] a.remove a.head @@ -752,12 +753,18 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) = var prev = L.head while prev.next != n and prev.next != nil: prev = prev.next - if prev.next != nil: - prev.next = n.next + if prev.next == nil: + return false + prev.next = n.next + true proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Removes a node `n` from `L`. Efficiency: O(1). - ## When the list is cyclic, the cycle is preserved after removal. + ## 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, + ## see the example for + ## `remove proc <#remove,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ runnableExamples: var a = initDoublyLinkedList[int]() diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 9723d42f60384..e69ffa9502553 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -217,3 +217,13 @@ template testCommon(initList, toList) = testCommon initSinglyLinkedList, toSinglyLinkedList 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] From a9085cbeb7f15c599042f789b819662b8f647190 Mon Sep 17 00:00:00 2001 From: Peter Salvi Date: Thu, 14 Jan 2021 16:55:48 +0100 Subject: [PATCH 05/13] More test for lists.remove --- lib/pure/collections/lists.nim | 26 ++++++++++++++++---------- tests/stdlib/tlists.nim | 4 ++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 632fa1c8b267f..6c2d97a407a37 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -762,17 +762,23 @@ proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## 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, - ## see the example for - ## `remove proc <#remove,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ + ## When the list is cyclic, the cycle is preserved after removal. runnableExamples: - var - a = initDoublyLinkedList[int]() - n = newDoublyLinkedNode[int](5) - a.add(n) - assert 5 in a - a.remove(n) - assert 5 notin a + import std/[sequtils, enumerate, sugar] + var a = [0, 1, 2].toSinglyLinkedList + let n = a.head.next + doAssert n.value == 1 + a.remove n + doAssert a.toSeq == [0, 2] + 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.head: L.head = n.next diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index e69ffa9502553..2d3165c9c8fbe 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -227,3 +227,7 @@ block remove: # return value check 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 == [] From c5ae194a0748c011b4c506f2b780c1ef77e5882a Mon Sep 17 00:00:00 2001 From: Peter Salvi Date: Tue, 19 Jan 2021 10:50:24 +0100 Subject: [PATCH 06/13] Moved `lists.append` to the end of the file to see all `add` definitions --- lib/pure/collections/lists.nim | 56 +++++++++++++++++----------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 6c2d97a407a37..56742f592fa06 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -361,34 +361,6 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = result = find(L, value) != nil -proc append*[T](a: var (SinglyLinkedList[T] | SinglyLinkedRing[T]), - b: SinglyLinkedList[T] | SinglyLinkedNode[T] | T) = - ## Deprecated 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) = - ## Deprecated 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).} = - ## Deprecated alias for `a.addMoved(b)`. - ## - ## See also: - ## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_ - ## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_ - a.addMoved b - proc prepend*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = ## Prepends a shallow copy of `b` to the beginning of `a`. ## @@ -980,3 +952,31 @@ proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = L.head = nil else: L.head = L.head.prev + +proc append*[T](a: var (SinglyLinkedList[T] | SinglyLinkedRing[T]), + b: SinglyLinkedList[T] | SinglyLinkedNode[T] | T) = + ## Deprecated 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) = + ## Deprecated 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).} = + ## Deprecated alias for `a.addMoved(b)`. + ## + ## See also: + ## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_ + ## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_ + a.addMoved b From e487328c75fdd5721b9f511c16a232daeba9a32f Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 20 Jan 2021 14:45:54 +0100 Subject: [PATCH 07/13] Disable testing js for now --- tests/stdlib/tlists.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 2d3165c9c8fbe..8ac94730929f5 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -1,7 +1,7 @@ discard """ - targets: "c js" + targets: "c" """ - +#XXX: js target currently disabled for this test because `swap a, b` call at lists.nim:408 has no effect import lists, sequtils const From e17a8ae1408c30eb5b901281b285954429291d8b Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 21 Jan 2021 01:09:04 +0100 Subject: [PATCH 08/13] Use workaround for swap js bug --- lib/pure/collections/lists.nim | 4 +++- tests/stdlib/tlists.nim | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 56742f592fa06..739ad5ae7b394 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -405,7 +405,9 @@ proc prependMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} = ci assert s == [0, 1, 0, 1, 0, 1] b.addMoved a - swap a, b + 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.} = diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 8ac94730929f5..e190f73a9c8c3 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -1,7 +1,6 @@ discard """ - targets: "c" + targets: "c js" """ -#XXX: js target currently disabled for this test because `swap a, b` call at lists.nim:408 has no effect import lists, sequtils const From 1fdcd8a0574d68be1fdb77d17e5509f4f4dceac2 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 21 Jan 2021 01:10:10 +0100 Subject: [PATCH 09/13] Smaller diff --- tests/stdlib/tlists.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index e190f73a9c8c3..2d3165c9c8fbe 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -1,6 +1,7 @@ discard """ targets: "c js" """ + import lists, sequtils const From e158639b8302a93be7ccfb8db930f60db0ea148a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 21 Jan 2021 01:25:14 +0100 Subject: [PATCH 10/13] Undo "silent" deprecation of append --- lib/pure/collections/lists.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 739ad5ae7b394..2bfad9d957ea3 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -957,7 +957,7 @@ proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = proc append*[T](a: var (SinglyLinkedList[T] | SinglyLinkedRing[T]), b: SinglyLinkedList[T] | SinglyLinkedNode[T] | T) = - ## Deprecated alias for `a.add(b)`. + ## Alias for `a.add(b)`. ## ## See also: ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ @@ -967,7 +967,7 @@ proc append*[T](a: var (SinglyLinkedList[T] | SinglyLinkedRing[T]), proc append*[T](a: var (DoublyLinkedList[T] | DoublyLinkedRing[T]), b: DoublyLinkedList[T] | DoublyLinkedNode[T] | T) = - ## Deprecated alias for `a.add(b)`. + ## Alias for `a.add(b)`. ## ## See also: ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ @@ -976,7 +976,7 @@ proc append*[T](a: var (DoublyLinkedList[T] | DoublyLinkedRing[T]), a.add b proc appendMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} = - ## Deprecated alias for `a.addMoved(b)`. + ## Alias for `a.addMoved(b)`. ## ## See also: ## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_ From 6e6d1de2d65d615b5684aea567b3b86f71efdf68 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 21 Jan 2021 01:27:39 +0100 Subject: [PATCH 11/13] Correct typo in changelog Co-authored-by: Timothee Cour --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index d95c47903a186..0e0dc2d45f580 100644 --- a/changelog.md +++ b/changelog.md @@ -110,7 +110,7 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) - In `lists`: renamed `append` to `add` and retained `append` (and added `appendMoved`) as an alias; - added `prepend` and `prependMoved` analogously to `add` and `andMoved`; + added `prepend` and `prependMoved` analogously to `add` and `addMoved`; added `remove` for `SinglyLinkedList`s. ## Language changes From d9f371b12d00c0247c492bb7cae76b364f138ef6 Mon Sep 17 00:00:00 2001 From: Peter Salvi Date: Thu, 21 Jan 2021 09:46:23 +0100 Subject: [PATCH 12/13] Remove `appendMoved` Co-authored-by: Timothee Cour --- changelog.md | 2 +- lib/pure/collections/lists.nim | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 0e0dc2d45f580..ed0e3216127a7 100644 --- a/changelog.md +++ b/changelog.md @@ -109,7 +109,7 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. - Added `math.signbit`. - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) -- In `lists`: renamed `append` to `add` and retained `append` (and added `appendMoved`) as an alias; +- 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. diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 2bfad9d957ea3..81f85df48936a 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -974,11 +974,3 @@ proc append*[T](a: var (DoublyLinkedList[T] | DoublyLinkedRing[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 From 79995aa0ab6476c6179f51bc1f80db97b32223d6 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 21 Jan 2021 11:17:02 +0100 Subject: [PATCH 13/13] Don't remove appendMoved --- lib/pure/collections/lists.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 81f85df48936a..2bfad9d957ea3 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -974,3 +974,11 @@ proc append*[T](a: var (DoublyLinkedList[T] | DoublyLinkedRing[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