-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtransformer_symbol.go
102 lines (86 loc) · 2.24 KB
/
transformer_symbol.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
package sinoname
import (
"context"
"strings"
"unicode/utf8"
"gonum.org/v1/gonum/stat/combin"
)
//TODO: test if for each symbol to add we can generate a random permutation and then
//TODO: check for it (and skip it) in the sequential passings of the permuations to randomise things up.
// SymbolTransformer adds symbol to the incoming word till it fills up any possible
// positions, starting with adding 1 symbol till len(incoming word) - 1 symbols.
//
// Incoming Word: ABC , Symbol: .
//
// Adding 1 Symbol:
// .ABC , A.BC , AB.C , ABC.
//
// Adding 2 Symbols:
// .A.BC , .AB.C , .ABC. , A.B.C , A.BC. , AB.C.
//
// Adding 3 Symbols
// .A.B.C , .A.BC. , .AB.C. , A.B.C.
var SymbolTransformer = func(symbol rune, max int) func(cfg *Config) (Transformer, bool) {
return func(cfg *Config) (Transformer, bool) {
if max < 0 {
max = 0
}
return &symbolTransformer{
cfg: cfg,
symbol: symbol,
maxSymbols: max,
}, false
}
}
type symbolTransformer struct {
cfg *Config
symbol rune
maxSymbols int
}
func (t *symbolTransformer) Transform(ctx context.Context, in MessagePacket) (MessagePacket, error) {
var g *combin.CombinationGenerator
n := len(in.Message)
nr := utf8.RuneLen(t.symbol)
for symbolsToAdd := 1; symbolsToAdd < n+1; symbolsToAdd++ {
// dont bother to generate and allocate buffer if we cant acomodate size after
// the symbols are added.
if n+symbolsToAdd*nr > t.cfg.MaxBytes {
return in, nil
}
if symbolsToAdd > t.maxSymbols && t.maxSymbols != 0 {
return in, nil
}
comb := make([]int, symbolsToAdd)
g = combin.NewCombinationGenerator(n+1, symbolsToAdd)
for g.Next() {
select {
case <-ctx.Done():
return MessagePacket{}, ctx.Err()
default:
}
var b strings.Builder
b.Grow(n + symbolsToAdd*nr)
g.Combination(comb)
var prevJ int
for i, j := range comb {
b.WriteString(in.Message[prevJ:j])
b.WriteRune(t.symbol)
prevJ = j
// last itteration, write remaining string.
if i == len(comb)-1 {
b.WriteString(in.Message[j:])
}
}
out := b.String()
ok, err := t.cfg.Source.Valid(ctx, out)
if err != nil {
return MessagePacket{}, err
}
if ok {
in.setAndIncrement(out)
return in, nil
}
}
}
return in, nil
}