Initial commit (code only without large binaries)
This commit is contained in:
14
EdgeNode/internal/utils/linkedlist/item.go
Normal file
14
EdgeNode/internal/utils/linkedlist/item.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package linkedlist
|
||||
|
||||
type Item[T any] struct {
|
||||
prev *Item[T]
|
||||
next *Item[T]
|
||||
|
||||
Value T
|
||||
}
|
||||
|
||||
func NewItem[T any](value T) *Item[T] {
|
||||
return &Item[T]{Value: value}
|
||||
}
|
||||
111
EdgeNode/internal/utils/linkedlist/list.go
Normal file
111
EdgeNode/internal/utils/linkedlist/list.go
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package linkedlist
|
||||
|
||||
type List[T any] struct {
|
||||
head *Item[T]
|
||||
end *Item[T]
|
||||
count int
|
||||
}
|
||||
|
||||
func NewList[T any]() *List[T] {
|
||||
return &List[T]{}
|
||||
}
|
||||
|
||||
func (this *List[T]) Head() *Item[T] {
|
||||
return this.head
|
||||
}
|
||||
|
||||
func (this *List[T]) End() *Item[T] {
|
||||
return this.end
|
||||
}
|
||||
|
||||
func (this *List[T]) Push(item *Item[T]) {
|
||||
if item == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果已经在末尾了,则do nothing
|
||||
if this.end == item {
|
||||
return
|
||||
}
|
||||
|
||||
if item.prev != nil || item.next != nil || this.head == item {
|
||||
this.Remove(item)
|
||||
}
|
||||
this.add(item)
|
||||
}
|
||||
|
||||
func (this *List[T]) Shift() *Item[T] {
|
||||
if this.head != nil {
|
||||
var old = this.head
|
||||
this.Remove(this.head)
|
||||
return old
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *List[T]) Remove(item *Item[T]) {
|
||||
if item == nil {
|
||||
return
|
||||
}
|
||||
if item.prev != nil {
|
||||
item.prev.next = item.next
|
||||
}
|
||||
if item.next != nil {
|
||||
item.next.prev = item.prev
|
||||
}
|
||||
if item == this.head {
|
||||
this.head = item.next
|
||||
}
|
||||
if item == this.end {
|
||||
this.end = item.prev
|
||||
}
|
||||
|
||||
item.prev = nil
|
||||
item.next = nil
|
||||
this.count--
|
||||
}
|
||||
|
||||
func (this *List[T]) Len() int {
|
||||
return this.count
|
||||
}
|
||||
|
||||
func (this *List[T]) Range(f func(item *Item[T]) (goNext bool)) {
|
||||
for e := this.head; e != nil; e = e.next {
|
||||
goNext := f(e)
|
||||
if !goNext {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *List[T]) RangeReverse(f func(item *Item[T]) (goNext bool)) {
|
||||
for e := this.end; e != nil; e = e.prev {
|
||||
goNext := f(e)
|
||||
if !goNext {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *List[T]) Reset() {
|
||||
this.head = nil
|
||||
this.end = nil
|
||||
}
|
||||
|
||||
func (this *List[T]) add(item *Item[T]) {
|
||||
if item == nil {
|
||||
return
|
||||
}
|
||||
if this.end != nil {
|
||||
this.end.next = item
|
||||
item.prev = this.end
|
||||
item.next = nil
|
||||
}
|
||||
this.end = item
|
||||
if this.head == nil {
|
||||
this.head = item
|
||||
}
|
||||
this.count++
|
||||
}
|
||||
147
EdgeNode/internal/utils/linkedlist/list_test.go
Normal file
147
EdgeNode/internal/utils/linkedlist/list_test.go
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package linkedlist_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/utils/linkedlist"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewList_Memory(t *testing.T) {
|
||||
var stat1 = &runtime.MemStats{}
|
||||
runtime.ReadMemStats(stat1)
|
||||
|
||||
var list = linkedlist.NewList[int]()
|
||||
for i := 0; i < 1_000_000; i++ {
|
||||
var item = &linkedlist.Item[int]{}
|
||||
list.Push(item)
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
|
||||
var stat2 = &runtime.MemStats{}
|
||||
runtime.ReadMemStats(stat2)
|
||||
t.Log((stat2.HeapInuse-stat1.HeapInuse)>>20, "MB")
|
||||
t.Log(list.Len())
|
||||
|
||||
var count = 0
|
||||
list.Range(func(item *linkedlist.Item[int]) (goNext bool) {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
t.Log(count)
|
||||
}
|
||||
|
||||
func TestNewList_Memory_String(t *testing.T) {
|
||||
var stat1 = &runtime.MemStats{}
|
||||
runtime.ReadMemStats(stat1)
|
||||
|
||||
var list = linkedlist.NewList[string]()
|
||||
for i := 0; i < 1_000_000; i++ {
|
||||
var item = &linkedlist.Item[string]{}
|
||||
item.Value = strconv.Itoa(i)
|
||||
list.Push(item)
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
|
||||
var stat2 = &runtime.MemStats{}
|
||||
runtime.ReadMemStats(stat2)
|
||||
t.Log((stat2.HeapInuse-stat1.HeapInuse)>>20, "MB")
|
||||
t.Log(list.Len())
|
||||
}
|
||||
|
||||
func TestList_Push(t *testing.T) {
|
||||
var list = linkedlist.NewList[int]()
|
||||
list.Push(linkedlist.NewItem(1))
|
||||
list.Push(linkedlist.NewItem(2))
|
||||
|
||||
var item3 = linkedlist.NewItem(3)
|
||||
list.Push(item3)
|
||||
|
||||
var item4 = linkedlist.NewItem(4)
|
||||
list.Push(item4)
|
||||
list.Range(func(item *linkedlist.Item[int]) (goNext bool) {
|
||||
t.Log(item.Value)
|
||||
return true
|
||||
})
|
||||
|
||||
t.Log("=== after push 3 ===")
|
||||
list.Push(item3)
|
||||
list.Range(func(item *linkedlist.Item[int]) (goNext bool) {
|
||||
t.Log(item.Value)
|
||||
return true
|
||||
})
|
||||
|
||||
t.Log("=== after push 4 ===")
|
||||
list.Push(item4)
|
||||
list.Push(item3)
|
||||
list.Push(item3)
|
||||
list.Push(item3)
|
||||
list.Push(item4)
|
||||
list.Push(item4)
|
||||
list.Range(func(item *linkedlist.Item[int]) (goNext bool) {
|
||||
t.Log(item.Value)
|
||||
return true
|
||||
})
|
||||
|
||||
t.Log("=== after remove 3 ===")
|
||||
list.Remove(item3)
|
||||
list.Range(func(item *linkedlist.Item[int]) (goNext bool) {
|
||||
t.Log(item.Value)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func TestList_Shift(t *testing.T) {
|
||||
var list = linkedlist.NewList[int]()
|
||||
list.Push(linkedlist.NewItem(1))
|
||||
list.Push(linkedlist.NewItem(2))
|
||||
list.Push(linkedlist.NewItem(3))
|
||||
list.Push(linkedlist.NewItem(4))
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
t.Log("=== before shift " + types.String(i) + " ===")
|
||||
list.Range(func(item *linkedlist.Item[int]) (goNext bool) {
|
||||
t.Log(item.Value)
|
||||
return true
|
||||
})
|
||||
|
||||
t.Logf("shift: %+v", list.Shift())
|
||||
|
||||
t.Log("=== after shift " + types.String(i) + " ===")
|
||||
list.Range(func(item *linkedlist.Item[int]) (goNext bool) {
|
||||
t.Log(item.Value)
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestList_RangeReverse(t *testing.T) {
|
||||
var list = linkedlist.NewList[int]()
|
||||
list.Push(linkedlist.NewItem(1))
|
||||
list.Push(linkedlist.NewItem(2))
|
||||
|
||||
var item3 = linkedlist.NewItem(3)
|
||||
list.Push(item3)
|
||||
|
||||
list.Push(linkedlist.NewItem(4))
|
||||
|
||||
//list.Push(item3)
|
||||
//list.Remove(item3)
|
||||
list.RangeReverse(func(item *linkedlist.Item[int]) (goNext bool) {
|
||||
t.Log(item.Value)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkList_Add(b *testing.B) {
|
||||
var list = linkedlist.NewList[int]()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var item = &linkedlist.Item[int]{}
|
||||
list.Push(item)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user