-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
multiplex.go
155 lines (128 loc) · 4.71 KB
/
multiplex.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
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
package kowalski
import (
"context"
"sync"
)
type MultiplexOption func(*multiplexOptions)
type multiplexOptions struct {
dedupe bool
}
// Dedupe removes duplicate entries from multiplexed results. That is, if the first checker provides words A, B and C,
// the second checker provides B and D, and the third A, D, and E, then the result will be: {A,B,C},{D},{E}.
func Dedupe(options *multiplexOptions) {
options.dedupe = true
}
// MultiplexMatch performs the Match operation over a number of different checkers.
func MultiplexMatch(ctx context.Context, checkers []*SpellChecker, pattern string, opts ... MultiplexOption) ([][]string, error) {
return multiplexWithErrors(checkers, func(checker *SpellChecker) ([]string, error) {
return Match(ctx, checker, pattern)
}, opts)
}
// MultiplexMultiMatch performs the MultiMatch operation over a number of different checkers.
func MultiplexMultiMatch(ctx context.Context, checkers []*SpellChecker, pattern string, opts ... MultiplexOption) ([][]string, error) {
return multiplexWithErrors(checkers, func(checker *SpellChecker) ([]string, error) {
return MultiMatch(ctx, checker, pattern)
}, opts)
}
// MultiplexAnagram performs the Anagram operation over a number of different checkers.
func MultiplexAnagram(ctx context.Context, checkers []*SpellChecker, pattern string, opts ... MultiplexOption) ([][]string, error) {
return multiplexWithErrors(checkers, func(checker *SpellChecker) ([]string, error) {
return Anagram(ctx, checker, pattern)
}, opts)
}
// MultiplexMultiAnagram performs the MultiAnagram operation over a number of different checkers.
func MultiplexMultiAnagram(ctx context.Context, checkers []*SpellChecker, pattern string, opts ... MultiplexOption) ([][]string, error) {
return multiplexWithErrors(checkers, func(checker *SpellChecker) ([]string, error) {
return MultiAnagram(ctx, checker, pattern)
}, opts)
}
// MultiplexFindWords performs the FindWords operation over a number of different checkers.
func MultiplexFindWords(checkers []*SpellChecker, pattern string, opts ... MultiplexOption) [][]string {
return multiplex(checkers, func(checker *SpellChecker) []string {
return FindWords(checker, pattern)
}, opts)
}
// MultiplexFromMorse performs the FromMorse operation over a number of different checkers.
func MultiplexFromMorse(checkers []*SpellChecker, pattern string, opts ... MultiplexOption) [][]string {
return multiplex(checkers, func(checker *SpellChecker) []string {
return FromMorse(checker, pattern)
}, opts)
}
// MultiplexOffByOne performs the OffByOne operation over a number of different checkers.
func MultiplexOffByOne(ctx context.Context, checkers []*SpellChecker, pattern string, opts ... MultiplexOption) ([][]string, error) {
return multiplexWithErrors(checkers, func(checker *SpellChecker) ([]string, error) {
return OffByOne(ctx, checker, pattern)
}, opts)
}
// MultiplexFromT9 performs the FromT9 operation over a number of different checkers.
func MultiplexFromT9(checkers []*SpellChecker, pattern string, opts ... MultiplexOption) [][]string {
return multiplex(checkers, func(checker *SpellChecker) []string {
return FromT9(checker, pattern)
}, opts)
}
// MultiplexWordSearch performs the WordSearch operation over a number of different checkers.
func MultiplexWordSearch(checkers []*SpellChecker, pattern []string, opts ... MultiplexOption) [][]string {
return multiplex(checkers, func(checker *SpellChecker) []string {
return WordSearch(checker, pattern)
}, opts)
}
func multiplex(checkers []*SpellChecker, f func(checker *SpellChecker)[]string, opts []MultiplexOption) [][]string {
o := &multiplexOptions{}
for i := range opts {
opts[i](o)
}
res := make([][]string, len(checkers))
wg := &sync.WaitGroup{}
for i := range checkers {
wg.Add(1)
go func(i int) {
res[i] = f(checkers[i])
wg.Done()
}(i)
}
wg.Wait()
if o.dedupe {
return dedupe(res)
}
return res
}
func multiplexWithErrors(checkers []*SpellChecker, f func(checker *SpellChecker)([]string, error), opts []MultiplexOption) ([][]string, error) {
o := &multiplexOptions{}
for i := range opts {
opts[i](o)
}
res := make([][]string, len(checkers))
errs := make([]error, len(checkers))
wg := &sync.WaitGroup{}
for i := range checkers {
wg.Add(1)
go func(i int) {
res[i], errs[i] = f(checkers[i])
wg.Done()
}(i)
}
wg.Wait()
for i := range errs {
if errs[i] != nil {
return nil, errs[i]
}
}
if o.dedupe {
return dedupe(res), nil
}
return res, nil
}
func dedupe(data [][]string) [][]string {
res := make([][]string, len(data))
existing := make(map[string]bool)
for i := range data {
words := data[i]
for j := range words {
if !existing[words[j]] {
res[i] = append(res[i], words[j])
existing[words[j]] = true
}
}
}
return res
}