diff --git a/README.md b/README.md index 9bc83ee..8de9125 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ Package stl4go is a generic container and algorithm library for go. - [func (l *DList[T]) ForEach(cb func(val T))](<#func-dlistt-foreach>) - [func (l *DList[T]) ForEachIf(cb func(val T) bool)](<#func-dlistt-foreachif>) - [func (l *DList[T]) IsEmpty() bool](<#func-dlistt-isempty>) + - [func (l *DList[T]) Iterate() Iterator[T]](<#func-dlistt-iterate>) - [func (l *DList[T]) Len() int](<#func-dlistt-len>) - [func (l *DList[T]) PopBack() (T, bool)](<#func-dlistt-popback>) - [func (l *DList[T]) PopFront() (T, bool)](<#func-dlistt-popfront>) @@ -110,8 +111,10 @@ Package stl4go is a generic container and algorithm library for go. - [type Float](<#type-float>) - [type HashFn](<#type-hashfn>) - [type Integer](<#type-integer>) +- [type Iterator](<#type-iterator>) - [type LessFn](<#type-lessfn>) - [type Map](<#type-map>) +- [type MapIterator](<#type-mapiterator>) - [type Numeric](<#type-numeric>) - [type Ordered](<#type-ordered>) - [type Queue](<#type-queue>) @@ -132,6 +135,7 @@ Package stl4go is a generic container and algorithm library for go. - [func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V]](<#func-newskiplistfunc>) - [func (sl *SkipList[K, V]) Clear()](<#func-skiplistk-v-clear>) - [func (sl *SkipList[K, V]) Find(key K) *V](<#func-skiplistk-v-find>) + - [func (sl *SkipList[K, V]) FindRange(first, last K) MapIterator[K, V]](<#func-skiplistk-v-findrange>) - [func (sl *SkipList[K, V]) ForEach(op func(K, V))](<#func-skiplistk-v-foreach>) - [func (sl *SkipList[K, V]) ForEachIf(op func(K, V) bool)](<#func-skiplistk-v-foreachif>) - [func (sl *SkipList[K, V]) ForEachMutable(op func(K, *V))](<#func-skiplistk-v-foreachmutable>) @@ -139,8 +143,11 @@ Package stl4go is a generic container and algorithm library for go. - [func (sl *SkipList[K, V]) Has(key K) bool](<#func-skiplistk-v-has>) - [func (sl *SkipList[K, V]) Insert(key K, value V)](<#func-skiplistk-v-insert>) - [func (sl *SkipList[K, V]) IsEmpty() bool](<#func-skiplistk-v-isempty>) + - [func (sl *SkipList[K, V]) Iterate() MapIterator[K, V]](<#func-skiplistk-v-iterate>) - [func (sl *SkipList[K, V]) Len() int](<#func-skiplistk-v-len>) + - [func (sl *SkipList[K, V]) LowerBound(key K) MapIterator[K, V]](<#func-skiplistk-v-lowerbound>) - [func (sl *SkipList[K, V]) Remove(key K) bool](<#func-skiplistk-v-remove>) + - [func (sl *SkipList[K, V]) UpperBound(key K) MapIterator[K, V]](<#func-skiplistk-v-upperbound>) - [type Stack](<#type-stack>) - [func NewStack[T any]() *Stack[T]](<#func-newstack>) - [func NewStackCap[T any](capicity int) *Stack[T]](<#func-newstackcap>) @@ -832,7 +839,7 @@ func (l *DList[T]) Clear() Clear cleanup the list -### func \(\*DList\[T\]\) [ForEach]() +### func \(\*DList\[T\]\) [ForEach]() ```go func (l *DList[T]) ForEach(cb func(val T)) @@ -840,7 +847,7 @@ func (l *DList[T]) ForEach(cb func(val T)) ForEach iterate the list, apply each element to the cb callback function -### func \(\*DList\[T\]\) [ForEachIf]() +### func \(\*DList\[T\]\) [ForEachIf]() ```go func (l *DList[T]) ForEachIf(cb func(val T) bool) @@ -856,6 +863,14 @@ func (l *DList[T]) IsEmpty() bool IsEmpty return whether the list is empty +### func \(\*DList\[T\]\) [Iterate]() + +```go +func (l *DList[T]) Iterate() Iterator[T] +``` + +Iterate returns an iterator to the first element in the list. + ### func \(\*DList\[T\]\) [Len]() ```go @@ -864,25 +879,25 @@ func (l *DList[T]) Len() int Len return the length of the list -### func \(\*DList\[T\]\) [PopBack]() +### func \(\*DList\[T\]\) [PopBack]() ```go func (l *DList[T]) PopBack() (T, bool) ``` -### func \(\*DList\[T\]\) [PopFront]() +### func \(\*DList\[T\]\) [PopFront]() ```go func (l *DList[T]) PopFront() (T, bool) ``` -### func \(\*DList\[T\]\) [PushBack]() +### func \(\*DList\[T\]\) [PushBack]() ```go func (l *DList[T]) PushBack(val T) ``` -### func \(\*DList\[T\]\) [PushFront]() +### func \(\*DList\[T\]\) [PushFront]() ```go func (l *DList[T]) PushFront(val T) @@ -924,6 +939,18 @@ type Integer interface { } ``` +## type [Iterator]() + +Iterator is the interface for container's iterator. + +```go +type Iterator[T any] interface { + IsNotEnd() bool // Whether it is point to the end of the range. + MoveToNext() // Let it point to the next element. + Value() T // Return the value of current element. +} +``` + ## type [LessFn]() LessFn is a function that returns whether 'a' is less than 'b'. @@ -950,6 +977,17 @@ type Map[K any, V any] interface { } ``` +## type [MapIterator]() + +MapIterator is the interface for map's iterator. + +```go +type MapIterator[K any, V any] interface { + Key() K // The key of the element + // contains filtered or unexported methods +} +``` + ## type [Numeric]() Numeric is a constraint that permits any numeric type. @@ -1075,7 +1113,7 @@ type SkipList[K any, V any] struct { } ``` -### func [NewSkipList]() +### func [NewSkipList]() ```go func NewSkipList[K Ordered, V any]() *SkipList[K, V] @@ -1083,7 +1121,7 @@ func NewSkipList[K Ordered, V any]() *SkipList[K, V] NewSkipList creates a new SkipList for Ordered key type. -### func [NewSkipListFromMap]() +### func [NewSkipListFromMap]() ```go func NewSkipListFromMap[K Ordered, V any](m map[K]V) *SkipList[K, V] @@ -1091,7 +1129,7 @@ func NewSkipListFromMap[K Ordered, V any](m map[K]V) *SkipList[K, V] NewSkipListFromMap creates a new SkipList from a map. -### func [NewSkipListFunc]() +### func [NewSkipListFunc]() ```go func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V] @@ -1099,13 +1137,13 @@ func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V] NewSkipListFunc creates a new SkipList with specified compare function keyCmp. -### func \(\*SkipList\[K, V\]\) [Clear]() +### func \(\*SkipList\[K, V\]\) [Clear]() ```go func (sl *SkipList[K, V]) Clear() ``` -### func \(\*SkipList\[K, V\]\) [Find]() +### func \(\*SkipList\[K, V\]\) [Find]() ```go func (sl *SkipList[K, V]) Find(key K) *V @@ -1113,37 +1151,45 @@ func (sl *SkipList[K, V]) Find(key K) *V Find returns the value associated with the passed key if the key is in the skiplist, otherwise returns nil. -### func \(\*SkipList\[K, V\]\) [ForEach]() +### func \(\*SkipList\[K, V\]\) [FindRange]() + +```go +func (sl *SkipList[K, V]) FindRange(first, last K) MapIterator[K, V] +``` + +FindRange returns an iterator in range \[first, last\) \(last is not includeed\). + +### func \(\*SkipList\[K, V\]\) [ForEach]() ```go func (sl *SkipList[K, V]) ForEach(op func(K, V)) ``` -### func \(\*SkipList\[K, V\]\) [ForEachIf]() +### func \(\*SkipList\[K, V\]\) [ForEachIf]() ```go func (sl *SkipList[K, V]) ForEachIf(op func(K, V) bool) ``` -### func \(\*SkipList\[K, V\]\) [ForEachMutable]() +### func \(\*SkipList\[K, V\]\) [ForEachMutable]() ```go func (sl *SkipList[K, V]) ForEachMutable(op func(K, *V)) ``` -### func \(\*SkipList\[K, V\]\) [ForEachMutableIf]() +### func \(\*SkipList\[K, V\]\) [ForEachMutableIf]() ```go func (sl *SkipList[K, V]) ForEachMutableIf(op func(K, *V) bool) ``` -### func \(\*SkipList\[K, V\]\) [Has]() +### func \(\*SkipList\[K, V\]\) [Has]() ```go func (sl *SkipList[K, V]) Has(key K) bool ``` -### func \(\*SkipList\[K, V\]\) [Insert]() +### func \(\*SkipList\[K, V\]\) [Insert]() ```go func (sl *SkipList[K, V]) Insert(key K, value V) @@ -1151,19 +1197,31 @@ func (sl *SkipList[K, V]) Insert(key K, value V) Insert inserts a key\-value pair into the skiplist. If the key is already in the skip list, it's value will be updated. -### func \(\*SkipList\[K, V\]\) [IsEmpty]() +### func \(\*SkipList\[K, V\]\) [IsEmpty]() ```go func (sl *SkipList[K, V]) IsEmpty() bool ``` -### func \(\*SkipList\[K, V\]\) [Len]() +### func \(\*SkipList\[K, V\]\) [Iterate]() + +```go +func (sl *SkipList[K, V]) Iterate() MapIterator[K, V] +``` + +### func \(\*SkipList\[K, V\]\) [Len]() ```go func (sl *SkipList[K, V]) Len() int ``` -### func \(\*SkipList\[K, V\]\) [Remove]() +### func \(\*SkipList\[K, V\]\) [LowerBound]() + +```go +func (sl *SkipList[K, V]) LowerBound(key K) MapIterator[K, V] +``` + +### func \(\*SkipList\[K, V\]\) [Remove]() ```go func (sl *SkipList[K, V]) Remove(key K) bool @@ -1171,6 +1229,12 @@ func (sl *SkipList[K, V]) Remove(key K) bool Remove removes the key\-value pair associated with the passed key and returns true if the key is in the skiplist, otherwise returns false. +### func \(\*SkipList\[K, V\]\) [UpperBound]() + +```go +func (sl *SkipList[K, V]) UpperBound(key K) MapIterator[K, V] +``` + ## type [Stack]() Stack s is a container adaptor that provides the functionality of a stack, a LIFO \(last\-in, first\-out\) data structure. diff --git a/README_zh.md b/README_zh.md index f960f12..fdc95ec 100644 --- a/README_zh.md +++ b/README_zh.md @@ -99,6 +99,7 @@ Package stl4go is a generic container and algorithm library for go. - [func (l *DList[T]) ForEach(cb func(val T))](<#func-dlistt-foreach>) - [func (l *DList[T]) ForEachIf(cb func(val T) bool)](<#func-dlistt-foreachif>) - [func (l *DList[T]) IsEmpty() bool](<#func-dlistt-isempty>) + - [func (l *DList[T]) Iterate() Iterator[T]](<#func-dlistt-iterate>) - [func (l *DList[T]) Len() int](<#func-dlistt-len>) - [func (l *DList[T]) PopBack() (T, bool)](<#func-dlistt-popback>) - [func (l *DList[T]) PopFront() (T, bool)](<#func-dlistt-popfront>) @@ -108,8 +109,10 @@ Package stl4go is a generic container and algorithm library for go. - [type Float](<#type-float>) - [type HashFn](<#type-hashfn>) - [type Integer](<#type-integer>) +- [type Iterator](<#type-iterator>) - [type LessFn](<#type-lessfn>) - [type Map](<#type-map>) +- [type MapIterator](<#type-mapiterator>) - [type Numeric](<#type-numeric>) - [type Ordered](<#type-ordered>) - [type Queue](<#type-queue>) @@ -130,6 +133,7 @@ Package stl4go is a generic container and algorithm library for go. - [func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V]](<#func-newskiplistfunc>) - [func (sl *SkipList[K, V]) Clear()](<#func-skiplistk-v-clear>) - [func (sl *SkipList[K, V]) Find(key K) *V](<#func-skiplistk-v-find>) + - [func (sl *SkipList[K, V]) FindRange(first, last K) MapIterator[K, V]](<#func-skiplistk-v-findrange>) - [func (sl *SkipList[K, V]) ForEach(op func(K, V))](<#func-skiplistk-v-foreach>) - [func (sl *SkipList[K, V]) ForEachIf(op func(K, V) bool)](<#func-skiplistk-v-foreachif>) - [func (sl *SkipList[K, V]) ForEachMutable(op func(K, *V))](<#func-skiplistk-v-foreachmutable>) @@ -137,8 +141,11 @@ Package stl4go is a generic container and algorithm library for go. - [func (sl *SkipList[K, V]) Has(key K) bool](<#func-skiplistk-v-has>) - [func (sl *SkipList[K, V]) Insert(key K, value V)](<#func-skiplistk-v-insert>) - [func (sl *SkipList[K, V]) IsEmpty() bool](<#func-skiplistk-v-isempty>) + - [func (sl *SkipList[K, V]) Iterate() MapIterator[K, V]](<#func-skiplistk-v-iterate>) - [func (sl *SkipList[K, V]) Len() int](<#func-skiplistk-v-len>) + - [func (sl *SkipList[K, V]) LowerBound(key K) MapIterator[K, V]](<#func-skiplistk-v-lowerbound>) - [func (sl *SkipList[K, V]) Remove(key K) bool](<#func-skiplistk-v-remove>) + - [func (sl *SkipList[K, V]) UpperBound(key K) MapIterator[K, V]](<#func-skiplistk-v-upperbound>) - [type Stack](<#type-stack>) - [func NewStack[T any]() *Stack[T]](<#func-newstack>) - [func NewStackCap[T any](capicity int) *Stack[T]](<#func-newstackcap>) @@ -830,7 +837,7 @@ func (l *DList[T]) Clear() Clear cleanup the list -### func \(\*DList\[T\]\) [ForEach]() +### func \(\*DList\[T\]\) [ForEach]() ```go func (l *DList[T]) ForEach(cb func(val T)) @@ -838,7 +845,7 @@ func (l *DList[T]) ForEach(cb func(val T)) ForEach iterate the list, apply each element to the cb callback function -### func \(\*DList\[T\]\) [ForEachIf]() +### func \(\*DList\[T\]\) [ForEachIf]() ```go func (l *DList[T]) ForEachIf(cb func(val T) bool) @@ -854,6 +861,14 @@ func (l *DList[T]) IsEmpty() bool IsEmpty return whether the list is empty +### func \(\*DList\[T\]\) [Iterate]() + +```go +func (l *DList[T]) Iterate() Iterator[T] +``` + +Iterate returns an iterator to the first element in the list. + ### func \(\*DList\[T\]\) [Len]() ```go @@ -862,25 +877,25 @@ func (l *DList[T]) Len() int Len return the length of the list -### func \(\*DList\[T\]\) [PopBack]() +### func \(\*DList\[T\]\) [PopBack]() ```go func (l *DList[T]) PopBack() (T, bool) ``` -### func \(\*DList\[T\]\) [PopFront]() +### func \(\*DList\[T\]\) [PopFront]() ```go func (l *DList[T]) PopFront() (T, bool) ``` -### func \(\*DList\[T\]\) [PushBack]() +### func \(\*DList\[T\]\) [PushBack]() ```go func (l *DList[T]) PushBack(val T) ``` -### func \(\*DList\[T\]\) [PushFront]() +### func \(\*DList\[T\]\) [PushFront]() ```go func (l *DList[T]) PushFront(val T) @@ -922,6 +937,18 @@ type Integer interface { } ``` +## type [Iterator]() + +Iterator is the interface for container's iterator. + +```go +type Iterator[T any] interface { + IsNotEnd() bool // Whether it is point to the end of the range. + MoveToNext() // Let it point to the next element. + Value() T // Return the value of current element. +} +``` + ## type [LessFn]() LessFn is a function that returns whether 'a' is less than 'b'. @@ -948,6 +975,17 @@ type Map[K any, V any] interface { } ``` +## type [MapIterator]() + +MapIterator is the interface for map's iterator. + +```go +type MapIterator[K any, V any] interface { + Key() K // The key of the element + // contains filtered or unexported methods +} +``` + ## type [Numeric]() Numeric is a constraint that permits any numeric type. @@ -1073,7 +1111,7 @@ type SkipList[K any, V any] struct { } ``` -### func [NewSkipList]() +### func [NewSkipList]() ```go func NewSkipList[K Ordered, V any]() *SkipList[K, V] @@ -1081,7 +1119,7 @@ func NewSkipList[K Ordered, V any]() *SkipList[K, V] NewSkipList creates a new SkipList for Ordered key type. -### func [NewSkipListFromMap]() +### func [NewSkipListFromMap]() ```go func NewSkipListFromMap[K Ordered, V any](m map[K]V) *SkipList[K, V] @@ -1089,7 +1127,7 @@ func NewSkipListFromMap[K Ordered, V any](m map[K]V) *SkipList[K, V] NewSkipListFromMap creates a new SkipList from a map. -### func [NewSkipListFunc]() +### func [NewSkipListFunc]() ```go func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V] @@ -1097,13 +1135,13 @@ func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V] NewSkipListFunc creates a new SkipList with specified compare function keyCmp. -### func \(\*SkipList\[K, V\]\) [Clear]() +### func \(\*SkipList\[K, V\]\) [Clear]() ```go func (sl *SkipList[K, V]) Clear() ``` -### func \(\*SkipList\[K, V\]\) [Find]() +### func \(\*SkipList\[K, V\]\) [Find]() ```go func (sl *SkipList[K, V]) Find(key K) *V @@ -1111,37 +1149,45 @@ func (sl *SkipList[K, V]) Find(key K) *V Find returns the value associated with the passed key if the key is in the skiplist, otherwise returns nil. -### func \(\*SkipList\[K, V\]\) [ForEach]() +### func \(\*SkipList\[K, V\]\) [FindRange]() + +```go +func (sl *SkipList[K, V]) FindRange(first, last K) MapIterator[K, V] +``` + +FindRange returns an iterator in range \[first, last\) \(last is not includeed\). + +### func \(\*SkipList\[K, V\]\) [ForEach]() ```go func (sl *SkipList[K, V]) ForEach(op func(K, V)) ``` -### func \(\*SkipList\[K, V\]\) [ForEachIf]() +### func \(\*SkipList\[K, V\]\) [ForEachIf]() ```go func (sl *SkipList[K, V]) ForEachIf(op func(K, V) bool) ``` -### func \(\*SkipList\[K, V\]\) [ForEachMutable]() +### func \(\*SkipList\[K, V\]\) [ForEachMutable]() ```go func (sl *SkipList[K, V]) ForEachMutable(op func(K, *V)) ``` -### func \(\*SkipList\[K, V\]\) [ForEachMutableIf]() +### func \(\*SkipList\[K, V\]\) [ForEachMutableIf]() ```go func (sl *SkipList[K, V]) ForEachMutableIf(op func(K, *V) bool) ``` -### func \(\*SkipList\[K, V\]\) [Has]() +### func \(\*SkipList\[K, V\]\) [Has]() ```go func (sl *SkipList[K, V]) Has(key K) bool ``` -### func \(\*SkipList\[K, V\]\) [Insert]() +### func \(\*SkipList\[K, V\]\) [Insert]() ```go func (sl *SkipList[K, V]) Insert(key K, value V) @@ -1149,19 +1195,31 @@ func (sl *SkipList[K, V]) Insert(key K, value V) Insert inserts a key\-value pair into the skiplist. If the key is already in the skip list, it's value will be updated. -### func \(\*SkipList\[K, V\]\) [IsEmpty]() +### func \(\*SkipList\[K, V\]\) [IsEmpty]() ```go func (sl *SkipList[K, V]) IsEmpty() bool ``` -### func \(\*SkipList\[K, V\]\) [Len]() +### func \(\*SkipList\[K, V\]\) [Iterate]() + +```go +func (sl *SkipList[K, V]) Iterate() MapIterator[K, V] +``` + +### func \(\*SkipList\[K, V\]\) [Len]() ```go func (sl *SkipList[K, V]) Len() int ``` -### func \(\*SkipList\[K, V\]\) [Remove]() +### func \(\*SkipList\[K, V\]\) [LowerBound]() + +```go +func (sl *SkipList[K, V]) LowerBound(key K) MapIterator[K, V] +``` + +### func \(\*SkipList\[K, V\]\) [Remove]() ```go func (sl *SkipList[K, V]) Remove(key K) bool @@ -1169,6 +1227,12 @@ func (sl *SkipList[K, V]) Remove(key K) bool Remove removes the key\-value pair associated with the passed key and returns true if the key is in the skiplist, otherwise returns false. +### func \(\*SkipList\[K, V\]\) [UpperBound]() + +```go +func (sl *SkipList[K, V]) UpperBound(key K) MapIterator[K, V] +``` + ## type [Stack]() Stack s is a container adaptor that provides the functionality of a stack, a LIFO \(last\-in, first\-out\) data structure. diff --git a/container.go b/container.go index e3cc896..948b8b0 100644 --- a/container.go +++ b/container.go @@ -31,3 +31,16 @@ type Set[K any] interface { ForEach(func(K)) // Iterate the container. ForEachIf(func(K) bool) // Iterate the container, stops when the callback returns false. } + +// Iterator is the interface for container's iterator. +type Iterator[T any] interface { + IsNotEnd() bool // Whether it is point to the end of the range. + MoveToNext() // Let it point to the next element. + Value() T // Return the value of current element. +} + +// MapIterator is the interface for map's iterator. +type MapIterator[K any, V any] interface { + Iterator[V] + Key() K // The key of the element +} diff --git a/dlist.go b/dlist.go index a7f6aee..a65478e 100644 --- a/dlist.go +++ b/dlist.go @@ -10,7 +10,7 @@ type DList[T any] struct { type dListNode[T any] struct { prev, next *dListNode[T] - val T + value T } // NewDList make a new DList object @@ -52,6 +52,28 @@ func (l *DList[T]) String() string { return fmt.Sprintf("DList[%v]", nameOfType[T]()) } +type dlistIterator[T any] struct { + dl *DList[T] + node *dListNode[T] +} + +func (it *dlistIterator[T]) IsNotEnd() bool { + return it.node != &it.dl.head +} + +func (it *dlistIterator[T]) MoveToNext() { + it.node = it.node.next +} + +func (it *dlistIterator[T]) Value() T { + return it.node.value +} + +// Iterate returns an iterator to the first element in the list. +func (l *DList[T]) Iterate() Iterator[T] { + return &dlistIterator[T]{l, l.head.next} +} + func (l *DList[T]) PushFront(val T) { n := dListNode[T]{&l.head, l.head.next, val} l.head.next.prev = &n @@ -71,7 +93,7 @@ func (l *DList[T]) PopFront() (T, bool) { if l.length == 0 { return val, false } - val = l.head.next.val + val = l.head.next.value l.head.next = l.head.next.next l.head.prev = &l.head l.length-- @@ -83,7 +105,7 @@ func (l *DList[T]) PopBack() (T, bool) { if l.length == 0 { return val, false } - val = l.head.prev.val + val = l.head.prev.value l.head.prev = l.head.prev.prev l.head.prev.next = &l.head l.length-- @@ -93,14 +115,14 @@ func (l *DList[T]) PopBack() (T, bool) { // ForEach iterate the list, apply each element to the cb callback function func (l *DList[T]) ForEach(cb func(val T)) { for n := l.head.next; n != &l.head; n = n.next { - cb(n.val) + cb(n.value) } } // ForEach iterate the list, apply each element to the cb callback function, stop if cb returns false. func (l *DList[T]) ForEachIf(cb func(val T) bool) { for n := l.head.next; n != &l.head; n = n.next { - if !cb(n.val) { + if !cb(n.value) { break } } diff --git a/dlist_test.go b/dlist_test.go index ce9109d..f0076e4 100644 --- a/dlist_test.go +++ b/dlist_test.go @@ -25,6 +25,16 @@ func Test_DList_String(t *testing.T) { expectEq(t, "DList[int]", l.String()) } +func Test_DList_Iterate(t *testing.T) { + l := NewDListOf(1, 2, 3) + i := 1 + for it := l.Iterate(); it.IsNotEnd(); it.MoveToNext() { + expectEq(t, it.Value(), i) + i++ + } + expectEq(t, i, 4) +} + func Test_DList_PushFront(t *testing.T) { l := NewDList[int]() l.PushFront(1) @@ -105,3 +115,21 @@ func Test_DList_ForEachIf(t *testing.T) { }) expectEq(t, c, 2) } + +func Benchmark_DList_Iterate(b *testing.B) { + l := NewDListOf(Range(1, 10000)...) + b.Run("Iterate", func(b *testing.B) { + sum := 0 + for i := 0; i < b.N; i++ { + for it := l.Iterate(); it.IsNotEnd(); it.MoveToNext() { + sum += it.Value() + } + } + }) + b.Run("Iterate", func(b *testing.B) { + sum := 0 + for i := 0; i < b.N; i++ { + l.ForEach(func(val int) { sum += val }) + } + }) +} diff --git a/skiplist.go b/skiplist.go index 751c938..d22b6e3 100644 --- a/skiplist.go +++ b/skiplist.go @@ -36,24 +36,6 @@ type SkipList[K any, V any] struct { impl skipListImpl[K, V] } -type skipListNode[K any, V any] struct { - key K - value V - next []*skipListNode[K, V] -} - -// skipListImpl is an interface to provide different implementation for Ordered key or CompareFn. -// -// We can use CompareFn to cumpare Ordered keys, but a separated implementation is much faster. -// We don't make the whole skip list an interface, in order to share the type independented method. -// And because these methods are called directly without going through the interface, they are also -// much faster. -type skipListImpl[K any, V any] interface { - findNode(key K) *skipListNode[K, V] - findInsertPoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) - findRemovePoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) -} - // NewSkipList creates a new SkipList for Ordered key type. func NewSkipList[K Ordered, V any]() *SkipList[K, V] { sl := skipListOrdered[K, V]{ @@ -103,6 +85,10 @@ func (sl *SkipList[K, V]) Clear() { sl.len = 0 } +func (sl *SkipList[K, V]) Iterate() MapIterator[K, V] { + return &skipListIterator[K, V]{sl.head.next[0], nil} +} + // Insert inserts a key-value pair into the skiplist. // If the key is already in the skip list, it's value will be updated. func (sl *SkipList[K, V]) Insert(key K, value V) { @@ -146,6 +132,19 @@ func (sl *SkipList[K, V]) Has(key K) bool { return sl.impl.findNode(key) != nil } +func (sl *SkipList[K, V]) LowerBound(key K) MapIterator[K, V] { + return &skipListIterator[K, V]{sl.impl.lowerBound(key), nil} +} + +func (sl *SkipList[K, V]) UpperBound(key K) MapIterator[K, V] { + return &skipListIterator[K, V]{sl.impl.upperBound(key), nil} +} + +// FindRange returns an iterator in range [first, last) (last is not includeed). +func (sl *SkipList[K, V]) FindRange(first, last K) MapIterator[K, V] { + return &skipListIterator[K, V]{sl.impl.lowerBound(first), sl.impl.upperBound(last)} +} + // Remove removes the key-value pair associated with the passed key and returns true if the key is // in the skiplist, otherwise returns false. func (sl *SkipList[K, V]) Remove(key K) bool { @@ -191,6 +190,51 @@ func (sl *SkipList[K, V]) ForEachMutableIf(op func(K, *V) bool) { } } +/// SkipList implementation part. + +type skipListNode[K any, V any] struct { + key K + value V + next []*skipListNode[K, V] +} + +//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] + +type skipListIterator[K any, V any] struct { + node, end *skipListNode[K, V] +} + +func (it *skipListIterator[K, V]) IsNotEnd() bool { + return it.node != it.end +} + +func (it *skipListIterator[K, V]) MoveToNext() { + it.node = it.node.next[0] +} + +func (it *skipListIterator[K, V]) Key() K { + return it.node.key +} + +func (it *skipListIterator[K, V]) Value() V { + return it.node.value +} + +// skipListImpl is an interface to provide different implementation for Ordered key or CompareFn. +// +// We can use CompareFn to cumpare Ordered keys, but a separated implementation is much faster. +// We don't make the whole skip list an interface, in order to share the type independented method. +// And because these methods are called directly without going through the interface, they are also +// much faster. +type skipListImpl[K any, V any] interface { + findNode(key K) *skipListNode[K, V] + lowerBound(key K) *skipListNode[K, V] + upperBound(key K) *skipListNode[K, V] + findInsertPoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) + findRemovePoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) +} + func (sl *SkipList[K, V]) init() { sl.level = 1 // #nosec G404 -- This is not a security condition @@ -199,9 +243,6 @@ func (sl *SkipList[K, V]) init() { sl.head.next = make([]*skipListNode[K, V], skipListMaxLevel) } -//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] - func (sl *SkipList[K, V]) randomLevel() int { total := uint64(1)<= 0; i-- { - cur := pre.next[i] - for ; cur != nil; cur = cur.next[i] { + for cur := prev.next[i]; cur != nil; cur = cur.next[i] { if cur.key == key { return cur } if cur.key > key { + // All other node in this level must be greater than the key, + // search the next level. break } - pre = cur + prev = cur } } - return nil + if eq { + return nil + } + return prev.next[0] +} + +func (sl *skipListOrdered[K, V]) lowerBound(key K) *skipListNode[K, V] { + return sl.doFindNode(key, false) +} + +func (sl *skipListOrdered[K, V]) upperBound(key K) *skipListNode[K, V] { + node := sl.lowerBound(key) + if node != nil && node.key == key { + return node.next[0] + } + return node } // findInsertPoint returns (*node, nil) to the existed node if the key exists, @@ -296,11 +360,18 @@ type skipListFunc[K any, V any] struct { keyCmp CompareFn[K] } -// findNodeSlow use keyCmp to compare key, which is slower. func (sl *skipListFunc[K, V]) findNode(key K) *skipListNode[K, V] { - var pre = &sl.head + node := sl.lowerBound(key) + if node != nil && sl.keyCmp(node.key, key) == 0 { + return node + } + return nil +} + +func (sl *skipListFunc[K, V]) lowerBound(key K) *skipListNode[K, V] { + var prev = &sl.head for i := sl.level - 1; i >= 0; i-- { - cur := pre.next[i] + cur := prev.next[i] for ; cur != nil; cur = cur.next[i] { cmpRet := sl.keyCmp(cur.key, key) if cmpRet == 0 { @@ -309,10 +380,18 @@ func (sl *skipListFunc[K, V]) findNode(key K) *skipListNode[K, V] { if cmpRet > 0 { break } - pre = cur + prev = cur } } - return nil + return prev.next[0] +} + +func (sl *skipListFunc[K, V]) upperBound(key K) *skipListNode[K, V] { + node := sl.lowerBound(key) + if node != nil && sl.keyCmp(node.key, key) == 0 { + return node.next[0] + } + return node } // findInsertPoint returns (*node, nil) to the existed node if the key exists, @@ -321,19 +400,19 @@ func (sl *skipListFunc[K, V]) findInsertPoint(key K) (*skipListNode[K, V], []*sk prevs := sl.prevsCache[0:sl.level] prev := &sl.head for i := sl.level - 1; i >= 0; i-- { - for next := prev.next[i]; next != nil; next = next.next[i] { - r := sl.keyCmp(next.key, key) + for cur := prev.next[i]; cur != nil; cur = cur.next[i] { + r := sl.keyCmp(cur.key, key) if r == 0 { // The key is already existed, prevs are useless because no new node insertion. // stop searching. - return next, nil + return cur, nil } if r > 0 { // All other node in this level must be greater than the key, // search the next level. break } - prev = next + prev = cur } prevs[i] = prev } diff --git a/skiplist_bench_test.go b/skiplist_bench_test.go index 36d16ec..d872674 100644 --- a/skiplist_bench_test.go +++ b/skiplist_bench_test.go @@ -18,6 +18,16 @@ func newMapN(n int) map[int]int { return m } +func BenchmarkSkipList_Iterate(b *testing.B) { + sl := newSkipListN(100) + b.ResetTimer() + for n := 0; n < b.N; n++ { + for i := sl.Iterate(); i.IsNotEnd(); i.MoveToNext() { + _, _ = i.Key(), i.Value() + } + } +} + func BenchmarkSkipList_Insert(b *testing.B) { start := benchInitSize sl := newSkipListN(start) @@ -82,10 +92,10 @@ func BenchmarkSkipList_Find(b *testing.B) { } } }) - b.Run("FindSlow", func(b *testing.B) { + b.Run("LowerBound", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { - _ = sl.Find(n) + _ = sl.impl.lowerBound(n) } } }) @@ -96,13 +106,6 @@ func BenchmarkSkipList_Find(b *testing.B) { } } }) - b.Run("FindEndSlow", func(b *testing.B) { - for i := 0; i < b.N; i++ { - for n := 0; n < benchBatchSize; n++ { - _ = sl.Find(benchInitSize) - } - } - }) } func BenchmarkSkipListString(b *testing.B) { diff --git a/skiplist_test.go b/skiplist_test.go index 1b32704..93ad0ee 100644 --- a/skiplist_test.go +++ b/skiplist_test.go @@ -5,8 +5,10 @@ import ( "testing" ) -func TestSkipListInterface(t *testing.T) { - _ = Map[int, int](NewSkipList[int, int]()) +func TestSkipList_Interface(t *testing.T) { + sl := NewSkipList[int, int]() + _ = Map[int, int](sl) + _ = MapIterator[int, int](sl.Iterate()) } func TestNewSkipList(t *testing.T) { @@ -93,6 +95,53 @@ func TestNewSkipListFromMap(t *testing.T) { } } +func TestNewSkipList_Iterate(t *testing.T) { + sl := newSkipListN(10) + i := 0 + for it := sl.Iterate(); it.IsNotEnd(); it.MoveToNext() { + expectEq(t, it.Key(), i) + expectEq(t, it.Value(), i) + i++ + } +} + +func testNewSkipList_Iterater(t *testing.T, sl *SkipList[int, int]) { + t.Run("LowerBound", func(t *testing.T) { + expectEq(t, sl.LowerBound(1).Key(), 1) + expectEq(t, sl.LowerBound(3).Key(), 4) + expectEq(t, sl.LowerBound(4).Key(), 4) + expectFalse(t, sl.LowerBound(5).IsNotEnd()) + }) + + t.Run("UpperBound", func(t *testing.T) { + expectEq(t, sl.UpperBound(0).Key(), 1) + expectEq(t, sl.UpperBound(1).Key(), 2) + expectEq(t, sl.UpperBound(3).Key(), 4) + expectFalse(t, sl.UpperBound(4).IsNotEnd()) + expectFalse(t, sl.UpperBound(5).IsNotEnd()) + }) + + t.Run("FindRange", func(t *testing.T) { + it := sl.FindRange(1, 3) + expectEq(t, it.Key(), 1) + it.MoveToNext() + expectEq(t, it.Key(), 2) + }) +} + +func TestNewSkipList_Iterater(t *testing.T) { + sl := NewSkipListFromMap(map[int]int{1: 1, 2: 2, 4: 4}) + testNewSkipList_Iterater(t, sl) +} + +func TestNewSkipList_Func_Iterater(t *testing.T) { + sl := NewSkipListFunc[int, int](OrderedCompare[int]) + m := map[int]int{1: 1, 2: 2, 4: 4} + for k, v := range m { + sl.Insert(k, v) + } + testNewSkipList_Iterater(t, sl) +} func TestSkipList_Insert(t *testing.T) { sl := NewSkipList[int, int]() for i := 0; i < 100; i++ {