summaryrefslogtreecommitdiff
path: root/src/pkg/container
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/container')
-rw-r--r--src/pkg/container/heap/example_intheap_test.go43
-rw-r--r--src/pkg/container/heap/example_pq_test.go95
-rw-r--r--src/pkg/container/heap/example_test.go105
-rw-r--r--src/pkg/container/heap/heap.go10
-rw-r--r--src/pkg/container/heap/heap_test.go16
-rw-r--r--src/pkg/container/list/example_test.go30
-rw-r--r--src/pkg/container/list/list.go238
-rw-r--r--src/pkg/container/list/list_test.go102
-rw-r--r--src/pkg/container/ring/ring.go2
9 files changed, 364 insertions, 277 deletions
diff --git a/src/pkg/container/heap/example_intheap_test.go b/src/pkg/container/heap/example_intheap_test.go
new file mode 100644
index 000000000..e718cbc58
--- /dev/null
+++ b/src/pkg/container/heap/example_intheap_test.go
@@ -0,0 +1,43 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This example demonstrates an integer heap built using the heap interface.
+package heap_test
+
+import (
+ "container/heap"
+ "fmt"
+)
+
+// An IntHeap is a min-heap of ints.
+type IntHeap []int
+
+func (h IntHeap) Len() int { return len(h) }
+func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
+func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
+
+func (h *IntHeap) Push(x interface{}) {
+ // Push and Pop use pointer receivers because they modify the slice's length,
+ // not just its contents.
+ *h = append(*h, x.(int))
+}
+
+func (h *IntHeap) Pop() interface{} {
+ old := *h
+ n := len(old)
+ x := old[n-1]
+ *h = old[0 : n-1]
+ return x
+}
+
+// This example inserts several ints into an IntHeap and removes them in order of priority.
+func Example_intHeap() {
+ h := &IntHeap{2, 1, 5}
+ heap.Init(h)
+ heap.Push(h, 3)
+ for h.Len() > 0 {
+ fmt.Printf("%d ", heap.Pop(h))
+ }
+ // Output: 1 2 3 5
+}
diff --git a/src/pkg/container/heap/example_pq_test.go b/src/pkg/container/heap/example_pq_test.go
new file mode 100644
index 000000000..8cbeb8d70
--- /dev/null
+++ b/src/pkg/container/heap/example_pq_test.go
@@ -0,0 +1,95 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This example demonstrates a priority queue built using the heap interface.
+package heap_test
+
+import (
+ "container/heap"
+ "fmt"
+)
+
+// An Item is something we manage in a priority queue.
+type Item struct {
+ value string // The value of the item; arbitrary.
+ priority int // The priority of the item in the queue.
+ // The index is needed by update and is maintained by the heap.Interface methods.
+ index int // The index of the item in the heap.
+}
+
+// A PriorityQueue implements heap.Interface and holds Items.
+type PriorityQueue []*Item
+
+func (pq PriorityQueue) Len() int { return len(pq) }
+
+func (pq PriorityQueue) Less(i, j int) bool {
+ // We want Pop to give us the highest, not lowest, priority so we use greater than here.
+ return pq[i].priority > pq[j].priority
+}
+
+func (pq PriorityQueue) Swap(i, j int) {
+ pq[i], pq[j] = pq[j], pq[i]
+ pq[i].index = i
+ pq[j].index = j
+}
+
+func (pq *PriorityQueue) Push(x interface{}) {
+ n := len(*pq)
+ item := x.(*Item)
+ item.index = n
+ *pq = append(*pq, item)
+}
+
+func (pq *PriorityQueue) Pop() interface{} {
+ old := *pq
+ n := len(old)
+ item := old[n-1]
+ item.index = -1 // for safety
+ *pq = old[0 : n-1]
+ return item
+}
+
+// update modifies the priority and value of an Item in the queue.
+func (pq *PriorityQueue) update(item *Item, value string, priority int) {
+ heap.Remove(pq, item.index)
+ item.value = value
+ item.priority = priority
+ heap.Push(pq, item)
+}
+
+// This example inserts some items into a PriorityQueue, manipulates an item,
+// and then removes the items in priority order.
+func Example_priorityQueue() {
+ // Some items and their priorities.
+ items := map[string]int{
+ "banana": 3, "apple": 2, "pear": 4,
+ }
+
+ // Create a priority queue and put the items in it.
+ pq := &PriorityQueue{}
+ heap.Init(pq)
+ for value, priority := range items {
+ item := &Item{
+ value: value,
+ priority: priority,
+ }
+ heap.Push(pq, item)
+ }
+
+ // Insert a new item and then modify its priority.
+ item := &Item{
+ value: "orange",
+ priority: 1,
+ }
+ heap.Push(pq, item)
+ pq.update(item, item.value, 5)
+
+ // Take the items out; they arrive in decreasing priority order.
+ for pq.Len() > 0 {
+ item := heap.Pop(pq).(*Item)
+ fmt.Printf("%.2d:%s ", item.priority, item.value)
+ }
+ // Output:
+ // 05:orange 04:pear 03:banana 02:apple
+}
diff --git a/src/pkg/container/heap/example_test.go b/src/pkg/container/heap/example_test.go
deleted file mode 100644
index 2050bc835..000000000
--- a/src/pkg/container/heap/example_test.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This example demonstrates a priority queue built using the heap interface.
-package heap_test
-
-import (
- "container/heap"
- "fmt"
-)
-
-// An Item is something we manage in a priority queue.
-type Item struct {
- value string // The value of the item; arbitrary.
- priority int // The priority of the item in the queue.
- // The index is needed by changePriority and is maintained by the heap.Interface methods.
- index int // The index of the item in the heap.
-}
-
-// A PriorityQueue implements heap.Interface and holds Items.
-type PriorityQueue []*Item
-
-func (pq PriorityQueue) Len() int { return len(pq) }
-
-func (pq PriorityQueue) Less(i, j int) bool {
- // We want Pop to give us the highest, not lowest, priority so we use greater than here.
- return pq[i].priority > pq[j].priority
-}
-
-func (pq PriorityQueue) Swap(i, j int) {
- pq[i], pq[j] = pq[j], pq[i]
- pq[i].index = i
- pq[j].index = j
-}
-
-func (pq *PriorityQueue) Push(x interface{}) {
- // Push and Pop use pointer receivers because they modify the slice's length,
- // not just its contents.
- // To simplify indexing expressions in these methods, we save a copy of the
- // slice object. We could instead write (*pq)[i].
- a := *pq
- n := len(a)
- a = a[0 : n+1]
- item := x.(*Item)
- item.index = n
- a[n] = item
- *pq = a
-}
-
-func (pq *PriorityQueue) Pop() interface{} {
- a := *pq
- n := len(a)
- item := a[n-1]
- item.index = -1 // for safety
- *pq = a[0 : n-1]
- return item
-}
-
-// update is not used by the example but shows how to take the top item from
-// the queue, update its priority and value, and put it back.
-func (pq *PriorityQueue) update(value string, priority int) {
- item := heap.Pop(pq).(*Item)
- item.value = value
- item.priority = priority
- heap.Push(pq, item)
-}
-
-// changePriority is not used by the example but shows how to change the
-// priority of an arbitrary item.
-func (pq *PriorityQueue) changePriority(item *Item, priority int) {
- heap.Remove(pq, item.index)
- item.priority = priority
- heap.Push(pq, item)
-}
-
-// This example pushes 10 items into a PriorityQueue and takes them out in
-// order of priority.
-func Example() {
- const nItem = 10
- // Random priorities for the items (a permutation of 0..9, times 11)).
- priorities := [nItem]int{
- 77, 22, 44, 55, 11, 88, 33, 99, 00, 66,
- }
- values := [nItem]string{
- "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
- }
- // Create a priority queue and put some items in it.
- pq := make(PriorityQueue, 0, nItem)
- for i := 0; i < cap(pq); i++ {
- item := &Item{
- value: values[i],
- priority: priorities[i],
- }
- heap.Push(&pq, item)
- }
- // Take the items out; should arrive in decreasing priority order.
- // For example, the highest priority (99) is the seventh item, so output starts with 99:"seven".
- for i := 0; i < nItem; i++ {
- item := heap.Pop(&pq).(*Item)
- fmt.Printf("%.2d:%s ", item.priority, item.value)
- }
- // Output:
- // 99:seven 88:five 77:zero 66:nine 55:three 44:two 33:six 22:one 11:four 00:eight
-}
diff --git a/src/pkg/container/heap/heap.go b/src/pkg/container/heap/heap.go
index 67018e6ba..c37e50e3c 100644
--- a/src/pkg/container/heap/heap.go
+++ b/src/pkg/container/heap/heap.go
@@ -4,13 +4,13 @@
// Package heap provides heap operations for any type that implements
// heap.Interface. A heap is a tree with the property that each node is the
-// highest-valued node in its subtree.
+// minimum-valued node in its subtree.
//
// A heap is a common way to implement a priority queue. To build a priority
// queue, implement the Heap interface with the (negative) priority as the
// ordering for the Less method, so Push adds items while Pop removes the
// highest-priority item from the queue. The Examples include such an
-// implementation; the file example_test.go has the complete source.
+// implementation; the file example_pq_test.go has the complete source.
//
package heap
@@ -79,7 +79,7 @@ func Remove(h Interface, i int) interface{} {
func up(h Interface, j int) {
for {
i := (j - 1) / 2 // parent
- if i == j || h.Less(i, j) {
+ if i == j || !h.Less(j, i) {
break
}
h.Swap(i, j)
@@ -90,14 +90,14 @@ func up(h Interface, j int) {
func down(h Interface, i, n int) {
for {
j1 := 2*i + 1
- if j1 >= n {
+ if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
break
}
j := j1 // left child
if j2 := j1 + 1; j2 < n && !h.Less(j1, j2) {
j = j2 // = 2*i + 2 // right child
}
- if h.Less(i, j) {
+ if !h.Less(j, i) {
break
}
h.Swap(i, j)
diff --git a/src/pkg/container/heap/heap_test.go b/src/pkg/container/heap/heap_test.go
index cb31ef6d3..274d587d8 100644
--- a/src/pkg/container/heap/heap_test.go
+++ b/src/pkg/container/heap/heap_test.go
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package heap_test
+package heap
import (
- . "container/heap"
"testing"
)
@@ -170,3 +169,16 @@ func TestRemove2(t *testing.T) {
}
}
}
+
+func BenchmarkDup(b *testing.B) {
+ const n = 10000
+ h := make(myHeap, n)
+ for i := 0; i < b.N; i++ {
+ for j := 0; j < n; j++ {
+ Push(&h, 0) // all elements are the same
+ }
+ for h.Len() > 0 {
+ Pop(&h)
+ }
+ }
+}
diff --git a/src/pkg/container/list/example_test.go b/src/pkg/container/list/example_test.go
new file mode 100644
index 000000000..7361212d7
--- /dev/null
+++ b/src/pkg/container/list/example_test.go
@@ -0,0 +1,30 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package list_test
+
+import (
+ "container/list"
+ "fmt"
+)
+
+func Example() {
+ // Create a new list and put some numbers in it.
+ l := list.New()
+ e4 := l.PushBack(4)
+ e1 := l.PushFront(1)
+ l.InsertBefore(3, e4)
+ l.InsertAfter(2, e1)
+
+ // Iterate through list and and print its contents.
+ for e := l.Front(); e != nil; e = e.Next() {
+ fmt.Println(e.Value)
+ }
+
+ // Output:
+ // 1
+ // 2
+ // 3
+ // 4
+}
diff --git a/src/pkg/container/list/list.go b/src/pkg/container/list/list.go
index a3fd4b39f..562a5badb 100644
--- a/src/pkg/container/list/list.go
+++ b/src/pkg/container/list/list.go
@@ -11,201 +11,187 @@
//
package list
-// Element is an element in the linked list.
+// Element is an element of a linked list.
type Element struct {
// Next and previous pointers in the doubly-linked list of elements.
- // The front of the list has prev = nil, and the back has next = nil.
+ // To simplify the implementation, internally a list l is implemented
+ // as a ring, such that &l.root is both the next element of the last
+ // list element (l.Back()) and the previous element of the first list
+ // element (l.Front()).
next, prev *Element
// The list to which this element belongs.
list *List
- // The contents of this list element.
+ // The value stored with this element.
Value interface{}
}
// Next returns the next list element or nil.
-func (e *Element) Next() *Element { return e.next }
+func (e *Element) Next() *Element {
+ if p := e.next; p != &e.list.root {
+ return p
+ }
+ return nil
+}
// Prev returns the previous list element or nil.
-func (e *Element) Prev() *Element { return e.prev }
+func (e *Element) Prev() *Element {
+ if p := e.prev; p != &e.list.root {
+ return p
+ }
+ return nil
+}
// List represents a doubly linked list.
// The zero value for List is an empty list ready to use.
type List struct {
- front, back *Element
- len int
+ root Element // sentinel list element, only &root, root.prev, and root.next are used
+ len int // current list length excluding (this) sentinel element
}
-// Init initializes or clears a List.
+// Init initializes or clears list l.
func (l *List) Init() *List {
- l.front = nil
- l.back = nil
+ l.root.next = &l.root
+ l.root.prev = &l.root
l.len = 0
return l
}
// New returns an initialized list.
-func New() *List { return new(List) }
-
-// Front returns the first element in the list.
-func (l *List) Front() *Element { return l.front }
+func New() *List { return new(List).Init() }
-// Back returns the last element in the list.
-func (l *List) Back() *Element { return l.back }
+// Len returns the number of elements of list l.
+func (l *List) Len() int { return l.len }
-// Remove removes the element from the list
-// and returns its Value.
-func (l *List) Remove(e *Element) interface{} {
- l.remove(e)
- e.list = nil // do what remove does not
- return e.Value
+// Front returns the first element of list l or nil
+func (l *List) Front() *Element {
+ if l.len == 0 {
+ return nil
+ }
+ return l.root.next
}
-// remove the element from the list, but do not clear the Element's list field.
-// This is so that other List methods may use remove when relocating Elements
-// without needing to restore the list field.
-func (l *List) remove(e *Element) {
- if e.list != l {
- return
- }
- if e.prev == nil {
- l.front = e.next
- } else {
- e.prev.next = e.next
- }
- if e.next == nil {
- l.back = e.prev
- } else {
- e.next.prev = e.prev
+// Back returns the last element of list l or nil.
+func (l *List) Back() *Element {
+ if l.len == 0 {
+ return nil
}
-
- e.prev = nil
- e.next = nil
- l.len--
+ return l.root.prev
}
-func (l *List) insertBefore(e *Element, mark *Element) {
- if mark.prev == nil {
- // new front of the list
- l.front = e
- } else {
- mark.prev.next = e
+// lazyInit lazily initializes a zero List value.
+func (l *List) lazyInit() {
+ if l.root.next == nil {
+ l.Init()
}
- e.prev = mark.prev
- mark.prev = e
- e.next = mark
- l.len++
}
-func (l *List) insertAfter(e *Element, mark *Element) {
- if mark.next == nil {
- // new back of the list
- l.back = e
- } else {
- mark.next.prev = e
- }
- e.next = mark.next
- mark.next = e
- e.prev = mark
+// insert inserts e after at, increments l.len, and returns e.
+func (l *List) insert(e, at *Element) *Element {
+ n := at.next
+ at.next = e
+ e.prev = at
+ e.next = n
+ n.prev = e
+ e.list = l
l.len++
+ return e
}
-func (l *List) insertFront(e *Element) {
- if l.front == nil {
- // empty list
- l.front, l.back = e, e
- e.prev, e.next = nil, nil
- l.len = 1
- return
- }
- l.insertBefore(e, l.front)
+// insertValue is a convenience wrapper for insert(&Element{Value: v}, at).
+func (l *List) insertValue(v interface{}, at *Element) *Element {
+ return l.insert(&Element{Value: v}, at)
}
-func (l *List) insertBack(e *Element) {
- if l.back == nil {
- // empty list
- l.front, l.back = e, e
- e.prev, e.next = nil, nil
- l.len = 1
- return
+// remove removes e from its list, decrements l.len, and returns e.
+func (l *List) remove(e *Element) *Element {
+ e.prev.next = e.next
+ e.next.prev = e.prev
+ e.next = nil // avoid memory leaks
+ e.prev = nil // avoid memory leaks
+ e.list = nil
+ l.len--
+ return e
+}
+
+// Remove removes e from l if e is an element of list l.
+// It returns the element value e.Value.
+func (l *List) Remove(e *Element) interface{} {
+ if e.list == l {
+ // if e.list == l, l must have been initialized when e was inserted
+ // in l or l == nil (e is a zero Element) and l.remove will crash
+ l.remove(e)
}
- l.insertAfter(e, l.back)
+ return e.Value
}
-// PushFront inserts the value at the front of the list and returns a new Element containing the value.
-func (l *List) PushFront(value interface{}) *Element {
- e := &Element{nil, nil, l, value}
- l.insertFront(e)
- return e
+// Pushfront inserts a new element e with value v at the front of list l and returns e.
+func (l *List) PushFront(v interface{}) *Element {
+ l.lazyInit()
+ return l.insertValue(v, &l.root)
}
-// PushBack inserts the value at the back of the list and returns a new Element containing the value.
-func (l *List) PushBack(value interface{}) *Element {
- e := &Element{nil, nil, l, value}
- l.insertBack(e)
- return e
+// PushBack inserts a new element e with value v at the back of list l and returns e.
+func (l *List) PushBack(v interface{}) *Element {
+ l.lazyInit()
+ return l.insertValue(v, l.root.prev)
}
-// InsertBefore inserts the value immediately before mark and returns a new Element containing the value.
-func (l *List) InsertBefore(value interface{}, mark *Element) *Element {
+// InsertBefore inserts a new element e with value v immediately before mark and returns e.
+// If mark is not an element of l, the list is not modified.
+func (l *List) InsertBefore(v interface{}, mark *Element) *Element {
if mark.list != l {
return nil
}
- e := &Element{nil, nil, l, value}
- l.insertBefore(e, mark)
- return e
+ // see comment in List.Remove about initialization of l
+ return l.insertValue(v, mark.prev)
}
-// InsertAfter inserts the value immediately after mark and returns a new Element containing the value.
-func (l *List) InsertAfter(value interface{}, mark *Element) *Element {
+// InsertAfter inserts a new element e with value v immediately after mark and returns e.
+// If mark is not an element of l, the list is not modified.
+func (l *List) InsertAfter(v interface{}, mark *Element) *Element {
if mark.list != l {
return nil
}
- e := &Element{nil, nil, l, value}
- l.insertAfter(e, mark)
- return e
+ // see comment in List.Remove about initialization of l
+ return l.insertValue(v, mark)
}
-// MoveToFront moves the element to the front of the list.
+// MoveToFront moves element e to the front of list l.
+// If e is not an element of l, the list is not modified.
func (l *List) MoveToFront(e *Element) {
- if e.list != l || l.front == e {
+ if e.list != l || l.root.next == e {
return
}
- l.remove(e)
- l.insertFront(e)
+ // see comment in List.Remove about initialization of l
+ l.insert(l.remove(e), &l.root)
}
-// MoveToBack moves the element to the back of the list.
+// MoveToBack moves element e to the back of list l.
+// If e is not an element of l, the list is not modified.
func (l *List) MoveToBack(e *Element) {
- if e.list != l || l.back == e {
+ if e.list != l || l.root.prev == e {
return
}
- l.remove(e)
- l.insertBack(e)
+ // see comment in List.Remove about initialization of l
+ l.insert(l.remove(e), l.root.prev)
}
-// Len returns the number of elements in the list.
-func (l *List) Len() int { return l.len }
-
-// PushBackList inserts each element of ol at the back of the list.
-func (l *List) PushBackList(ol *List) {
- last := ol.Back()
- for e := ol.Front(); e != nil; e = e.Next() {
- l.PushBack(e.Value)
- if e == last {
- break
- }
+// PushBackList inserts a copy of an other list at the back of list l.
+// The lists l and other may be the same.
+func (l *List) PushBackList(other *List) {
+ l.lazyInit()
+ for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
+ l.insertValue(e.Value, l.root.prev)
}
}
-// PushFrontList inserts each element of ol at the front of the list. The ordering of the passed list is preserved.
-func (l *List) PushFrontList(ol *List) {
- first := ol.Front()
- for e := ol.Back(); e != nil; e = e.Prev() {
- l.PushFront(e.Value)
- if e == first {
- break
- }
+// PushFrontList inserts a copy of an other list at the front of list l.
+// The lists l and other may be the same.
+func (l *List) PushFrontList(other *List) {
+ l.lazyInit()
+ for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() {
+ l.insertValue(e.Value, &l.root)
}
}
diff --git a/src/pkg/container/list/list_test.go b/src/pkg/container/list/list_test.go
index 1d44ff84e..b4fc77d14 100644
--- a/src/pkg/container/list/list_test.go
+++ b/src/pkg/container/list/list_test.go
@@ -4,65 +4,75 @@
package list
-import (
- "testing"
-)
+import "testing"
+
+func checkListLen(t *testing.T, l *List, len int) bool {
+ if n := l.Len(); n != len {
+ t.Errorf("l.Len() = %d, want %d", n, len)
+ return false
+ }
+ return true
+}
func checkListPointers(t *testing.T, l *List, es []*Element) {
- if len(es) == 0 {
- if l.front != nil || l.back != nil {
- t.Errorf("l.front/l.back = %v/%v should be nil/nil", l.front, l.back)
- }
+ root := &l.root
+
+ if !checkListLen(t, l, len(es)) {
return
}
- if l.front != es[0] {
- t.Errorf("l.front = %v, want %v", l.front, es[0])
- }
- if last := es[len(es)-1]; l.back != last {
- t.Errorf("l.back = %v, want %v", l.back, last)
+ // zero length lists must be the zero value or properly initialized (sentinel circle)
+ if len(es) == 0 {
+ if l.root.next != nil && l.root.next != root || l.root.prev != nil && l.root.prev != root {
+ t.Errorf("l.root.next = %p, l.root.prev = %p; both should both be nil or %p", l.root.next, l.root.prev, root)
+ }
+ return
}
+ // len(es) > 0
+ // check internal and external prev/next connections
for i, e := range es {
- var e_prev, e_next *Element = nil, nil
+ prev := root
+ Prev := (*Element)(nil)
if i > 0 {
- e_prev = es[i-1]
+ prev = es[i-1]
+ Prev = prev
+ }
+ if p := e.prev; p != prev {
+ t.Errorf("elt[%d](%p).prev = %p, want %p", i, e, p, prev)
+ }
+ if p := e.Prev(); p != Prev {
+ t.Errorf("elt[%d](%p).Prev() = %p, want %p", i, e, p, Prev)
}
+
+ next := root
+ Next := (*Element)(nil)
if i < len(es)-1 {
- e_next = es[i+1]
+ next = es[i+1]
+ Next = next
}
- if e.prev != e_prev {
- t.Errorf("elt #%d (%v) has prev=%v, want %v", i, e, e.prev, e_prev)
+ if n := e.next; n != next {
+ t.Errorf("elt[%d](%p).next = %p, want %p", i, e, n, next)
}
- if e.next != e_next {
- t.Errorf("elt #%d (%v) has next=%v, want %v", i, e, e.next, e_next)
+ if n := e.Next(); n != Next {
+ t.Errorf("elt[%d](%p).Next() = %p, want %p", i, e, n, Next)
}
}
}
-func checkListLen(t *testing.T, l *List, n int) {
- if an := l.Len(); an != n {
- t.Errorf("l.Len() = %d, want %d", an, n)
- }
-}
-
func TestList(t *testing.T) {
l := New()
checkListPointers(t, l, []*Element{})
- checkListLen(t, l, 0)
// Single element list
e := l.PushFront("a")
- checkListLen(t, l, 1)
checkListPointers(t, l, []*Element{e})
l.MoveToFront(e)
checkListPointers(t, l, []*Element{e})
l.MoveToBack(e)
checkListPointers(t, l, []*Element{e})
- checkListLen(t, l, 1)
l.Remove(e)
checkListPointers(t, l, []*Element{})
- checkListLen(t, l, 0)
// Bigger list
e2 := l.PushFront(2)
@@ -70,11 +80,9 @@ func TestList(t *testing.T) {
e3 := l.PushBack(3)
e4 := l.PushBack("banana")
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
- checkListLen(t, l, 4)
l.Remove(e2)
checkListPointers(t, l, []*Element{e1, e3, e4})
- checkListLen(t, l, 3)
l.MoveToFront(e3) // move from middle
checkListPointers(t, l, []*Element{e3, e1, e4})
@@ -121,7 +129,7 @@ func TestList(t *testing.T) {
}
}
if sum != 4 {
- t.Errorf("sum over l.Iter() = %d, want 4", sum)
+ t.Errorf("sum over l = %d, want 4", sum)
}
// Clear all elements by iterating
@@ -131,19 +139,18 @@ func TestList(t *testing.T) {
l.Remove(e)
}
checkListPointers(t, l, []*Element{})
- checkListLen(t, l, 0)
}
func checkList(t *testing.T, l *List, es []interface{}) {
- if l.Len() != len(es) {
- t.Errorf("list has len=%v, want %v", l.Len(), len(es))
+ if !checkListLen(t, l, len(es)) {
return
}
+
i := 0
for e := l.Front(); e != nil; e = e.Next() {
le := e.Value.(int)
if le != es[i] {
- t.Errorf("elt #%d has value=%v, want %v", i, le, es[i])
+ t.Errorf("elt[%d].Value = %v, want %v", i, le, es[i])
}
i++
}
@@ -202,8 +209,27 @@ func TestRemove(t *testing.T) {
e := l.Front()
l.Remove(e)
checkListPointers(t, l, []*Element{e2})
- checkListLen(t, l, 1)
l.Remove(e)
checkListPointers(t, l, []*Element{e2})
- checkListLen(t, l, 1)
+}
+
+func TestIssue4103(t *testing.T) {
+ l1 := New()
+ l1.PushBack(1)
+ l1.PushBack(2)
+
+ l2 := New()
+ l2.PushBack(3)
+ l2.PushBack(4)
+
+ e := l1.Front()
+ l2.Remove(e) // l2 should not change because e is not an element of l2
+ if n := l2.Len(); n != 2 {
+ t.Errorf("l2.Len() = %d, want 2", n)
+ }
+
+ l1.InsertBefore(8, e)
+ if n := l1.Len(); n != 3 {
+ t.Errorf("l1.Len() = %d, want 3", n)
+ }
}
diff --git a/src/pkg/container/ring/ring.go b/src/pkg/container/ring/ring.go
index 1d96918d3..6d3b3e5b3 100644
--- a/src/pkg/container/ring/ring.go
+++ b/src/pkg/container/ring/ring.go
@@ -74,7 +74,7 @@ func New(n int) *Ring {
return r
}
-// Link connects ring r with with ring s such that r.Next()
+// Link connects ring r with ring s such that r.Next()
// becomes s and returns the original value for r.Next().
// r must not be empty.
//