-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmap.go
More file actions
169 lines (139 loc) · 4.36 KB
/
Copy pathmap.go
File metadata and controls
169 lines (139 loc) · 4.36 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
package concurrent
import (
"fmt"
"runtime"
"sync"
)
// ReduceOption reduce order
type ReduceOption int
const (
UnorderedReduce ReduceOption = iota + 1 // UnorderedReduce unordered
OrderedReduce // OrderedReduce ordered
)
// DefGoroutines default goroutines count(runtime.NumCPU())
var DefGoroutines = runtime.NumCPU()
// Map calls function once for each item in sequence. The function takes a reference to the item, so that any modifications done to the item will appear in sequence.
func Map[T any](goroutines int, data []T, function func(*T)) error {
if goroutines == 0 {
return fmt.Errorf("goroutines = 0")
}
if len(data) == 0 {
return nil
}
wg := sync.WaitGroup{}
wg.Add(goroutines)
for i := 0; i < goroutines; i++ {
go func(start, step int, datSize int) {
defer wg.Done()
for index := start; index < datSize; index += step {
function(&data[index])
}
}(i, goroutines, len(data))
}
wg.Wait()
return nil
}
// DefMap calls function once for each item in sequence. The function takes a reference to the item, so that any modifications done to the item will appear in sequence.
func DefMap[T any](data []T, function func(*T)) {
err := Map(DefGoroutines, data, function)
if err != nil {
panic(err)
}
}
// Mapped calls function once for each item in sequence and returns a sequence with each mapped item as a result
func Mapped[S any, R any](goroutines int, data []S, function func(S) R) ([]R, error) {
if goroutines == 0 {
return nil, fmt.Errorf("goroutines = 0")
}
if len(data) == 0 {
return nil, nil
}
result := make([]R, len(data))
wg := sync.WaitGroup{}
wg.Add(goroutines)
for i := 0; i < goroutines; i++ {
go func(start, step int, datSize int) {
defer wg.Done()
for index := start; index < datSize; index += step {
result[index] = function(data[index])
}
}(i, goroutines, len(data))
}
wg.Wait()
return result, nil
}
// DefMapped calls function once for each item in sequence and returns a sequence with each mapped item as a result
func DefMapped[S any, R any](data []S, function func(S) R) ([]R, error) {
result, err := Mapped(DefGoroutines, data, function)
if err != nil {
panic(err)
}
return result, nil
}
// MappedReduced calls mapFunction once for each item in sequence. The return value of each mapFunction is passed to reduceFunction.
//
// Note that while mapFunction is called concurrently, only one thread at a time will call reduceFunction.
// The order in which reduceFunction is called is determined by reduceOptions.
func MappedReduced[S any, R any](goroutines int, data []S, mapFunction func(S) R, reduceFunction func(*R, R), reduceOptions ReduceOption) (R, error) {
var empty R
if goroutines == 0 {
return empty, fmt.Errorf("goroutines = 0")
}
if len(data) == 0 {
return empty, fmt.Errorf("empty data")
}
switch reduceOptions {
case UnorderedReduce:
return unorderedMappedReduced(goroutines, data, mapFunction, reduceFunction)
case OrderedReduce:
return orderedMappedReduced(goroutines, data, mapFunction, reduceFunction)
default:
return empty, fmt.Errorf("invalid reduce order")
}
}
func orderedMappedReduced[S any, R any](goroutines int, data []S, mapFunction func(S) R, reduceFunction func(*R, R)) (R, error) {
result := make([]chan R, goroutines)
for i := range result {
result[i] = make(chan R, goroutines)
}
for i := 0; i < goroutines; i++ {
go func(start, step int, datSize int) {
for index := start; index < datSize; index += step {
idx := index % goroutines
result[idx] <- mapFunction(data[index])
}
}(i, goroutines, len(data))
}
accumulator := <-result[0]
for j := 1; j < len(data); j++ {
idx := j % goroutines
res := <-result[idx]
reduceFunction(&accumulator, res)
}
for _, ch := range result {
close(ch)
}
return accumulator, nil
}
func unorderedMappedReduced[S any, R any](goroutines int, data []S, mapFunction func(S) R, reduceFunction func(*R, R)) (R, error) {
wg := sync.WaitGroup{}
wg.Add(goroutines)
result := make(chan R, goroutines)
for i := 0; i < goroutines; i++ {
go func(start, step int, datSize int) {
defer wg.Done()
for index := start; index < datSize; index += step {
result <- mapFunction(data[index])
}
}(i, goroutines, len(data))
}
go func() {
wg.Wait()
close(result)
}()
accumulator := <-result
for res := range result {
reduceFunction(&accumulator, res)
}
return accumulator, nil
}