From bf0a339bf3af00550bd328d1059051fdb3c220a6 Mon Sep 17 00:00:00 2001 From: David Symonds Date: Tue, 2 Jun 2009 20:26:14 -0700 Subject: [PATCH] Add container/list package. This is imported from //cacheserving/gash/cache/list*.go, but with style changes to suit the Go standard library. R=r,rsc APPROVED=r DELTA=286 (286 added, 0 deleted, 0 changed) OCL=29438 CL=29796 --- src/lib/Make.deps | 1 + src/lib/Makefile | 2 + src/lib/container/list/Makefile | 68 +++++++++++++++ src/lib/container/list/list.go | 130 ++++++++++++++++++++++++++++ src/lib/container/list/list_test.go | 91 +++++++++++++++++++ 5 files changed, 292 insertions(+) create mode 100644 src/lib/container/list/Makefile create mode 100755 src/lib/container/list/list.go create mode 100755 src/lib/container/list/list_test.go diff --git a/src/lib/Make.deps b/src/lib/Make.deps index 12f086291b..538e17039b 100644 --- a/src/lib/Make.deps +++ b/src/lib/Make.deps @@ -1,5 +1,6 @@ bignum.install: fmt.install bufio.install: io.install os.install utf8.install +container/list.install: container/vector.install: crypto/aes.install: os.install crypto/block.install: fmt.install io.install os.install diff --git a/src/lib/Makefile b/src/lib/Makefile index 3bce7d6392..0f76507a4c 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -16,6 +16,7 @@ GC=6g DIRS=\ bignum\ bufio\ + container/list\ container/vector\ crypto/aes\ crypto/block\ @@ -65,6 +66,7 @@ DIRS=\ TEST=\ bignum\ bufio\ + container/list\ container/vector\ crypto/aes\ crypto/block\ diff --git a/src/lib/container/list/Makefile b/src/lib/container/list/Makefile new file mode 100644 index 0000000000..e40a81345e --- /dev/null +++ b/src/lib/container/list/Makefile @@ -0,0 +1,68 @@ +# Copyright 2009 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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/container/ + +O_arm=5 +O_amd64=6 +O_386=8 +OS=568vq + +O=$(O_$(GOARCH)) +GC=$(O)g -I_obj +CC=$(O)c -FVw +AS=$(O)a +AR=6ar + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + list.$O\ + + +phases: a1 +_obj$D/list.a: phases + +a1: $(O1) + $(AR) grc _obj$D/list.a list.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/list.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg$D/list.a + +packages: _obj$D/list.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg$D + cp _obj$D/list.a $(GOROOT)/pkg$D/list.a diff --git a/src/lib/container/list/list.go b/src/lib/container/list/list.go new file mode 100755 index 0000000000..7e8daa65a7 --- /dev/null +++ b/src/lib/container/list/list.go @@ -0,0 +1,130 @@ +// Copyright 2009 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. + +// The list package implements a doubly linked list. +package list + +// Element is an element in the 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. + next, prev *Element; + + // The contents of this list element. + Value interface {}; +} + +// List represents a doubly linked list. +type List struct { + front, back *Element; +} + +// Init initializes or clears a List. +func (l *List) Init() *List { + l.front = nil; + l.back = nil; + return l +} + +// New returns an initialized list. +func New() *List { + return new(List).Init() +} + +// Front returns the first element in the list. +func (l *List) Front() *Element { + return l.front +} + +// Back returns the last element in the list. +func (l *List) Back() *Element { + return l.back +} + +// Remove removes the element from the list. +func (l *List) Remove(e *Element) { + 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; + } + + e.prev = nil; + e.next = nil; +} + +func (l *List) insertFront(e *Element) { + e.prev = nil; + e.next = l.front; + l.front = e; + if e.next != nil { + e.next.prev = e; + } else { + l.back = e; + } +} + +func (l *List) insertBack(e *Element) { + e.next = nil; + e.prev = l.back; + l.back = e; + if e.prev != nil { + e.prev.next = e; + } else { + l.front = e; + } +} + +// PushFront inserts the value at the front of the list, and returns a new Element containing it. +func (l *List) PushFront(value interface {}) *Element { + e := &Element{ nil, nil, value }; + l.insertFront(e); + return e +} + +// PushBack inserts the value at the back of the list, and returns a new Element containing it. +func (l *List) PushBack(value interface {}) *Element { + e := &Element{ nil, nil, value }; + l.insertBack(e); + return e +} + +// MoveToFront moves the element to the front of the list. +func (l *List) MoveToFront(e *Element) { + if l.front == e { + return + } + l.Remove(e); + l.insertFront(e); +} + +// MoveToBack moves the element to the back of the list. +func (l *List) MoveToBack(e *Element) { + if l.back == e { + return + } + l.Remove(e); + l.insertBack(e); +} + +func (l *List) iterate(c chan <- *Element) { + var next *Element; + for e := l.front; e != nil; e = next { + // Save next in case reader of c changes e. + next = e.next; + c <- e; + } + close(c); +} + +func (l *List) Iter() <-chan *Element { + c := make(chan *Element); + go l.iterate(c); + return c +} diff --git a/src/lib/container/list/list_test.go b/src/lib/container/list/list_test.go new file mode 100755 index 0000000000..d5b2672e05 --- /dev/null +++ b/src/lib/container/list/list_test.go @@ -0,0 +1,91 @@ +// Copyright 2009 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 + +import ( + "container/list"; + "testing"; +) + +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); + } + 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); + } + + for i := 0; i < len(es); i++ { + e := es[i]; + var e_prev, e_next *Element = nil, nil; + if i > 0 { + e_prev = es[i-1]; + } + if i < len(es) - 1 { + e_next = es[i+1]; + } + if e.prev != e_prev { + t.Errorf("elt #%d (%v) has prev=%v, want %v", i, e, e.prev, e_prev); + } + if e.next != e_next { + t.Errorf("elt #%d (%v) has next=%v, want %v", i, e, e.next, e_next); + } + } +} + +func TestList(t *testing.T) { + l := New(); + checkListPointers(t, l, []*Element{}); + + // Single element list + e := l.PushFront("a"); + checkListPointers(t, l, []*Element{ e }); + l.MoveToFront(e); + checkListPointers(t, l, []*Element{ e }); + l.MoveToBack(e); + checkListPointers(t, l, []*Element{ e }); + l.Remove(e); + checkListPointers(t, l, []*Element{}); + + // Bigger list + e2 := l.PushFront(2); + e1 := l.PushFront(1); + e3 := l.PushBack(3); + e4 := l.PushBack("banana"); + checkListPointers(t, l, []*Element{ e1, e2, e3, e4 }); + + l.Remove(e2); + checkListPointers(t, l, []*Element{ e1, e3, e4 }); + + l.MoveToFront(e3); // move from middle + checkListPointers(t, l, []*Element{ e3, e1, e4 }); + + l.MoveToFront(e1); + l.MoveToBack(e3); // move from middle + checkListPointers(t, l, []*Element{ e1, e4, e3 }); + + l.MoveToFront(e3); // move from back + checkListPointers(t, l, []*Element{ e3, e1, e4 }); + l.MoveToFront(e3); // should be no-op + checkListPointers(t, l, []*Element{ e3, e1, e4 }); + + l.MoveToBack(e3); // move from front + checkListPointers(t, l, []*Element{ e1, e4, e3 }); + l.MoveToBack(e3); // should be no-op + checkListPointers(t, l, []*Element{ e1, e4, e3 }); + + // Clear all elements by iterating + for e := range l.Iter() { + l.Remove(e); + } + checkListPointers(t, l, []*Element{}); +}