mirror of
https://github.com/charlienet/go-mixed.git
synced 2025-07-17 16:12:42 +08:00
196 lines
3.0 KiB
Go
196 lines
3.0 KiB
Go
package list
|
|
|
|
const minCapacity = 16
|
|
|
|
type ArrayList[T any] struct {
|
|
buf []T
|
|
head int
|
|
tail int
|
|
minCap int
|
|
list[T]
|
|
}
|
|
|
|
func NewArrayList[T any](elems ...T) *ArrayList[T] {
|
|
minCap := minCapacity
|
|
|
|
size := len(elems)
|
|
for minCap < size {
|
|
minCap <<= 1
|
|
}
|
|
|
|
var tail int = size
|
|
var buf []T
|
|
|
|
if len(elems) > 0 {
|
|
buf = make([]T, minCap)
|
|
copy(buf, elems)
|
|
}
|
|
|
|
l := &ArrayList[T]{
|
|
list: list[T]{size: size},
|
|
buf: buf,
|
|
tail: tail,
|
|
minCap: minCap,
|
|
}
|
|
|
|
// for _, v := range elems {
|
|
// l.PushBack(v)
|
|
// }
|
|
|
|
return l
|
|
}
|
|
|
|
func (l *ArrayList[T]) PushFront(v T) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.grow()
|
|
|
|
l.head = l.prev(l.head)
|
|
l.buf[l.head] = v
|
|
l.size++
|
|
}
|
|
|
|
func (l *ArrayList[T]) PushBack(v T) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.grow()
|
|
|
|
l.buf[l.tail] = v
|
|
|
|
l.tail = l.next(l.tail)
|
|
l.size++
|
|
}
|
|
|
|
func (l *ArrayList[T]) PopFront() T {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
if l.size <= 0 {
|
|
panic("list: PopFront() called on empty list")
|
|
}
|
|
ret := l.buf[l.head]
|
|
var zero T
|
|
l.buf[l.head] = zero
|
|
|
|
l.head = l.next(l.head)
|
|
l.size--
|
|
|
|
l.shrink()
|
|
return ret
|
|
}
|
|
|
|
func (l *ArrayList[T]) PopBack() T {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
l.tail = l.prev(l.tail)
|
|
|
|
ret := l.buf[l.tail]
|
|
var zero T
|
|
l.buf[l.tail] = zero
|
|
l.size--
|
|
|
|
l.shrink()
|
|
return ret
|
|
}
|
|
|
|
func (l *ArrayList[T]) RemoveAt(at int) T {
|
|
if at < 0 || at >= l.Size() {
|
|
panic(ErrorOutOffRange)
|
|
}
|
|
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
rm := (l.head + at) & (len(l.buf) - 1)
|
|
if at*2 < l.size {
|
|
for i := 0; i < at; i++ {
|
|
prev := l.prev(rm)
|
|
l.buf[prev], l.buf[rm] = l.buf[rm], l.buf[prev]
|
|
rm = prev
|
|
}
|
|
return l.PopFront()
|
|
}
|
|
swaps := l.size - at - 1
|
|
for i := 0; i < swaps; i++ {
|
|
next := l.next(rm)
|
|
l.buf[rm], l.buf[next] = l.buf[next], l.buf[rm]
|
|
rm = next
|
|
}
|
|
return l.PopBack()
|
|
}
|
|
|
|
func (l *ArrayList[T]) Front() T {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
return l.buf[l.head]
|
|
}
|
|
|
|
func (l *ArrayList[T]) Back() T {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
return l.buf[l.tail]
|
|
}
|
|
|
|
func (l *ArrayList[T]) ForEach(fn func(T)) {
|
|
l.mu.RLock()
|
|
defer l.mu.RUnlock()
|
|
|
|
n := l.head
|
|
for i := 0; i < l.size; i++ {
|
|
fn(l.buf[n])
|
|
|
|
n = l.next(n)
|
|
}
|
|
}
|
|
|
|
func (q *ArrayList[T]) prev(i int) int {
|
|
return (i - 1) & (len(q.buf) - 1)
|
|
}
|
|
|
|
func (l *ArrayList[T]) next(i int) int {
|
|
return (i + 1) & (len(l.buf) - 1)
|
|
}
|
|
|
|
func (l *ArrayList[T]) grow() {
|
|
if l.size != len(l.buf) {
|
|
return
|
|
}
|
|
if len(l.buf) == 0 {
|
|
if l.minCap == 0 {
|
|
l.minCap = minCapacity
|
|
}
|
|
l.buf = make([]T, l.minCap)
|
|
return
|
|
}
|
|
|
|
l.resize()
|
|
}
|
|
|
|
func (l *ArrayList[T]) shrink() {
|
|
if len(l.buf) > l.minCap && (l.size<<2) == len(l.buf) {
|
|
l.resize()
|
|
}
|
|
}
|
|
|
|
// resize resizes the list to fit exactly twice its current contents. This is
|
|
// used to grow the list when it is full, and also to shrink it when it is
|
|
// only a quarter full.
|
|
func (l *ArrayList[T]) resize() {
|
|
newBuf := make([]T, l.size<<1)
|
|
if l.tail > l.head {
|
|
copy(newBuf, l.buf[l.head:l.tail])
|
|
} else {
|
|
n := copy(newBuf, l.buf[l.head:])
|
|
copy(newBuf[n:], l.buf[:l.tail])
|
|
}
|
|
|
|
l.head = 0
|
|
l.tail = l.size
|
|
l.buf = newBuf
|
|
}
|