Commit 01389b96 authored by Andrew Gerrand's avatar Andrew Gerrand

container/list: fix Remove bug and use pointer to self as identifier

Remove wasn't nil'ing the *Element.id. This property was exploited
by MoveToFront and MoveToBack internally, so I renamed the existing
Remove to "remove", and created an exported wrapper "Remove" that does
the right thing for the user's sake.

Also, saved an allocation by using *List as the id rather than *byte.

Fixes #1224.

R=rsc, dsymonds
CC=golang-dev
https://golang.org/cl/2685042
parent ee065332
...@@ -11,8 +11,8 @@ type Element struct { ...@@ -11,8 +11,8 @@ type Element struct {
// The front of the list has prev = nil, and the back has next = nil. // The front of the list has prev = nil, and the back has next = nil.
next, prev *Element next, prev *Element
// A unique ID for the list to which this element belongs. // Thie list to which this element belongs.
id *byte list *List
// The contents of this list element. // The contents of this list element.
Value interface{} Value interface{}
...@@ -29,7 +29,6 @@ func (e *Element) Prev() *Element { return e.prev } ...@@ -29,7 +29,6 @@ func (e *Element) Prev() *Element { return e.prev }
type List struct { type List struct {
front, back *Element front, back *Element
len int len int
id *byte
} }
// Init initializes or clears a List. // Init initializes or clears a List.
...@@ -37,7 +36,6 @@ func (l *List) Init() *List { ...@@ -37,7 +36,6 @@ func (l *List) Init() *List {
l.front = nil l.front = nil
l.back = nil l.back = nil
l.len = 0 l.len = 0
l.id = new(byte)
return l return l
} }
...@@ -52,7 +50,15 @@ func (l *List) Back() *Element { return l.back } ...@@ -52,7 +50,15 @@ func (l *List) Back() *Element { return l.back }
// Remove removes the element from the list. // Remove removes the element from the list.
func (l *List) Remove(e *Element) { func (l *List) Remove(e *Element) {
if e.id != l.id { l.remove(e)
e.list = nil // do what remove does not
}
// 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 return
} }
if e.prev == nil { if e.prev == nil {
...@@ -121,59 +127,59 @@ func (l *List) insertBack(e *Element) { ...@@ -121,59 +127,59 @@ func (l *List) insertBack(e *Element) {
// PushFront inserts the value at the front of the list and returns a new Element containing the 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 { func (l *List) PushFront(value interface{}) *Element {
if l.id == nil { if l == nil {
l.Init() l.Init()
} }
e := &Element{nil, nil, l.id, value} e := &Element{nil, nil, l, value}
l.insertFront(e) l.insertFront(e)
return e return e
} }
// PushBack inserts the value at the back of the list and returns a new Element containing the value. // 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 { func (l *List) PushBack(value interface{}) *Element {
if l.id == nil { if l == nil {
l.Init() l.Init()
} }
e := &Element{nil, nil, l.id, value} e := &Element{nil, nil, l, value}
l.insertBack(e) l.insertBack(e)
return e return e
} }
// InsertBefore inserts the value immediately before mark and returns a new Element containing the value. // InsertBefore inserts the value immediately before mark and returns a new Element containing the value.
func (l *List) InsertBefore(value interface{}, mark *Element) *Element { func (l *List) InsertBefore(value interface{}, mark *Element) *Element {
if mark.id != l.id { if mark.list != l {
return nil return nil
} }
e := &Element{nil, nil, l.id, value} e := &Element{nil, nil, l, value}
l.insertBefore(e, mark) l.insertBefore(e, mark)
return e return e
} }
// InsertAfter inserts the value immediately after mark and returns a new Element containing the value. // InsertAfter inserts the value immediately after mark and returns a new Element containing the value.
func (l *List) InsertAfter(value interface{}, mark *Element) *Element { func (l *List) InsertAfter(value interface{}, mark *Element) *Element {
if mark.id != l.id { if mark.list != l {
return nil return nil
} }
e := &Element{nil, nil, l.id, value} e := &Element{nil, nil, l, value}
l.insertAfter(e, mark) l.insertAfter(e, mark)
return e return e
} }
// MoveToFront moves the element to the front of the list. // MoveToFront moves the element to the front of the list.
func (l *List) MoveToFront(e *Element) { func (l *List) MoveToFront(e *Element) {
if e.id != l.id || l.front == e { if e.list != l || l.front == e {
return return
} }
l.Remove(e) l.remove(e)
l.insertFront(e) l.insertFront(e)
} }
// MoveToBack moves the element to the back of the list. // MoveToBack moves the element to the back of the list.
func (l *List) MoveToBack(e *Element) { func (l *List) MoveToBack(e *Element) {
if e.id != l.id || l.back == e { if e.list != l || l.back == e {
return return
} }
l.Remove(e) l.remove(e)
l.insertBack(e) l.insertBack(e)
} }
......
...@@ -23,8 +23,7 @@ func checkListPointers(t *testing.T, l *List, es []*Element) { ...@@ -23,8 +23,7 @@ func checkListPointers(t *testing.T, l *List, es []*Element) {
t.Errorf("l.back = %v, want %v", l.back, last) t.Errorf("l.back = %v, want %v", l.back, last)
} }
for i := 0; i < len(es); i++ { for i, e := range es {
e := es[i]
var e_prev, e_next *Element = nil, nil var e_prev, e_next *Element = nil, nil
if i > 0 { if i > 0 {
e_prev = es[i-1] e_prev = es[i-1]
...@@ -194,3 +193,17 @@ func TestExtending(t *testing.T) { ...@@ -194,3 +193,17 @@ func TestExtending(t *testing.T) {
l1.PushFrontList(l3) l1.PushFrontList(l3)
checkList(t, l1, []interface{}{1, 2, 3}) checkList(t, l1, []interface{}{1, 2, 3})
} }
func TestRemove(t *testing.T) {
l := New()
e1 := l.PushBack(1)
e2 := l.PushBack(2)
checkListPointers(t, l, []*Element{e1, e2})
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)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment