1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
package collection
import (
"bytes"
"context"
"fmt"
"sync"
)
// List is a dynamically sized list akin to List in the .NET world,
// ArrayList in the Java world, or vector in the C++ world.
type List[T any] struct {
underlyer []T
key sync.RWMutex
}
// NewList creates a new list which contains the elements provided.
func NewList[T any](entries ...T) *List[T] {
return &List[T]{
underlyer: entries,
}
}
// Add appends an entry to the logical end of the List.
func (l *List[T]) Add(entries ...T) {
l.key.Lock()
defer l.key.Unlock()
l.underlyer = append(l.underlyer, entries...)
}
// AddAt injects values beginning at `pos`. If multiple values
// are provided in `entries` they are placed in the same order
// they are provided.
func (l *List[T]) AddAt(pos uint, entries ...T) {
l.key.Lock()
defer l.key.Unlock()
l.underlyer = append(l.underlyer[:pos], append(entries, l.underlyer[pos:]...)...)
}
// Enumerate lists each element present in the collection
func (l *List[T]) Enumerate(ctx context.Context) Enumerator[T] {
retval := make(chan T)
go func() {
l.key.RLock()
defer l.key.RUnlock()
defer close(retval)
for _, entry := range l.underlyer {
select {
case retval <- entry:
// Intentionally Left Blank
case <-ctx.Done():
return
}
}
}()
return retval
}
// Get retreives the value stored in a particular position of the list.
// If no item exists at the given position, the second parameter will be
// returned as false.
func (l *List[T]) Get(pos uint) (T, bool) {
l.key.RLock()
defer l.key.RUnlock()
if pos > uint(len(l.underlyer)) {
return *new(T), false
}
return l.underlyer[pos], true
}
// IsEmpty tests to see if this List has any elements present.
func (l *List[T]) IsEmpty() bool {
l.key.RLock()
defer l.key.RUnlock()
return len(l.underlyer) == 0
}
// Length returns the number of elements in the List.
func (l *List[T]) Length() uint {
l.key.RLock()
defer l.key.RUnlock()
return uint(len(l.underlyer))
}
// Remove retreives a value from this List and shifts all other values.
func (l *List[T]) Remove(pos uint) (T, bool) {
l.key.Lock()
defer l.key.Unlock()
if pos > uint(len(l.underlyer)) {
return *new(T), false
}
retval := l.underlyer[pos]
l.underlyer = append(l.underlyer[:pos], l.underlyer[pos+1:]...)
return retval, true
}
// Set updates the value stored at a given position in the List.
func (l *List[T]) Set(pos uint, val T) bool {
l.key.Lock()
defer l.key.Unlock()
var retval bool
count := uint(len(l.underlyer))
if pos > count {
retval = false
} else {
l.underlyer[pos] = val
retval = true
}
return retval
}
// String generates a textual representation of the List for the sake of debugging.
func (l *List[T]) String() string {
l.key.RLock()
defer l.key.RUnlock()
builder := bytes.NewBufferString("[")
for i, entry := range l.underlyer {
if i >= 15 {
builder.WriteString("... ")
break
}
builder.WriteString(fmt.Sprintf("%v ", entry))
}
builder.Truncate(builder.Len() - 1)
builder.WriteRune(']')
return builder.String()
}
// Swap switches the values that are stored at positions `x` and `y`
func (l *List[T]) Swap(x, y uint) bool {
l.key.Lock()
defer l.key.Unlock()
return l.swap(x, y)
}
func (l *List[T]) swap(x, y uint) bool {
count := uint(len(l.underlyer))
if x < count && y < count {
temp := l.underlyer[x]
l.underlyer[x] = l.underlyer[y]
l.underlyer[y] = temp
return true
}
return false
}
|