-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patharray.go
More file actions
184 lines (169 loc) · 4.3 KB
/
Copy patharray.go
File metadata and controls
184 lines (169 loc) · 4.3 KB
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// SPDX-License-Identifier: EUPL-1.2
// Generic slice operations for the Core framework.
// Based on leaanthony/slicer, rewritten with Go 1.18+ generics.
package core
// Array is a typed slice with common operations.
//
// agents := core.NewArray("codex", "hades")
// agents.AddUnique("homelab")
type Array[T comparable] struct {
items []T
}
// NewArray creates an empty Array.
//
// agents := core.NewArray("codex", "hades")
// core.Println(agents.Len())
func NewArray[T comparable](items ...T) *Array[T] {
return &Array[T]{items: items}
}
// Add appends values.
//
// agents := core.NewArray("codex")
// agents.Add("hades", "homelab")
func (s *Array[T]) Add(values ...T) {
s.items = append(s.items, values...)
}
// AddUnique appends values only if not already present.
//
// agents := core.NewArray("codex")
// agents.AddUnique("codex", "hades")
func (s *Array[T]) AddUnique(values ...T) {
for _, v := range values {
if !s.Contains(v) {
s.items = append(s.items, v)
}
}
}
// Contains returns true if the value is in the slice.
//
// agents := core.NewArray("codex", "hades")
// if agents.Contains("hades") {
// core.Println("agent present")
// }
func (s *Array[T]) Contains(val T) bool {
for _, v := range s.items {
if v == val {
return true
}
}
return false
}
// IndexOf returns the index of the first occurrence of val, or -1 when
// absent. Companion to Contains for callers that need the position.
//
// if i := agents.IndexOf("hades"); i >= 0 {
// core.Println("at", i)
// }
func (s *Array[T]) IndexOf(val T) int {
for i, v := range s.items {
if v == val {
return i
}
}
return -1
}
// Filter returns a new Array with elements matching the predicate.
//
// agents := core.NewArray("codex", "hades", "homelab")
// r := agents.Filter(func(name string) bool { return core.HasPrefix(name, "h") })
// if !r.OK {
// return r
// }
// filtered := r.Value.(*core.Array[string])
// core.Println(filtered.Len())
func (s *Array[T]) Filter(fn func(T) bool) Result {
filtered := &Array[T]{}
if len(s.items) == 0 {
return Result{filtered, true}
}
// Pre-size to len(s.items) so the inner append never grows the
// backing array. Unmatched elements waste capacity but no allocs.
filtered.items = make([]T, 0, len(s.items))
for _, v := range s.items {
if fn(v) {
filtered.items = append(filtered.items, v)
}
}
return Result{filtered, true}
}
// Each runs a function on every element.
//
// agents := core.NewArray("codex", "hades")
// agents.Each(func(name string) { core.Println(name) })
func (s *Array[T]) Each(fn func(T)) {
for _, v := range s.items {
fn(v)
}
}
// Remove removes the first occurrence of a value.
//
// agents := core.NewArray("codex", "hades", "homelab")
// agents.Remove("hades")
func (s *Array[T]) Remove(val T) {
for i, v := range s.items {
if v == val {
s.items = append(s.items[:i], s.items[i+1:]...)
return
}
}
}
// Deduplicate removes duplicate values, preserving order.
//
// agents := core.NewArray("codex", "codex", "hades")
// agents.Deduplicate()
func (s *Array[T]) Deduplicate() {
// Small-N linear path. For up to 16 elements, a linear scan on the
// growing result (O(N²) compares) beats the map allocation + hashing
// cost of the general path. Same shape as SliceUniq.
if len(s.items) <= 16 {
result := make([]T, 0, len(s.items))
outer:
for _, v := range s.items {
for _, r := range result {
if r == v {
continue outer
}
}
result = append(result, v)
}
s.items = result
return
}
seen := make(map[T]struct{}, len(s.items))
result := make([]T, 0, len(s.items))
for _, v := range s.items {
if _, exists := seen[v]; !exists {
seen[v] = struct{}{}
result = append(result, v)
}
}
s.items = result
}
// Len returns the number of elements.
//
// agents := core.NewArray("codex", "hades")
// count := agents.Len()
// core.Println(count)
func (s *Array[T]) Len() int {
return len(s.items)
}
// Clear removes all elements.
//
// agents := core.NewArray("codex", "hades")
// agents.Clear()
func (s *Array[T]) Clear() {
s.items = nil
}
// AsSlice returns a copy of the underlying slice.
//
// agents := core.NewArray("codex", "hades")
// names := agents.AsSlice()
// core.Println(core.Join(", ", names...))
func (s *Array[T]) AsSlice() []T {
if s.items == nil {
return nil
}
out := make([]T, len(s.items))
copy(out, s.items)
return out
}