diff --git a/arraylist/arraylist.go b/arraylist/arraylist.go new file mode 100644 index 0000000..4c601b0 --- /dev/null +++ b/arraylist/arraylist.go @@ -0,0 +1,249 @@ +package arraylist + +const defaultSize = 1024 + +var none interface{} + +type Element struct { + Value interface{} + + prev int + next int + + index int + + list *List +} + +func (e *Element) Next() *Element { + if e.next == 0 || e.Value == none || e.list == nil { + return nil + } + + return e.list.elems[e.next] +} + +func (e *Element) Prev() *Element { + if e.prev == 0 || e.Value == none || e.list == nil { + return nil + } + + return e.list.elems[e.prev] +} + +type List struct { + elems []*Element + + num int + + root *Element + + free int +} + +func New() *List { + return NewSize(defaultSize) +} + +func NewSize(size int) *List { + if size < defaultSize { + size = defaultSize + } + + l := new(List) + + l.elems = make([]*Element, size) + for i := range l.elems { + e := new(Element) + + e.list = l + e.index = i + e.next = i + 1 + if i+1 == len(l.elems) { + e.next = -1 + } + + l.elems[i] = e + } + + //use first for root + l.root = l.elems[0] + l.root.next = 0 + l.root.prev = 0 + + l.free = 1 + l.num = 0 + + return l +} + +func (l *List) Len() int { + return l.num +} + +func (l *List) Front() *Element { + if l.root.next == 0 { + return nil + } else { + return l.elems[l.root.next] + } +} + +func (l *List) Back() *Element { + if l.root.prev == 0 { + return nil + } else { + return l.elems[l.root.prev] + } +} + +func (l *List) remove(e *Element) *Element { + next := e.next + prev := e.prev + + l.elems[prev].next = next + l.elems[next].prev = prev + + e.next = -1 + e.prev = -1 + + l.num-- + + return e +} + +func (l *List) Remove(e *Element) interface{} { + if e.list != l { + return nil + } + + if e.next == -1 || e.prev == -1 { + return e.Value + } + + l.remove(e) + + v := e.Value + e.Value = none + + e.next = l.free + l.free = e.index + + return v +} + +func (l *List) getFreeElem() *Element { + if l.free == -1 { + //no free elements, create + num := len(l.elems) + + newElems := make([]*Element, 2*num) + for i := num; i < 2*num; i++ { + e := new(Element) + e.list = l + e.index = i + e.next = i + 1 + if i+1 == 2*num { + e.next = -1 + } + + newElems[i] = e + } + + l.free = num + + copy(newElems, l.elems) + + l.elems = newElems + } + + n := l.free + l.free = l.elems[n].next + + return l.elems[n] +} + +func (l *List) insert(e *Element, index int) *Element { + at := l.elems[index] + n := at.next + at.next = e.index + e.prev = at.index + e.next = n + l.elems[n].prev = e.index + e.list = l + l.num++ + return e +} + +func (l *List) insertValue(v interface{}, index int) *Element { + e := l.getFreeElem() + e.Value = v + + return l.insert(e, index) +} + +func (l *List) PushFront(v interface{}) *Element { + return l.insertValue(v, l.root.index) +} + +func (l *List) PushBack(v interface{}) *Element { + return l.insertValue(v, l.root.prev) +} + +func (l *List) InsertBefore(v interface{}, mark *Element) *Element { + if mark.list != l { + return nil + } + + return l.insertValue(v, mark.prev) +} + +func (l *List) InsertAfter(v interface{}, mark *Element) *Element { + if mark.list != l { + return nil + } + + return l.insertValue(v, mark.index) +} + +func (l *List) MoveToFront(e *Element) { + if e.list != l || l.root.next == e.index { + return + } + + l.insert(l.remove(e), l.root.index) +} + +func (l *List) MoveToBack(e *Element) { + if e.list != l || l.root.prev == e.index { + return + } + l.insert(l.remove(e), l.root.prev) +} + +func (l *List) MoveBefore(e, mark *Element) { + if e.list != l || e == mark { + return + } + + l.insert(l.remove(e), mark.prev) +} + +func (l *List) MoveAfter(e, mark *Element) { + if e.list != l || e == mark { + return + } + l.insert(l.remove(e), mark.index) +} + +func (l *List) PushBackList(other *List) { + for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { + l.insertValue(e.Value, l.root.prev) + } +} + +func (l *List) PushFrontList(other *List) { + for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { + l.insertValue(e.Value, l.root.index) + } +} diff --git a/arraylist/arraylist_test.go b/arraylist/arraylist_test.go new file mode 100644 index 0000000..598fc58 --- /dev/null +++ b/arraylist/arraylist_test.go @@ -0,0 +1,307 @@ +package arraylist + +import ( + "reflect" + "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) { + + root := l.root + + if !checkListLen(t, l, len(es)) { + return + } + + // zero length lists must be the zero value or properly initialized (sentinel circle) + if len(es) == 0 { + if l.root.next != 0 && l.root.next != root.index || l.root.prev != 0 && l.root.prev != root.index { + t.Errorf("l.root.next = %d, l.root.prev = %d; both should both be 0 or %d", l.root.next, l.root.prev, root.index) + } + return + } + // len(es) > 0 + + e1 := []*Element{} + for e := l.Front(); e != nil; e = e.Next() { + e1 = append(e1, e) + } + + if !reflect.DeepEqual(e1, es) { + t.Fatal("front not equal") + } + + e2 := []*Element{} + for e := l.Back(); e != nil; e = e.Prev() { + e2 = append([]*Element{e}, e2...) + } + + if !reflect.DeepEqual(e2, es) { + t.Fatal("front not equal") + } + + // check internal and external prev/next connections + for i, e := range es { + prev := root + Prev := (*Element)(nil) + if i > 0 { + prev = es[i-1] + Prev = prev + } + if p := e.prev; p != prev.index { + 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 { + next = es[i+1] + Next = next + } + if n := e.next; n != next.index { + t.Errorf("elt[%d](%p).next = %p, want %p", i, e, n, next) + } + if n := e.Next(); n != Next { + t.Errorf("elt[%d](%p).Next() = %p, want %p", i, e, n, 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}) + + e2 = l.InsertBefore(2, e1) // insert before front + checkListPointers(t, l, []*Element{e2, e1, e4, e3}) + l.Remove(e2) + e2 = l.InsertBefore(2, e4) // insert before middle + checkListPointers(t, l, []*Element{e1, e2, e4, e3}) + l.Remove(e2) + e2 = l.InsertBefore(2, e3) // insert before back + checkListPointers(t, l, []*Element{e1, e4, e2, e3}) + l.Remove(e2) + + e2 = l.InsertAfter(2, e1) // insert after front + checkListPointers(t, l, []*Element{e1, e2, e4, e3}) + l.Remove(e2) + e2 = l.InsertAfter(2, e4) // insert after middle + checkListPointers(t, l, []*Element{e1, e4, e2, e3}) + l.Remove(e2) + e2 = l.InsertAfter(2, e3) // insert after back + checkListPointers(t, l, []*Element{e1, e4, e3, e2}) + l.Remove(e2) + + // Check standard iteration. + sum := 0 + for e := l.Front(); e != nil; e = e.Next() { + if i, ok := e.Value.(int); ok { + sum += i + } + } + if sum != 4 { + t.Errorf("sum over l = %d, want 4", sum) + } + + // Clear all elements by iterating + var next *Element + for e := l.Front(); e != nil; e = next { + next = e.Next() + l.Remove(e) + } + checkListPointers(t, l, []*Element{}) +} + +func checkList(t *testing.T, l *List, es []interface{}) { + 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].Value = %v, want %v", i, le, es[i]) + } + i++ + } +} + +func TestExtending(t *testing.T) { + l1 := New() + l2 := New() + + l1.PushBack(1) + l1.PushBack(2) + l1.PushBack(3) + + l2.PushBack(4) + l2.PushBack(5) + + l3 := New() + l3.PushBackList(l1) + checkList(t, l3, []interface{}{1, 2, 3}) + l3.PushBackList(l2) + checkList(t, l3, []interface{}{1, 2, 3, 4, 5}) + + l3 = New() + l3.PushFrontList(l2) + checkList(t, l3, []interface{}{4, 5}) + l3.PushFrontList(l1) + checkList(t, l3, []interface{}{1, 2, 3, 4, 5}) + + checkList(t, l1, []interface{}{1, 2, 3}) + checkList(t, l2, []interface{}{4, 5}) + + l3 = New() + l3.PushBackList(l1) + checkList(t, l3, []interface{}{1, 2, 3}) + l3.PushBackList(l3) + checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3}) + + l3 = New() + l3.PushFrontList(l1) + checkList(t, l3, []interface{}{1, 2, 3}) + l3.PushFrontList(l3) + checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3}) + + l3 = New() + l1.PushBackList(l3) + checkList(t, l1, []interface{}{1, 2, 3}) + l1.PushFrontList(l3) + 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}) + l.Remove(e) + checkListPointers(t, l, []*Element{e2}) +} + +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) + } +} + +func TestIssue6349(t *testing.T) { + l := New() + l.PushBack(1) + l.PushBack(2) + + e := l.Front() + v := l.Remove(e) + + if v != 1 { + t.Errorf("e.value = %d, want 1", e.Value) + } + + if e.Next() != nil { + t.Errorf("e.Next() != nil") + } + if e.Prev() != nil { + t.Errorf("e.Prev() != nil") + } +} + +func TestMove(t *testing.T) { + l := New() + e1 := l.PushBack(1) + e2 := l.PushBack(2) + e3 := l.PushBack(3) + e4 := l.PushBack(4) + + l.MoveAfter(e3, e3) + checkListPointers(t, l, []*Element{e1, e2, e3, e4}) + l.MoveBefore(e2, e2) + checkListPointers(t, l, []*Element{e1, e2, e3, e4}) + + l.MoveAfter(e3, e2) + checkListPointers(t, l, []*Element{e1, e2, e3, e4}) + l.MoveBefore(e2, e3) + checkListPointers(t, l, []*Element{e1, e2, e3, e4}) + + l.MoveBefore(e2, e4) + checkListPointers(t, l, []*Element{e1, e3, e2, e4}) + e1, e2, e3, e4 = e1, e3, e2, e4 + + l.MoveBefore(e4, e1) + checkListPointers(t, l, []*Element{e4, e1, e2, e3}) + e1, e2, e3, e4 = e4, e1, e2, e3 + + l.MoveAfter(e4, e1) + checkListPointers(t, l, []*Element{e1, e4, e2, e3}) + e1, e2, e3, e4 = e1, e4, e2, e3 + + l.MoveAfter(e2, e3) + checkListPointers(t, l, []*Element{e1, e3, e2, e4}) + e1, e2, e3, e4 = e1, e3, e2, e4 +}