Added CList
This commit is contained in:
parent
0424228e97
commit
c65e9e7d91
|
@ -0,0 +1,152 @@
|
|||
package common
|
||||
|
||||
/*
|
||||
The purpose of CList is to provide a goroutine-safe linked-list.
|
||||
NOTE: Not all methods of container/list are (yet) implemented.
|
||||
*/
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// CElement is an element of a linked-list
|
||||
// Traversal from a CElement are goroutine-safe.
|
||||
type CElement struct {
|
||||
next unsafe.Pointer
|
||||
wg *sync.WaitGroup
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// Blocking implementation of Next().
|
||||
// If return is nil, this element was removed from the list.
|
||||
func (e *CElement) NextWait() *CElement {
|
||||
e.wg.Wait()
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
func (e *CElement) Next() *CElement {
|
||||
next := atomic.LoadPointer(&e.next)
|
||||
if next == nil {
|
||||
return nil
|
||||
}
|
||||
return (*CElement)(next)
|
||||
}
|
||||
|
||||
// CList represents a linked list.
|
||||
// The zero value for CList is an empty list ready to use.
|
||||
// Operations are goroutine-safe.
|
||||
type CList struct {
|
||||
mtx sync.Mutex
|
||||
wg *sync.WaitGroup
|
||||
head *CElement // first element
|
||||
tail *CElement // last element
|
||||
len int // list length
|
||||
}
|
||||
|
||||
func (l *CList) Init() *CList {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
l.wg = waitGroup1()
|
||||
l.head = nil
|
||||
l.tail = nil
|
||||
l.len = 0
|
||||
return l
|
||||
}
|
||||
|
||||
func NewCList() *CList { return new(CList).Init() }
|
||||
|
||||
func (l *CList) Len() int {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
return l.len
|
||||
}
|
||||
|
||||
func (l *CList) Front() *CElement {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
return l.head
|
||||
}
|
||||
|
||||
func (l *CList) FrontWait() *CElement {
|
||||
for {
|
||||
l.mtx.Lock()
|
||||
head := l.head
|
||||
wg := l.wg
|
||||
l.mtx.Unlock()
|
||||
if head == nil {
|
||||
wg.Wait()
|
||||
} else {
|
||||
return head
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CList) Back() *CElement {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
return l.tail
|
||||
}
|
||||
|
||||
func (l *CList) BackWait() *CElement {
|
||||
for {
|
||||
l.mtx.Lock()
|
||||
tail := l.tail
|
||||
wg := l.wg
|
||||
l.mtx.Unlock()
|
||||
if tail == nil {
|
||||
wg.Wait()
|
||||
} else {
|
||||
return tail
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CList) PushBack(v interface{}) *CElement {
|
||||
e := &CElement{
|
||||
next: nil,
|
||||
wg: waitGroup1(),
|
||||
Value: v,
|
||||
}
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
l.len += 1
|
||||
if l.tail == nil {
|
||||
l.head = e
|
||||
l.tail = e
|
||||
l.wg.Done()
|
||||
return e
|
||||
} else {
|
||||
oldTail := l.tail
|
||||
atomic.StorePointer(&oldTail.next, unsafe.Pointer(e))
|
||||
l.tail = e
|
||||
oldTail.wg.Done()
|
||||
return e
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (l *CList) RemoveFront() interface{} {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
if l.head == nil {
|
||||
return nil
|
||||
}
|
||||
oldFront := l.head
|
||||
next := (*CElement)(oldFront.next)
|
||||
l.head = next
|
||||
if next == nil {
|
||||
l.tail = nil
|
||||
l.wg = waitGroup1()
|
||||
}
|
||||
l.len -= 1
|
||||
atomic.StorePointer(&oldFront.next, unsafe.Pointer(nil))
|
||||
return oldFront.Value
|
||||
}
|
||||
|
||||
func waitGroup1() (wg *sync.WaitGroup) {
|
||||
wg = &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue