From b7ffe4719348a7e9aa0cd12e5f8148ebdc944805 Mon Sep 17 00:00:00 2001 From: Magnus Kokk Date: Thu, 6 Jul 2023 17:55:19 +0300 Subject: [PATCH] Use the separate ringlist package --- backend.go | 2 +- go.mod | 7 +- go.sum | 18 ++-- ringlist/doc.go | 4 - ringlist/element.go | 44 -------- ringlist/ringlist.go | 163 ----------------------------- ringlist/ringlist_test.go | 213 -------------------------------------- 7 files changed, 16 insertions(+), 435 deletions(-) delete mode 100644 ringlist/doc.go delete mode 100644 ringlist/element.go delete mode 100644 ringlist/ringlist.go delete mode 100644 ringlist/ringlist_test.go diff --git a/backend.go b/backend.go index 11cd849..8d55931 100644 --- a/backend.go +++ b/backend.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/mgnsk/evcache/v3/ringlist" + "github.com/mgnsk/ringlist" ) type recordList[V any] struct { diff --git a/go.mod b/go.mod index c835cac..11d3724 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,15 @@ module github.com/mgnsk/evcache/v3 go 1.19 -require github.com/onsi/gomega v1.27.6 +require ( + github.com/mgnsk/ringlist v0.0.0-20230706145047-c9cc2d2b2956 + github.com/onsi/gomega v1.27.8 +) require ( github.com/google/go-cmp v0.5.9 // indirect github.com/kr/pretty v0.1.0 // indirect - golang.org/x/net v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect golang.org/x/text v0.9.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index b3c7b7a..09d6e82 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -8,15 +8,17 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +github.com/mgnsk/ringlist v0.0.0-20230706145047-c9cc2d2b2956 h1:xWkdgeXchPtA9l83VHfBRuOAcLKpX8zWolO5xaU2ZbQ= +github.com/mgnsk/ringlist v0.0.0-20230706145047-c9cc2d2b2956/go.mod h1:2LPZhApq+vOgHJLmpyTQmQuGQLZ5MEzBUNv0bKbfbS0= +github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= +github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/ringlist/doc.go b/ringlist/doc.go deleted file mode 100644 index 6418326..0000000 --- a/ringlist/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package ringlist implements a circular doubly linked list. -*/ -package ringlist diff --git a/ringlist/element.go b/ringlist/element.go deleted file mode 100644 index 8385a20..0000000 --- a/ringlist/element.go +++ /dev/null @@ -1,44 +0,0 @@ -package ringlist - -// Element is a list element. -type Element[V any] struct { - Value V - next, prev *Element[V] -} - -// NewElement creates a list element. -func NewElement[V any](v V) *Element[V] { - e := &Element[V]{ - Value: v, - } - e.next = e - e.prev = e - return e -} - -// Next returns the next element or nil. -func (e *Element[V]) Next() *Element[V] { - return e.next -} - -// Prev returns the previous element or nil. -func (e *Element[V]) Prev() *Element[V] { - return e.prev -} - -// Link inserts an element after this element. -func (e *Element[V]) Link(s *Element[V]) { - n := e.next - e.next = s - s.prev = e - n.prev = s - s.next = n -} - -// Unlink unlinks this element. -func (e *Element[V]) Unlink() { - e.prev.next = e.next - e.next.prev = e.prev - e.next = e - e.prev = e -} diff --git a/ringlist/ringlist.go b/ringlist/ringlist.go deleted file mode 100644 index f9d78ad..0000000 --- a/ringlist/ringlist.go +++ /dev/null @@ -1,163 +0,0 @@ -package ringlist - -// ElementList is a built in list type that uses the Element type as its element. -// The zero value is a ready to use empty list. -type ElementList[V any] struct { - List[Element[V], *Element[V]] -} - -// ListElement is the constraint for a generic list element. -type ListElement[E any] interface { - Link(E) - Unlink() - Next() E - Prev() E -} - -// List is a generic circular doubly linked list. -// The zero value is a ready to use empty list. -type List[T any, E interface { - *T - ListElement[E] -}] struct { - tail E - len int -} - -// Len returns the number of elements in the list. -func (l *List[T, E]) Len() int { - return l.len -} - -// Front returns the first element of the list or nil. -func (l *List[T, E]) Front() E { - if l.len == 0 { - return nil - } - return l.tail.Next() -} - -// Back returns the last element of the list or nil. -func (l *List[T, E]) Back() E { - return l.tail -} - -// PushBack inserts a new element at the back of list l. -func (l *List[T, E]) PushBack(e E) { - if l.tail != nil { - l.tail.Link(e) - } - l.tail = e - l.len++ -} - -// PushFront inserts a new element at the front of list l. -func (l *List[T, E]) PushFront(e E) { - if l.tail != nil { - l.tail.Link(e) - } else { - l.tail = e - } - l.len++ -} - -// Do calls function f on each element of the list, in forward order. -// If f returns false, Do stops the iteration. -// f must not change l. -func (l *List[T, E]) Do(f func(e E) bool) { - e := l.Front() - if e == nil { - return - } - - if !f(e) { - return - } - - for p := e.Next(); p != e; p = p.Next() { - if !f(p) { - return - } - } -} - -// MoveAfter moves an element to its new position after mark. -func (l *List[T, E]) MoveAfter(e, mark E) { - l.Remove(e) - - mark.Link(e) - l.len++ - - if mark == l.tail { - l.tail = e - } -} - -// MoveBefore moves an element to its new position before mark. -func (l *List[T, E]) MoveBefore(e, mark E) { - l.Remove(e) - - mark.Prev().Link(e) - - l.len++ -} - -// MoveToFront moves the element to the front of list l. -func (l *List[T, E]) MoveToFront(e E) { - l.MoveBefore(e, l.Front()) -} - -// MoveToBack moves the element to the back of list l. -func (l *List[T, E]) MoveToBack(e E) { - l.MoveAfter(e, l.Back()) -} - -// Move moves element e forward or backwards by at most delta positions -// or until the element becomes the front or back element in the list. -func (l *List[T, E]) Move(e E, delta int) { - if l.tail == nil { - panic("ringlist: invalid element") - } - - if l.len == 1 && e != l.tail { - panic("ringlist: invalid element") - } - - mark := e - - switch { - case delta == 0: - return - - case delta > 0: - for i := 0; i < delta; i++ { - if mark = mark.Next(); mark == l.tail { - break - } - } - - l.MoveAfter(e, mark) - - case delta < 0: - for i := 0; i > delta; i-- { - if mark = mark.Prev(); mark == l.tail.Next() { - break - } - } - - l.MoveBefore(e, mark) - } -} - -// Remove an element from the list. -func (l *List[T, E]) Remove(e E) { - if e == l.tail { - if l.len == 1 { - l.tail = nil - } else { - l.tail = e.Prev() - } - } - e.Unlink() - l.len-- -} diff --git a/ringlist/ringlist_test.go b/ringlist/ringlist_test.go deleted file mode 100644 index d95a6ad..0000000 --- a/ringlist/ringlist_test.go +++ /dev/null @@ -1,213 +0,0 @@ -package ringlist_test - -import ( - "testing" - - "github.com/mgnsk/evcache/v3/ringlist" - . "github.com/onsi/gomega" -) - -func TestPushFront(t *testing.T) { - var list ringlist.ElementList[int] - - g := NewWithT(t) - - list.PushFront(ringlist.NewElement(0)) - g.Expect(list.Len()).To(Equal(1)) - - list.PushFront(ringlist.NewElement(1)) - g.Expect(list.Len()).To(Equal(2)) - - expectValidRing(g, &list) -} - -func TestPushBack(t *testing.T) { - var list ringlist.ElementList[int] - - g := NewWithT(t) - - list.PushFront(ringlist.NewElement(0)) - g.Expect(list.Len()).To(Equal(1)) - - list.PushFront(ringlist.NewElement(1)) - g.Expect(list.Len()).To(Equal(2)) - - expectValidRing(g, &list) -} - -func TestMoveToFront(t *testing.T) { - t.Run("moving the back element", func(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.MoveToFront(list.Back()) - - expectValidRing(g, &list) - g.Expect(list.Front().Value).To(Equal("two")) - g.Expect(list.Back().Value).To(Equal("one")) - }) - - t.Run("moving the middle element", func(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.PushBack(ringlist.NewElement("three")) - list.MoveToFront(list.Front().Next()) - - expectValidRing(g, &list) - g.Expect(list.Front().Value).To(Equal("two")) - g.Expect(list.Back().Value).To(Equal("three")) - }) -} - -func TestMoveToBack(t *testing.T) { - t.Run("moving the front element", func(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.MoveToBack(list.Front()) - - expectValidRing(g, &list) - g.Expect(list.Front().Value).To(Equal("two")) - g.Expect(list.Back().Value).To(Equal("one")) - }) - - t.Run("moving the middle element", func(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.PushBack(ringlist.NewElement("three")) - list.MoveToBack(list.Front().Next()) - - expectValidRing(g, &list) - g.Expect(list.Front().Value).To(Equal("one")) - g.Expect(list.Back().Value).To(Equal("two")) - }) -} - -func TestMoveForward(t *testing.T) { - t.Run("overflow", func(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.Move(list.Front(), 3) - - expectValidRing(g, &list) - g.Expect(list.Front().Value).To(Equal("two")) - g.Expect(list.Back().Value).To(Equal("one")) - }) - - t.Run("not overflow", func(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.PushBack(ringlist.NewElement("three")) - list.Move(list.Front(), 1) - - expectValidRing(g, &list) - g.Expect(list.Front().Value).To(Equal("two")) - g.Expect(list.Front().Next().Value).To(Equal("one")) - g.Expect(list.Back().Value).To(Equal("three")) - }) -} - -func TestMoveBackwards(t *testing.T) { - t.Run("overflow", func(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.Move(list.Back(), -3) - - expectValidRing(g, &list) - g.Expect(list.Front().Value).To(Equal("two")) - g.Expect(list.Back().Value).To(Equal("one")) - }) - - t.Run("not overflow", func(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.PushBack(ringlist.NewElement("three")) - list.Move(list.Back(), -1) - - expectValidRing(g, &list) - g.Expect(list.Front().Value).To(Equal("one")) - g.Expect(list.Front().Next().Value).To(Equal("three")) - g.Expect(list.Back().Value).To(Equal("two")) - }) -} - -func TestDo(t *testing.T) { - var list ringlist.ElementList[string] - - g := NewWithT(t) - - list.PushBack(ringlist.NewElement("one")) - list.PushBack(ringlist.NewElement("two")) - list.PushBack(ringlist.NewElement("three")) - - g.Expect(list.Len()).To(Equal(3)) - expectValidRing(g, &list) - - var elems []string - list.Do(func(e *ringlist.Element[string]) bool { - elems = append(elems, e.Value) - return true - }) - - g.Expect(elems).To(Equal([]string{"one", "two", "three"})) -} - -func expectValidRing[T any](g *WithT, list *ringlist.ElementList[T]) { - g.Expect(list.Len()).To(BeNumerically(">", 0)) - g.Expect(list.Front()).To(Equal(list.Back().Next())) - g.Expect(list.Back()).To(Equal(list.Front().Prev())) - - { - expectedFront := list.Front() - - front := list.Front() - - for i := 0; i < list.Len(); i++ { - front = front.Next() - } - - g.Expect(front).To(Equal(expectedFront)) - } - - { - expectedBack := list.Back() - - back := list.Back() - - for i := 0; i < list.Len(); i++ { - back = back.Prev() - } - - g.Expect(back).To(Equal(expectedBack)) - } -}