-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathordering.go
130 lines (114 loc) · 2.61 KB
/
ordering.go
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
package chains
import (
"cmp"
"iter"
"slices"
)
type cycleItem[T any] struct {
next func() (T, bool)
done func()
}
type itemListForCycling[T any] []cycleItem[T]
// RoundRobin takes an arbitrary number of iterators and takes one from each
// until they are all exhausted.
func RoundRobin[T cmp.Ordered](iterators ...iter.Seq[T]) iter.Seq[T] {
itemList := make(itemListForCycling[T], len(iterators))
for index, iterable := range iterators {
next, stop := iter.Pull(iterable)
itemList[index] = cycleItem[T]{
next: next,
done: stop,
}
}
return func(yield func(T) bool) {
defer func() {
for _, i := range itemList {
if i.done != nil {
i.done()
}
}
}()
index := 0
missedItems := 0
for missedItems < len(itemList) {
if itemList[index].next != nil {
if nextVal, ok := itemList[index].next(); ok {
if !yield(nextVal) {
return
}
} else {
itemList[index].done = nil
itemList[index].next = nil
}
missedItems = 0
} else {
missedItems += 1
}
index += 1
index %= len(itemList)
}
}
}
type mergeSortedItem[T cmp.Ordered] struct {
value T
next func() (T, bool)
done func()
}
type itemListForSorting[T cmp.Ordered] []mergeSortedItem[T]
// TODO: Make this a proper heap
func sortItems[T cmp.Ordered](itemList itemListForSorting[T]) {
slices.SortFunc(itemList, func(a, b mergeSortedItem[T]) int {
if a.value < b.value {
return -1
} else if a.value == b.value {
return 0
} else {
return 1
}
})
}
// Merged takes an arbitrary number of iterators in ascending order and attempts to merge
// them into a single sorted iterable -- this has similar limitations to Uniq in that if
// the sequences are not ordered, the iterable will not magically be sorted -- it will
// be a best effort.
func Merged[T cmp.Ordered](iterators ...iter.Seq[T]) iter.Seq[T] {
itemList := make(itemListForSorting[T], len(iterators))
index := 0
for _, iterable := range iterators {
next, stop := iter.Pull(iterable)
firstVal, ok := next()
if ok {
itemList[index] = mergeSortedItem[T]{
value: firstVal,
next: next,
done: stop,
}
index += 1
}
}
itemList = itemList[:index]
sortItems(itemList)
return func(yield func(T) bool) {
defer func() {
for _, i := range itemList {
i.done()
}
}()
for len(itemList) > 0 {
if ok := yield(itemList[0].value); !ok {
return
}
nextVal, ok := itemList[0].next()
if ok {
itemList[0].value = nextVal
if len(itemList) > 1 {
if itemList[0].value > itemList[1].value {
sortItems(itemList)
}
}
} else {
itemList = itemList[1:]
}
}
}
}