File: list.go

package info (click to toggle)
golang-github-marstr-collection 2.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 208 kB
  • sloc: makefile: 2
file content (153 lines) | stat: -rw-r--r-- 3,459 bytes parent folder | download
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
}