/wasmbase64

Primary LanguageCOtherNOASSERTION

Webassembly base64 encoder/decoder for Javascript

How to use

Currently only exported as base64.mjs (see JS Modules).

Converts to/from ArrayBuffer.

Example:

<script type="module">
    import {Base64Decoder, Base64Encoder} from 'https://rawcdn.githack.com/NLeSC/wasmbase64/2e96082440cb78832465e8d6314c0a9ba0072897/dist/base64.mjs';
    
    // not really random.
    const randomBuffer = (size) => {
        const a = new Uint8Array(size);
        for (let i = 0; i< size; i++) {
            a[i] = i;
        }
        return a;
    };

    // init() (async) must be called first
    const encoder = new Base64Encoder();
    encoder.init().then(() => {
       const result_uint8 = encoder.encode(randomBuffer(1000));
       console.log(result_uint8);
    });
</script>

Memory

Note that memory is not immediately released after encoding/decoding. It should be released when the instance is garbage collected when it goes out of scope.

Build requirements

  • build-essential
  • clang-11
  • lldb
  • clangd-11
  • lld-11 wabt

Build:

make

Performance benchmark

There is an interesting story here. Native window.btoa and window.atob work on 'binary strings', which are quite annoying to work with.

Modern JS has ArrayBuffer to work with binary data, which is much nicer, but conversion to/from the binary string format is still very confusing. Try googling arraybuffer to binary string.

This library uses ArrayBuffer only (there is encodeString and decodeString) though.

To try a fair comparison we're comparing encoders/decoders that work with binary strings directly on binary strings - conversion to/from ArrayBuffer will have some overhead which is not included in the results.

Comparing:

Machine:

  • Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
  • Linux 5.3.0-3-amd64 #1 SMP Debian 5.3.15-1 (2019-12-07) x86_64 GNU/Linux

Results

  • Dict index is the size of the ArrayBuffer in bytes (10B, 10kB, 10MB).
  • Time is the total time in milliseconds of running each implementation 10 times.

Chrome/encode.

{
    "10": {
      "wasm": "0.2",
      "ab": "0.2",
      "native": "0.1",
      "jsbase64": "0.2"
    },
    "10000": {
      "wasm": "1.2",
      "ab": "18.4",
      "native": "0.3",
      "jsbase64": "13.1"
    },
    "10000000": {
      "wasm": "216.4",
      "ab": "17073.0",
      "native": "371.3",
      "jsbase64": "9826.1"
    }
}

Chrome/decode

{
    "10": {
      "wasm": "0.2",
      "ab": "0.2",
      "native": "0.1",
      "jsbase64": "0.2"
    },
    "10000": {
      "wasm": "0.2",
      "ab": "11.5",
      "native": "1.1",
      "jsbase64": "1.4"
    },
    "10000000": {
      "wasm": "213.1",
      "ab": "632.4",
      "native": "871.7",
      "jsbase64": "1355.6"
    }
}

Firefox/encode

{
    "10": {
      "wasm": "2.0",
      "ab": "0.0",
      "native": "0.0",
      "jsbase64": "0.0"
    },
    "10000": {
      "wasm": "0.0",
      "ab": "7.0",
      "native": "0.0",
      "jsbase64": "12.0"
    },
    "10000000": {
      "wasm": "218.0",
      "ab": "4632.0",
      "native": "585.0",
      "jsbase64": "6215.0"
    }
}
{
    "10": {
      "wasm": "1.0",
      "ab": "1.0",
      "native": "0.0",
      "jsbase64": "0.0"
    },
    "10000": {
      "wasm": "0.0",
      "ab": "3.0",
      "native": "0.0",
      "jsbase64": "2.0"
    },
    "10000000": {
      "wasm": "186.0",
      "ab": "640.0",
      "native": "949.0",
      "jsbase64": "1679.0"
    }
}

Note

Todo

  • input/error handling
  • add tests
  • publish to npm