All files / cli / _run_length.ts

100.00% Branches 8/8
100.00% Lines 32/32
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
 
 
x4
x9
x9
 
x9
 
x9
x278
x536
x278
x289
x289
x289
x289
x278
 
x9
x20
x21
x21
x20
 
x13
x13
x13
x13
x9
 
x4
x17
x17
x17
 
x51
x4538
x4538
 
x87
x17







































// Copyright 2018-2025 the Deno authors. MIT license.

export function runLengthEncode(arr: number[]) {
  const data: number[] = [];
  const runLengths: number[] = [];

  let prev: symbol | number = Symbol("none");

  for (const x of arr) {
    if (x === prev) {
      ++runLengths[runLengths.length - 1]!;
    } else {
      prev = x;
      data.push(x);
      runLengths.push(1);
    }
  }

  for (const r of runLengths) {
    if (r >= 0x100) {
      throw new Error(`Run length too long: ${r}`);
    }
  }

  return {
    d: btoa(String.fromCharCode(...data)),
    r: btoa(String.fromCharCode(...runLengths)),
  };
}

export function runLengthDecode({ d, r }: { d: string; r: string }) {
  const data = atob(d);
  const runLengths = atob(r);
  let out = "";

  for (const [i, ch] of [...runLengths].entries()) {
    out += data[i]!.repeat(ch.codePointAt(0)!);
  }

  return Uint8Array.from([...out].map((x) => x.codePointAt(0)!));
}