From 4dd167350fd4c27970fc09622572706bfa9ee07f Mon Sep 17 00:00:00 2001 From: lrleon Date: Sat, 20 Mar 2021 13:57:14 -0500 Subject: [PATCH] First operating version compatible with functional library --- .idea/.gitignore | 8 ++ go.mod | 5 ++ slist.go | 209 +++++++++++++++++++++++++++++++++++++++++++++++ slist_test.go | 69 ++++++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 go.mod create mode 100644 slist.go create mode 100644 slist_test.go diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..43d310d --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/geniussportsgroup/Slist + +go 1.15 + +require github.com/stretchr/testify v1.7.0 diff --git a/slist.go b/slist.go new file mode 100644 index 0000000..09517a6 --- /dev/null +++ b/slist.go @@ -0,0 +1,209 @@ +package Slist + +type Snode struct { + item interface{} + next *Snode +} + +func NilSnode() *Snode { + return nil +} + +type Slist struct { + head *Snode + tail *Snode +} + +// Swap in O(1) two sequences +func (seq *Slist) Swap(rhs interface{}) interface{} { + + other := rhs.(*Slist) + seq.head, other.head = other.head, seq.head + seq.tail, other.tail = other.tail, seq.tail + + return seq +} + +// Create a new sequence with the received items +func New(items ...interface{}) *Slist { + + seq := new(Slist) + for _, item := range items { + seq.Append(item) + } + return seq +} + +// Return true if sequence is empty +func (seq *Slist) IsEmpty() bool { + + return seq.head == nil && seq.tail == nil // double check! +} + +func (seq *Slist) __append(item interface{}) *Slist { + + ptr := new(Snode) + ptr.item = item + if seq.IsEmpty() { + seq.head = ptr + seq.tail = ptr + return seq + } + + seq.tail.next = ptr + seq.tail = ptr + return seq +} + +// Append the received items at the end of the sequence +func (seq *Slist) Append(item interface{}, items ...interface{}) interface{} { + + result := seq.__append(item) + for _, i := range items { + result.__append(i) + } + return result +} + +func (seq *Slist) __insert(item interface{}) *Slist { + + ptr := new(Snode) + ptr.item = item + if seq.IsEmpty() { + seq.head = ptr + seq.tail = ptr + return seq + } + + ptr.next = seq.head + seq.head = ptr + return seq +} + +// Insert at the beginning of the sequence all the received items (in the given order) +func (seq *Slist) Insert(item interface{}, items ...interface{}) *Slist { + + result := seq.__insert(item) + for _, i := range items { + result.__insert(i) + } + return result +} + +// Remove the first item of the sequence +func (seq *Slist) RemoveFirst() interface{} { + + if seq.IsEmpty() { + return nil + } + + ret := seq.head.item + seq.head = seq.head.next + if seq.head == nil { // list became empty? + seq.tail = nil + } + return ret +} + +func (seq *Slist) First() interface{} { + + if seq == nil { + return nil + } + return seq.head.item +} + +func (seq *Slist) Last() interface{} { + if seq == nil { + return nil + } + return seq.tail.item +} + +func (seq *Slist) Empty() *Slist { + seq.head = nil + seq.tail = nil + return seq +} + +// Append in O(1) l to list_ptr and destroys l +func (seq *Slist) staticAppendList(l *Slist) *Slist { + + if l.IsEmpty() { + return seq + } + + if seq.IsEmpty() { + return seq.Swap(l).(*Slist) + } + + seq.tail.next = l.head + seq.tail = l.tail + l.head = nil + l.tail = nil + + return seq +} + +func (seq *Slist) AppendList(l *Slist, ln ...*Slist) *Slist { + seq.staticAppendList(l) + for _, ll := range ln { + seq.staticAppendList(ll) + } + return seq +} + +type Iterator struct { + listPtr *Slist + curr *Snode +} + +func NewIterator(seq *Slist) *Iterator { + it := new(Iterator) + it.listPtr = seq + it.curr = seq.head + return it +} + +func (it *Iterator) HasCurr() bool { + return it.curr != nil +} + +func (it *Iterator) IsLast() bool { + return it.curr == it.listPtr.tail +} + +func (it *Iterator) GetCurr() interface{} { + if it.curr == nil { + return nil + } + return it.curr.item +} + +func (it *Iterator) Next() interface{} { + it.curr = it.curr.next + if it.curr == nil { + return nil + } + return it.curr.item +} + +func (seq *Slist) Size() int { + + n := 0 + for it := NewIterator(seq); it.HasCurr(); it.Next() { + n++ + } + return n +} + +func (seq *Slist) Traverse(operation func(key interface{}) bool) bool { + + for it := NewIterator(seq); it.HasCurr(); it.Next() { + if !operation(it.GetCurr()) { + return false + } + } + + return true +} diff --git a/slist_test.go b/slist_test.go new file mode 100644 index 0000000..46d437f --- /dev/null +++ b/slist_test.go @@ -0,0 +1,69 @@ +package Slist + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestNew(t *testing.T) { + + l := New() + + assert.Equal(t, l.Size(), 0) + + l1 := New(1, 2, 3) + + assert.Equal(t, l1.Size(), 3) +} + +func TestSlist_Swap(t *testing.T) { + + l0 := New() + lpos := New(1, 2, 3, 4, 5) + lneg := New(-5, -4, -3, -2, -1) + + result := l0.Swap(lpos) // test empty swap non-empty + assert.Equal(t, l0.Size(), 5) + assert.Equal(t, result, l0) + assert.Equal(t, lpos.Size(), 0) + + result = l0.Swap(lpos) // test non-empty swap empty + assert.Equal(t, l0.Size(), 0) + assert.Equal(t, lpos.Size(), 5) + assert.Equal(t, result, l0) + + result = lpos.Swap(lneg) + assert.Equal(t, lpos.Size(), 5) + assert.Equal(t, lneg.Size(), 5) + assert.Equal(t, result, lpos) + + assert.True(t, lpos.Traverse(func(key interface{}) bool { + return key.(int) >= -5 && key.(int) <= -1 + })) + + assert.True(t, lneg.Traverse(func(key interface{}) bool { + return key.(int) >= 1 && key.(int) <= 5 + })) +} + +func Test_misc(t *testing.T) { + + l := New(1, 2, 3) + + assert.Equal(t, l.First().(int), 1) + assert.Equal(t, l.Last().(int), 3) +} + +func TestSlist_RemoveFirst(t *testing.T) { + + assert.Nil(t, New().RemoveFirst()) + + l := New(1, 2, 3) + + for i := 1; !l.IsEmpty(); i++ { + item := l.RemoveFirst() + assert.NotNil(t, item) + assert.Equal(t, item.(int), i) + assert.LessOrEqual(t, i, 3) + } +}