diff --git a/cmd/ll/main.go b/cmd/ll/main.go index 198db3e..cda6c48 100644 --- a/cmd/ll/main.go +++ b/cmd/ll/main.go @@ -2,13 +2,28 @@ package main import ( "fmt" - "github.com/mojosa-software/godat/llx" + "github.com/reklesio/gods/lists" ) func main() { - ll := llx.New[string]("zero", "one", "two", "three", "four", "five") - ll.Push("-one", "-two") + list := lists.NewSingly[string]("zero", "one", "two", "three", "four", "five") + fmt.Println(list) + list.Push("-one", "-two") + fmt.Println(list) - ll.Swap(0, 2) - fmt.Println(ll.Slice()) + list.Swap(0, 2) + fmt.Println(list) + + intList := lists.NewSingly[int](100, 5, -1, 1000, 200, 1337) + fmt.Println(intList) + + intList.Sort(func(vi, vj int) bool { + return vi < vj + }) + fmt.Println(intList) + + intList.Sort(func(vi, vj int) bool { + return vj < vi + }) + fmt.Println(intList) } diff --git a/container.go b/container.go new file mode 100644 index 0000000..7f45388 --- /dev/null +++ b/container.go @@ -0,0 +1,14 @@ +package gods + +// All the containers must implement the interface. +type Container[V any] interface { + Empty() bool + Size() int + Clear() + Values() []V + //String() string +} + +type Comparator[V any] interface { + Less(v1, v2 V) +} diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..293959f --- /dev/null +++ b/errors.go @@ -0,0 +1,10 @@ +package gods + +import ( + "errors" +) + +var ( + IndexRangeErr = errors.New("index out of range") +) + diff --git a/go.mod b/go.mod index 90a9c15..faf55be 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/mojosa-software/godat +module github.com/reklesio/gods go 1.19 diff --git a/lists/main.go b/lists/main.go new file mode 100644 index 0000000..b9371c4 --- /dev/null +++ b/lists/main.go @@ -0,0 +1,34 @@ +package lists + +import ( + "github.com/reklesio/gods" +) + +// The interface all the lists must implement. +type List[V any] interface { + gods.Container[V] + Push(...V) + // Get length of the list + Len() int + // Get the value by index. + Get(int) V + // Delete the value by index. + Del(int) + // Change already existing value. + Set(int, V) + // Add the values + Add(...V) + + // Insert the value before the specifed index. + InsB(V, int) + // Insert the value after the specified index. + InsA(int, V) + + // Swap elements by indexes specified in arguments. + Swap(i, j int) + + // The sort function that gets the Less function as argument + // and sorts the list corresponding to it. + Sort(gods.LessFunc[V]) +} + diff --git a/llx/main.go b/lists/single.go similarity index 52% rename from llx/main.go rename to lists/single.go index 1a6bbf8..3d130b6 100644 --- a/llx/main.go +++ b/lists/single.go @@ -1,111 +1,111 @@ -package llx +package lists + +import ( + "github.com/reklesio/gods" + "sort" + "fmt" +) // Linked list X . // The package implements better variation of // linked list than in standard library since it uses // the new conception of generics. -// The type represents linked list data structure. -type LinkedList[V any] struct { +// The type represents singly linked list data structure. +type sLinkedList[V any] struct { // First empty element (not used to store values). // For fast pushing. - before *Element[V] + before *sElement[V] // Points to the last for fast appending. - last *Element[V] + last *sElement[V] // Length. ln int } // The type represents element of the linked list. -type Element[V any] struct { - next *Element[V] +type sElement[V any] struct { + next *sElement[V] value V } -// Returns new empty linked list storing the V type. -func New[V any](values ...V) *LinkedList[V] { - ret := &LinkedList[V]{ - &Element[V]{}, - nil, - 0, +func newSingly[V any](values ...V) *sLinkedList[V] { + ret := &sLinkedList[V]{ + before: &sElement[V]{}, + last: nil, + ln: 0, } - ret.Append(values...) + ret.Add(values...) return ret } -// Get length of the linked list. -func (ll *LinkedList[V]) Length() int { +// Returns new empty linked list storing the V type. +func NewSingly[V any](values ...V) List[V] { + return newSingly[V](values...) +} + +func (ll *sLinkedList[V]) Empty() bool { + return ll == nil +} + +func (ll *sLinkedList[V]) Size() int { return ll.ln } -func (ll *LinkedList[V]) Len() int { - return ll.Length() +func (ll *sLinkedList[V]) Clear() { + buf := newSingly[V]() + *ll = *buf } +func (ll *sLinkedList[V]) Len() int { + return ll.ln +} + + // Get the index-indexed element itself. -func (ll *LinkedList[V]) GetEl(index int) (*Element[V], bool) { - if ll.ln <= index { - return nil, false +func (ll *sLinkedList[V]) getEl(index int) *sElement[V] { + if ll.ln <= index || index < 0 { + panic(gods.IndexRangeErr) } p := ll.before for i := 0 ; i <= index ; i++ { p = p.next } - return p, true + return p } // Get the value of index-indexed element. -func (ll *LinkedList[V]) Get(index int) (V, bool) { - el, ok := ll.GetEl(index) - var v V - if ok { - v = el.value - } - - return v, ok +func (ll *sLinkedList[V]) Get(index int) V { + return ll.getEl(index).value } // Set the new value in i-indexed element. -func (ll *LinkedList[V]) Set(i int, v V) (bool) { - el, ok := ll.GetEl(i) - if !ok { - return false - } - +func (ll *sLinkedList[V]) Set(i int, v V) { + el := ll.getEl(i) el.value = v - return true } // Insert the V value before the i-th element. -func (ll *LinkedList[V]) InsertBefore(v V, i int) { +func (ll *sLinkedList[V]) InsB(v V, i int) { if i == 0 { - ll.before = &Element[V]{ + ll.before = &sElement[V]{ value: v, next: ll.before.next, } return } - el, ok := ll.GetEl(i-1) - if !ok { - panic("index out of range") - } - - el.next = &Element[V]{ + el := ll.getEl(i-1) + el.next = &sElement[V]{ value: v, next: el.next, } } // Insert the V value after the i-th element. -func (ll *LinkedList[V]) InsertAfter(i int, v V) { - el, ok := ll.GetEl(i) - if !ok { - panic("index out of range") - } - - el.next = &Element[V]{ +func (ll *sLinkedList[V]) InsA(i int, v V) { + el := ll.getEl(i) + el.next = &sElement[V]{ value: v, next: el.next, } @@ -113,29 +113,20 @@ func (ll *LinkedList[V]) InsertAfter(i int, v V) { // Swap element values indexed by i1 and i2. // Panic on "index out of range". -func (ll *LinkedList[V]) Swap(i1, i2 int) { +func (ll *sLinkedList[V]) Swap(i1, i2 int) { if i1 == i2 { return } - max := ll.ln - 1 - if i1 < 0 || i2 < 0 || i1 > max || i2 > max { - panic("index out of range") - } - - el1, _ := ll.GetEl(i1) - el2, _ := ll.GetEl(i2) + el1 := ll.getEl(i1) + el2 := ll.getEl(i2) el1.value, el2.value = el2.value, el1.value } // Deletes the element by its index. -func (ll *LinkedList[V]) Delete(i int) { - if ll.ln <= i && i < 0 { - panic("index out of range") - } - +func (ll *sLinkedList[V]) Del(i int) { if i == 0 { ll.before.next = ll.before.next.next @@ -143,33 +134,28 @@ func (ll *LinkedList[V]) Delete(i int) { return } - el1, _ := ll.GetEl(i-1) + el1 := ll.getEl(i-1) if i == ll.ln - 1 { el1.next = nil } else { - el2, _ := ll.GetEl(i+1) + el2 := ll.getEl(i+1) el1.next = el2 } ll.ln-- } -// Alias to Delete method. -func (ll *LinkedList[V]) Del(i int) { - ll.Delete(i) -} - // Push in the beginning of the list. -func (ll *LinkedList[V]) Push(values ...V) { +func (ll *sLinkedList[V]) Push(values ...V) { for _, value := range values { ll.push(value) } } // Push in the beginning of the list. -func (ll *LinkedList[V]) push(v V) { +func (ll *sLinkedList[V]) push(v V) { prevNext := ll.before.next - nextNext := &Element[V]{ + nextNext := &sElement[V]{ next: prevNext, value: v, } @@ -182,19 +168,19 @@ func (ll *LinkedList[V]) push(v V) { } // Append to the end of the list. -func (ll *LinkedList[V]) Append(values ...V) { +func (ll *sLinkedList[V]) Add(values ...V) { for _, value := range values { ll.gappend(value) } } -func (ll *LinkedList[V]) gappend(v V) { +func (ll *sLinkedList[V]) gappend(v V) { if ll.ln == 0 { ll.Push(v) return } - last := &Element[V]{ + last := &sElement[V]{ next: nil, value: v, } @@ -207,28 +193,28 @@ func (ll *LinkedList[V]) gappend(v V) { } // Returns the first element of the linked list. -func (ll *LinkedList[V]) First() *Element[V] { +func (ll *sLinkedList[V]) First() *sElement[V] { return ll.before.next } // Get elements value. -func (ll *Element[V]) Value() V { +func (ll *sElement[V]) Value() V { return ll.value } // Returns the next element. If the returned value == nil, // then it is the last element. -func (ll *Element[V]) Next() *Element[V] { +func (ll *sElement[V]) Next() *sElement[V] { return ll.next } // Returns the last element. -func (ll *LinkedList[V]) Last() *Element[V] { +func (ll *sLinkedList[V]) Last() *sElement[V] { return ll.last } // Returns a channel with values ordered as in list. -func (ll *LinkedList[V]) Chan() chan V { +func (ll *sLinkedList[V]) Chan() chan V { chn := make(chan V) go func(){ el := ll.before @@ -242,19 +228,27 @@ func (ll *LinkedList[V]) Chan() chan V { } // Returns slice of values in the list ordered as in the list. -func (ll *LinkedList[V]) Slice() []V { - buf := make([]V, ll.Length()) - chn := ll.Chan() - +func (ll *sLinkedList[V]) Values() []V { + buf := make([]V, ll.Len()) i := 0 - for v := range chn { - buf[i] = v + el := ll.before + for el.next != nil { + el = el.next + buf[i] = el.value i++ } return buf } -func (ll *LinkedList[V]) Sort() { +func (ll *sLinkedList[V]) String() string { + return fmt.Sprintf("%v", ll.Values()) +} + +func (ll *sLinkedList[V]) Sort(fn gods.LessFunc[V]) { + sort.Sort(gods.CustomSort[V]{ + CustomSorter: ll, + LessFunc: fn, + }) } diff --git a/media/gopher.png b/media/gopher.png new file mode 100644 index 0000000..56289f4 Binary files /dev/null and b/media/gopher.png differ diff --git a/mkconfig b/mkconfig deleted file mode 100644 index 175c4f3..0000000 --- a/mkconfig +++ /dev/null @@ -1,5 +0,0 @@ -MKSHELL = sh -<$(MKINCDIR)/config -WATCH_FILES = src tmpl -CC = cc - diff --git a/mkfile b/mkfile deleted file mode 100644 index 5911453..0000000 --- a/mkfile +++ /dev/null @@ -1,7 +0,0 @@ -all: build -build:V: - go build -o ./exe/ ./cmd/... - -clean:V: - rm -f ./exe/* - diff --git a/readme b/readme deleted file mode 100644 index 178ce68..0000000 --- a/readme +++ /dev/null @@ -1,8 +0,0 @@ -# godat - -Golang custom data structures for specific purposes. - -- Linked list: llx -- List: listx -- Sparse array: sparsex - diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..3c3a994 --- /dev/null +++ b/readme.md @@ -0,0 +1,10 @@ +# Gods + +![Put a gopher image here, please](https://raw.githubusercontent.com/reklesio/gods/main/media/gopher.png) + +Golang data structures. + + +# Tasks + +- [ ] Write the tasks diff --git a/sort.go b/sort.go new file mode 100644 index 0000000..202da4f --- /dev/null +++ b/sort.go @@ -0,0 +1,29 @@ +package gods + +type Getter[V any] interface { + Get(int) V +} + +type Swapper interface { + Swap(i, j int) + Len() int +} + +type CustomSorter[V any] interface { + Getter[V] + Swapper +} + +type LessFunc[V any] func(v1, v2 V) bool +// The type implements way to sort +// swappers via custom function. +type CustomSort[V any] struct { + CustomSorter[V] + LessFunc LessFunc[V] +} + +func (cs CustomSort[V]) Less(i, j int) bool { + vi, vj := cs.Get(i), cs.Get(j) + return cs.LessFunc(vi, vj) +} + diff --git a/stacks/main.go b/stacks/main.go new file mode 100644 index 0000000..766b995 --- /dev/null +++ b/stacks/main.go @@ -0,0 +1,11 @@ +package stacks + +import ( + "github.com/reklesio/gods" +) + +type Stack[V any] interface { + gods.Container[V] + Push(V) + Pop() V +}