1
2
3
4
5 package colltab
6
7 import (
8 "unicode"
9 "unicode/utf8"
10 )
11
12
13
14
15
16
17
18 func NewNumericWeighter(w Weighter) Weighter {
19 getElem := func(s string) Elem {
20 elems, _ := w.AppendNextString(nil, s)
21 return elems[0]
22 }
23 nine := getElem("9")
24
25
26
27 ns, _ := MakeElem(nine.Primary()+1, nine.Secondary(), int(nine.Tertiary()), 0)
28
29 return &numericWeighter{
30 Weighter: w,
31
32
33
34
35
36
37 zero: getElem("0"),
38 zeroSpecialLo: getElem("0"),
39 zeroSpecialHi: getElem("₀"),
40 nine: nine,
41 nineSpecialHi: getElem("₉"),
42 numberStart: ns,
43 }
44 }
45
46
47
48 type numericWeighter struct {
49 Weighter
50
51
52
53
54
55
56
57
58
59
60 zero Elem
61 zeroSpecialLo Elem
62 zeroSpecialHi Elem
63 nine Elem
64 nineSpecialHi Elem
65 numberStart Elem
66 }
67
68
69
70 func (nw *numericWeighter) AppendNext(buf []Elem, s []byte) (ce []Elem, n int) {
71 ce, n = nw.Weighter.AppendNext(buf, s)
72 nc := numberConverter{
73 elems: buf,
74 w: nw,
75 b: s,
76 }
77 isZero, ok := nc.checkNextDigit(ce)
78 if !ok {
79 return ce, n
80 }
81
82 nc.init(ce, len(buf), isZero)
83 for n < len(s) {
84 ce, sz := nw.Weighter.AppendNext(nc.elems, s[n:])
85 nc.b = s
86 n += sz
87 if !nc.update(ce) {
88 break
89 }
90 }
91 return nc.result(), n
92 }
93
94
95
96 func (nw *numericWeighter) AppendNextString(buf []Elem, s string) (ce []Elem, n int) {
97 ce, n = nw.Weighter.AppendNextString(buf, s)
98 nc := numberConverter{
99 elems: buf,
100 w: nw,
101 s: s,
102 }
103 isZero, ok := nc.checkNextDigit(ce)
104 if !ok {
105 return ce, n
106 }
107 nc.init(ce, len(buf), isZero)
108 for n < len(s) {
109 ce, sz := nw.Weighter.AppendNextString(nc.elems, s[n:])
110 nc.s = s
111 n += sz
112 if !nc.update(ce) {
113 break
114 }
115 }
116 return nc.result(), n
117 }
118
119 type numberConverter struct {
120 w *numericWeighter
121
122 elems []Elem
123 nDigits int
124 lenIndex int
125
126 s string
127 b []byte
128 }
129
130
131
132 func (nc *numberConverter) init(elems []Elem, oldLen int, isZero bool) {
133
134
135 if isZero {
136 elems = append(elems[:oldLen], nc.w.numberStart, 0)
137 } else {
138 elems = append(elems, 0, 0)
139 copy(elems[oldLen+2:], elems[oldLen:])
140 elems[oldLen] = nc.w.numberStart
141 elems[oldLen+1] = 0
142
143 nc.nDigits = 1
144 }
145 nc.elems = elems
146 nc.lenIndex = oldLen + 1
147 }
148
149
150
151 func (nc *numberConverter) checkNextDigit(bufNew []Elem) (isZero, ok bool) {
152 if len(nc.elems) >= len(bufNew) {
153 return false, false
154 }
155 e := bufNew[len(nc.elems)]
156 if e < nc.w.zeroSpecialLo || nc.w.nine < e {
157
158 return false, false
159 }
160 if e < nc.w.zero {
161 if e > nc.w.nineSpecialHi {
162
163 return false, false
164 }
165 if !nc.isDigit() {
166 return false, false
167 }
168 isZero = e <= nc.w.zeroSpecialHi
169 } else {
170
171 isZero = e == nc.w.zero
172 }
173
174 if n := len(bufNew) - len(nc.elems); n > 1 {
175 for i := len(nc.elems) + 1; i < len(bufNew); i++ {
176 if bufNew[i].Primary() != 0 {
177 return false, false
178 }
179 }
180
181
182
183
184
185
186
187
188
189
190 if !nc.isDigit() {
191 return false, false
192 }
193 }
194 return isZero, true
195 }
196
197 func (nc *numberConverter) isDigit() bool {
198 if nc.b != nil {
199 r, _ := utf8.DecodeRune(nc.b)
200 return unicode.In(r, unicode.Nd)
201 }
202 r, _ := utf8.DecodeRuneInString(nc.s)
203 return unicode.In(r, unicode.Nd)
204 }
205
206
207
208
209
210
211
212
213
214
215 const maxDigits = 1<<maxPrimaryBits - 1
216
217 func (nc *numberConverter) update(elems []Elem) bool {
218 isZero, ok := nc.checkNextDigit(elems)
219 if nc.nDigits == 0 && isZero {
220 return true
221 }
222 nc.elems = elems
223 if !ok {
224 return false
225 }
226 nc.nDigits++
227 return nc.nDigits < maxDigits
228 }
229
230
231
232 func (nc *numberConverter) result() []Elem {
233 e, _ := MakeElem(nc.nDigits, defaultSecondary, defaultTertiary, 0)
234 nc.elems[nc.lenIndex] = e
235 return nc.elems
236 }
237
View as plain text