1
0
mirror of https://github.com/charlienet/go-mixed.git synced 2025-07-17 16:12:42 +08:00
Files
go-mixed/collections/list/array_list.go
2023-08-25 15:31:00 +08:00

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
}