diff --git a/collections/ArrayList.go b/collections/ArrayList.go new file mode 100644 index 0000000..e61c27b --- /dev/null +++ b/collections/ArrayList.go @@ -0,0 +1,129 @@ +package collections + +import "collections/exceptions" + +type ArrayList struct { + array []interface{} + used uint32 +} + +func NewArrayList() *ArrayList { + return &ArrayList{ + make([]interface{}, 16), + 0, + } +} + +func (a ArrayList) Iterator() Iterator { + return a.MutableIterator() +} + +func (a ArrayList) Size() uint32 { + return a.used +} + +func (a ArrayList) IsEmpty() bool { + return a.Size() == 0 +} + +func (a ArrayList) Contains(element interface{}) bool { + return Contains(a, element) +} + +func (a ArrayList) ContainsAll(c Collection) bool { + return ContainsAll(a, c) +} + +func (a *ArrayList) MutableIterator() MutableIterator { + panic("implement me") +} + +func (a *ArrayList) Add(element interface{}) bool { + if a.used >= uint32(len(a.array)) { + oldArray := a.array + a.array = make([]interface{}, a.used*2) + copy(a.array, oldArray) + } + a.array[a.used] = element + a.used++ + return true +} + +func (a ArrayList) IndexOf(element interface{}) int { + var i uint32 = 0 + for ; i < a.used; i++ { + if a.array[i] == element { + return int(i) + } + } + return -1 +} + +func (a *ArrayList) RemoveIndex(index uint32) error { + if index >= a.used { + return exceptions.NewIndexOutOfBound("", true) + } + + array := a.array + for i := index + 1; i < a.used; i++ { + array[index-1] = array[index] + } + return nil +} + +func (a *ArrayList) Remove(element interface{}) error { + index := a.IndexOf(element) + if index < 0 { + return exceptions.NewElementNotFoundException("", true) + } else { + return a.RemoveIndex(uint32(index)) + } +} + +func (a *ArrayList) AddAll(c Collection) bool { + return AddAll(a, c) +} + +func (a *ArrayList) RemoveAll(c Collection) bool { + return RemoveAll(a, c) +} + +func (a *ArrayList) RetainAll(c Collection) bool { + return RetainAll(a, c) +} + +func (a *ArrayList) Clear() { + a.used = 0 +} + +func (a ArrayList) Get(index uint32) (interface{}, error) { + if index >= a.used { + return nil, exceptions.NewIndexOutOfBound("", true) + } else { + return a.array[index], nil + } +} + +func (a ArrayList) SubList(from, to uint32) List { + return NewSubList(a, from, to) +} + +func (a *ArrayList) Set(index uint32, element interface{}) error { + if index >= a.used { + return exceptions.NewIndexOutOfBound("", true) + } + a.array[index] = element + return nil +} + +func (a *ArrayList) AddAtIndex(index uint32, element interface{}) bool { + panic("implement me") +} + +func (a *ArrayList) RemoveAt(index uint32) bool { + panic("implement me") +} + +func (a *ArrayList) SubMutableList(from, to uint32) MutableList { + panic("implement me") +} diff --git a/collections/Collection.go b/collections/Collection.go index fd68910..badd284 100644 --- a/collections/Collection.go +++ b/collections/Collection.go @@ -24,7 +24,7 @@ type ( MutableIterator() MutableIterator Add(element interface{}) bool - Remove(element interface{}) bool + Remove(element interface{}) error AddAll(c Collection) bool RemoveAll(c Collection) bool RetainAll(c Collection) bool @@ -51,7 +51,7 @@ type ( MutableIterator() MutableIterator Add(element interface{}) bool - Remove(element interface{}) bool + Remove(element interface{}) error AddAll(c Collection) bool RemoveAll(c Collection) bool RetainAll(c Collection) bool @@ -60,7 +60,7 @@ type ( Get(index uint32) (interface{}, error) SubList(from, to uint32) List - Set(index uint32, element interface{}) bool + Set(index uint32, element interface{}) error AddAtIndex(index uint32, element interface{}) bool RemoveAt(index uint32) bool SubMutableList(from, to uint32) MutableList @@ -97,10 +97,7 @@ func AddAll(l MutableCollection, collection Collection) bool { func RemoveAll(l MutableCollection, collection Collection) bool { return Loop(collection, func(e interface{}) error { - if !l.Remove(e) { - return exceptions.CollectionLoopFinished - } - return nil + return l.Remove(e) }) == nil } @@ -122,11 +119,11 @@ func String(l List) string { builder := strings.Builder{} builder.WriteString("[") iterator := l.Iterator() - next := iterator.Next() + next, _ := iterator.Next() builder.WriteString(fmt.Sprint(next)) for iterator.HasNext() { builder.WriteString(", ") - next = iterator.Next() + next, _ = iterator.Next() builder.WriteString(fmt.Sprint(next)) } builder.WriteString("]") diff --git a/collections/Iterable.go b/collections/Iterable.go index 50bae8b..409e621 100644 --- a/collections/Iterable.go +++ b/collections/Iterable.go @@ -2,7 +2,7 @@ package collections type Iterator interface { HasNext() bool - Next() interface{} + Next() (interface{}, error) } type Iterable interface { @@ -11,7 +11,7 @@ type Iterable interface { type MutableIterator interface { HasNext() bool - Next() interface{} + Next() (interface{}, error) Remove() bool } @@ -26,7 +26,11 @@ func Loop(iterable Iterable, f func(element interface{}) error) error { } iterator := iterable.Iterator() for iterator.HasNext() { - err := f(iterator.Next()) + next, err := iterator.Next() + if err != nil { + return err + } + err = f(next) if err != nil { return err } @@ -40,7 +44,11 @@ func LoopMutable(iterable MutableIterable, f func(element interface{}, iterator } iterator := iterable.MutableIterator() for iterator.HasNext() { - err := f(iterator.Next(), iterator) + next, err := iterator.Next() + if err != nil { + return err + } + err = f(next, iterator) if err != nil { return err } diff --git a/collections/LinkedList.go b/collections/LinkedList.go index 8ad0a0e..a66443e 100644 --- a/collections/LinkedList.go +++ b/collections/LinkedList.go @@ -50,14 +50,19 @@ func (l *LinkedList) Add(element interface{}) bool { return true } -func (l *LinkedList) Remove(element interface{}) bool { - return LoopMutable(l, func(e interface{}, iterator MutableIterator) error { +func (l *LinkedList) Remove(element interface{}) error { + err := LoopMutable(l, func(e interface{}, iterator MutableIterator) error { if element == e { iterator.Remove() return exceptions.CollectionLoopFinished } return nil - }) != nil + }) + if err != nil { + return nil + } else { + return exceptions.NewElementNotFoundException("", true) + } } func (l *LinkedList) AddAll(c Collection) bool { @@ -81,16 +86,16 @@ func (l LinkedList) SubList(from, to uint32) List { return NewSubList(l, from, to) } -func (l *LinkedList) Set(index uint32, element interface{}) bool { +func (l *LinkedList) Set(index uint32, element interface{}) error { node := l.head for node != l.head { if index == 0 { node.value = element - return true + return nil } index-- } - return false + return exceptions.NewIndexOutOfBound("", true) } func (l *LinkedList) AddAtIndex(index uint32, element interface{}) bool { @@ -153,12 +158,12 @@ func (l *linkedListIterator) HasNext() bool { return l.node != l.head } -func (l *linkedListIterator) Next() interface{} { +func (l *linkedListIterator) Next() (interface{}, error) { if l.node == l.head { - panic("iterator loop finished") + return nil, exceptions.NewIndexOutOfBound("", true) } l.node = l.node.next - return l.node.prev.value + return l.node.prev.value, nil } func (l *linkedListIterator) Remove() bool { diff --git a/collections/MutableSubList.go b/collections/MutableSubList.go index 944cdc7..0a48c69 100644 --- a/collections/MutableSubList.go +++ b/collections/MutableSubList.go @@ -1,5 +1,7 @@ package collections +import "collections/exceptions" + type MutableSubList struct { list MutableList from, to uint32 @@ -12,7 +14,10 @@ func NewMutableSubList(list MutableList, from, to uint32) *MutableSubList { func (s *MutableSubList) Iterator() Iterator { iterator := s.list.Iterator() for i := 0; i < int(s.from); i++ { - iterator.Next() + _, err := iterator.Next() + if err != nil { + return nil + } } return iterator } @@ -45,41 +50,41 @@ func (s *MutableSubList) MutableIterator() MutableIterator { return nil } -func (s *MutableSubList) Add(element interface{}) bool { +func (s *MutableSubList) Add(_ interface{}) bool { return false } -func (s *MutableSubList) Remove(element interface{}) bool { +func (s *MutableSubList) Remove(element interface{}) error { + return nil +} + +func (s *MutableSubList) AddAll(_ Collection) bool { return false } -func (s *MutableSubList) AddAll(c Collection) bool { +func (s *MutableSubList) RemoveAll(_ Collection) bool { return false } -func (s *MutableSubList) RemoveAll(c Collection) bool { - return false -} - -func (s *MutableSubList) RetainAll(c Collection) bool { +func (s *MutableSubList) RetainAll(_ Collection) bool { return false } func (s *MutableSubList) Clear() { } -func (s *MutableSubList) Set(index uint32, element interface{}) bool { +func (s *MutableSubList) Set(index uint32, element interface{}) error { if index >= s.to-s.from { - return false + return exceptions.NewIndexOutOfBound("", true) } return s.list.Set(index+s.from, element) } -func (s *MutableSubList) AddAtIndex(index uint32, element interface{}) bool { +func (s *MutableSubList) AddAtIndex(_ uint32, _ interface{}) bool { return false } -func (s *MutableSubList) RemoveAt(index uint32) bool { +func (s *MutableSubList) RemoveAt(_ uint32) bool { return false } diff --git a/collections/SubList.go b/collections/SubList.go index 7ccec9e..061e88a 100644 --- a/collections/SubList.go +++ b/collections/SubList.go @@ -12,7 +12,10 @@ func NewSubList(list List, from, to uint32) *SubList { func (s *SubList) Iterator() Iterator { iterator := s.list.Iterator() for i := 0; i < int(s.from); i++ { - iterator.Next() + _, err := iterator.Next() + if err != nil { + return nil + } } return iterator } diff --git a/exceptions/ElementNotFound.go b/exceptions/ElementNotFound.go new file mode 100644 index 0000000..a2753d7 --- /dev/null +++ b/exceptions/ElementNotFound.go @@ -0,0 +1,42 @@ +package exceptions + +import ( + "io" + "os" +) + +type ElementNotFoundException struct { + message string + stackTrace []StackTrace +} + +func NewElementNotFoundException(message string, getStackTrace bool) *ElementNotFoundException { + var stackTrace []StackTrace = nil + if getStackTrace { + stackTrace = GetStackTrace() + } + return &ElementNotFoundException{ + message: message, + stackTrace: stackTrace, + } +} + +func (e ElementNotFoundException) Error() string { + if len(e.message) == 0 { + return "element not found" + } else { + return e.message + } +} + +func (e ElementNotFoundException) StackTrace() []StackTrace { + return e.stackTrace +} + +func (e ElementNotFoundException) PrintStackTrace() { + e.PrintStackTraceTo(os.Stderr) +} + +func (e ElementNotFoundException) PrintStackTraceTo(writer io.Writer) { + PrintStackTrace(writer, e, "exception caused ElementNotFoundException:") +} diff --git a/exceptions/Exception.go b/exceptions/Exception.go index a4fa626..fbcab98 100644 --- a/exceptions/Exception.go +++ b/exceptions/Exception.go @@ -1,6 +1,9 @@ package exceptions -import "io" +import ( + "fmt" + "io" +) type Exception interface { Error() string @@ -8,3 +11,29 @@ type Exception interface { PrintStackTrace() PrintStackTraceTo(writer io.Writer) } + +func PrintStackTrace(writer io.Writer, e Exception, exceptionMsg string) { + _, err := fmt.Fprintln(writer, exceptionMsg, e.Error()) + if err != nil { + return + } + if e.StackTrace() == nil { + return + } + for _, stackTrace := range e.StackTrace() { + stackTrace.PrintLn(writer) + } +} + +func Try(f func() (interface{}, error), catch func(interface{}) interface{}) (ret interface{}) { + defer func() { + if r := recover(); r != nil { + ret = catch(r) + } + }() + ret, err := f() + if err != nil { + ret = catch(err) + } + return +} diff --git a/exceptions/IndexOutOfBoundError.go b/exceptions/IndexOutOfBoundError.go index 1fcc4d1..f613ad4 100644 --- a/exceptions/IndexOutOfBoundError.go +++ b/exceptions/IndexOutOfBoundError.go @@ -1,7 +1,6 @@ package exceptions import ( - "fmt" "io" "os" ) @@ -31,16 +30,7 @@ func (i IndexOutOfBound) PrintStackTrace() { } func (i IndexOutOfBound) PrintStackTraceTo(writer io.Writer) { - _, err := fmt.Fprintln(writer, "exception caused IndexOutOfBound:", i.Error()) - if err != nil { - return - } - if i.stackTrace == nil { - return - } - for _, stackTrace := range i.stackTrace { - stackTrace.PrintLn(writer) - } + PrintStackTrace(writer, i, "exception caused IndexOutOfBound:") } func (i IndexOutOfBound) Error() string { diff --git a/main.go b/main.go index a0cc799..db4635a 100644 --- a/main.go +++ b/main.go @@ -2,10 +2,18 @@ package main import ( "collections/collections" + "collections/exceptions" "fmt" ) func main() { + fmt.Println(exceptions.Try(func() (interface{}, error) { + panic("test") + }, func(r interface{}) interface{} { + fmt.Println("recover from panic", r) + return exceptions.NewIndexOutOfBound("", true) + })) + list := collections.NewLinkedList() fmt.Println(list) for i := 0; i < 20; i++ {