Skip to content

Commit

Permalink
Add NewSkipListFunc (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
chen3feng committed Aug 7, 2022
1 parent 52b473a commit 81e8ac2
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 18 deletions.
29 changes: 17 additions & 12 deletions skiplist.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const (
// asymptotic expected time bounds as balanced trees and are simpler, faster and use less space.
//
// See https://en.wikipedia.org/wiki/Skip_list for more details.
type SkipList[K Ordered, V any] struct {
type SkipList[K any, V any] struct {
keyCmp CompareFn[K]
level int // Current level, may increase dynamically during insertion
len int // Total elements numner in the skiplist.
Expand All @@ -25,7 +25,7 @@ type SkipList[K Ordered, V any] struct {
rander *rand.Rand
}

type skipListNode[K Ordered, V any] struct {
type skipListNode[K any, V any] struct {
key K
value V
next []*skipListNode[K, V]
Expand All @@ -34,17 +34,9 @@ type skipListNode[K Ordered, V any] struct {
//go:generate bash ./skiplist_newnode_generate.sh skipListMaxLevel skiplist_newnode.go
// func newSkipListNode[K Ordered, V any](level int, key K, value V) *skipListNode[K, V]

// NewSkipList create a new Skiplist.
// NewSkipList creates a new Skiplist.
func NewSkipList[K Ordered, V any]() *SkipList[K, V] {
l := &SkipList[K, V]{
level: 1,
keyCmp: OrderedCompare[K],
// #nosec G404 -- This is not a security condition
rander: rand.New(rand.NewSource(time.Now().Unix())),
prevsCache: make([]*skipListNode[K, V], skipListMaxLevel),
}
l.head.next = make([]*skipListNode[K, V], skipListMaxLevel)
return l
return NewSkipListFunc[K, V](OrderedCompare[K])
}

// NewSkipListFromMap create a new Skiplist from a map.
Expand All @@ -56,6 +48,19 @@ func NewSkipListFromMap[K Ordered, V any](m map[K]V) *SkipList[K, V] {
return sl
}

// NewSkipListFunc creates a new Skiplist with specified compare function keyCmp.
func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V] {
l := &SkipList[K, V]{
level: 1,
keyCmp: keyCmp,
// #nosec G404 -- This is not a security condition
rander: rand.New(rand.NewSource(time.Now().Unix())),
prevsCache: make([]*skipListNode[K, V], skipListMaxLevel),
}
l.head.next = make([]*skipListNode[K, V], skipListMaxLevel)
return l
}

func (sl *SkipList[K, V]) IsEmpty() bool {
return sl.len == 0
}
Expand Down
2 changes: 1 addition & 1 deletion skiplist_newnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
package stl4go

// newSkipListNode creates a new node initialized with specified key, value and next slice.
func newSkipListNode[K Ordered, V any](level int, key K, value V) *skipListNode[K, V] {
func newSkipListNode[K any, V any](level int, key K, value V) *skipListNode[K, V] {
// For nodes with each levels, point their next slice to the nexts array allocated together,
// which can reduce 1 memory allocation and improve performance.
//
Expand Down
2 changes: 1 addition & 1 deletion skiplist_newnode_generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ generate() {
echo "package $GOPACKAGE"
echo "
// newSkipListNode creates a new node initialized with specified key, value and next slice.
func newSkipListNode[K Ordered, V any](level int, key K, value V) *skipListNode[K, V] {
func newSkipListNode[K any, V any](level int, key K, value V) *skipListNode[K, V] {
// For nodes with each levels, point their next slice to the nexts array allocated together,
// which can reduce 1 memory allocation and improve performance.
//
Expand Down
31 changes: 30 additions & 1 deletion skiplist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,37 @@ func TestNewSkipList(t *testing.T) {
NewSkipList[int, int]()
}

func TestNewSkipListFunc(t *testing.T) {
type Person struct {
name string
age int
}
personCmp := func(a, b Person) int {
r := OrderedCompare(a.age, b.age)
if r != 0 {
return r
}
return OrderedCompare(a.name, b.name)
}
sl := NewSkipListFunc[Person, int](personCmp)
sl.Insert(Person{"zhangsan", 20}, 1)
sl.Insert(Person{"lisi", 20}, 1)
sl.Insert(Person{"wangwu", 30}, 1)
var ps []Person
sl.ForEach(func(p Person, _ *int) {
ps = append(ps, p)
})
expectEq(t, ps[0].name, "lisi")
expectEq(t, ps[1].name, "zhangsan")
expectEq(t, ps[2].name, "wangwu")
}

func TestNewSkipListFromMap(t *testing.T) {
NewSkipListFromMap(map[int]int{1: 1, 2: 2, 3: 3})
m := map[int]int{1: -1, 2: -2, 3: -3}
sl := NewSkipListFromMap(m)
for k := range m {
expectTrue(t, sl.Has(k))
}
}

func TestSkipList_Insert(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ func Less[T Ordered](a, b T) bool {

// OrderedCompare provide default CompareFn for ordered types.
func OrderedCompare[T Ordered](a, b T) int {
switch {
case a < b:
if a < b {
return -1
case a > b:
}
if a > b {
return 1
}
return 0
Expand Down

0 comments on commit 81e8ac2

Please sign in to comment.