Skip to content

Commit

Permalink
Added more unit tests and fixed some issues revealed by the unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pzaino committed Jul 26, 2024
1 parent 135e548 commit 6a57950
Show file tree
Hide file tree
Showing 3 changed files with 306 additions and 0 deletions.
49 changes: 49 additions & 0 deletions pkg/csdlinkList/csdlinkList.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,41 @@ func (cs *CSDLinkList[T]) ForEach(f func(*T)) {
cs.l.ForEach(f)
}

// ForFrom traverses the doubly linked list starting from the given index and applies the given function to each node.
func (cs *CSDLinkList[T]) ForFrom(index int, f func(*T)) {
cs.mu.Lock()
defer cs.mu.Unlock()
cs.l.ForFrom(index, f)
}

// ForReverseFrom traverses the doubly linked list in reverse order starting from the given index and applies the given function to each node.
func (cs *CSDLinkList[T]) ForReverseFrom(index int, f func(*T)) {
cs.mu.Lock()
defer cs.mu.Unlock()
cs.l.ForReverseFrom(index, f)
}

// ForEachReverse traverses the doubly linked list in reverse order and applies the given function to each node.
func (cs *CSDLinkList[T]) ForEachReverse(f func(*T)) {
cs.mu.Lock()
defer cs.mu.Unlock()
cs.l.ForEachReverse(f)
}

// ForRange traverses the doubly linked list in the given range and applies the given function to each node.
func (cs *CSDLinkList[T]) ForRange(start, end int, f func(*T)) {
cs.mu.Lock()
defer cs.mu.Unlock()
cs.l.ForRange(start, end, f)
}

// ForReverseRange traverses the doubly linked list in reverse order in the given range and applies the given function to each node.
func (cs *CSDLinkList[T]) ForReverseRange(start, end int, f func(*T)) {
cs.mu.Lock()
defer cs.mu.Unlock()
cs.l.ForReverseRange(start, end, f)
}

// Any returns true if the given function returns true for any node in the doubly linked list.
func (cs *CSDLinkList[T]) Any(f func(T) bool) bool {
cs.mu.Lock()
Expand Down Expand Up @@ -259,6 +294,20 @@ func (cs *CSDLinkList[T]) Map(f func(T) T) *CSDLinkList[T] {
return &CSDLinkList[T]{l: cs.l.Map(f)}
}

// MapFrom returns a new doubly linked list containing the result of applying the given function to each node starting from the given index.
func (cs *CSDLinkList[T]) MapFrom(index int, f func(T) T) *CSDLinkList[T] {
cs.mu.Lock()
defer cs.mu.Unlock()
return &CSDLinkList[T]{l: cs.l.MapFrom(index, f)}
}

// MapRange returns a new doubly linked list containing the result of applying the given function to each node in the given range.
func (cs *CSDLinkList[T]) MapRange(start, end int, f func(T) T) *CSDLinkList[T] {
cs.mu.Lock()
defer cs.mu.Unlock()
return &CSDLinkList[T]{l: cs.l.MapRange(start, end, f)}
}

// Reduce reduces the doubly linked list to a single value using the given function.
func (cs *CSDLinkList[T]) Reduce(f func(T, T) T) T {
cs.mu.Lock()
Expand Down
88 changes: 88 additions & 0 deletions pkg/csdlinkList/csdlinkList_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,22 @@ func TestCSDLinkListToSliceFrom(t *testing.T) {
})
}

func TestCSDLinkListToSliceReverseFromIndex(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
for i := 0; i < 1000; i++ {
cs.Append(i)
}
runConcurrent(t, 1000, func() {
test := cs.ToSliceReverseFromIndex(50)
if len(test) != 950 {
t.Fatalf("expected size 50, got %d", len(test))
}
if test[0] != 949 {
t.Fatalf("expected first element to be 950, got %d", test[0])
}
})
}

func TestCSDLinkListFind(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
cs.Append(1)
Expand Down Expand Up @@ -281,6 +297,58 @@ func TestCSDLinkListForEach(t *testing.T) {
})
}

func TestCSDLinkListForEachReverse(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
for i := 1000; i > 0; i-- {
cs.Append(i)
}
runConcurrent(t, 1000, func() {
cs.ForEachReverse(func(item *int) {
*item = *item + 1
})
})
}

func TestCSDLinkListForRange(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
cs.Append(1)
runConcurrent(t, 1000, func() {
cs.ForRange(0, 1, func(item *int) {
*item = *item + 1
})
})
}

func TestCSDLinkListForFrom(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
cs.Append(1)
runConcurrent(t, 1000, func() {
cs.ForFrom(0, func(item *int) {
*item = *item + 1
})
})
}

func TestCSDLinkListForReverseFrom(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
cs.Append(1)
runConcurrent(t, 1000, func() {
cs.ForReverseFrom(0, func(item *int) {
*item = *item + 1
})
})
}

func TestCSDLinkListForReverseRange(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
cs.Append(1)
runConcurrent(t, 1000, func() {
cs.ForReverseRange(0, 1, func(item *int) {
*item = *item + 1
})
})
}

func TestCSDLinkListAny(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
for i := 0; i < 1000; i++ {
Expand Down Expand Up @@ -349,6 +417,26 @@ func TestCSDLinkListMap(t *testing.T) {
})
}

func TestCSDLinkListMapFrom(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
cs.Append(1)
runConcurrent(t, 1000, func() {
cs.MapFrom(0, func(item int) int {
return item * 2
})
})
}

func TestCSDLinkListMapRange(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
cs.Append(1)
runConcurrent(t, 1000, func() {
cs.MapRange(0, 1, func(item int) int {
return item * 2
})
})
}

func TestCSDLinkListReduce(t *testing.T) {
cs := csdlinkList.NewCSDLinkList[int]()
for i := 0; i < 1000; i++ {
Expand Down
169 changes: 169 additions & 0 deletions pkg/dlinkList/dlinkList.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,13 +442,126 @@ func (l *DLinkList[T]) Contains(value T) bool {

// ForEach traverses the doubly linked list and applies the given function to each node
func (l *DLinkList[T]) ForEach(f func(*T)) {
if l.IsEmpty() {
return
}

current := l.Head
for current != nil {
f(&current.Value)
current = current.Next
}
}

// ForFrom traverses the doubly linked list starting from the given index and applies the given function to each node
func (l *DLinkList[T]) ForFrom(index int, f func(*T)) {
if index < 0 {
return
}

if l.IsEmpty() {
return
}

current, err := l.GetAt(index)
if err != nil {
return
}

for current != nil {
f(&current.Value)
current = current.Next
if current == nil {
break
}
}
}

// ForEachReverse traverses the doubly linked list in reverse order and applies the given function to each node
func (l *DLinkList[T]) ForEachReverse(f func(*T)) {
if l.IsEmpty() {
return
}

current := l.Tail
for current != nil {
f(&current.Value)
current = current.Prev
}
}

// ForReverseFrom traverses the doubly linked list in reverse order starting from the given index and applies the given function to each node
func (l *DLinkList[T]) ForReverseFrom(index int, f func(*T)) {
if index < 0 {
return
}

if l.IsEmpty() {
return
}

current, err := l.GetAt((l.Size() - 1) - index)
if err != nil {
return
}

for current != nil {
f(&current.Value)
current = current.Prev
if current == nil {
break
}
}
}

// ForRange traverses the doubly linked list from the start index to the end index and applies the given function to each node
func (l *DLinkList[T]) ForRange(start, end int, f func(*T)) {
if start < 0 || end < 0 || start > end {
return
}

if l.IsEmpty() {
return
}

current, err := l.GetAt(start)
if err != nil {
return
}

for i := start; i <= end; i++ {
f(&current.Value)
current = current.Next
if current == nil {
break
}
}
}

// ForReverseRange traverses the doubly linked list in reverse order from the start index to the end index and applies the given function to each node
func (l *DLinkList[T]) ForReverseRange(start, end int, f func(*T)) {
if start < 0 || end < 0 || start > end {
return
}

if l.IsEmpty() {
return
}

current, err := l.GetAt((l.Size() - 1) - start)
if err != nil {
return
}

for i := start; i <= end; i++ {
f(&current.Value)
current = current.Prev
if current == nil {
break
}
}
}

// Any returns true if the given function returns true for any node in the doubly linked list
func (l *DLinkList[T]) Any(f func(T) bool) bool {
current := l.Head
Expand Down Expand Up @@ -533,6 +646,62 @@ func (l *DLinkList[T]) Map(f func(T) T) *DLinkList[T] {
return result
}

// MapFrom returns a new doubly linked list containing the result of applying the given function to each node starting from the given index
func (l *DLinkList[T]) MapFrom(index int, f func(T) T) *DLinkList[T] {
result := NewDLinkList[T]()

if index < 0 {
return result
}

if l.IsEmpty() {
return result
}

current, err := l.GetAt(index)
if err != nil {
return result
}

for current != nil {
result.Append(f(current.Value))
current = current.Next
if current == nil {
break
}
}

return result
}

// MapRange returns a new doubly linked list containing the result of applying the given function to each node in the range [start, end)
func (l *DLinkList[T]) MapRange(start, end int, f func(T) T) *DLinkList[T] {
result := NewDLinkList[T]()

if start < 0 || end < 0 || start > end {
return result
}

if l.IsEmpty() {
return result
}

current, err := l.GetAt(start)
if err != nil {
return result
}

for i := start; i <= end; i++ {
result.Append(f(current.Value))
current = current.Next
if current == nil {
break
}
}

return result
}

// Reduce reduces the doubly linked list to a single value using the given function
func (l *DLinkList[T]) Reduce(f func(T, T) T) T {
if l.IsEmpty() {
Expand Down

0 comments on commit 6a57950

Please sign in to comment.