@thi.ng/rle-pack 3.1.117 → 3.2.0
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/README.md +60 -26
- package/binary.d.ts +17 -0
- package/binary.js +102 -0
- package/index.d.ts +2 -12
- package/index.js +2 -98
- package/package.json +14 -6
- package/simple.d.ts +33 -0
- package/simple.js +32 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://mastodon.thi.ng/@toxi)
|
|
8
8
|
|
|
9
9
|
> [!NOTE]
|
|
10
|
-
> This is one of
|
|
10
|
+
> This is one of 214 standalone projects, maintained as part
|
|
11
11
|
> of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo
|
|
12
12
|
> and anti-framework.
|
|
13
13
|
>
|
|
@@ -15,7 +15,10 @@
|
|
|
15
15
|
> GitHub](https://github.com/sponsors/postspectacular). Thank you! ❤️
|
|
16
16
|
|
|
17
17
|
- [About](#about)
|
|
18
|
-
- [
|
|
18
|
+
- [Simple RLE](#simple-rle)
|
|
19
|
+
- [Binary encoding](#binary-encoding)
|
|
20
|
+
- [Encoding format](#encoding-format)
|
|
21
|
+
- [Code example](#code-example)
|
|
19
22
|
- [Status](#status)
|
|
20
23
|
- [Related packages](#related-packages)
|
|
21
24
|
- [Installation](#installation)
|
|
@@ -26,6 +29,31 @@
|
|
|
26
29
|
|
|
27
30
|
## About
|
|
28
31
|
|
|
32
|
+
The package provides two approaches for [Run-length
|
|
33
|
+
encoding/decoding](https://en.wikipedia.org/wiki/Run-length_encoding):
|
|
34
|
+
|
|
35
|
+
### Simple RLE
|
|
36
|
+
|
|
37
|
+
The naive approach operates on arrays of arbitrary values and supports
|
|
38
|
+
user-defined predicates to determine if a consecutive input values are equal
|
|
39
|
+
(i.e. repeated). By default uses `===` strict comparison.
|
|
40
|
+
|
|
41
|
+
```ts tangle:export/readme-simple.ts
|
|
42
|
+
import { encodeSimple, decodeSimple } from "@thi.ng/rle-pack";
|
|
43
|
+
|
|
44
|
+
const src = [..."aaaaaabbbbaaaxyxxx"];
|
|
45
|
+
|
|
46
|
+
const encoded = encodeSimple(src);
|
|
47
|
+
console.log(encoded);
|
|
48
|
+
// ["a", 6, "b", 4, "a", 3, "x", 1, "y", 1, "x", 3]
|
|
49
|
+
|
|
50
|
+
const decoded = decodeSimple(encoded);
|
|
51
|
+
console.log(decoded);
|
|
52
|
+
// ["a", "a", "a", "a", "a", "a", "b", "b", "b", "b", "a", "a", "a", "x", "y", "x", "x", "x"]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Binary encoding
|
|
56
|
+
|
|
29
57
|
Binary [run-length
|
|
30
58
|
encoding](https://en.wikipedia.org/wiki/Run-length_encoding)
|
|
31
59
|
packer/unpacker with support for customizable input word sizes (1 - 32
|
|
@@ -36,7 +64,7 @@ lengths is 16 bits (i.e. 65536 repetitions). If a value is repeated more
|
|
|
36
64
|
often than that, the remainder will be encoded using additional RLE
|
|
37
65
|
chunks...
|
|
38
66
|
|
|
39
|
-
|
|
67
|
+
#### Encoding format
|
|
40
68
|
|
|
41
69
|

|
|
42
70
|
|
|
@@ -54,6 +82,31 @@ Then per value:
|
|
|
54
82
|
then split into chunks...)
|
|
55
83
|
- n bits - value(s)
|
|
56
84
|
|
|
85
|
+
#### Code example
|
|
86
|
+
|
|
87
|
+
```ts tangle:export/readme-binary.ts
|
|
88
|
+
import { encodeBinary, decodeBinary } from "@thi.ng/rle-pack";
|
|
89
|
+
|
|
90
|
+
// prepare dummy data
|
|
91
|
+
const src = new Uint8Array(1024);
|
|
92
|
+
src.set([1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,4,4,3,3,3,2,2,2,2,1,1,1,1,1], 512);
|
|
93
|
+
|
|
94
|
+
// pack data
|
|
95
|
+
const packed = encodeBinary(src, src.length);
|
|
96
|
+
console.log(packed.length);
|
|
97
|
+
// 30 => 2.93% of original
|
|
98
|
+
|
|
99
|
+
// pack with custom word size (3 bits, i.e. our value range is only 0-7)
|
|
100
|
+
// and use custom repeat group sizes suitable for our data
|
|
101
|
+
const alt = encodeBinary(src, src.length, 3, [1, 2, 3, 9]);
|
|
102
|
+
console.log(alt.length);
|
|
103
|
+
// 20 => 1.95% of original, 66% of default config
|
|
104
|
+
|
|
105
|
+
// unpack
|
|
106
|
+
const unpacked = decodeBinary(alt);
|
|
107
|
+
console.log(unpacked.length);
|
|
108
|
+
```
|
|
109
|
+
|
|
57
110
|
## Status
|
|
58
111
|
|
|
59
112
|
**STABLE** - used in production
|
|
@@ -92,39 +145,20 @@ For Node.js REPL:
|
|
|
92
145
|
const rle = await import("@thi.ng/rle-pack");
|
|
93
146
|
```
|
|
94
147
|
|
|
95
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
148
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 802 bytes
|
|
96
149
|
|
|
97
150
|
## Dependencies
|
|
98
151
|
|
|
152
|
+
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
|
|
99
153
|
- [@thi.ng/bitstream](https://github.com/thi-ng/umbrella/tree/develop/packages/bitstream)
|
|
100
154
|
- [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/develop/packages/errors)
|
|
101
155
|
|
|
156
|
+
Note: @thi.ng/api is in _most_ cases a type-only import (not used at runtime)
|
|
157
|
+
|
|
102
158
|
## API
|
|
103
159
|
|
|
104
160
|
[Generated API docs](https://docs.thi.ng/umbrella/rle-pack/)
|
|
105
161
|
|
|
106
|
-
```ts
|
|
107
|
-
import { encode, decode } from "@thi.ng/rle-pack";
|
|
108
|
-
|
|
109
|
-
// prepare dummy data
|
|
110
|
-
src = new Uint8Array(1024);
|
|
111
|
-
src.set([1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,4,4,3,3,3,2,2,2,2,1,1,1,1,1], 512);
|
|
112
|
-
|
|
113
|
-
// pack data
|
|
114
|
-
packed = encode(src, src.length);
|
|
115
|
-
packed.length
|
|
116
|
-
// 30 => 2.93% of original
|
|
117
|
-
|
|
118
|
-
// pack with custom word size (3 bits, i.e. our value range is only 0-7)
|
|
119
|
-
// and use custom repeat group sizes suitable for our data
|
|
120
|
-
alt = encode(src, src.length, 3, [1, 2, 3, 9]);
|
|
121
|
-
alt.length
|
|
122
|
-
// 20 => 1.95% of original, 66% of default config
|
|
123
|
-
|
|
124
|
-
// unpack
|
|
125
|
-
unpacked = new Uint8Array(decode(alt));
|
|
126
|
-
```
|
|
127
|
-
|
|
128
162
|
## Authors
|
|
129
163
|
|
|
130
164
|
- [Karsten Schmidt](https://thi.ng)
|
package/binary.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type RLESizes = [number, number, number, number];
|
|
2
|
+
/**
|
|
3
|
+
* Compresses input using dynamically sized RLE compression and returns
|
|
4
|
+
* result as `Uint8Array`.
|
|
5
|
+
*
|
|
6
|
+
* @param src -
|
|
7
|
+
* @param num - number of input words
|
|
8
|
+
* @param wordSize - in bits, range 1 - 32
|
|
9
|
+
* @param rleSizes - run-length group sizes (in bits, max. 16)
|
|
10
|
+
*/
|
|
11
|
+
export declare const encodeBinary: (src: Iterable<number>, num: number, wordSize?: number, rleSizes?: RLESizes) => Uint8Array<ArrayBuffer>;
|
|
12
|
+
export declare const decodeBinary: (src: Uint8Array) => Uint8Array<ArrayBuffer> | Uint16Array<ArrayBuffer> | Uint32Array<ArrayBuffer>;
|
|
13
|
+
/** @deprecated renamed to {@link encodeBinary} */
|
|
14
|
+
export declare const encode: (src: Iterable<number>, num: number, wordSize?: number, rleSizes?: RLESizes) => Uint8Array<ArrayBuffer>;
|
|
15
|
+
/** @deprecated renamed to {@link decodeBinary} */
|
|
16
|
+
export declare const decode: (src: Uint8Array) => Uint8Array<ArrayBuffer> | Uint16Array<ArrayBuffer> | Uint32Array<ArrayBuffer>;
|
|
17
|
+
//# sourceMappingURL=binary.d.ts.map
|
package/binary.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { BitInputStream } from "@thi.ng/bitstream/input";
|
|
2
|
+
import { BitOutputStream } from "@thi.ng/bitstream/output";
|
|
3
|
+
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
|
|
4
|
+
const encodeBinary = (src, num, wordSize = 8, rleSizes = [3, 4, 8, 16]) => {
|
|
5
|
+
(wordSize < 1 || wordSize > 32) && illegalArgs("word size (1-32 bits only)");
|
|
6
|
+
const out = new BitOutputStream(Math.ceil(num * wordSize / 8) + 4 + 2 + 1).write(num, 32).write(wordSize - 1, 5);
|
|
7
|
+
rleSizes.forEach((x) => {
|
|
8
|
+
(x < 1 || x > 16) && illegalArgs("RLE repeat size (1-16 bits only)");
|
|
9
|
+
out.write(x - 1, 4);
|
|
10
|
+
});
|
|
11
|
+
const [rle0, rle1, rle2, rle3] = rleSizes.map((x) => 1 << x);
|
|
12
|
+
const chunk = [];
|
|
13
|
+
const n1 = num - 1;
|
|
14
|
+
let val;
|
|
15
|
+
let tail = true;
|
|
16
|
+
let n = 0;
|
|
17
|
+
let i = 0;
|
|
18
|
+
const writeRLE = () => {
|
|
19
|
+
const t = n < rle0 ? 0 : n < rle1 ? 1 : n < rle2 ? 2 : 3;
|
|
20
|
+
out.writeBit(1);
|
|
21
|
+
out.write(t, 2);
|
|
22
|
+
out.write(n, rleSizes[t]);
|
|
23
|
+
out.write(val, wordSize);
|
|
24
|
+
n = 0;
|
|
25
|
+
};
|
|
26
|
+
const writeChunk = () => {
|
|
27
|
+
const m = chunk.length - 1;
|
|
28
|
+
const t = m < rle0 ? 0 : m < rle1 ? 1 : m < rle2 ? 2 : 3;
|
|
29
|
+
out.writeBit(0);
|
|
30
|
+
out.write(t, 2);
|
|
31
|
+
out.write(m, rleSizes[t]);
|
|
32
|
+
out.writeWords(chunk, wordSize);
|
|
33
|
+
chunk.length = 0;
|
|
34
|
+
};
|
|
35
|
+
for (const x of src) {
|
|
36
|
+
if (val === void 0) {
|
|
37
|
+
val = x;
|
|
38
|
+
} else if (x !== val) {
|
|
39
|
+
if (n > 0) {
|
|
40
|
+
writeRLE();
|
|
41
|
+
} else {
|
|
42
|
+
chunk.push(val);
|
|
43
|
+
if (chunk.length === rle3) {
|
|
44
|
+
writeChunk();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
val = x;
|
|
48
|
+
} else {
|
|
49
|
+
if (chunk.length) {
|
|
50
|
+
writeChunk();
|
|
51
|
+
}
|
|
52
|
+
if (++n === rle3) {
|
|
53
|
+
n--;
|
|
54
|
+
writeRLE();
|
|
55
|
+
tail = i < n1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (i === n1) {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
i++;
|
|
62
|
+
}
|
|
63
|
+
if (chunk.length) {
|
|
64
|
+
chunk.push(val);
|
|
65
|
+
writeChunk();
|
|
66
|
+
} else if (tail) {
|
|
67
|
+
writeRLE();
|
|
68
|
+
}
|
|
69
|
+
return out.bytes();
|
|
70
|
+
};
|
|
71
|
+
const decodeBinary = (src) => {
|
|
72
|
+
const input = new BitInputStream(src);
|
|
73
|
+
const num = input.read(32);
|
|
74
|
+
const wordSize = input.read(5) + 1;
|
|
75
|
+
const rleSizes = [0, 0, 0, 0].map(() => input.read(4) + 1);
|
|
76
|
+
const out = __arrayForWordSize(wordSize, num);
|
|
77
|
+
let x, j;
|
|
78
|
+
for (let i = 0; i < num; ) {
|
|
79
|
+
x = input.readBit();
|
|
80
|
+
j = i + 1 + input.read(rleSizes[input.read(2)]);
|
|
81
|
+
if (x) {
|
|
82
|
+
out.fill(input.read(wordSize), i, j);
|
|
83
|
+
i = j;
|
|
84
|
+
} else {
|
|
85
|
+
for (; i < j; i++) {
|
|
86
|
+
out[i] = input.read(wordSize);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
};
|
|
92
|
+
const __arrayForWordSize = (ws, n) => {
|
|
93
|
+
return new (ws < 9 ? Uint8Array : ws < 17 ? Uint16Array : Uint32Array)(n);
|
|
94
|
+
};
|
|
95
|
+
const encode = encodeBinary;
|
|
96
|
+
const decode = decodeBinary;
|
|
97
|
+
export {
|
|
98
|
+
decode,
|
|
99
|
+
decodeBinary,
|
|
100
|
+
encode,
|
|
101
|
+
encodeBinary
|
|
102
|
+
};
|
package/index.d.ts
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
* Compresses input using dynamically sized RLE compression and returns
|
|
4
|
-
* result as `Uint8Array`.
|
|
5
|
-
*
|
|
6
|
-
* @param src -
|
|
7
|
-
* @param num - number of input words
|
|
8
|
-
* @param wordSize - in bits, range 1 - 32
|
|
9
|
-
* @param rleSizes - run-length group sizes (in bits, max. 16)
|
|
10
|
-
*/
|
|
11
|
-
export declare const encode: (src: Iterable<number>, num: number, wordSize?: number, rleSizes?: RLESizes) => Uint8Array<ArrayBuffer>;
|
|
12
|
-
export declare const decode: (src: Uint8Array) => Uint8Array<ArrayBuffer> | Uint16Array<ArrayBuffer> | Uint32Array<ArrayBuffer>;
|
|
1
|
+
export * from "./binary.js";
|
|
2
|
+
export * from "./simple.js";
|
|
13
3
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,98 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
|
|
4
|
-
const encode = (src, num, wordSize = 8, rleSizes = [3, 4, 8, 16]) => {
|
|
5
|
-
(wordSize < 1 || wordSize > 32) && illegalArgs("word size (1-32 bits only)");
|
|
6
|
-
const out = new BitOutputStream(Math.ceil(num * wordSize / 8) + 4 + 2 + 1).write(num, 32).write(wordSize - 1, 5);
|
|
7
|
-
rleSizes.forEach((x) => {
|
|
8
|
-
(x < 1 || x > 16) && illegalArgs("RLE repeat size (1-16 bits only)");
|
|
9
|
-
out.write(x - 1, 4);
|
|
10
|
-
});
|
|
11
|
-
const [rle0, rle1, rle2, rle3] = rleSizes.map((x) => 1 << x);
|
|
12
|
-
const chunk = [];
|
|
13
|
-
const n1 = num - 1;
|
|
14
|
-
let val;
|
|
15
|
-
let tail = true;
|
|
16
|
-
let n = 0;
|
|
17
|
-
let i = 0;
|
|
18
|
-
const writeRLE = () => {
|
|
19
|
-
const t = n < rle0 ? 0 : n < rle1 ? 1 : n < rle2 ? 2 : 3;
|
|
20
|
-
out.writeBit(1);
|
|
21
|
-
out.write(t, 2);
|
|
22
|
-
out.write(n, rleSizes[t]);
|
|
23
|
-
out.write(val, wordSize);
|
|
24
|
-
n = 0;
|
|
25
|
-
};
|
|
26
|
-
const writeChunk = () => {
|
|
27
|
-
const m = chunk.length - 1;
|
|
28
|
-
const t = m < rle0 ? 0 : m < rle1 ? 1 : m < rle2 ? 2 : 3;
|
|
29
|
-
out.writeBit(0);
|
|
30
|
-
out.write(t, 2);
|
|
31
|
-
out.write(m, rleSizes[t]);
|
|
32
|
-
out.writeWords(chunk, wordSize);
|
|
33
|
-
chunk.length = 0;
|
|
34
|
-
};
|
|
35
|
-
for (const x of src) {
|
|
36
|
-
if (val === void 0) {
|
|
37
|
-
val = x;
|
|
38
|
-
} else if (x !== val) {
|
|
39
|
-
if (n > 0) {
|
|
40
|
-
writeRLE();
|
|
41
|
-
} else {
|
|
42
|
-
chunk.push(val);
|
|
43
|
-
if (chunk.length === rle3) {
|
|
44
|
-
writeChunk();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
val = x;
|
|
48
|
-
} else {
|
|
49
|
-
if (chunk.length) {
|
|
50
|
-
writeChunk();
|
|
51
|
-
}
|
|
52
|
-
if (++n === rle3) {
|
|
53
|
-
n--;
|
|
54
|
-
writeRLE();
|
|
55
|
-
tail = i < n1;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (i === n1) {
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
i++;
|
|
62
|
-
}
|
|
63
|
-
if (chunk.length) {
|
|
64
|
-
chunk.push(val);
|
|
65
|
-
writeChunk();
|
|
66
|
-
} else if (tail) {
|
|
67
|
-
writeRLE();
|
|
68
|
-
}
|
|
69
|
-
return out.bytes();
|
|
70
|
-
};
|
|
71
|
-
const decode = (src) => {
|
|
72
|
-
const input = new BitInputStream(src);
|
|
73
|
-
const num = input.read(32);
|
|
74
|
-
const wordSize = input.read(5) + 1;
|
|
75
|
-
const rleSizes = [0, 0, 0, 0].map(() => input.read(4) + 1);
|
|
76
|
-
const out = __arrayForWordSize(wordSize, num);
|
|
77
|
-
let x, j;
|
|
78
|
-
for (let i = 0; i < num; ) {
|
|
79
|
-
x = input.readBit();
|
|
80
|
-
j = i + 1 + input.read(rleSizes[input.read(2)]);
|
|
81
|
-
if (x) {
|
|
82
|
-
out.fill(input.read(wordSize), i, j);
|
|
83
|
-
i = j;
|
|
84
|
-
} else {
|
|
85
|
-
for (; i < j; i++) {
|
|
86
|
-
out[i] = input.read(wordSize);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return out;
|
|
91
|
-
};
|
|
92
|
-
const __arrayForWordSize = (ws, n) => {
|
|
93
|
-
return new (ws < 9 ? Uint8Array : ws < 17 ? Uint16Array : Uint32Array)(n);
|
|
94
|
-
};
|
|
95
|
-
export {
|
|
96
|
-
decode,
|
|
97
|
-
encode
|
|
98
|
-
};
|
|
1
|
+
export * from "./binary.js";
|
|
2
|
+
export * from "./simple.js";
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/rle-pack",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Binary run-length encoding packer w/ flexible repeat bit widths",
|
|
3
|
+
"version": "3.2.0",
|
|
4
|
+
"description": "Binary run-length encoding packer w/ flexible repeat bit widths and a naive RLE encoder/decoder for arrays of arbitrary typed values",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
7
7
|
"typings": "./index.d.ts",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/thi-ng/umbrella.git"
|
|
11
|
+
"url": "git+https://github.com/thi-ng/umbrella.git",
|
|
12
|
+
"directory": "packages/rle-pack"
|
|
12
13
|
},
|
|
13
14
|
"homepage": "https://thi.ng/rle-pack",
|
|
14
15
|
"funding": [
|
|
@@ -39,8 +40,9 @@
|
|
|
39
40
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
42
|
-
"@thi.ng/
|
|
43
|
-
"@thi.ng/
|
|
43
|
+
"@thi.ng/api": "^8.12.14",
|
|
44
|
+
"@thi.ng/bitstream": "^2.4.41",
|
|
45
|
+
"@thi.ng/errors": "^2.6.3"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
48
|
"esbuild": "^0.27.2",
|
|
@@ -69,6 +71,12 @@
|
|
|
69
71
|
"exports": {
|
|
70
72
|
".": {
|
|
71
73
|
"default": "./index.js"
|
|
74
|
+
},
|
|
75
|
+
"./binary": {
|
|
76
|
+
"default": "./binary.js"
|
|
77
|
+
},
|
|
78
|
+
"./simple": {
|
|
79
|
+
"default": "./simple.js"
|
|
72
80
|
}
|
|
73
81
|
},
|
|
74
82
|
"thi.ng": {
|
|
@@ -80,5 +88,5 @@
|
|
|
80
88
|
],
|
|
81
89
|
"year": 2017
|
|
82
90
|
},
|
|
83
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "b90a2f41eb0b3c89391bbb7cfff940192f23a83c\n"
|
|
84
92
|
}
|
package/simple.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Predicate2 } from "@thi.ng/api";
|
|
2
|
+
/**
|
|
3
|
+
* Performs basic RLE encoding on the given `src` array(like) input, using the
|
|
4
|
+
* optional `equiv` predicate to determine if the current value is a repetition
|
|
5
|
+
* of an earlier one (i.e consecutive values are considered repetitions as long
|
|
6
|
+
* as that predicate returns true). The default predicate is using `===` for
|
|
7
|
+
* comparison. Returns RLE result array of `[value1, count1, value2, count2...]`
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts tangle:../export/encode-simple.ts
|
|
11
|
+
* import { encodeSimple } from "@thi.ng/rle-pack";
|
|
12
|
+
*
|
|
13
|
+
* const src = [..."aaaaaabbbbaaaxyxxx"];
|
|
14
|
+
*
|
|
15
|
+
* console.log(src);
|
|
16
|
+
* // ["a", "a", "a", "a", "a", "a", "b", "b", "b", "b", "a", "a", "a", "x", "y", "x", "x", "x"]
|
|
17
|
+
*
|
|
18
|
+
* console.log(encodeSimple(src));
|
|
19
|
+
* // ["a", 6, "b", 4, "a", 3, "x", 1, "y", 1, "x", 3]
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @param src
|
|
23
|
+
* @param equiv
|
|
24
|
+
*/
|
|
25
|
+
export declare const encodeSimple: <T = any>(src: ArrayLike<T>, equiv?: Predicate2<T>) => any[];
|
|
26
|
+
/**
|
|
27
|
+
* Reverse op of {@link encodeSimple}. Takes an RLE array and returns restored
|
|
28
|
+
* original version. Throws an error if `src.length` is not even.
|
|
29
|
+
*
|
|
30
|
+
* @param src
|
|
31
|
+
*/
|
|
32
|
+
export declare const decodeSimple: (src: any[]) => any[];
|
|
33
|
+
//# sourceMappingURL=simple.d.ts.map
|
package/simple.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
|
|
2
|
+
const encodeSimple = (src, equiv = (a, b) => a === b) => {
|
|
3
|
+
const result = [];
|
|
4
|
+
const n = src.length;
|
|
5
|
+
if (!n) return result;
|
|
6
|
+
let val = src[0];
|
|
7
|
+
let start = 0;
|
|
8
|
+
for (let i = 1; i < n; i++) {
|
|
9
|
+
if (!equiv(src[i], val)) {
|
|
10
|
+
result.push(val, i - start);
|
|
11
|
+
val = src[i];
|
|
12
|
+
start = i;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
result.push(val, n - start);
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
18
|
+
const decodeSimple = (src) => {
|
|
19
|
+
const n = src.length;
|
|
20
|
+
if (n & 1) illegalArgs(`input length must be even`);
|
|
21
|
+
const result = [];
|
|
22
|
+
for (let i = 0; i < n; i += 2) {
|
|
23
|
+
const val = src[i];
|
|
24
|
+
const count = src[i + 1];
|
|
25
|
+
for (let j = 0; j < count; j++) result.push(val);
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
export {
|
|
30
|
+
decodeSimple,
|
|
31
|
+
encodeSimple
|
|
32
|
+
};
|