yencode 1.0.8 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +339 -231
  2. package/binding.gyp +292 -39
  3. package/crcutil-1.0/code/multiword_64_64_gcc_amd64_asm.cc +7 -7
  4. package/crcutil-1.0/code/multiword_64_64_gcc_i386_mmx.cc +14 -14
  5. package/crcutil-1.0/code/multiword_64_64_intrinsic_i386_mmx.cc +1 -1
  6. package/crcutil-1.0/code/uint128_sse2.h +2 -0
  7. package/index.js +329 -22
  8. package/package.json +2 -2
  9. package/src/common.h +299 -0
  10. package/src/crc.cc +95 -0
  11. package/src/crc.h +23 -0
  12. package/src/crc_arm.cc +175 -0
  13. package/src/crc_common.h +4 -0
  14. package/{crc_folding.c → src/crc_folding.cc} +175 -185
  15. package/src/decoder.cc +61 -0
  16. package/src/decoder.h +53 -0
  17. package/src/decoder_avx.cc +18 -0
  18. package/src/decoder_avx2.cc +18 -0
  19. package/src/decoder_avx2_base.h +615 -0
  20. package/src/decoder_common.h +512 -0
  21. package/src/decoder_neon.cc +474 -0
  22. package/src/decoder_neon64.cc +451 -0
  23. package/src/decoder_sse2.cc +16 -0
  24. package/src/decoder_sse_base.h +711 -0
  25. package/src/decoder_ssse3.cc +18 -0
  26. package/src/encoder.cc +170 -0
  27. package/src/encoder.h +21 -0
  28. package/src/encoder_avx.cc +16 -0
  29. package/src/encoder_avx2.cc +16 -0
  30. package/src/encoder_avx_base.h +564 -0
  31. package/src/encoder_common.h +109 -0
  32. package/src/encoder_neon.cc +547 -0
  33. package/src/encoder_sse2.cc +13 -0
  34. package/src/encoder_sse_base.h +724 -0
  35. package/src/encoder_ssse3.cc +18 -0
  36. package/src/hedley.h +1899 -0
  37. package/src/platform.cc +147 -0
  38. package/src/yencode.cc +449 -0
  39. package/test/_maxsize.js +9 -0
  40. package/test/_speedbase.js +147 -0
  41. package/test/speedcrc.js +20 -0
  42. package/test/speeddec.js +92 -0
  43. package/test/speedenc.js +44 -0
  44. package/{testcrc.js → test/testcrc.js} +53 -39
  45. package/test/testdec.js +183 -0
  46. package/test/testenc.js +163 -0
  47. package/test/testpostdec.js +126 -0
  48. package/test.js +0 -91
  49. package/yencode.cc +0 -1622
@@ -0,0 +1,512 @@
1
+ #include "decoder.h"
2
+
3
+ // TODO: need to support max output length somehow
4
+ // TODO: add branch probabilities
5
+
6
+
7
+ // state var: refers to the previous state - only used for incremental processing
8
+ template<bool isRaw>
9
+ size_t do_decode_noend_scalar(const unsigned char* HEDLEY_RESTRICT src, unsigned char* HEDLEY_RESTRICT dest, size_t len, YencDecoderState* state) {
10
+ const unsigned char *es = src + len; // end source pointer
11
+ unsigned char *p = dest; // destination pointer
12
+ long i = -(long)len; // input position
13
+ unsigned char c; // input character
14
+
15
+ if(len < 1) return 0;
16
+
17
+ if(isRaw) {
18
+
19
+ if(state) switch(*state) {
20
+ case YDEC_STATE_EQ:
21
+ c = es[i];
22
+ *p++ = c - 42 - 64;
23
+ i++;
24
+ if(c == '\r') {
25
+ *state = YDEC_STATE_CR;
26
+ if(i >= 0) return 0;
27
+ } else {
28
+ *state = YDEC_STATE_NONE;
29
+ break;
30
+ }
31
+ // fall-thru
32
+ case YDEC_STATE_CR:
33
+ if(es[i] != '\n') break;
34
+ i++;
35
+ *state = YDEC_STATE_CRLF;
36
+ if(i >= 0) return 0;
37
+ // Else fall-thru
38
+ case YDEC_STATE_CRLF:
39
+ // skip past first dot
40
+ if(es[i] == '.') i++;
41
+ // fall-thru
42
+ default: break; // silence compiler warnings
43
+ } else // treat as YDEC_STATE_CRLF
44
+ if(es[i] == '.') i++;
45
+
46
+ for(; i < -2; i++) {
47
+ c = es[i];
48
+ switch(c) {
49
+ case '\r':
50
+ // skip past \r\n. sequences
51
+ //i += (es[i+1] == '\n' && es[i+2] == '.') << 1;
52
+ if(es[i+1] == '\n' && es[i+2] == '.')
53
+ i += 2;
54
+ // fall-thru
55
+ case '\n':
56
+ continue;
57
+ case '=':
58
+ c = es[i+1];
59
+ *p++ = c - 42 - 64;
60
+ i += (c != '\r'); // if we have a \r, reprocess character to deal with \r\n. case
61
+ continue;
62
+ default:
63
+ *p++ = c - 42;
64
+ }
65
+ }
66
+ if(state) *state = YDEC_STATE_NONE;
67
+
68
+ if(i == -2) { // 2nd last char
69
+ c = es[i];
70
+ switch(c) {
71
+ case '\r':
72
+ if(state && es[i+1] == '\n') {
73
+ *state = YDEC_STATE_CRLF;
74
+ return p - dest;
75
+ }
76
+ // Else fall-thru
77
+ case '\n':
78
+ break;
79
+ case '=':
80
+ c = es[i+1];
81
+ *p++ = c - 42 - 64;
82
+ i += (c != '\r');
83
+ break;
84
+ default:
85
+ *p++ = c - 42;
86
+ }
87
+ i++;
88
+ }
89
+
90
+ // do final char; we process this separately to prevent an overflow if the final char is '='
91
+ if(i == -1) {
92
+ c = es[i];
93
+ if(c != '\n' && c != '\r' && c != '=') {
94
+ *p++ = c - 42;
95
+ } else if(state) {
96
+ if(c == '=') *state = YDEC_STATE_EQ;
97
+ else if(c == '\r') *state = YDEC_STATE_CR;
98
+ else *state = YDEC_STATE_NONE;
99
+ }
100
+ }
101
+
102
+ } else {
103
+
104
+ if(state && *state == YDEC_STATE_EQ) {
105
+ *p++ = es[i] - 42 - 64;
106
+ i++;
107
+ *state = YDEC_STATE_NONE;
108
+ }
109
+
110
+ /*for(i = 0; i < len - 1; i++) {
111
+ c = src[i];
112
+ if(c == '\n' || c == '\r') continue;
113
+ unsigned char isEquals = (c == '=');
114
+ i += isEquals;
115
+ *p++ = src[i] - (42 + (isEquals << 6));
116
+ }*/
117
+ for(; i < -1; i++) {
118
+ c = es[i];
119
+ switch(c) {
120
+ case '\n': case '\r': continue;
121
+ case '=':
122
+ i++;
123
+ c = es[i] - 64;
124
+ }
125
+ *p++ = c - 42;
126
+ }
127
+ if(state) *state = YDEC_STATE_NONE;
128
+ // do final char; we process this separately to prevent an overflow if the final char is '='
129
+ if(i == -1) {
130
+ c = es[i];
131
+ if(c != '\n' && c != '\r' && c != '=') {
132
+ *p++ = c - 42;
133
+ } else
134
+ if(state) *state = (c == '=' ? YDEC_STATE_EQ : YDEC_STATE_NONE);
135
+ }
136
+
137
+ }
138
+
139
+ return p - dest;
140
+ }
141
+
142
+ template<bool isRaw>
143
+ YencDecoderEnd do_decode_end_scalar(const unsigned char* HEDLEY_RESTRICT* src, unsigned char* HEDLEY_RESTRICT* dest, size_t len, YencDecoderState* state) {
144
+ const unsigned char *es = (*src) + len; // end source pointer
145
+ unsigned char *p = *dest; // destination pointer
146
+ long i = -(long)len; // input position
147
+ unsigned char c; // input character
148
+
149
+ if(len < 1) return YDEC_END_NONE;
150
+
151
+ #define YDEC_CHECK_END(s) if(i == 0) { \
152
+ *state = s; \
153
+ *src = es; \
154
+ *dest = p; \
155
+ return YDEC_END_NONE; \
156
+ }
157
+ if(state) switch(*state) {
158
+ case YDEC_STATE_CRLFEQ: do_decode_endable_scalar_ceq:
159
+ if(es[i] == 'y') {
160
+ *state = YDEC_STATE_NONE;
161
+ *src = es+i+1;
162
+ *dest = p;
163
+ return YDEC_END_CONTROL;
164
+ } // Else fall-thru
165
+ case YDEC_STATE_EQ:
166
+ c = es[i];
167
+ *p++ = c - 42 - 64;
168
+ i++;
169
+ if(c != '\r') break;
170
+ YDEC_CHECK_END(YDEC_STATE_CR)
171
+ // fall-through
172
+ case YDEC_STATE_CR:
173
+ if(es[i] != '\n') break;
174
+ i++;
175
+ YDEC_CHECK_END(YDEC_STATE_CRLF)
176
+ // fall-through
177
+ case YDEC_STATE_CRLF: do_decode_endable_scalar_c0:
178
+ if(es[i] == '.' && isRaw) {
179
+ i++;
180
+ YDEC_CHECK_END(YDEC_STATE_CRLFDT)
181
+ // fall-through
182
+ } else if(es[i] == '=') {
183
+ i++;
184
+ YDEC_CHECK_END(YDEC_STATE_CRLFEQ)
185
+ goto do_decode_endable_scalar_ceq;
186
+ } else
187
+ break;
188
+ case YDEC_STATE_CRLFDT:
189
+ if(isRaw && es[i] == '\r') {
190
+ i++;
191
+ YDEC_CHECK_END(YDEC_STATE_CRLFDTCR)
192
+ // fall-through
193
+ } else if(isRaw && es[i] == '=') { // check for dot-stuffed ending: \r\n.=y
194
+ i++;
195
+ YDEC_CHECK_END(YDEC_STATE_CRLFEQ)
196
+ goto do_decode_endable_scalar_ceq;
197
+ } else
198
+ break;
199
+ case YDEC_STATE_CRLFDTCR:
200
+ if(es[i] == '\n') {
201
+ if(isRaw) {
202
+ *state = YDEC_STATE_CRLF;
203
+ *src = es + i + 1;
204
+ *dest = p;
205
+ return YDEC_END_ARTICLE;
206
+ } else {
207
+ i++;
208
+ YDEC_CHECK_END(YDEC_STATE_CRLF)
209
+ goto do_decode_endable_scalar_c0; // handle as CRLF
210
+ }
211
+ } else
212
+ break;
213
+ case YDEC_STATE_NONE: break; // silence compiler warning
214
+ } else // treat as YDEC_STATE_CRLF
215
+ goto do_decode_endable_scalar_c0;
216
+
217
+ for(; i < -2; i++) {
218
+ c = es[i];
219
+ switch(c) {
220
+ case '\r': if(es[i+1] == '\n') {
221
+ if(isRaw && es[i+2] == '.') {
222
+ // skip past \r\n. sequences
223
+ i += 3;
224
+ YDEC_CHECK_END(YDEC_STATE_CRLFDT)
225
+ // check for end
226
+ if(es[i] == '\r') {
227
+ i++;
228
+ YDEC_CHECK_END(YDEC_STATE_CRLFDTCR)
229
+ if(es[i] == '\n') {
230
+ *src = es + i + 1;
231
+ *dest = p;
232
+ *state = YDEC_STATE_CRLF;
233
+ return YDEC_END_ARTICLE;
234
+ } else i--;
235
+ } else if(es[i] == '=') {
236
+ i++;
237
+ YDEC_CHECK_END(YDEC_STATE_CRLFEQ)
238
+ if(es[i] == 'y') {
239
+ *src = es + i + 1;
240
+ *dest = p;
241
+ *state = YDEC_STATE_NONE;
242
+ return YDEC_END_CONTROL;
243
+ } else {
244
+ // escape char & continue
245
+ c = es[i];
246
+ *p++ = c - 42 - 64;
247
+ i -= (c == '\r');
248
+ }
249
+ } else i--;
250
+ }
251
+ else if(es[i+2] == '=') {
252
+ i += 3;
253
+ YDEC_CHECK_END(YDEC_STATE_CRLFEQ)
254
+ if(es[i] == 'y') {
255
+ // ended
256
+ *src = es + i + 1;
257
+ *dest = p;
258
+ *state = YDEC_STATE_NONE;
259
+ return YDEC_END_CONTROL;
260
+ } else {
261
+ // escape char & continue
262
+ c = es[i];
263
+ *p++ = c - 42 - 64;
264
+ i -= (c == '\r');
265
+ }
266
+ }
267
+ } // fall-thru
268
+ case '\n':
269
+ continue;
270
+ case '=':
271
+ c = es[i+1];
272
+ *p++ = c - 42 - 64;
273
+ i += (c != '\r'); // if we have a \r, reprocess character to deal with \r\n. case
274
+ continue;
275
+ default:
276
+ *p++ = c - 42;
277
+ }
278
+ }
279
+ if(state) *state = YDEC_STATE_NONE;
280
+
281
+ if(i == -2) { // 2nd last char
282
+ c = es[i];
283
+ switch(c) {
284
+ case '\r':
285
+ if(state && es[i+1] == '\n') {
286
+ *state = YDEC_STATE_CRLF;
287
+ *src = es;
288
+ *dest = p;
289
+ return YDEC_END_NONE;
290
+ }
291
+ // Else fall-thru
292
+ case '\n':
293
+ break;
294
+ case '=':
295
+ c = es[i+1];
296
+ *p++ = c - 42 - 64;
297
+ i += (c != '\r');
298
+ break;
299
+ default:
300
+ *p++ = c - 42;
301
+ }
302
+ i++;
303
+ }
304
+
305
+ // do final char; we process this separately to prevent an overflow if the final char is '='
306
+ if(i == -1) {
307
+ c = es[i];
308
+ if(c != '\n' && c != '\r' && c != '=') {
309
+ *p++ = c - 42;
310
+ } else if(state) {
311
+ if(c == '=') *state = YDEC_STATE_EQ;
312
+ else if(c == '\r') *state = YDEC_STATE_CR;
313
+ else *state = YDEC_STATE_NONE;
314
+ }
315
+ }
316
+ #undef YDEC_CHECK_END
317
+
318
+ *src = es;
319
+ *dest = p;
320
+ return YDEC_END_NONE;
321
+ }
322
+
323
+ template<bool isRaw, bool searchEnd>
324
+ YencDecoderEnd do_decode_scalar(const unsigned char* HEDLEY_RESTRICT* src, unsigned char* HEDLEY_RESTRICT* dest, size_t len, YencDecoderState* state) {
325
+ if(searchEnd)
326
+ return do_decode_end_scalar<isRaw>(src, dest, len, state);
327
+ *dest += do_decode_noend_scalar<isRaw>(*src, *dest, len, state);
328
+ *src += len;
329
+ return YDEC_END_NONE;
330
+ }
331
+
332
+
333
+
334
+ template<bool isRaw, bool searchEnd, int width, void(&kernel)(const uint8_t* HEDLEY_RESTRICT, long&, unsigned char* HEDLEY_RESTRICT &, unsigned char&, uint16_t&)>
335
+ YencDecoderEnd do_decode_simd(const unsigned char* HEDLEY_RESTRICT* src, unsigned char* HEDLEY_RESTRICT* dest, size_t len, YencDecoderState* state) {
336
+ if(len <= width*2) return do_decode_scalar<isRaw, searchEnd>(src, dest, len, state);
337
+
338
+ YencDecoderState tState = YDEC_STATE_CRLF;
339
+ YencDecoderState* pState = state ? state : &tState;
340
+ if((uintptr_t)(*src) & ((width-1))) {
341
+ // find source memory alignment
342
+ unsigned char* aSrc = (unsigned char*)(((uintptr_t)(*src) + (width-1)) & ~(width-1));
343
+ int amount = (int)(aSrc - *src);
344
+ len -= amount;
345
+ YencDecoderEnd ended = do_decode_scalar<isRaw, searchEnd>(src, dest, amount, pState);
346
+ if(ended) return ended;
347
+ }
348
+
349
+ size_t lenBuffer = width -1;
350
+ if(searchEnd) lenBuffer += 3 + (isRaw?1:0);
351
+ else if(isRaw) lenBuffer += 2;
352
+
353
+ if(len > lenBuffer) {
354
+ unsigned char *p = *dest; // destination pointer
355
+ unsigned char escFirst = 0; // input character; first char needs escaping
356
+ uint16_t nextMask = 0;
357
+ // handle finicky case of special sequences straddled across initial boundary
358
+ switch(*pState) {
359
+ case YDEC_STATE_CRLF:
360
+ if(isRaw && **src == '.') {
361
+ nextMask = 1;
362
+ if(searchEnd && *(uint16_t*)(*src +1) == UINT16_PACK('\r','\n')) {
363
+ (*src) += 3;
364
+ *pState = YDEC_STATE_CRLF;
365
+ return YDEC_END_ARTICLE;
366
+ }
367
+ if(searchEnd && *(uint16_t*)(*src +1) == UINT16_PACK('=','y')) {
368
+ (*src) += 3;
369
+ *pState = YDEC_STATE_NONE;
370
+ return YDEC_END_CONTROL;
371
+ }
372
+ }
373
+ else if(searchEnd && *(uint16_t*)(*src) == UINT16_PACK('=','y')) {
374
+ (*src) += 2;
375
+ *pState = YDEC_STATE_NONE;
376
+ return YDEC_END_CONTROL;
377
+ }
378
+ break;
379
+ case YDEC_STATE_CR:
380
+ if(isRaw && *(uint16_t*)(*src) == UINT16_PACK('\n','.')) {
381
+ nextMask = 2;
382
+ if(searchEnd && *(uint16_t*)(*src +2) == UINT16_PACK('\r','\n')) {
383
+ (*src) += 4;
384
+ *pState = YDEC_STATE_CRLF;
385
+ return YDEC_END_ARTICLE;
386
+ }
387
+ if(searchEnd && *(uint16_t*)(*src +2) == UINT16_PACK('=','y')) {
388
+ (*src) += 4;
389
+ *pState = YDEC_STATE_NONE;
390
+ return YDEC_END_CONTROL;
391
+ }
392
+ }
393
+ else if(searchEnd && (*(uint32_t*)(*src) & 0xffffff) == UINT32_PACK('\n','=','y',0)) {
394
+ (*src) += 3;
395
+ *pState = YDEC_STATE_NONE;
396
+ return YDEC_END_CONTROL;
397
+ }
398
+ break;
399
+ case YDEC_STATE_CRLFDT:
400
+ if(searchEnd && isRaw && *(uint16_t*)(*src) == UINT16_PACK('\r','\n')) {
401
+ (*src) += 2;
402
+ *pState = YDEC_STATE_CRLF;
403
+ return YDEC_END_ARTICLE;
404
+ }
405
+ if(searchEnd && isRaw && *(uint16_t*)(*src) == UINT16_PACK('=','y')) {
406
+ (*src) += 2;
407
+ *pState = YDEC_STATE_NONE;
408
+ return YDEC_END_CONTROL;
409
+ }
410
+ break;
411
+ case YDEC_STATE_CRLFDTCR:
412
+ if(searchEnd && isRaw && **src == '\n') {
413
+ (*src) += 1;
414
+ *pState = YDEC_STATE_CRLF;
415
+ return YDEC_END_ARTICLE;
416
+ }
417
+ break;
418
+ case YDEC_STATE_CRLFEQ:
419
+ if(searchEnd && **src == 'y') {
420
+ (*src) += 1;
421
+ *pState = YDEC_STATE_NONE;
422
+ return YDEC_END_CONTROL;
423
+ }
424
+ break;
425
+ default: break; // silence compiler warning
426
+ }
427
+ escFirst = (*pState == YDEC_STATE_EQ || *pState == YDEC_STATE_CRLFEQ);
428
+
429
+ // our algorithm may perform an aligned load on the next part, of which we consider 2 bytes (for \r\n. sequence checking)
430
+ long dLen = (long)(len - lenBuffer);
431
+ dLen = (dLen + (width-1)) & ~(width-1);
432
+
433
+ kernel((const uint8_t*)(*src) + dLen, dLen, p, escFirst, nextMask);
434
+
435
+ if(escFirst) *pState = YDEC_STATE_EQ; // escape next character
436
+ else if(nextMask == 1) *pState = YDEC_STATE_CRLF; // next character is '.', where previous two were \r\n
437
+ else if(nextMask == 2) *pState = YDEC_STATE_CR; // next characters are '\n.', previous is \r
438
+ else *pState = YDEC_STATE_NONE;
439
+
440
+ *src += dLen;
441
+ len -= dLen;
442
+ *dest = p;
443
+ }
444
+
445
+ // end alignment
446
+ if(len)
447
+ return do_decode_scalar<isRaw, searchEnd>(src, dest, len, pState);
448
+ /** for debugging: ensure that the SIMD routine doesn't exit early
449
+ if(len && !searchEnd) {
450
+ const uint8_t* s = *src;
451
+ unsigned char* p = *dest;
452
+ int ended = do_decode_scalar<isRaw, searchEnd>(src, dest, len, pState);
453
+ if(*src - s > width*2) {
454
+ // this shouldn't happen, corrupt some data to fail the test
455
+ while(p < *dest)
456
+ *p++ = 0;
457
+ }
458
+ return ended;
459
+ }
460
+ */
461
+ return YDEC_END_NONE;
462
+ }
463
+
464
+ static inline void decoder_init_lut(uint8_t* eqFixLUT, void* compactLUT) {
465
+ for(int i=0; i<256; i++) {
466
+ int k = i;
467
+ int p = 0;
468
+
469
+ // fix LUT
470
+ k = i;
471
+ p = 0;
472
+ for(int j=0; j<8; j++) {
473
+ k = i >> j;
474
+ if(k & 1) {
475
+ p |= 1 << j;
476
+ j++;
477
+ }
478
+ }
479
+ eqFixLUT[i] = p;
480
+
481
+ #ifdef YENC_DEC_USE_THINTABLE
482
+ uint8_t* res = (uint8_t*)compactLUT + i*8;
483
+ k = i;
484
+ p = 0;
485
+ for(int j=0; j<8; j++) {
486
+ if(!(k & 1)) {
487
+ res[p++] = j;
488
+ }
489
+ k >>= 1;
490
+ }
491
+ for(; p<8; p++)
492
+ res[p] = 0x80;
493
+ #endif
494
+ }
495
+ #ifndef YENC_DEC_USE_THINTABLE
496
+ for(int i=0; i<32768; i++) {
497
+ int k = i;
498
+ uint8_t* res = (uint8_t*)compactLUT + i*16;
499
+ int p = 0;
500
+
501
+ for(int j=0; j<16; j++) {
502
+ if(!(k & 1)) {
503
+ res[p++] = j;
504
+ }
505
+ k >>= 1;
506
+ }
507
+ for(; p<16; p++)
508
+ res[p] = 0x80;
509
+ }
510
+ #endif
511
+ }
512
+