Skip to content

Commit

Permalink
Feat (list): Contains and ContainsDeep
Browse files Browse the repository at this point in the history
  • Loading branch information
yunginnanet committed Jul 17, 2024
1 parent 0c77493 commit b46f1c8
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 0 deletions.
56 changes: 56 additions & 0 deletions list/iter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package list

import (
"reflect"
)

func (ll *LockingList) contains(e any, deep bool) bool {
if err := ll.RLock(); err != nil {
return false
}

var checker func(any, any) bool

switch deep {
case true:
checker = reflect.DeepEqual
case false:
checker = func(x, y any) bool {
return x == y
}
}

start := ll.Front()
for {
if start == nil {
break
}
if start.Value() == e {
break
}

if //goland:noinspection GoNilness
checker(start.Value(), e) {
return true
}

start = start.Next()
}
ll.RUnlock()
return start != nil
}

// Contains checks if the list contains e.
//
// [Contains] iterates through the entire list until it finds e, this means it is quite slow.
func (ll *LockingList) Contains(e any) bool {
return ll.contains(e, false)
}

// ContainsDeep checks if the list contains e, or a value that is is deeply equal to e.
//
// This function iterates through the entire list until it finds e, this means it is quite slow.
// [ContainsDeep] uses [reflect.DeepEqual] to compare values, this makes it even slower than [Contains].
func (ll *LockingList) ContainsDeep(e any) bool {
return ll.contains(e, true)
}
130 changes: 130 additions & 0 deletions list/iter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package list

import (
"strings"
"testing"
)

type testCommon interface {
Error(args ...any)
Errorf(format string, args ...any)
Fatal(args ...any)
Fatalf(format string, args ...any)
Helper()
}

func addGarbo(ll *LockingList, amount int, t testCommon) {
t.Helper()
for i := 0; i < amount; i++ {
if i%2 == 0 {
if err := ll.Push(strings.Repeat("e", i)); err != nil {
t.Fatalf("unexpected error: %s", err.Error())
}
continue
}
if err := ll.Push(i); err != nil {
t.Fatalf("unexpected error: %s", err.Error())
}
}
}

func TestContains(t *testing.T) {
ll := New()
if ll.Contains(1) {
t.Error("expected 1 not to be in an empty list")
}
ll.PushFront(2)
if ll.Contains(1) {
t.Error("expected 1 not to be in the list")
}
if !ll.Contains(2) {
t.Error("expected 2 to be in the list")
}
_ = ll.Pop()

addGarbo(ll, 1000, t)

for i := 0; i < 1000; i++ {
switch i % 2 {
case 0:
if ll.Contains(i) {
t.Fatalf("%d should not be in list", i)
}
if !ll.Contains(strings.Repeat("e", i)) {
t.Fatal("missing string value")
}
default:
if !ll.Contains(i) {
t.Fatalf("%d should be in list", i)
}
}
}

t.Run("deep", func(t *testing.T) {
type mcgee int

type structy struct {
yeeterson any
yeetsalot string
}

if err := ll.Push(&structy{yeeterson: mcgee(1), yeetsalot: "yeet"}); err != nil {
t.Fatalf("unexpected error: %s", err.Error())
}

if !ll.ContainsDeep(&structy{yeeterson: mcgee(1), yeetsalot: "yeet"}) {
t.Fatal("reflect.DeepEqual should have caught this")
}

})

t.Run("list not initialized", func(t *testing.T) {
var l = &LockingList{}
if l.Contains(1) {
t.Error("expected 1 not to be in an empty list")
}
})
}

/*
Wed Jul 17 04:20:42 PM PDT 2024
goos: linux
goarch: amd64
pkg: git.tcp.direct/kayos/common/list
cpu: 13th Gen Intel(R) Core(TM) i9-13900K
BenchmarkLockingList_Contains-32 6034 196409 ns/op 120801 B/op 7550 allocs/op
BenchmarkLockingList_ContainsDeep-32 4717 245886 ns/op 120800 B/op 7550 allocs/op
PASS
ok git.tcp.direct/kayos/common/list 16.810s
*/

func BenchmarkLockingList_Contains(b *testing.B) {
b.StopTimer()
ll := New()
addGarbo(ll, 100, b)
b.ReportAllocs()
for i := 0; i < b.N; i++ {
for ii := 0; ii < 100; ii++ {
b.StartTimer()
_ = ll.Contains(ii)
b.StopTimer()
}
}
}

func BenchmarkLockingList_ContainsDeep(b *testing.B) {
b.StopTimer()
ll := New()
addGarbo(ll, 100, b)
b.ReportAllocs()
for i := 0; i < b.N; i++ {
for ii := 0; ii < 100; ii++ {
b.StartTimer()
_ = ll.ContainsDeep(ii)
b.StopTimer()
}
}
}

0 comments on commit b46f1c8

Please sign in to comment.