@thi.ng/leb128 3.0.5 → 3.0.6

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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-01-10T15:20:19Z
3
+ - **Last updated**: 2023-02-05T14:42:21Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/leb128",
3
- "version": "3.0.5",
3
+ "version": "3.0.6",
4
4
  "description": "WASM based LEB128 encoder / decoder (signed & unsigned)",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -35,17 +35,17 @@
35
35
  "test": "testament test"
36
36
  },
37
37
  "dependencies": {
38
- "@thi.ng/checks": "^3.3.7",
39
- "@thi.ng/errors": "^2.2.8",
40
- "@thi.ng/transducers-binary": "^2.1.35"
38
+ "@thi.ng/checks": "^3.3.8",
39
+ "@thi.ng/errors": "^2.2.9",
40
+ "@thi.ng/transducers-binary": "^2.1.36"
41
41
  },
42
42
  "devDependencies": {
43
- "@microsoft/api-extractor": "^7.33.7",
44
- "@thi.ng/testament": "^0.3.9",
45
- "rimraf": "^3.0.2",
43
+ "@microsoft/api-extractor": "^7.34.2",
44
+ "@thi.ng/testament": "^0.3.10",
45
+ "rimraf": "^4.1.2",
46
46
  "tools": "^0.0.1",
47
- "typedoc": "^0.23.22",
48
- "typescript": "^4.9.4"
47
+ "typedoc": "^0.23.24",
48
+ "typescript": "^4.9.5"
49
49
  },
50
50
  "keywords": [
51
51
  "64bit",
@@ -69,7 +69,8 @@
69
69
  },
70
70
  "files": [
71
71
  "./*.js",
72
- "./*.d.ts"
72
+ "./*.d.ts",
73
+ "zig"
73
74
  ],
74
75
  "exports": {
75
76
  ".": {
@@ -79,5 +80,5 @@
79
80
  "thi.ng": {
80
81
  "year": 2019
81
82
  },
82
- "gitHead": "3f0b3e2a7c82aefc7e46fb4338369836b5e1b8cf\n"
83
+ "gitHead": "50ba9c87676fac60c46d2bc0e4d2c7711a374a68\n"
83
84
  }
package/zig/leb128.zig ADDED
@@ -0,0 +1,132 @@
1
+ export var buf: [10]u8 = undefined;
2
+
3
+ /// Encodes 64bit uint `src` and writes result bytes into `dest` (must
4
+ /// have at least 10 bytes capacity)
5
+ pub fn leb128EncodeU(src: u64, dest: []u8) u8 {
6
+ if (src < 0x80) {
7
+ dest[0] = @intCast(u8, src & 0x7f);
8
+ return 1;
9
+ }
10
+ var n: u8 = 0;
11
+ var x: u64 = src;
12
+ while (true) {
13
+ var byte: u8 = @intCast(u8, x & 0x7f);
14
+ x = x >> 7;
15
+ if (x != 0) {
16
+ byte |= 0x80;
17
+ }
18
+ dest[n] = byte;
19
+ n += 1;
20
+ if (x == 0) break;
21
+ }
22
+ return n;
23
+ }
24
+
25
+ /// Decodes LEB128 bytes in `src` as u64 and writes number of bytes
26
+ /// consumed into `num`.
27
+ pub fn leb128DecodeU(src: []u8, num: *u8) u64 {
28
+ var res: u64 = 0;
29
+ var shift: u6 = 0;
30
+ var n: u8 = 0;
31
+ while (n < 10) {
32
+ var byte = src[n];
33
+ res |= @intCast(u64, byte & 0x7f) << shift;
34
+ shift += 7;
35
+ n += 1;
36
+ if (byte < 0x80) {
37
+ break;
38
+ }
39
+ }
40
+ num.* = n;
41
+ return res;
42
+ }
43
+
44
+ /// Like `leb128EncodeU` but for signed integers
45
+ pub fn leb128EncodeI(src: i64, dest: []u8) u8 {
46
+ const neg: bool = src < 0;
47
+ if (src >= -64 and src < 64) {
48
+ dest[0] = @intCast(u8, src & 0x3f) |
49
+ @intCast(u8, @boolToInt(neg)) << 6;
50
+ return 1;
51
+ }
52
+ var n: u8 = 0;
53
+ var x: i64 = src;
54
+ var more: bool = true;
55
+ while (more) {
56
+ var byte: u8 = @intCast(u8, x & 0x7f);
57
+ var sign: bool = (byte & 0x40) > 0;
58
+ x >>= 7;
59
+ if ((x == 0 and !sign) or (x == -1 and sign)) {
60
+ more = false;
61
+ } else {
62
+ byte |= 0x80;
63
+ }
64
+ dest[n] = byte;
65
+ n += 1;
66
+ }
67
+ return n;
68
+ }
69
+
70
+ /// Like `leb128DecodeU` but for signed integers
71
+ pub fn leb128DecodeI(src: []u8, num: *u8) i64 {
72
+ var res: i64 = 0;
73
+ var shift: u6 = 0;
74
+ var n: u8 = 0;
75
+ var byte: u8 = 0;
76
+ while (true) {
77
+ byte = src[n];
78
+ res |= @intCast(i64, byte & 0x7f) << shift;
79
+ shift += 7;
80
+ n += 1;
81
+ if ((byte & 0x80) == 0 or n > 9) {
82
+ break;
83
+ }
84
+ }
85
+ if (n < 10 and (byte & 0x40) > 0) {
86
+ res |= @intCast(i64, -1) << shift;
87
+ }
88
+ num.* = n;
89
+ return res;
90
+ }
91
+
92
+ /// WASM only. JS interop to exchange data via f64 (for lack of i64/u64
93
+ /// on JS side). Writes results to exported `buf` array and returns
94
+ /// number of bytes used.
95
+ export fn leb128EncodeU64(x: u64) u8 {
96
+ return leb128EncodeU(x, buf[0..]);
97
+ }
98
+
99
+ /// WASM only. JS interop to exchange data via f64 (for lack of i64/u64
100
+ /// on JS side). Consumes bytes from the exported `buf` array and returns
101
+ /// decoded value. Writes number of bytes consumed into `buf[0]`
102
+ export fn leb128DecodeU64() u64 {
103
+ return leb128DecodeU(buf[0..], &buf[0]);
104
+ }
105
+
106
+ /// See `leb128_encode_u_js`
107
+ export fn leb128EncodeI64(x: i64) u8 {
108
+ return leb128EncodeI(x, buf[0..]);
109
+ }
110
+
111
+ /// See `leb128_decode_u_js`
112
+ export fn leb128DecodeI64() i64 {
113
+ return leb128DecodeI(buf[0..], &buf[0]);
114
+ }
115
+
116
+ const std = @import("std");
117
+ const warn = std.debug.warn;
118
+ const assert = std.debug.assert;
119
+ const mem = std.mem;
120
+
121
+ test "min safe integer" {
122
+ assert(leb128EncodeI(-9007199254740991, buf[0..]) == 8);
123
+ assert(mem.eql(u8, buf[0..8], &[_]u8{ 129, 128, 128, 128, 128, 128, 128, 112 }));
124
+ }
125
+
126
+ test "max safe integer" {
127
+ assert(leb128EncodeI(9007199254740991, buf[0..]) == 8);
128
+ assert(mem.eql(u8, buf[0..8], &[_]u8{ 255, 255, 255, 255, 255, 255, 255, 15 }));
129
+
130
+ assert(leb128EncodeU(9007199254740991, buf[0..]) == 8);
131
+ assert(mem.eql(u8, buf[0..8], &[_]u8{ 255, 255, 255, 255, 255, 255, 255, 15 }));
132
+ }