Codebase list golang-github-marstr-collection / 3592c3f
New upstream version 0.3.3+git20171004.e631537 Dr. Tobias Quathamer 6 years ago
21 changed file(s) with 2956 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 # Compiled Object files, Static and Dynamic libs (Shared Objects)
1 *.o
2 *.a
3 *.so
4
5 # Folders
6 _obj
7 _test
8
9 # Architecture specific extensions/prefixes
10 *.[568vq]
11 [568vq].out
12
13 *.cgo1.go
14 *.cgo2.c
15 _cgo_defun.c
16 _cgo_gotypes.go
17 _cgo_export.*
18
19 _testmain.go
20
21 *.exe
22 *.test
23 *.prof
0 language: go
1
2 go:
3 - 1.7
4 - 1.8
5 - 1.9
6
7 install:
8 - go get -u github.com/golang/lint/golint
9
10 script:
11 - go test -v -cover
12 - test -z "$(golint | tee /dev/stderr)"
13 - test -z "$(go vet | tee /dev/stderr | grep error)"
14 - test -z "$(gofmt -l *.go | tee /dev/stderr)"
0 MIT License
1
2 Copyright (c) 2017 Martin Strobel
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
0 # collection
1 [![GoDoc](https://godoc.org/github.com/marstr/collection?status.svg)](https://godoc.org/github.com/marstr/collection) [![Build Status](https://travis-ci.org/marstr/collection.svg?branch=master)](https://travis-ci.org/marstr/collection) [![Go Report Card](https://goreportcard.com/badge/github.com/marstr/collection)](https://goreportcard.com/report/github.com/marstr/collection)
2
3 # Usage
4
5 ## Querying Collections
6 Inspired by .NET's Linq, querying data structures used in this library is a snap! Build Go pipelines quickly and easily which will apply lambdas as they query your data structures.
7
8 ### Slices
9 Converting between slices and a queryable structure is as trivial as it should be.
10 ``` Go
11 original := []interface{}{"a", "b", "c"}
12 subject := collection.AsEnumerable(original...)
13
14 for entry := range subject.Enumerate(nil) {
15 fmt.Println(entry)
16 }
17 // Output:
18 // a
19 // b
20 // c
21
22 ```
23
24 ### Where
25 ``` Go
26 subject := collection.AsEnumerable(1, 2, 3, 4, 5, 6)
27 filtered := collection.Where(subject, func(num interface{}) bool{
28 return num.(int) > 3
29 })
30 for entry := range filtered.Enumerate(nil) {
31 fmt.Println(entry)
32 }
33 // Output:
34 // 4
35 // 5
36 // 6
37 ```
38 ### Select
39 ``` Go
40 subject := collection.AsEnumerable(1, 2, 3, 4, 5, 6)
41 updated := collection.Select(subject, func(num interface{}) interface{}{
42 return num.(int) + 10
43 })
44 for entry := range updated.Enumerate(nil) {
45 fmt.Println(entry)
46 }
47 // Output:
48 // 11
49 // 12
50 // 13
51 // 14
52 // 15
53 // 16
54 ```
55
56 ## Queues
57 ### Creating a Queue
58
59 ``` Go
60 done := make(chan struct{})
61 subject := collection.NewQueue(1, 2, 3, 5, 8, 13, 21)
62 selected := subject.Enumerate(done).Skip(3).Take(3)
63 for entry := range selected {
64 fmt.Println(entry)
65 }
66 close(done)
67 // Output:
68 // 5
69 // 8
70 // 13
71 ```
72
73 ### Checking if a Queue is empty
74 ``` Go
75 populated := collection.NewQueue(1, 2, 3, 5, 8, 13)
76 notPopulated := collection.NewQueue()
77 fmt.Println(populated.IsEmpty())
78 fmt.Println(notPopulated.IsEmpty())
79 // Output:
80 // false
81 // true
82 ```
83
84 # Versioning
85 This library will conform to strict semantic versions as defined by [semver.org](http://semver.org/spec/v2.0.0.html)'s v2 specification.
86
87 # Contributing
88 I accept contributions! To ensure `glide` users and `go get` users retrieve the same commit, please submit PRs to the 'dev' branch. Remember to add tests!
0 package collection
1
2 type fibonacciGenerator struct{}
3
4 // Fibonacci is an Enumerable which will dynamically generate the fibonacci sequence.
5 var Fibonacci Enumerable = fibonacciGenerator{}
6
7 func (gen fibonacciGenerator) Enumerate(cancel <-chan struct{}) Enumerator {
8 retval := make(chan interface{})
9
10 go func() {
11 defer close(retval)
12 a, b := 0, 1
13
14 for {
15 select {
16 case retval <- a:
17 a, b = b, a+b
18 case <-cancel:
19 return
20 }
21 }
22 }()
23
24 return retval
25 }
0 package collection
1
2 import (
3 "errors"
4 "os"
5 "path/filepath"
6 )
7
8 // DirectoryOptions is a means of configuring a `Directory` instance to including various children in its enumeration without
9 // supplying a `Where` clause later.
10 type DirectoryOptions uint
11
12 // These constants define all of the supported options for configuring a `Directory`
13 const (
14 DirectoryOptionsExcludeFiles = 1 << iota
15 DirectoryOptionsExcludeDirectories
16 DirectoryOptionsRecursive
17 )
18
19 // Directory treats a filesystem path as a collection of filesystem entries, specifically a collection of directories and files.
20 type Directory struct {
21 Location string
22 Options DirectoryOptions
23 }
24
25 func defaultEnumeratePredicate(loc string, info os.FileInfo) bool {
26 return true
27 }
28
29 func (d Directory) applyOptions(loc string, info os.FileInfo) bool {
30 if info.IsDir() && 0 != (d.Options&DirectoryOptionsExcludeDirectories) {
31 return false
32 }
33
34 if !info.IsDir() && 0 != d.Options&DirectoryOptionsExcludeFiles {
35 return false
36 }
37
38 return true
39 }
40
41 // Enumerate lists the items in a `Directory`
42 func (d Directory) Enumerate(cancel <-chan struct{}) Enumerator {
43 results := make(chan interface{})
44
45 go func() {
46 defer close(results)
47
48 filepath.Walk(d.Location, func(currentLocation string, info os.FileInfo, openErr error) (err error) {
49 if openErr != nil {
50 err = openErr
51 return
52 }
53
54 if d.Location == currentLocation {
55 return
56 }
57
58 if info.IsDir() && 0 == d.Options&DirectoryOptionsRecursive {
59 err = filepath.SkipDir
60 }
61
62 if d.applyOptions(currentLocation, info) {
63 select {
64 case results <- currentLocation:
65 // Intentionally Left Blank
66 case <-cancel:
67 err = errors.New("directory enumeration cancelled")
68 }
69 }
70
71 return
72 })
73 }()
74
75 return results
76 }
0 package collection
1
2 import (
3 "fmt"
4 "math"
5 "path"
6 "path/filepath"
7 "testing"
8 )
9
10 func TestEnumerateDirectoryOptions_UniqueBits(t *testing.T) {
11 isPowerOfTwo := func(subject float64) bool {
12 a := math.Abs(math.Log2(subject))
13 b := math.Floor(a)
14
15 return a-b < .0000001
16 }
17
18 if !isPowerOfTwo(64) {
19 t.Log("isPowerOfTwo decided 64 is not a power of two.")
20 t.FailNow()
21 }
22
23 if isPowerOfTwo(91) {
24 t.Log("isPowerOfTwo decided 91 is a power of two.")
25 t.FailNow()
26 }
27
28 seen := make(map[DirectoryOptions]struct{})
29
30 declared := []DirectoryOptions{
31 DirectoryOptionsExcludeFiles,
32 DirectoryOptionsExcludeDirectories,
33 DirectoryOptionsRecursive,
34 }
35
36 for _, option := range declared {
37 if _, ok := seen[option]; ok {
38 t.Logf("Option: %d has already been declared.", option)
39 t.Fail()
40 }
41 seen[option] = struct{}{}
42
43 if !isPowerOfTwo(float64(option)) {
44 t.Logf("Option should have been a power of two, got %g instead.", float64(option))
45 t.Fail()
46 }
47 }
48 }
49
50 func ExampleDirectory_Enumerate() {
51 traverser := Directory{
52 Location: ".",
53 Options: DirectoryOptionsExcludeDirectories,
54 }
55
56 done := make(chan struct{})
57
58 filesOfInterest := traverser.Enumerate(done).Select(func(subject interface{}) (result interface{}) {
59 cast, ok := subject.(string)
60 if ok {
61 result = path.Base(cast)
62 } else {
63 result = subject
64 }
65 return
66 }).Where(func(subject interface{}) bool {
67 cast, ok := subject.(string)
68 if !ok {
69 return false
70 }
71 return cast == "filesystem_test.go"
72 })
73
74 for entry := range filesOfInterest {
75 fmt.Println(entry.(string))
76 }
77 close(done)
78
79 // Output: filesystem_test.go
80 }
81
82 func TestDirectory_Enumerate(t *testing.T) {
83 subject := Directory{
84 Location: filepath.Join(".", "testdata", "foo"),
85 }
86
87 testCases := []struct {
88 options DirectoryOptions
89 expected map[string]struct{}
90 }{
91 {
92 options: 0,
93 expected: map[string]struct{}{
94 filepath.Join("testdata", "foo", "a.txt"): struct{}{},
95 filepath.Join("testdata", "foo", "c.txt"): struct{}{},
96 filepath.Join("testdata", "foo", "bar"): struct{}{},
97 },
98 },
99 {
100 options: DirectoryOptionsExcludeFiles,
101 expected: map[string]struct{}{
102 filepath.Join("testdata", "foo", "bar"): struct{}{},
103 },
104 },
105 {
106 options: DirectoryOptionsExcludeDirectories,
107 expected: map[string]struct{}{
108 filepath.Join("testdata", "foo", "a.txt"): struct{}{},
109 filepath.Join("testdata", "foo", "c.txt"): struct{}{},
110 },
111 },
112 {
113 options: DirectoryOptionsRecursive,
114 expected: map[string]struct{}{
115 filepath.Join("testdata", "foo", "bar"): struct{}{},
116 filepath.Join("testdata", "foo", "bar", "b.txt"): struct{}{},
117 filepath.Join("testdata", "foo", "a.txt"): struct{}{},
118 filepath.Join("testdata", "foo", "c.txt"): struct{}{},
119 },
120 },
121 {
122 options: DirectoryOptionsExcludeFiles | DirectoryOptionsRecursive,
123 expected: map[string]struct{}{
124 filepath.Join("testdata", "foo", "bar"): struct{}{},
125 },
126 },
127 {
128 options: DirectoryOptionsRecursive | DirectoryOptionsExcludeDirectories,
129 expected: map[string]struct{}{
130 filepath.Join("testdata", "foo", "a.txt"): struct{}{},
131 filepath.Join("testdata", "foo", "bar", "b.txt"): struct{}{},
132 filepath.Join("testdata", "foo", "c.txt"): struct{}{},
133 },
134 },
135 {
136 options: DirectoryOptionsExcludeDirectories | DirectoryOptionsExcludeFiles,
137 expected: map[string]struct{}{},
138 },
139 {
140 options: DirectoryOptionsExcludeFiles | DirectoryOptionsRecursive | DirectoryOptionsExcludeDirectories,
141 expected: map[string]struct{}{},
142 },
143 }
144
145 for _, tc := range testCases {
146 subject.Options = tc.options
147 t.Run(fmt.Sprintf("%d", uint(tc.options)), func(t *testing.T) {
148 for entry := range subject.Enumerate(nil) {
149 cast := entry.(string)
150 if _, ok := tc.expected[cast]; !ok {
151 t.Logf("unexpected result: %q", cast)
152 t.Fail()
153 }
154 delete(tc.expected, cast)
155 }
156
157 if len(tc.expected) != 0 {
158 for unseenFile := range tc.expected {
159 t.Logf("missing file: %q", unseenFile)
160 }
161 t.Fail()
162 }
163 })
164 }
165 }
0 package collection
1
2 import (
3 "bytes"
4 "errors"
5 "fmt"
6 "strings"
7 "sync"
8 )
9
10 // LinkedList encapsulates a list where each entry is aware of only the next entry in the list.
11 type LinkedList struct {
12 first *llNode
13 last *llNode
14 length uint
15 key sync.RWMutex
16 }
17
18 type llNode struct {
19 payload interface{}
20 next *llNode
21 }
22
23 // Comparator is a function which evaluates two values to determine their relation to one another.
24 // - Zero is returned when `a` and `b` are equal.
25 // - Positive numbers are returned when `a` is greater than `b`.
26 // - Negative numbers are returned when `a` is less than `b`.
27 type Comparator func(a, b interface{}) (int, error)
28
29 // A collection of errors that may be thrown by functions in this file.
30 var (
31 ErrUnexpectedType = errors.New("value was of an unexpected type")
32 )
33
34 // NewLinkedList instantiates a new LinkedList with the entries provided.
35 func NewLinkedList(entries ...interface{}) *LinkedList {
36 list := &LinkedList{}
37
38 for _, entry := range entries {
39 list.AddBack(entry)
40 }
41
42 return list
43 }
44
45 // AddBack creates an entry in the LinkedList that is logically at the back of the list.
46 func (list *LinkedList) AddBack(entry interface{}) {
47 toAppend := &llNode{
48 payload: entry,
49 }
50
51 list.key.Lock()
52 defer list.key.Unlock()
53
54 list.length++
55
56 if list.first == nil {
57 list.first = toAppend
58 list.last = toAppend
59 return
60 }
61
62 list.last.next = toAppend
63 list.last = toAppend
64 }
65
66 // AddFront creates an entry in the LinkedList that is logically at the front of the list.
67 func (list *LinkedList) AddFront(entry interface{}) {
68 toAppend := &llNode{
69 payload: entry,
70 }
71
72 list.key.Lock()
73 defer list.key.Unlock()
74
75 list.length++
76
77 toAppend.next = list.first
78 if list.first == nil {
79 list.last = toAppend
80 }
81
82 list.first = toAppend
83 }
84
85 // Enumerate creates a new instance of Enumerable which can be executed on.
86 func (list *LinkedList) Enumerate(cancel <-chan struct{}) Enumerator {
87 retval := make(chan interface{})
88
89 go func() {
90 list.key.RLock()
91 defer list.key.RUnlock()
92 defer close(retval)
93
94 current := list.first
95 for current != nil {
96 select {
97 case retval <- current.payload:
98 break
99 case <-cancel:
100 return
101 }
102 current = current.next
103 }
104 }()
105
106 return retval
107 }
108
109 // Get finds the value from the LinkedList.
110 // pos is expressed as a zero-based index begining from the 'front' of the list.
111 func (list *LinkedList) Get(pos uint) (interface{}, bool) {
112 list.key.RLock()
113 defer list.key.RUnlock()
114 node, ok := get(list.first, pos)
115 if ok {
116 return node.payload, true
117 }
118 return nil, false
119 }
120
121 // IsEmpty tests the list to determine if it is populate or not.
122 func (list *LinkedList) IsEmpty() bool {
123 list.key.RLock()
124 defer list.key.RUnlock()
125
126 return list.first == nil
127 }
128
129 // Length returns the number of elements present in the LinkedList.
130 func (list *LinkedList) Length() uint {
131 list.key.RLock()
132 defer list.key.RUnlock()
133
134 return list.length
135 }
136
137 // PeekBack returns the entry logicall stored at the back of the list without removing it.
138 func (list *LinkedList) PeekBack() (interface{}, bool) {
139 list.key.RLock()
140 defer list.key.RUnlock()
141
142 if list.last == nil {
143 return nil, false
144 }
145 return list.last.payload, true
146 }
147
148 // PeekFront returns the entry logically stored at the front of this list without removing it.
149 func (list *LinkedList) PeekFront() (interface{}, bool) {
150 list.key.RLock()
151 defer list.key.RUnlock()
152
153 if list.first == nil {
154 return nil, false
155 }
156 return list.first.payload, true
157 }
158
159 // RemoveFront returns the entry logically stored at the front of this list and removes it.
160 func (list *LinkedList) RemoveFront() (interface{}, bool) {
161 list.key.Lock()
162 defer list.key.Unlock()
163
164 if list.first == nil {
165 return nil, false
166 }
167
168 retval := list.first.payload
169
170 list.first = list.first.next
171 list.length--
172
173 if 0 == list.length {
174 list.last = nil
175 }
176
177 return retval, true
178 }
179
180 // RemoveBack returns the entry logically stored at the back of this list and removes it.
181 func (list *LinkedList) RemoveBack() (interface{}, bool) {
182 list.key.Lock()
183 defer list.key.Unlock()
184
185 if list.last == nil {
186 return nil, false
187 }
188
189 retval := list.last.payload
190 list.length--
191
192 if list.length == 0 {
193 list.first = nil
194 } else {
195 node, _ := get(list.first, list.length-1)
196 node.next = nil
197 }
198 return retval, true
199 }
200
201 // Sort rearranges the positions of the entries in this list so that they are
202 // ascending.
203 func (list *LinkedList) Sort(comparator Comparator) error {
204 list.key.Lock()
205 defer list.key.Unlock()
206 var err error
207 list.first, err = mergeSort(list.first, comparator)
208 if err != nil {
209 return err
210 }
211 list.last = findLast(list.first)
212 return err
213 }
214
215 // Sorta rearranges the position of string entries in this list so that they
216 // are ascending.
217 func (list *LinkedList) Sorta() error {
218 list.key.Lock()
219 defer list.key.Unlock()
220
221 var err error
222 list.first, err = mergeSort(list.first, func(a, b interface{}) (int, error) {
223 castA, ok := a.(string)
224 if !ok {
225 return 0, ErrUnexpectedType
226 }
227 castB, ok := b.(string)
228 if !ok {
229 return 0, ErrUnexpectedType
230 }
231
232 return strings.Compare(castA, castB), nil
233 })
234 list.last = findLast(list.first)
235 return err
236 }
237
238 // Sorti rearranges the position of integer entries in this list so that they
239 // are ascending.
240 func (list *LinkedList) Sorti() (err error) {
241 list.key.Lock()
242 defer list.key.Unlock()
243
244 list.first, err = mergeSort(list.first, func(a, b interface{}) (int, error) {
245 castA, ok := a.(int)
246 if !ok {
247 return 0, ErrUnexpectedType
248 }
249 castB, ok := b.(int)
250 if !ok {
251 return 0, ErrUnexpectedType
252 }
253
254 return castA - castB, nil
255 })
256 if err != nil {
257 return
258 }
259 list.last = findLast(list.first)
260 return
261 }
262
263 // String prints upto the first fifteen elements of the list in string format.
264 func (list *LinkedList) String() string {
265 list.key.RLock()
266 defer list.key.RUnlock()
267
268 builder := bytes.NewBufferString("[")
269 current := list.first
270 for i := 0; i < 15 && current != nil; i++ {
271 builder.WriteString(fmt.Sprintf("%v ", current.payload))
272 current = current.next
273 }
274 if current == nil || current.next == nil {
275 builder.Truncate(builder.Len() - 1)
276 } else {
277 builder.WriteString("...")
278 }
279 builder.WriteRune(']')
280 return builder.String()
281 }
282
283 // Swap switches the positions in which two values are stored in this list.
284 // x and y represent the indexes of the items that should be swapped.
285 func (list *LinkedList) Swap(x, y uint) error {
286 list.key.Lock()
287 defer list.key.Unlock()
288
289 var xNode, yNode *llNode
290 if temp, ok := get(list.first, x); ok {
291 xNode = temp
292 } else {
293 return fmt.Errorf("index out of bounds 'x', wanted less than %d got %d", list.length, x)
294 }
295 if temp, ok := get(list.first, y); ok {
296 yNode = temp
297 } else {
298 return fmt.Errorf("index out of bounds 'y', wanted less than %d got %d", list.length, y)
299 }
300
301 temp := xNode.payload
302 xNode.payload = yNode.payload
303 yNode.payload = temp
304 return nil
305 }
306
307 // ToSlice converts the contents of the LinkedList into a slice.
308 func (list *LinkedList) ToSlice() []interface{} {
309 return list.Enumerate(nil).ToSlice()
310 }
311
312 func findLast(head *llNode) *llNode {
313 if head == nil {
314 return nil
315 }
316 current := head
317 for current.next != nil {
318 current = current.next
319 }
320 return current
321 }
322
323 func get(head *llNode, pos uint) (*llNode, bool) {
324 for i := uint(0); i < pos; i++ {
325 if head == nil {
326 return nil, false
327 }
328 head = head.next
329 }
330 return head, true
331 }
332
333 // merge takes two sorted lists and merges them into one sorted list.
334 // Behavior is undefined when you pass a non-sorted list as `left` or `right`
335 func merge(left, right *llNode, comparator Comparator) (first *llNode, err error) {
336 curLeft := left
337 curRight := right
338
339 var last *llNode
340
341 appendResults := func(updated *llNode) {
342 if last == nil {
343 last = updated
344 } else {
345 last.next = updated
346 last = last.next
347 }
348 if first == nil {
349 first = last
350 }
351 }
352
353 for curLeft != nil && curRight != nil {
354 var res int
355 if res, err = comparator(curLeft.payload, curRight.payload); nil != err {
356 break // Don't return, stitch the remaining elements back on.
357 } else if res < 0 {
358 appendResults(curLeft)
359 curLeft = curLeft.next
360 } else {
361 appendResults(curRight)
362 curRight = curRight.next
363 }
364 }
365
366 if curLeft != nil {
367 appendResults(curLeft)
368 }
369 if curRight != nil {
370 appendResults(curRight)
371 }
372 return
373 }
374
375 func mergeSort(head *llNode, comparator Comparator) (*llNode, error) {
376 if head == nil {
377 return nil, nil
378 }
379
380 left, right := split(head)
381
382 repair := func(left, right *llNode) *llNode {
383 lastLeft := findLast(left)
384 lastLeft.next = right
385 return left
386 }
387
388 var err error
389 if left != nil && left.next != nil {
390 left, err = mergeSort(left, comparator)
391 if err != nil {
392 return repair(left, right), err
393 }
394 }
395 if right != nil && right.next != nil {
396 right, err = mergeSort(right, comparator)
397 if err != nil {
398 return repair(left, right), err
399 }
400 }
401
402 return merge(left, right, comparator)
403 }
404
405 // split breaks a list in half.
406 func split(head *llNode) (left, right *llNode) {
407 left = head
408 if head == nil || head.next == nil {
409 return
410 }
411 right = head
412 sprinter := head
413 prev := head
414 for sprinter != nil && sprinter.next != nil {
415 prev = right
416 right = right.next
417 sprinter = sprinter.next.next
418 }
419 prev.next = nil
420 return
421 }
0 package collection
1
2 import "fmt"
3 import "testing"
4
5 func ExampleLinkedList_AddFront() {
6 subject := NewLinkedList(2, 3)
7 subject.AddFront(1)
8 result, _ := subject.PeekFront()
9 fmt.Println(result)
10 // Output: 1
11 }
12
13 func ExampleLinkedList_AddBack() {
14 subject := NewLinkedList(2, 3, 5)
15 subject.AddBack(8)
16 result, _ := subject.PeekBack()
17 fmt.Println(result)
18 fmt.Println(subject.Length())
19 // Output:
20 // 8
21 // 4
22 }
23
24 func ExampleLinkedList_Enumerate() {
25 subject := NewLinkedList(2, 3, 5, 8)
26 results := subject.Enumerate(nil).Select(func(a interface{}) interface{} {
27 return -1 * a.(int)
28 })
29 for entry := range results {
30 fmt.Println(entry)
31 }
32 // Output:
33 // -2
34 // -3
35 // -5
36 // -8
37 }
38
39 func ExampleLinkedList_Get() {
40 subject := NewLinkedList(2, 3, 5, 8)
41 val, _ := subject.Get(2)
42 fmt.Println(val)
43 // Output: 5
44 }
45
46 func TestLinkedList_Get_OutsideBounds(t *testing.T) {
47 subject := NewLinkedList(2, 3, 5, 8, 13, 21)
48 result, ok := subject.Get(10)
49 if !(result == nil && ok == false) {
50 t.Logf("got: %v %v\nwant: %v %v", result, ok, nil, false)
51 t.Fail()
52 }
53 }
54
55 func ExampleNewLinkedList() {
56 subject1 := NewLinkedList('a', 'b', 'c', 'd', 'e')
57 fmt.Println(subject1.Length())
58
59 slice := []interface{}{1, 2, 3, 4, 5, 6}
60 subject2 := NewLinkedList(slice...)
61 fmt.Println(subject2.Length())
62 // Output:
63 // 5
64 // 6
65 }
66
67 func TestLinkedList_findLast_empty(t *testing.T) {
68 if result := findLast(nil); result != nil {
69 t.Logf("got: %v\nwant: %v", result, nil)
70 }
71 }
72
73 func TestLinkedList_merge(t *testing.T) {
74 testCases := []struct {
75 Left *LinkedList
76 Right *LinkedList
77 Expected []int
78 Comp Comparator
79 }{
80 {
81 NewLinkedList(1, 3, 5),
82 NewLinkedList(2, 4),
83 []int{1, 2, 3, 4, 5},
84 UncheckedComparatori,
85 },
86 {
87 NewLinkedList(1, 2, 3),
88 NewLinkedList(),
89 []int{1, 2, 3},
90 UncheckedComparatori,
91 },
92 {
93 NewLinkedList(),
94 NewLinkedList(1, 2, 3),
95 []int{1, 2, 3},
96 UncheckedComparatori,
97 },
98 {
99 NewLinkedList(),
100 NewLinkedList(),
101 []int{},
102 UncheckedComparatori,
103 },
104 {
105 NewLinkedList(1),
106 NewLinkedList(1),
107 []int{1, 1},
108 UncheckedComparatori,
109 },
110 {
111 NewLinkedList(2),
112 NewLinkedList(1),
113 []int{1, 2},
114 UncheckedComparatori,
115 },
116 {
117 NewLinkedList(3),
118 NewLinkedList(),
119 []int{3},
120 UncheckedComparatori,
121 },
122 {
123 NewLinkedList(),
124 NewLinkedList(10),
125 []int{10},
126 UncheckedComparatori,
127 },
128 }
129
130 for _, tc := range testCases {
131 t.Run("", func(t *testing.T) {
132 result, err := merge(tc.Left.first, tc.Right.first, tc.Comp)
133 if err != nil {
134 t.Error(err)
135 }
136
137 i := 0
138 for cursor := result; cursor != nil; cursor, i = cursor.next, i+1 {
139 if cursor.payload != tc.Expected[i] {
140 t.Logf("got: %d want: %d", cursor.payload.(int), tc.Expected[i])
141 t.Fail()
142 }
143 }
144
145 if expectedLength := len(tc.Expected); i != expectedLength {
146 t.Logf("Unexpected length:\n\tgot: %d\n\twant: %d", i, expectedLength)
147 t.Fail()
148 }
149 })
150 }
151 }
152
153 func TestLinkedList_mergeSort_repair(t *testing.T) {
154 testCases := []*LinkedList{
155 NewLinkedList(1, 2, "str1", 4, 5, 6),
156 NewLinkedList(1, 2, 3, "str1", 5, 6),
157 NewLinkedList(1, 'a', 3, 4, 5, 6),
158 NewLinkedList(1, 2, 3, 4, 5, uint(8)),
159 NewLinkedList("alpha", 0),
160 NewLinkedList(0, "kappa"),
161 }
162
163 for _, tc := range testCases {
164 t.Run(tc.String(), func(t *testing.T) {
165 originalLength := tc.Length()
166 originalElements := tc.Enumerate(nil).ToSlice()
167 originalContents := tc.String()
168
169 if err := tc.Sorti(); err != ErrUnexpectedType {
170 t.Log("`Sorti() should have thrown ErrUnexpectedType")
171 t.Fail()
172 }
173
174 t.Logf("Contents:\n\tOriginal: \t%s\n\tPost Merge: \t%s", originalContents, tc.String())
175
176 if newLength := tc.Length(); newLength != originalLength {
177 t.Logf("Length changed. got: %d want: %d", newLength, originalLength)
178 t.Fail()
179 }
180
181 remaining := tc.Enumerate(nil).ToSlice()
182
183 for _, desired := range originalElements {
184 found := false
185 for i, got := range remaining {
186 if got == desired {
187 remaining = append(remaining[:i], remaining[i+1:]...)
188 found = true
189 break
190 }
191 }
192
193 if !found {
194 t.Logf("couldn't find element: %v", desired)
195 t.Fail()
196 }
197 }
198 })
199 }
200 }
201
202 func ExampleLinkedList_Sort() {
203 // Sorti sorts into ascending order, this example demonstrates sorting
204 // into descending order.
205 subject := NewLinkedList(2, 4, 3, 5, 7, 7)
206 subject.Sort(func(a, b interface{}) (int, error) {
207 castA, ok := a.(int)
208 if !ok {
209 return 0, ErrUnexpectedType
210 }
211 castB, ok := b.(int)
212 if !ok {
213 return 0, ErrUnexpectedType
214 }
215
216 return castB - castA, nil
217 })
218 fmt.Println(subject)
219 // Output: [7 7 5 4 3 2]
220 }
221
222 func ExampleLinkedList_Sorta() {
223 subject := NewLinkedList("charlie", "alfa", "bravo", "delta")
224 subject.Sorta()
225 for _, entry := range subject.ToSlice() {
226 fmt.Println(entry.(string))
227 }
228 // Output:
229 // alfa
230 // bravo
231 // charlie
232 // delta
233 }
234
235 func ExampleLinkedList_Sorti() {
236 subject := NewLinkedList(7, 3, 2, 2, 3, 6)
237 subject.Sorti()
238 fmt.Println(subject)
239 // Output: [2 2 3 3 6 7]
240 }
241
242 func TestLinkedList_Sorti(t *testing.T) {
243 testCases := []struct {
244 *LinkedList
245 Expected []int
246 }{
247 {
248 NewLinkedList(),
249 []int{},
250 },
251 {
252 NewLinkedList(1, 2, 3, 4),
253 []int{1, 2, 3, 4},
254 },
255 {
256 NewLinkedList(0, -1, 2, 8, 9),
257 []int{-1, 0, 2, 8, 9},
258 },
259 }
260
261 for _, tc := range testCases {
262 t.Run(tc.String(), func(t *testing.T) {
263 if err := tc.Sorti(); err != nil {
264 t.Error(err)
265 }
266
267 sorted := tc.ToSlice()
268
269 if countSorted, countExpected := len(sorted), len(tc.Expected); countSorted != countExpected {
270 t.Logf("got: %d want: %d", countSorted, countExpected)
271 t.FailNow()
272 }
273
274 for i, entry := range sorted {
275 cast, ok := entry.(int)
276 if !ok {
277 t.Errorf("Element was not an int: %v", entry)
278 }
279
280 if cast != tc.Expected[i] {
281 t.Logf("got: %d want: %d at: %d", cast, tc.Expected[i], i)
282 t.Fail()
283 }
284 }
285 })
286 }
287 }
288
289 func TestLinkedList_split_Even(t *testing.T) {
290 subject := NewLinkedList(1, 2, 3, 4)
291
292 left, right := split(subject.first)
293 if left == nil {
294 t.Logf("unexpected nil value for left")
295 t.Fail()
296 } else if left.payload != 1 {
297 t.Logf("got: %d\nwant: %d", left.payload, 1)
298 t.Fail()
299 }
300
301 if right == nil {
302 t.Logf("unexpected nil for right")
303 t.Fail()
304 } else if right.payload != 3 {
305 t.Logf("got: %d\nwant: %d", right.payload, 3)
306 }
307 }
308
309 func TestLinkedList_split_Odd(t *testing.T) {
310 subject := NewLinkedList(1, 2, 3, 4, 5)
311
312 left, right := split(subject.first)
313
314 if left == nil {
315 t.Logf("unexpected nil value for left")
316 t.Fail()
317 } else if left.payload != 1 {
318 t.Logf("got: %d\n want: %d", left.payload, 1)
319 t.Fail()
320 } else if last := findLast(left).payload; last != 2 {
321 t.Logf("got:\n%d\nwant:\n%d", last, 2)
322 t.Fail()
323 }
324
325 if right == nil {
326 t.Logf("unexpected nil value for right")
327 t.Fail()
328 } else if right.payload != 3 {
329 t.Logf("got:\n%d\nwant:\n%d", right.payload, 3)
330 t.Fail()
331 } else if last := findLast(right).payload; last != 5 {
332 t.Logf("got:\n%d\nwant:%d", last, 5)
333 }
334 }
335
336 func TestLinkedList_split_Empty(t *testing.T) {
337 subject := NewLinkedList()
338
339 left, right := split(subject.first)
340
341 if left != nil {
342 t.Logf("got: %v\nwant: %v", left, nil)
343 t.Fail()
344 }
345
346 if right != nil {
347 t.Logf("got: %v\nwant: %v", right, nil)
348 t.Fail()
349 }
350 }
351
352 func TestLinkedList_split_Single(t *testing.T) {
353 subject := NewLinkedList(1)
354
355 left, right := split(subject.first)
356
357 if left == nil {
358 t.Logf("unexpected nil value for left")
359 t.Fail()
360 } else if left.payload != 1 {
361 t.Logf("got: %d\nwant: %d", left.payload, 1)
362 t.Fail()
363 }
364
365 if right != nil {
366 t.Logf("got: %v\nwant: %v", right, nil)
367 t.Fail()
368 }
369
370 if last := findLast(left).payload; last != 1 {
371 t.Logf("got:\n%d\nwant:\n%d", last, 1)
372 t.Fail()
373 }
374 }
375
376 func TestLinkedList_split_Double(t *testing.T) {
377 subject := NewLinkedList(1, 2)
378 left, right := split(subject.first)
379
380 if left == nil {
381 t.Logf("unexpected nil value for left")
382 t.Fail()
383 } else if left.payload != 1 {
384 t.Logf("got: %d\nwant: %d", left.payload, 1)
385 }
386
387 if right == nil {
388 t.Logf("unexpected nil value for right")
389 t.Fail()
390 } else if right.payload != 2 {
391 t.Logf("got: %d\nwant: %d", right.payload, 2)
392 }
393 }
394
395 func UncheckedComparatori(a, b interface{}) (int, error) {
396 return a.(int) - b.(int), nil
397 }
398
399 func ExampleLinkedList_String() {
400 subject1 := NewLinkedList()
401 for i := 0; i < 20; i++ {
402 subject1.AddBack(i)
403 }
404 fmt.Println(subject1)
405
406 subject2 := NewLinkedList(1, 2, 3)
407 fmt.Println(subject2)
408 // Output:
409 // [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...]
410 // [1 2 3]
411 }
412
413 func ExampleLinkedList_Swap() {
414 subject := NewLinkedList(2, 3, 5, 8, 13)
415 subject.Swap(1, 3)
416 fmt.Println(subject)
417 // Output: [2 8 5 3 13]
418 }
419
420 func TestLinkedList_Swap_OutOfBounds(t *testing.T) {
421 subject := NewLinkedList(2, 3)
422 if err := subject.Swap(0, 8); err == nil {
423 t.Log("swap should have failed on y")
424 t.Fail()
425 }
426
427 if err := subject.Swap(11, 1); err == nil {
428 t.Logf("swap shoud have failed on x")
429 t.Fail()
430 }
431
432 if count := subject.Length(); count != 2 {
433 t.Logf("got: %d\nwant: %d", count, 2)
434 t.Fail()
435 }
436
437 wantStr := "[2 3]"
438 gotStr := subject.String()
439 if wantStr != gotStr {
440 t.Logf("got: %s\nwant: %s", gotStr, wantStr)
441 t.Fail()
442 }
443 }
0 package collection
1
2 import (
3 "bytes"
4 "fmt"
5 "sync"
6 )
7
8 // List is a dynamically sized list akin to List in the .NET world,
9 // ArrayList in the Java world, or vector in the C++ world.
10 type List struct {
11 underlyer []interface{}
12 key sync.RWMutex
13 }
14
15 // NewList creates a new list which contains the elements provided.
16 func NewList(entries ...interface{}) *List {
17 return &List{
18 underlyer: entries,
19 }
20 }
21
22 // Add appends an entry to the logical end of the List.
23 func (l *List) Add(entries ...interface{}) {
24 l.key.Lock()
25 defer l.key.Unlock()
26 l.underlyer = append(l.underlyer, entries...)
27 }
28
29 // AddAt injects values beginning at `pos`. If multiple values
30 // are provided in `entries` they are placed in the same order
31 // they are provided.
32 func (l *List) AddAt(pos uint, entries ...interface{}) {
33 l.key.Lock()
34 defer l.key.Unlock()
35
36 l.underlyer = append(l.underlyer[:pos], append(entries, l.underlyer[pos:]...)...)
37 }
38
39 // Enumerate lists each element present in the collection
40 func (l *List) Enumerate(cancel <-chan struct{}) Enumerator {
41 retval := make(chan interface{})
42
43 go func() {
44 l.key.RLock()
45 defer l.key.RUnlock()
46 defer close(retval)
47
48 for _, entry := range l.underlyer {
49 select {
50 case retval <- entry:
51 break
52 case <-cancel:
53 return
54 }
55 }
56 }()
57
58 return retval
59 }
60
61 // Get retreives the value stored in a particular position of the list.
62 // If no item exists at the given position, the second parameter will be
63 // returned as false.
64 func (l *List) Get(pos uint) (interface{}, bool) {
65 l.key.RLock()
66 defer l.key.RUnlock()
67
68 if pos > uint(len(l.underlyer)) {
69 return nil, false
70 }
71 return l.underlyer[pos], true
72 }
73
74 // IsEmpty tests to see if this List has any elements present.
75 func (l *List) IsEmpty() bool {
76 l.key.RLock()
77 defer l.key.RUnlock()
78 return 0 == len(l.underlyer)
79 }
80
81 // Length returns the number of elements in the List.
82 func (l *List) Length() uint {
83 l.key.RLock()
84 defer l.key.RUnlock()
85 return uint(len(l.underlyer))
86 }
87
88 // Remove retreives a value from this List and shifts all other values.
89 func (l *List) Remove(pos uint) (interface{}, bool) {
90 l.key.Lock()
91 defer l.key.Unlock()
92
93 if pos > uint(len(l.underlyer)) {
94 return nil, false
95 }
96 retval := l.underlyer[pos]
97 l.underlyer = append(l.underlyer[:pos], l.underlyer[pos+1:]...)
98 return retval, true
99 }
100
101 // Set updates the value stored at a given position in the List.
102 func (l *List) Set(pos uint, val interface{}) bool {
103 l.key.Lock()
104 defer l.key.Unlock()
105 var retval bool
106 count := uint(len(l.underlyer))
107 if pos > count {
108 retval = false
109 } else {
110 l.underlyer[pos] = val
111 retval = true
112 }
113 return retval
114 }
115
116 // String generates a textual representation of the List for the sake of debugging.
117 func (l *List) String() string {
118 l.key.RLock()
119 defer l.key.RUnlock()
120
121 builder := bytes.NewBufferString("[")
122
123 for i, entry := range l.underlyer {
124 if i >= 15 {
125 builder.WriteString("... ")
126 break
127 }
128 builder.WriteString(fmt.Sprintf("%v ", entry))
129 }
130 builder.Truncate(builder.Len() - 1)
131 builder.WriteRune(']')
132 return builder.String()
133 }
134
135 // Swap switches the values that are stored at positions `x` and `y`
136 func (l *List) Swap(x, y uint) bool {
137 l.key.Lock()
138 defer l.key.Unlock()
139 return l.swap(x, y)
140 }
141
142 func (l *List) swap(x, y uint) bool {
143 count := uint(len(l.underlyer))
144 if x < count && y < count {
145 temp := l.underlyer[x]
146 l.underlyer[x] = l.underlyer[y]
147 l.underlyer[y] = temp
148 return true
149 }
150 return false
151 }
0 package collection
1
2 import "fmt"
3
4 func ExampleList_AddAt() {
5 subject := NewList(0, 1, 4, 5, 6)
6 subject.AddAt(2, 2, 3)
7 fmt.Println(subject)
8 // Output: [0 1 2 3 4 5 6]
9 }
0 package collection
1
2 import (
3 "errors"
4 "reflect"
5 "runtime"
6 "sync"
7 )
8
9 // Enumerable offers a means of easily converting into a channel. It is most
10 // useful for types where mutability is not in question.
11 type Enumerable interface {
12 Enumerate(cancel <-chan struct{}) Enumerator
13 }
14
15 // Enumerator exposes a new syntax for querying familiar data structures.
16 type Enumerator <-chan interface{}
17
18 // Predicate defines an interface for funcs that make some logical test.
19 type Predicate func(interface{}) bool
20
21 // Transform defines a function which takes a value, and returns some value based on the original.
22 type Transform func(interface{}) interface{}
23
24 // Unfolder defines a function which takes a single value, and exposes many of them as an Enumerator
25 type Unfolder func(interface{}) Enumerator
26
27 type emptyEnumerable struct{}
28
29 var (
30 errNoElements = errors.New("Enumerator encountered no elements")
31 errMultipleElements = errors.New("Enumerator encountered multiple elements")
32 )
33
34 // IsErrorNoElements determines whethr or not the given error is the result of no values being
35 // returned when one or more were expected.
36 func IsErrorNoElements(err error) bool {
37 return err == errNoElements
38 }
39
40 // IsErrorMultipleElements determines whether or not the given error is the result of multiple values
41 // being returned when one or zero were expected.
42 func IsErrorMultipleElements(err error) bool {
43 return err == errMultipleElements
44 }
45
46 // Identity is a trivial Transform which applies no operation on the value.
47 var Identity Transform = func(value interface{}) interface{} {
48 return value
49 }
50
51 // Empty is an Enumerable that has no elements, and will never have any elements.
52 var Empty Enumerable = &emptyEnumerable{}
53
54 func (e emptyEnumerable) Enumerate(cancel <-chan struct{}) Enumerator {
55 results := make(chan interface{})
56 close(results)
57 return results
58 }
59
60 // All tests whether or not all items present in an Enumerable meet a criteria.
61 func All(subject Enumerable, p Predicate) bool {
62 done := make(chan struct{})
63 defer close(done)
64
65 return subject.Enumerate(done).All(p)
66 }
67
68 // All tests whether or not all items present meet a criteria.
69 func (iter Enumerator) All(p Predicate) bool {
70 for entry := range iter {
71 if !p(entry) {
72 return false
73 }
74 }
75 return true
76 }
77
78 // Any tests an Enumerable to see if there are any elements present.
79 func Any(iterator Enumerable) bool {
80 done := make(chan struct{})
81 defer close(done)
82
83 for range iterator.Enumerate(done) {
84 return true
85 }
86 return false
87 }
88
89 // Anyp tests an Enumerable to see if there are any elements present that meet a criteria.
90 func Anyp(iterator Enumerable, p Predicate) bool {
91 done := make(chan struct{})
92 defer close(done)
93
94 for element := range iterator.Enumerate(done) {
95 if p(element) {
96 return true
97 }
98 }
99 return false
100 }
101
102 type enumerableSlice []interface{}
103
104 func (f enumerableSlice) Enumerate(cancel <-chan struct{}) Enumerator {
105 results := make(chan interface{})
106
107 go func() {
108 defer close(results)
109 for _, entry := range f {
110 select {
111 case results <- entry:
112 break
113 case <-cancel:
114 return
115 }
116 }
117 }()
118
119 return results
120 }
121
122 type enumerableValue struct {
123 reflect.Value
124 }
125
126 func (v enumerableValue) Enumerate(cancel <-chan struct{}) Enumerator {
127 results := make(chan interface{})
128
129 go func() {
130 defer close(results)
131
132 elements := v.Len()
133
134 for i := 0; i < elements; i++ {
135 select {
136 case results <- v.Index(i).Interface():
137 break
138 case <-cancel:
139 return
140 }
141 }
142 }()
143
144 return results
145 }
146
147 // AsEnumerable allows for easy conversion of a slice to a re-usable Enumerable object.
148 func AsEnumerable(entries ...interface{}) Enumerable {
149 if len(entries) != 1 {
150 return enumerableSlice(entries)
151 }
152
153 val := reflect.ValueOf(entries[0])
154
155 if kind := val.Kind(); kind == reflect.Slice || kind == reflect.Array {
156 return enumerableValue{
157 Value: val,
158 }
159 }
160 return enumerableSlice(entries)
161 }
162
163 // AsEnumerable stores the results of an Enumerator so the results can be enumerated over repeatedly.
164 func (iter Enumerator) AsEnumerable() Enumerable {
165 return enumerableSlice(iter.ToSlice())
166 }
167
168 // Count iterates over a list and keeps a running tally of the number of elements
169 // satisfy a predicate.
170 func Count(iter Enumerable, p Predicate) int {
171 return iter.Enumerate(nil).Count(p)
172 }
173
174 // Count iterates over a list and keeps a running tally of the number of elements
175 // satisfy a predicate.
176 func (iter Enumerator) Count(p Predicate) int {
177 tally := 0
178 for entry := range iter {
179 if p(entry) {
180 tally++
181 }
182 }
183 return tally
184 }
185
186 // CountAll iterates over a list and keeps a running tally of how many it's seen.
187 func CountAll(iter Enumerable) int {
188 return iter.Enumerate(nil).CountAll()
189 }
190
191 // CountAll iterates over a list and keeps a running tally of how many it's seen.
192 func (iter Enumerator) CountAll() int {
193 tally := 0
194 for range iter {
195 tally++
196 }
197 return tally
198 }
199
200 // Discard reads an enumerator to the end but does nothing with it.
201 // This method should be used in circumstances when it doesn't make sense to explicitly cancel the Enumeration.
202 func (iter Enumerator) Discard() {
203 for range iter {
204 // Intentionally Left Blank
205 }
206 }
207
208 // ElementAt retreives an item at a particular position in an Enumerator.
209 func ElementAt(iter Enumerable, n uint) interface{} {
210 done := make(chan struct{})
211 defer close(done)
212 return iter.Enumerate(done).ElementAt(n)
213 }
214
215 // ElementAt retreives an item at a particular position in an Enumerator.
216 func (iter Enumerator) ElementAt(n uint) interface{} {
217 for i := uint(0); i < n; i++ {
218 <-iter
219 }
220 return <-iter
221 }
222
223 // First retrieves just the first item in the list, or returns an error if there are no elements in the array.
224 func First(subject Enumerable) (retval interface{}, err error) {
225 done := make(chan struct{})
226
227 err = errNoElements
228
229 var isOpen bool
230
231 if retval, isOpen = <-subject.Enumerate(done); isOpen {
232 err = nil
233 }
234 close(done)
235
236 return
237 }
238
239 // Last retreives the item logically behind all other elements in the list.
240 func Last(iter Enumerable) interface{} {
241 return iter.Enumerate(nil).Last()
242 }
243
244 // Last retreives the item logically behind all other elements in the list.
245 func (iter Enumerator) Last() (retval interface{}) {
246 for retval = range iter {
247 // Intentionally Left Blank
248 }
249 return
250 }
251
252 type merger struct {
253 originals []Enumerable
254 }
255
256 func (m merger) Enumerate(cancel <-chan struct{}) Enumerator {
257 retval := make(chan interface{})
258
259 var wg sync.WaitGroup
260 wg.Add(len(m.originals))
261 for _, item := range m.originals {
262 go func(input Enumerable) {
263 defer wg.Done()
264 for value := range input.Enumerate(cancel) {
265 retval <- value
266 }
267 }(item)
268 }
269
270 go func() {
271 wg.Wait()
272 close(retval)
273 }()
274 return retval
275 }
276
277 // Merge takes the results as it receives them from several channels and directs
278 // them into a single channel.
279 func Merge(channels ...Enumerable) Enumerable {
280 return merger{
281 originals: channels,
282 }
283 }
284
285 // Merge takes the results of this Enumerator and others, and funnels them into
286 // a single Enumerator. The order of in which they will be combined is non-deterministic.
287 func (iter Enumerator) Merge(others ...Enumerator) Enumerator {
288 retval := make(chan interface{})
289
290 var wg sync.WaitGroup
291 wg.Add(len(others) + 1)
292
293 funnel := func(prevResult Enumerator) {
294 for entry := range prevResult {
295 retval <- entry
296 }
297 wg.Done()
298 }
299
300 go funnel(iter)
301 for _, item := range others {
302 go funnel(item)
303 }
304
305 go func() {
306 wg.Wait()
307 close(retval)
308 }()
309 return retval
310 }
311
312 type parallelSelecter struct {
313 original Enumerable
314 operation Transform
315 }
316
317 func (ps parallelSelecter) Enumerate(cancel <-chan struct{}) Enumerator {
318 return ps.original.Enumerate(cancel).ParallelSelect(ps.operation)
319 }
320
321 // ParallelSelect creates an Enumerable which will use all logically available CPUs to
322 // execute a Transform.
323 func ParallelSelect(original Enumerable, operation Transform) Enumerable {
324 return parallelSelecter{
325 original: original,
326 operation: operation,
327 }
328 }
329
330 // ParallelSelect will execute a Transform across all logical CPUs available to the current process.
331 func (iter Enumerator) ParallelSelect(operation Transform) Enumerator {
332 if cpus := runtime.NumCPU(); cpus != 1 {
333 intermediate := iter.splitN(operation, uint(cpus))
334 return intermediate[0].Merge(intermediate[1:]...)
335 }
336 return iter
337 }
338
339 type reverser struct {
340 original Enumerable
341 }
342
343 // Reverse will enumerate all values of an enumerable, store them in a Stack, then replay them all.
344 func Reverse(original Enumerable) Enumerable {
345 return reverser{
346 original: original,
347 }
348 }
349
350 func (r reverser) Enumerate(cancel <-chan struct{}) Enumerator {
351 return r.original.Enumerate(cancel).Reverse()
352 }
353
354 // Reverse returns items in the opposite order it encountered them in.
355 func (iter Enumerator) Reverse() Enumerator {
356 cache := NewStack()
357 for entry := range iter {
358 cache.Push(entry)
359 }
360
361 retval := make(chan interface{})
362
363 go func() {
364 for !cache.IsEmpty() {
365 val, _ := cache.Pop()
366 retval <- val
367 }
368 close(retval)
369 }()
370 return retval
371 }
372
373 type selecter struct {
374 original Enumerable
375 transform Transform
376 }
377
378 func (s selecter) Enumerate(cancel <-chan struct{}) Enumerator {
379 return s.original.Enumerate(cancel).Select(s.transform)
380 }
381
382 // Select creates a reusable stream of transformed values.
383 func Select(subject Enumerable, transform Transform) Enumerable {
384 return selecter{
385 original: subject,
386 transform: transform,
387 }
388 }
389
390 // Select iterates over a list and returns a transformed item.
391 func (iter Enumerator) Select(transform Transform) Enumerator {
392 retval := make(chan interface{})
393
394 go func() {
395 for item := range iter {
396 retval <- transform(item)
397 }
398 close(retval)
399 }()
400
401 return retval
402 }
403
404 type selectManyer struct {
405 original Enumerable
406 toMany Unfolder
407 }
408
409 func (s selectManyer) Enumerate(cancel <-chan struct{}) Enumerator {
410 return s.original.Enumerate(cancel).SelectMany(s.toMany)
411 }
412
413 // SelectMany allows for unfolding of values.
414 func SelectMany(subject Enumerable, toMany Unfolder) Enumerable {
415 return selectManyer{
416 original: subject,
417 toMany: toMany,
418 }
419 }
420
421 // SelectMany allows for flattening of data structures.
422 func (iter Enumerator) SelectMany(lister Unfolder) Enumerator {
423 retval := make(chan interface{})
424
425 go func() {
426 for parent := range iter {
427 for child := range lister(parent) {
428 retval <- child
429 }
430 }
431 close(retval)
432 }()
433
434 return retval
435 }
436
437 // Single retreives the only element from a list, or returns nil and an error.
438 func Single(iter Enumerable) (retval interface{}, err error) {
439 done := make(chan struct{})
440 defer close(done)
441
442 err = errNoElements
443
444 firstPass := true
445 for entry := range iter.Enumerate(done) {
446 if firstPass {
447 retval = entry
448 err = nil
449 } else {
450 retval = nil
451 err = errMultipleElements
452 break
453 }
454 firstPass = false
455 }
456 return
457 }
458
459 // Singlep retrieces the only element from a list that matches a criteria. If
460 // no match is found, or two or more are found, `Singlep` returns nil and an
461 // error.
462 func Singlep(iter Enumerable, pred Predicate) (retval interface{}, err error) {
463 iter = Where(iter, pred)
464 return Single(iter)
465 }
466
467 type skipper struct {
468 original Enumerable
469 skipCount uint
470 }
471
472 func (s skipper) Enumerate(cancel <-chan struct{}) Enumerator {
473 return s.original.Enumerate(cancel).Skip(s.skipCount)
474 }
475
476 // Skip creates a reusable stream which will skip the first `n` elements before iterating
477 // over the rest of the elements in an Enumerable.
478 func Skip(subject Enumerable, n uint) Enumerable {
479 return skipper{
480 original: subject,
481 skipCount: n,
482 }
483 }
484
485 // Skip retreives all elements after the first 'n' elements.
486 func (iter Enumerator) Skip(n uint) Enumerator {
487 results := make(chan interface{})
488
489 go func() {
490 defer close(results)
491
492 i := uint(0)
493 for entry := range iter {
494 if i < n {
495 i++
496 continue
497 }
498 results <- entry
499 }
500 }()
501
502 return results
503 }
504
505 // splitN creates N Enumerators, each will be a subset of the original Enumerator and will have
506 // distinct populations from one another.
507 func (iter Enumerator) splitN(operation Transform, n uint) []Enumerator {
508 results, cast := make([]chan interface{}, n, n), make([]Enumerator, n, n)
509
510 for i := uint(0); i < n; i++ {
511 results[i] = make(chan interface{})
512 cast[i] = results[i]
513 }
514
515 go func() {
516 for i := uint(0); i < n; i++ {
517 go func(addr uint) {
518 defer close(results[addr])
519 for {
520 read, ok := <-iter
521 if !ok {
522 return
523 }
524 results[addr] <- operation(read)
525 }
526 }(i)
527 }
528 }()
529
530 return cast
531 }
532
533 type taker struct {
534 original Enumerable
535 n uint
536 }
537
538 func (t taker) Enumerate(cancel <-chan struct{}) Enumerator {
539 return t.original.Enumerate(cancel).Take(t.n)
540 }
541
542 // Take retreives just the first `n` elements from an Enumerable.
543 func Take(subject Enumerable, n uint) Enumerable {
544 return taker{
545 original: subject,
546 n: n,
547 }
548 }
549
550 // Take retreives just the first 'n' elements from an Enumerator.
551 func (iter Enumerator) Take(n uint) Enumerator {
552 results := make(chan interface{})
553
554 go func() {
555 defer close(results)
556 i := uint(0)
557 for entry := range iter {
558 if i >= n {
559 return
560 }
561 i++
562 results <- entry
563 }
564 }()
565
566 return results
567 }
568
569 type takeWhiler struct {
570 original Enumerable
571 criteria func(interface{}, uint) bool
572 }
573
574 func (tw takeWhiler) Enumerate(cancel <-chan struct{}) Enumerator {
575 return tw.original.Enumerate(cancel).TakeWhile(tw.criteria)
576 }
577
578 // TakeWhile creates a reusable stream which will halt once some criteria is no longer met.
579 func TakeWhile(subject Enumerable, criteria func(interface{}, uint) bool) Enumerable {
580 return takeWhiler{
581 original: subject,
582 criteria: criteria,
583 }
584 }
585
586 // TakeWhile continues returning items as long as 'criteria' holds true.
587 func (iter Enumerator) TakeWhile(criteria func(interface{}, uint) bool) Enumerator {
588 results := make(chan interface{})
589
590 go func() {
591 defer close(results)
592 i := uint(0)
593 for entry := range iter {
594 if !criteria(entry, i) {
595 return
596 }
597 i++
598 results <- entry
599 }
600 }()
601
602 return results
603 }
604
605 // Tee creates two Enumerators which will have identical contents as one another.
606 func (iter Enumerator) Tee() (Enumerator, Enumerator) {
607 left, right := make(chan interface{}), make(chan interface{})
608
609 go func() {
610 for entry := range iter {
611 left <- entry
612 right <- entry
613 }
614 close(left)
615 close(right)
616 }()
617
618 return left, right
619 }
620
621 // ToSlice places all iterated over values in a Slice for easy consumption.
622 func ToSlice(iter Enumerable) []interface{} {
623 return iter.Enumerate(nil).ToSlice()
624 }
625
626 // ToSlice places all iterated over values in a Slice for easy consumption.
627 func (iter Enumerator) ToSlice() []interface{} {
628 retval := make([]interface{}, 0)
629 for entry := range iter {
630 retval = append(retval, entry)
631 }
632 return retval
633 }
634
635 type wherer struct {
636 original Enumerable
637 filter Predicate
638 }
639
640 func (w wherer) Enumerate(cancel <-chan struct{}) Enumerator {
641 retval := make(chan interface{})
642
643 go func() {
644 defer close(retval)
645 for entry := range w.original.Enumerate(cancel) {
646 if w.filter(entry) {
647 retval <- entry
648 }
649 }
650 }()
651
652 return retval
653 }
654
655 // Where creates a reusable means of filtering a stream.
656 func Where(original Enumerable, p Predicate) Enumerable {
657 return wherer{
658 original: original,
659 filter: p,
660 }
661 }
662
663 // Where iterates over a list and returns only the elements that satisfy a
664 // predicate.
665 func (iter Enumerator) Where(predicate Predicate) Enumerator {
666 retval := make(chan interface{})
667 go func() {
668 for item := range iter {
669 if predicate(item) {
670 retval <- item
671 }
672 }
673 close(retval)
674 }()
675
676 return retval
677 }
678
679 // UCount iterates over a list and keeps a running tally of the number of elements
680 // satisfy a predicate.
681 func UCount(iter Enumerable, p Predicate) uint {
682 return iter.Enumerate(nil).UCount(p)
683 }
684
685 // UCount iterates over a list and keeps a running tally of the number of elements
686 // satisfy a predicate.
687 func (iter Enumerator) UCount(p Predicate) uint {
688 tally := uint(0)
689 for entry := range iter {
690 if p(entry) {
691 tally++
692 }
693 }
694 return tally
695 }
696
697 // UCountAll iterates over a list and keeps a running tally of how many it's seen.
698 func UCountAll(iter Enumerable) uint {
699 return iter.Enumerate(nil).UCountAll()
700 }
701
702 // UCountAll iterates over a list and keeps a running tally of how many it's seen.
703 func (iter Enumerator) UCountAll() uint {
704 tally := uint(0)
705 for range iter {
706 tally++
707 }
708 return tally
709 }
0 package collection
1
2 import (
3 "fmt"
4 "sync"
5 )
6
7 func ExampleAsEnumerable() {
8 // When a single value is provided, and it is an array or slice, each value in the array or slice is treated as an enumerable value.
9 original := []int{1, 2, 3, 4, 5}
10 wrapped := AsEnumerable(original)
11
12 for entry := range wrapped.Enumerate(nil) {
13 fmt.Print(entry)
14 }
15 fmt.Println()
16
17 // When multiple values are provided, regardless of their type, they are each treated as enumerable values.
18 wrapped = AsEnumerable("red", "orange", "yellow", "green", "blue", "indigo", "violet")
19 for entry := range wrapped.Enumerate(nil) {
20 fmt.Println(entry)
21 }
22 // Output:
23 // 12345
24 // red
25 // orange
26 // yellow
27 // green
28 // blue
29 // indigo
30 // violet
31 }
32
33 func ExampleEnumerator_Count() {
34 subject := AsEnumerable("str1", "str1", "str2")
35 count1 := subject.Enumerate(nil).Count(func(a interface{}) bool {
36 return a == "str1"
37 })
38 fmt.Println(count1)
39 // Output: 2
40 }
41
42 func ExampleEnumerator_CountAll() {
43 subject := AsEnumerable('a', 'b', 'c', 'd', 'e')
44 fmt.Println(subject.Enumerate(nil).CountAll())
45 // Ouput: 5
46 }
47
48 func ExampleEnumerator_ElementAt() {
49 done := make(chan struct{})
50 defer close(done)
51 fmt.Print(Fibonacci.Enumerate(done).ElementAt(4))
52 // Output: 3
53 }
54
55 func ExampleFirst() {
56 empty := NewQueue()
57 notEmpty := NewQueue(1, 2, 3, 4)
58
59 fmt.Println(First(empty))
60 fmt.Println(First(notEmpty))
61 // Output:
62 // <nil> Enumerator encountered no elements
63 // 1 <nil>
64 }
65
66 func ExampleLast() {
67 subject := NewList(1, 2, 3, 4)
68 fmt.Println(Last(subject))
69 // Output: 4
70 }
71
72 func ExampleEnumerator_Last() {
73 subject := AsEnumerable(1, 2, 3)
74 fmt.Print(subject.Enumerate(nil).Last())
75 //Output: 3
76 }
77
78 func ExampleMerge() {
79 a := AsEnumerable(1, 2, 4)
80 b := AsEnumerable(8, 16, 32)
81 c := Merge(a, b)
82 sum := 0
83 for x := range c.Enumerate(nil) {
84 sum += x.(int)
85 }
86 fmt.Println(sum)
87
88 product := 1
89 for y := range a.Enumerate(nil) {
90 product *= y.(int)
91 }
92 fmt.Println(product)
93 // Output:
94 // 63
95 // 8
96 }
97
98 func ExampleEnumerator_Reverse() {
99 a := AsEnumerable(1, 2, 3).Enumerate(nil)
100 a = a.Reverse()
101 fmt.Println(a.ToSlice())
102 // Output: [3 2 1]
103 }
104
105 func ExampleSelect() {
106 const offset = 'a' - 1
107
108 subject := AsEnumerable('a', 'b', 'c')
109 subject = Select(subject, func(a interface{}) interface{} {
110 return a.(rune) - offset
111 })
112
113 fmt.Println(ToSlice(subject))
114 // Output: [1 2 3]
115 }
116
117 func ExampleEnumerator_Select() {
118 subject := AsEnumerable('a', 'b', 'c').Enumerate(nil)
119 const offset = 'a' - 1
120 results := subject.Select(func(a interface{}) interface{} {
121 return a.(rune) - offset
122 })
123
124 fmt.Println(results.ToSlice())
125 // Output: [1 2 3]
126 }
127
128 func ExampleEnumerator_SelectMany() {
129
130 type BrewHouse struct {
131 Name string
132 Beers Enumerable
133 }
134
135 breweries := AsEnumerable(
136 BrewHouse{
137 "Mac & Jacks",
138 AsEnumerable(
139 "African Amber",
140 "Ibis IPA",
141 ),
142 },
143 BrewHouse{
144 "Post Doc",
145 AsEnumerable(
146 "Prereq Pale",
147 ),
148 },
149 BrewHouse{
150 "Resonate",
151 AsEnumerable(
152 "Comfortably Numb IPA",
153 "Lithium Altbier",
154 ),
155 },
156 BrewHouse{
157 "Triplehorn",
158 AsEnumerable(
159 "Samson",
160 "Pepper Belly",
161 ),
162 },
163 )
164
165 beers := breweries.Enumerate(nil).SelectMany(func(brewer interface{}) Enumerator {
166 return brewer.(BrewHouse).Beers.Enumerate(nil)
167 })
168
169 for beer := range beers {
170 fmt.Println(beer)
171 }
172
173 // Output:
174 // African Amber
175 // Ibis IPA
176 // Prereq Pale
177 // Comfortably Numb IPA
178 // Lithium Altbier
179 // Samson
180 // Pepper Belly
181 }
182
183 func ExampleSkip() {
184 done := make(chan struct{})
185 defer close(done)
186
187 trimmed := Take(Skip(Fibonacci, 1), 3)
188 for entry := range trimmed.Enumerate(done) {
189 fmt.Println(entry)
190 }
191 // Output:
192 // 1
193 // 1
194 // 2
195 }
196
197 func ExampleEnumerator_Skip() {
198 subject := AsEnumerable(1, 2, 3, 4, 5, 6, 7)
199 skipped := subject.Enumerate(nil).Skip(5)
200 for entry := range skipped {
201 fmt.Println(entry)
202 }
203 // Output:
204 // 6
205 // 7
206 }
207
208 func ExampleTake() {
209 done := make(chan struct{})
210 defer close(done)
211
212 taken := Take(Fibonacci, 4)
213 for entry := range taken.Enumerate(done) {
214 fmt.Println(entry)
215 }
216 // Output:
217 // 0
218 // 1
219 // 1
220 // 2
221 }
222
223 func ExampleEnumerator_Take() {
224 done := make(chan struct{})
225 defer close(done)
226
227 taken := Fibonacci.Enumerate(done).Skip(4).Take(2)
228 for entry := range taken {
229 fmt.Println(entry)
230 }
231 // Output:
232 // 3
233 // 5
234 }
235
236 func ExampleTakeWhile() {
237 taken := TakeWhile(Fibonacci, func(x interface{}, n uint) bool {
238 return x.(int) < 10
239 })
240 for entry := range taken.Enumerate(nil) {
241 fmt.Println(entry)
242 }
243 // Output:
244 // 0
245 // 1
246 // 1
247 // 2
248 // 3
249 // 5
250 // 8
251 }
252
253 func ExampleEnumerator_TakeWhile() {
254 taken := Fibonacci.Enumerate(nil).TakeWhile(func(x interface{}, n uint) bool {
255 return x.(int) < 6
256 })
257 for entry := range taken {
258 fmt.Println(entry)
259 }
260 // Output:
261 // 0
262 // 1
263 // 1
264 // 2
265 // 3
266 // 5
267 }
268
269 func ExampleEnumerator_Tee() {
270 base := AsEnumerable(1, 2, 4)
271 left, right := base.Enumerate(nil).Tee()
272 var wg sync.WaitGroup
273 wg.Add(2)
274
275 product := 1
276 go func() {
277 for x := range left {
278 product *= x.(int)
279 }
280 wg.Done()
281 }()
282
283 sum := 0
284 go func() {
285 for x := range right {
286 sum += x.(int)
287 }
288 wg.Done()
289 }()
290
291 wg.Wait()
292
293 fmt.Printf("Sum: %d\n", sum)
294 fmt.Printf("Product: %d\n", product)
295 // Output:
296 // Sum: 7
297 // Product: 8
298 }
299
300 func ExampleUCount() {
301 subject := NewStack(9, 'a', "str1")
302 result := UCount(subject, func(a interface{}) bool {
303 _, ok := a.(string)
304 return ok
305 })
306 fmt.Println(result)
307 // Output: 1
308 }
309
310 func ExampleEnumerator_UCount() {
311 subject := AsEnumerable("str1", "str1", "str2")
312 count1 := subject.Enumerate(nil).UCount(func(a interface{}) bool {
313 return a == "str1"
314 })
315 fmt.Println(count1)
316 // Output: 2
317 }
318
319 func ExampleUCountAll() {
320 subject := NewStack(8, 9, 10, 11)
321 fmt.Println(UCountAll(subject))
322 // Output: 4
323 }
324
325 func ExampleEnumerator_UCountAll() {
326 subject := AsEnumerable('a', 2, "str1")
327 fmt.Println(subject.Enumerate(nil).UCountAll())
328 // Output: 3
329 }
330
331 func ExampleEnumerator_Where() {
332 done := make(chan struct{})
333 defer close(done)
334 results := Fibonacci.Enumerate(done).Where(func(a interface{}) bool {
335 return a.(int) > 8
336 }).Take(3)
337 fmt.Println(results.ToSlice())
338 // Output: [13 21 34]
339 }
340
341 func ExampleWhere() {
342 results := Where(AsEnumerable(1, 2, 3, 4, 5), func(a interface{}) bool {
343 return a.(int) < 3
344 })
345 fmt.Println(ToSlice(results))
346 // Output: [1 2]
347 }
0 package collection
1
2 import (
3 "testing"
4 "time"
5 )
6
7 func Test_Empty(t *testing.T) {
8 if Any(Empty) {
9 t.Log("empty should not have any elements")
10 t.Fail()
11 }
12
13 if CountAll(Empty) != 0 {
14 t.Log("empty should have counted to zero elements")
15 t.Fail()
16 }
17
18 alwaysTrue := func(x interface{}) bool {
19 return true
20 }
21
22 if Count(Empty, alwaysTrue) != 0 {
23 t.Log("empty should have counted to zero even when discriminating")
24 t.Fail()
25 }
26 }
27
28 func BenchmarkEnumerator_Sum(b *testing.B) {
29 nums := AsEnumerable(getInitializedSequentialArray()...)
30
31 b.ResetTimer()
32 for i := 0; i < b.N; i++ {
33 for range nums.Enumerate(nil).Select(sleepIdentity) {
34 // Intentionally Left Blank
35 }
36 }
37 }
38
39 func sleepIdentity(num interface{}) interface{} {
40 time.Sleep(2 * time.Millisecond)
41 return Identity(num)
42 }
43
44 func getInitializedSequentialArray() []interface{} {
45
46 rawNums := make([]interface{}, 1000, 1000)
47 for i := range rawNums {
48 rawNums[i] = i + 1
49 }
50 return rawNums
51 }
0 package collection
1
2 import (
3 "sync"
4 )
5
6 // Queue implements a basic FIFO structure.
7 type Queue struct {
8 underlyer *LinkedList
9 key sync.RWMutex
10 }
11
12 // NewQueue instantiates a new FIFO structure.
13 func NewQueue(entries ...interface{}) *Queue {
14 retval := &Queue{
15 underlyer: NewLinkedList(entries...),
16 }
17 return retval
18 }
19
20 // Add places an item at the back of the Queue.
21 func (q *Queue) Add(entry interface{}) {
22 q.key.Lock()
23 defer q.key.Unlock()
24 if nil == q.underlyer {
25 q.underlyer = NewLinkedList()
26 }
27 q.underlyer.AddBack(entry)
28 }
29
30 // Enumerate peeks at each element of this queue without mutating it.
31 func (q *Queue) Enumerate(cancel <-chan struct{}) Enumerator {
32 q.key.RLock()
33 defer q.key.RUnlock()
34 return q.underlyer.Enumerate(cancel)
35 }
36
37 // IsEmpty tests the Queue to determine if it is populate or not.
38 func (q *Queue) IsEmpty() bool {
39 q.key.RLock()
40 defer q.key.RUnlock()
41 return q.underlyer == nil || q.underlyer.IsEmpty()
42 }
43
44 // Length returns the number of items in the Queue.
45 func (q *Queue) Length() uint {
46 q.key.RLock()
47 defer q.key.RUnlock()
48 if nil == q.underlyer {
49 return 0
50 }
51 return q.underlyer.length
52 }
53
54 // Next removes and returns the next item in the Queue.
55 func (q *Queue) Next() (interface{}, bool) {
56 q.key.Lock()
57 defer q.key.Unlock()
58 if q.underlyer == nil {
59 return nil, false
60 }
61 return q.underlyer.RemoveFront()
62 }
63
64 // Peek returns the next item in the Queue without removing it.
65 func (q *Queue) Peek() (interface{}, bool) {
66 q.key.RLock()
67 defer q.key.RUnlock()
68 if q.underlyer == nil {
69 return nil, false
70 }
71 return q.underlyer.PeekFront()
72 }
73
74 // ToSlice converts a Queue into a slice.
75 func (q *Queue) ToSlice() []interface{} {
76 q.key.RLock()
77 defer q.key.RUnlock()
78
79 if q.underlyer == nil {
80 return []interface{}{}
81 }
82 return q.underlyer.ToSlice()
83 }
0 package collection
1
2 import (
3 "fmt"
4 "testing"
5 )
6
7 func ExampleQueue_Add() {
8 subject := &Queue{}
9 subject.Add(1)
10 subject.Add(2)
11 res, _ := subject.Peek()
12 fmt.Println(res)
13 // Output: 1
14 }
15
16 func ExampleNewQueue() {
17 empty := NewQueue()
18 fmt.Println(empty.Length())
19
20 populated := NewQueue(1, 2, 3, 5, 8, 13)
21 fmt.Println(populated.Length())
22 // Output:
23 // 0
24 // 6
25 }
26
27 func ExampleQueue_IsEmpty() {
28 empty := NewQueue()
29 fmt.Println(empty.IsEmpty())
30
31 populated := NewQueue(1, 2, 3, 5, 8, 13)
32 fmt.Println(populated.IsEmpty())
33 // Output:
34 // true
35 // false
36 }
37
38 func ExampleQueue_Next() {
39 subject := NewQueue(1, 2, 3, 5, 8, 13)
40 for !subject.IsEmpty() {
41 val, _ := subject.Next()
42 fmt.Println(val)
43 }
44 // Output:
45 // 1
46 // 2
47 // 3
48 // 5
49 // 8
50 // 13
51 }
52
53 func TestQueue_Length(t *testing.T) {
54 empty := NewQueue()
55 if count := empty.Length(); count != 0 {
56 t.Logf("got: %d\nwant: %d", count, 0)
57 t.Fail()
58 }
59
60 // Not the type magic number you're thinking of!
61 // https://en.wikipedia.org/wiki/1729_(number)
62 single := NewQueue(1729)
63 if count := single.Length(); count != 1 {
64 t.Logf("got: %d\nwant: %d", count, 1)
65 t.Fail()
66 }
67
68 expectedMany := []interface{}{'a', 'b', 'c', 'd', 'e', 'e', 'f', 'g'}
69 many := NewQueue(expectedMany...)
70 if count := many.Length(); count != uint(len(expectedMany)) {
71 t.Logf("got: %d\nwant: %d", count, len(expectedMany))
72 }
73 }
74
75 func TestQueue_Length_NonConstructed(t *testing.T) {
76 subject := &Queue{}
77 if got := subject.Length(); got != 0 {
78 t.Logf("got: %d\nwant: %d", got, 0)
79 t.Fail()
80 }
81 }
82
83 func TestQueue_Next_NonConstructed(t *testing.T) {
84 subject := &Queue{}
85 if got, ok := subject.Next(); ok {
86 t.Logf("Next should not have been ok")
87 t.Fail()
88 } else if got != nil {
89 t.Logf("got: %v\nwant: %v", got, nil)
90 t.Fail()
91 }
92 }
93
94 func TestQueue_Peek_DoesntRemove(t *testing.T) {
95 expected := []interface{}{1, 2, 3}
96 subject := NewQueue(expected...)
97 if result, ok := subject.Peek(); !ok {
98 t.Logf("no item present")
99 t.Fail()
100 } else if result != expected[0] {
101 t.Logf("got: %d\nwant: %d", result, 1)
102 t.Fail()
103 } else if count := subject.Length(); count != uint(len(expected)) {
104 t.Logf("got: %d\nwant: %d", count, len(expected))
105 }
106 }
107
108 func TestQueue_Peek_NonConstructed(t *testing.T) {
109 subject := &Queue{}
110 if got, ok := subject.Peek(); ok {
111 t.Logf("Peek should not have been ok")
112 t.Fail()
113 } else if got != nil {
114 t.Logf("got: %v\nwant: %v", got, nil)
115 t.Fail()
116 }
117 }
118
119 func TestQueue_ToSlice(t *testing.T) {
120 subject := NewQueue(0, 1, 1, 2, 3, 5)
121 expectedSliceString := "[0 1 1 2 3 5]"
122 if result := subject.ToSlice(); len(result) != 6 {
123 t.Logf("got: %d\nwant: %d", len(result), 6)
124 t.Fail()
125 } else if fmt.Sprintf("%v", result) != expectedSliceString {
126 t.Logf("got:\n%v\nwant:\n%s\n", result, expectedSliceString)
127 t.Fail()
128 }
129 }
130
131 func TestQueue_ToSlice_Empty(t *testing.T) {
132 subject := NewQueue()
133 result := subject.ToSlice()
134
135 if len(result) != 0 {
136 t.Logf("result should have been empty")
137 t.Fail()
138 }
139 expectedStr := "[]"
140 resultStr := fmt.Sprintf("%v", result)
141 if resultStr != expectedStr {
142 t.Logf("got:\n%s\nwant:\n%s", resultStr, expectedStr)
143 t.Fail()
144 }
145 }
146
147 func TestQueue_ToSlice_NotConstructed(t *testing.T) {
148 subject := &Queue{}
149 result := subject.ToSlice()
150
151 if len(result) != 0 {
152 t.Logf("result should have been empty")
153 t.Fail()
154 }
155 expectedStr := "[]"
156 resultStr := fmt.Sprintf("%v", result)
157 if resultStr != expectedStr {
158 t.Logf("got:\n%s\nwant:\n%s", resultStr, expectedStr)
159 t.Fail()
160 }
161 }
0 package collection
1
2 import (
3 "sync"
4 )
5
6 // Stack implements a basic FILO structure.
7 type Stack struct {
8 underlyer *LinkedList
9 key sync.RWMutex
10 }
11
12 // NewStack instantiates a new FILO structure.
13 func NewStack(entries ...interface{}) *Stack {
14 retval := &Stack{}
15 retval.underlyer = NewLinkedList()
16
17 for _, entry := range entries {
18 retval.Push(entry)
19 }
20 return retval
21 }
22
23 // Enumerate peeks at each element in the stack without mutating it.
24 func (stack *Stack) Enumerate(cancel <-chan struct{}) Enumerator {
25 stack.key.RLock()
26 defer stack.key.RUnlock()
27
28 return stack.underlyer.Enumerate(cancel)
29 }
30
31 // IsEmpty tests the Stack to determine if it is populate or not.
32 func (stack *Stack) IsEmpty() bool {
33 stack.key.RLock()
34 defer stack.key.RUnlock()
35 return stack.underlyer == nil || stack.underlyer.IsEmpty()
36 }
37
38 // Push adds an entry to the top of the Stack.
39 func (stack *Stack) Push(entry interface{}) {
40 stack.key.Lock()
41 defer stack.key.Unlock()
42
43 if nil == stack.underlyer {
44 stack.underlyer = NewLinkedList()
45 }
46 stack.underlyer.AddFront(entry)
47 }
48
49 // Pop returns the entry at the top of the Stack then removes it.
50 func (stack *Stack) Pop() (interface{}, bool) {
51 stack.key.Lock()
52 defer stack.key.Unlock()
53
54 if nil == stack.underlyer {
55 return nil, false
56 }
57 return stack.underlyer.RemoveFront()
58 }
59
60 // Peek returns the entry at the top of the Stack without removing it.
61 func (stack *Stack) Peek() (interface{}, bool) {
62 stack.key.RLock()
63 defer stack.key.RUnlock()
64 return stack.underlyer.PeekFront()
65 }
66
67 // Size returns the number of entries populating the Stack.
68 func (stack *Stack) Size() uint {
69 stack.key.RLock()
70 defer stack.key.RUnlock()
71 if stack.underlyer == nil {
72 return 0
73 }
74 return stack.underlyer.Length()
75 }
0 package collection
1
2 import (
3 "fmt"
4 "testing"
5 )
6
7 func TestStack_NewStack_FromEmpty(t *testing.T) {
8 subject := NewStack()
9 subject.Push("alfa")
10 subject.Push("bravo")
11 subject.Push("charlie")
12
13 if result, ok := subject.Pop(); result != "charlie" || ok != true {
14 t.Logf("got: %s %v\nwant: %s %v", result, ok, "charlie", true)
15 t.Fail()
16 }
17 if result, ok := subject.Pop(); result != "bravo" || ok != true {
18 t.Logf("got: %s %v\nwant: %s %v", result, ok, "bravo", true)
19 t.Fail()
20 }
21 if result, ok := subject.Pop(); result != "alfa" || ok != true {
22 t.Logf("got: %s %v\nwant: %s %v", result, ok, "alfa", true)
23 t.Fail()
24 }
25 if !subject.IsEmpty() {
26 t.Log("subject should have been empty.")
27 t.Fail()
28 }
29 }
30
31 func ExampleNewStack() {
32 subject := NewStack(1, 2, 3)
33 for !subject.IsEmpty() {
34 val, _ := subject.Pop()
35 fmt.Println(val)
36 }
37 // Output:
38 // 3
39 // 2
40 // 1
41 }
42
43 func TestStack_Push_NonConstructor(t *testing.T) {
44 subject := &Stack{}
45
46 sizeAssertion := func(want uint) {
47 if got := subject.Size(); got != want {
48 t.Logf("got: %d\nwant:%d\n", got, want)
49 t.Fail()
50 }
51 }
52
53 sizeAssertion(0)
54 subject.Push(1)
55 sizeAssertion(1)
56 subject.Push(2)
57 sizeAssertion(2)
58
59 if result, ok := subject.Pop(); !ok {
60 t.Logf("Pop is not ok")
61 t.Fail()
62 } else if result != 2 {
63 t.Logf("got: %d\nwant: %d", result, 2)
64 t.Fail()
65 }
66 }
67
68 func TestStack_Pop_NonConstructorEmpty(t *testing.T) {
69 subject := &Stack{}
70
71 if result, ok := subject.Pop(); ok {
72 t.Logf("Pop should not have been okay")
73 t.Fail()
74 } else if result != nil {
75 t.Logf("got: %v\nwant: %v", result, nil)
76 }
77 }
(New empty file)
(New empty file)
(New empty file)