Browse Source

Optimize performance; remove side effects

Arjun Barrett 4 years ago
parent
commit
fe2a3b1bcb
7 changed files with 40 additions and 35 deletions
  1. 12 11
      README.md
  2. 7 7
      docs/README.md
  3. 2 2
      docs/interfaces/deflateoptions.md
  4. 4 4
      docs/interfaces/gzipoptions.md
  5. 2 2
      docs/interfaces/zliboptions.md
  6. 6 2
      package.json
  7. 7 7
      src/index.ts

+ 12 - 11
README.md

@@ -2,16 +2,17 @@
 High performance (de)compression in an 8kB package
 High performance (de)compression in an 8kB package
 
 
 ## Why fflate?
 ## Why fflate?
-`fflate` (short for fast flate) is the **fastest, smallest, and most versatile** pure JavaScript compression and decompression library in existence, handily beating [`pako`](https://npmjs.com/package/pako), [`tiny-inflate`](https://npmjs.com/package/tiny-inflate), and [`UZIP.js`](https://github.com/photopea/UZIP.js) in performance benchmarks while being multiple times more lightweight. It includes support for DEFLATE, GZIP, and Zlib data. Data compressed by `fflate` can be decompressed by other tools, and vice versa.
-
-|                        | `pako` | `tiny-inflate`       | `UZIP.js`         | `fflate`                       |
-|------------------------|--------|----------------------|-------------------|--------------------------------|
-| Relative performance   | 1x     | up to 10x slower     | up to 40% faster  | **Up to 60% faster**           |
-| Bundle size (minified) | 44.5kB | **3 kB**             | 14.2kB            | 8kB **(3kB for only inflate)** |
-| Compression support    | ✅     | ❌                    | ✅                | ✅                             |
-| Thread/Worker safe     | ✅     | ✅                    | ❌                | ✅                             |
-| GZIP/Zlib support      | ✅     | ❌                    | ❌                | ✅                             |
-| Uses ES Modules        | ❌     | ❌                    | ❌                | ✅                             |
+`fflate` (short for fast flate) is the **fastest, smallest, and most versatile** pure JavaScript compression and decompression library in existence, handily beating [`pako`](https://npmjs.com/package/pako), [`tiny-inflate`](https://npmjs.com/package/tiny-inflate), and [`UZIP.js`](https://github.com/photopea/UZIP.js) in performance benchmarks while being multiple times more lightweight. Its compression ratios are often better than even the original Zlib C library. It includes support for DEFLATE, GZIP, and Zlib data. Data compressed by `fflate` can be decompressed by other tools, and vice versa.
+
+|                           | `pako` | `tiny-inflate`       | `UZIP.js`             | `fflate`                       |
+|---------------------------|--------|----------------------|-----------------------|--------------------------------|
+| Decompression performance | 1x     | up to 10x slower     | **up to 40% faster**  | **up to 40% faster**           |
+| Compression performance   | 1x     | N/A                  | up to 5% faster       | **up to 50% faster**           |
+| Bundle size (minified)    | 44.5kB | **3 kB**             | 14.2kB                | 8kB **(3kB for only inflate)** |
+| Compression support       | ✅     | ❌                    | ✅                    | ✅                             |
+| Thread/Worker safe        | ✅     | ✅                    | ❌                    | ✅                             |
+| GZIP/Zlib support         | ✅     | ❌                    | ❌                    | ✅                             |
+| Uses ES Modules           | ❌     | ❌                    | ❌                    | ✅                             |
 
 
 ## Usage
 ## Usage
 
 
@@ -105,7 +106,7 @@ Note that there exist some small libraries like [`tiny-inflate`](https://npmjs.c
 
 
 So what makes `fflate` different? It takes the brilliant innovations of `UZIP.js` and optimizes them while adding direct support for GZIP and Zlib data. And unlike all of the above libraries, it uses ES Modules to allow for partial builds, meaning that it can rival even `tiny-inflate` in size while maintaining excellent performance. The end result is a library that, in total, weighs 8kB minified for the entire build (3kB for decompression only and 5kB for compression only), is about 15% faster than `UZIP.js` or up to 60% faster than `pako`, and achieves the same or better compression ratio than the rest.
 So what makes `fflate` different? It takes the brilliant innovations of `UZIP.js` and optimizes them while adding direct support for GZIP and Zlib data. And unlike all of the above libraries, it uses ES Modules to allow for partial builds, meaning that it can rival even `tiny-inflate` in size while maintaining excellent performance. The end result is a library that, in total, weighs 8kB minified for the entire build (3kB for decompression only and 5kB for compression only), is about 15% faster than `UZIP.js` or up to 60% faster than `pako`, and achieves the same or better compression ratio than the rest.
 
 
-Before you decide that `fflate` is the end-all compression library, you should note that JavaScript simply cannot rival the performance of a compiled language. If you're willing to have 160 kB of extra weight and [much less browser support](https://caniuse.com/wasm), you can achieve around 30% more performance than `fflate` with a WASM build of Zlib like [`wasm-flate`](https://www.npmjs.com/package/wasm-flate). And if you're only using Node.js, just use the [native Zlib bindings](https://nodejs.org/api/zlib.html) that offer the best performance and compression ratios.
+Before you decide that `fflate` is the end-all compression library, you should note that JavaScript simply cannot rival the performance of a compiled language. If you're willing to have 160 kB of extra weight and [much less browser support](https://caniuse.com/wasm), you can achieve  more performance than `fflate` with a WASM build of Zlib like [`wasm-flate`](https://www.npmjs.com/package/wasm-flate). And if you're only using Node.js, just use the [native Zlib bindings](https://nodejs.org/api/zlib.html) that offer the best performance. Though note that even against these compiled libraries, `fflate` is only around 30% slower in decompression and 10% slower in compression, and can still achieve better compression ratios!
 
 
 ## Browser support
 ## Browser support
 `fflate` makes heavy use of typed arrays (`Uint8Array`, `Uint16Array`, etc.). Typed arrays can be polyfilled at the cost of performance, but the most recent browser that doesn't support them [is from 2011](https://caniuse.com/typedarrays), so I wouldn't bother.
 `fflate` makes heavy use of typed arrays (`Uint8Array`, `Uint16Array`, etc.). Typed arrays can be polyfilled at the cost of performance, but the most recent browser that doesn't support them [is from 2011](https://caniuse.com/typedarrays), so I wouldn't bother.

+ 7 - 7
docs/README.md

@@ -24,7 +24,7 @@
 
 
 ▸ **decompress**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
 ▸ **decompress**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
 
 
-*Defined in [index.ts:774](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L774)*
+*Defined in [index.ts:774](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L774)*
 
 
 Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format
 Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format
 
 
@@ -43,7 +43,7 @@ ___
 
 
 ▸ **deflate**(`data`: Uint8Array, `opts`: [DeflateOptions](interfaces/deflateoptions.md)): Uint8Array
 ▸ **deflate**(`data`: Uint8Array, `opts`: [DeflateOptions](interfaces/deflateoptions.md)): Uint8Array
 
 
-*Defined in [index.ts:680](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L680)*
+*Defined in [index.ts:680](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L680)*
 
 
 Compresses data with DEFLATE without any wrapper
 Compresses data with DEFLATE without any wrapper
 
 
@@ -62,7 +62,7 @@ ___
 
 
 ▸ **gunzip**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
 ▸ **gunzip**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
 
 
-*Defined in [index.ts:720](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L720)*
+*Defined in [index.ts:720](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L720)*
 
 
 Expands GZIP data
 Expands GZIP data
 
 
@@ -81,7 +81,7 @@ ___
 
 
 ▸ **gzip**(`data`: Uint8Array, `opts`: [GZIPOptions](interfaces/gzipoptions.md)): Uint8Array
 ▸ **gzip**(`data`: Uint8Array, `opts`: [GZIPOptions](interfaces/gzipoptions.md)): Uint8Array
 
 
-*Defined in [index.ts:700](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L700)*
+*Defined in [index.ts:700](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L700)*
 
 
 Compresses data with GZIP
 Compresses data with GZIP
 
 
@@ -100,7 +100,7 @@ ___
 
 
 ▸ **inflate**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
 ▸ **inflate**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
 
 
-*Defined in [index.ts:690](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L690)*
+*Defined in [index.ts:690](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L690)*
 
 
 Expands DEFLATE data with no wrapper
 Expands DEFLATE data with no wrapper
 
 
@@ -119,7 +119,7 @@ ___
 
 
 ▸ **unzlib**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
 ▸ **unzlib**(`data`: Uint8Array, `out?`: Uint8Array): Uint8Array
 
 
-*Defined in [index.ts:758](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L758)*
+*Defined in [index.ts:758](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L758)*
 
 
 Expands Zlib data
 Expands Zlib data
 
 
@@ -138,7 +138,7 @@ ___
 
 
 ▸ **zlib**(`data`: Uint8Array, `opts`: [ZlibOptions](interfaces/zliboptions.md)): Uint8Array
 ▸ **zlib**(`data`: Uint8Array, `opts`: [ZlibOptions](interfaces/zliboptions.md)): Uint8Array
 
 
-*Defined in [index.ts:737](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L737)*
+*Defined in [index.ts:737](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L737)*
 
 
 Compress data with Zlib
 Compress data with Zlib
 
 

+ 2 - 2
docs/interfaces/deflateoptions.md

@@ -23,7 +23,7 @@ Options for compressing data into a DEFLATE format
 
 
 • `Optional` **level**: 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9
 • `Optional` **level**: 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9
 
 
-*Defined in [index.ts:632](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L632)*
+*Defined in [index.ts:632](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L632)*
 
 
 The level of compression to use, ranging from 0-9.
 The level of compression to use, ranging from 0-9.
 
 
@@ -45,7 +45,7 @@ ___
 
 
 • `Optional` **mem**: 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10 \| 11 \| 12
 • `Optional` **mem**: 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10 \| 11 \| 12
 
 
-*Defined in [index.ts:641](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L641)*
+*Defined in [index.ts:641](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L641)*
 
 
 The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory.
 The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory.
 
 

+ 4 - 4
docs/interfaces/gzipoptions.md

@@ -23,7 +23,7 @@ Options for compressing data into a GZIP format
 
 
 • `Optional` **filename**: string
 • `Optional` **filename**: string
 
 
-*Defined in [index.ts:657](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L657)*
+*Defined in [index.ts:657](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L657)*
 
 
 The filename of the data. If the `gunzip` command is used to decompress the data, it will output a file
 The filename of the data. If the `gunzip` command is used to decompress the data, it will output a file
 with this name instead of the name of the compressed file.
 with this name instead of the name of the compressed file.
@@ -36,7 +36,7 @@ ___
 
 
 *Inherited from [DeflateOptions](deflateoptions.md).[level](deflateoptions.md#level)*
 *Inherited from [DeflateOptions](deflateoptions.md).[level](deflateoptions.md#level)*
 
 
-*Defined in [index.ts:632](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L632)*
+*Defined in [index.ts:632](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L632)*
 
 
 The level of compression to use, ranging from 0-9.
 The level of compression to use, ranging from 0-9.
 
 
@@ -60,7 +60,7 @@ ___
 
 
 *Inherited from [DeflateOptions](deflateoptions.md).[mem](deflateoptions.md#mem)*
 *Inherited from [DeflateOptions](deflateoptions.md).[mem](deflateoptions.md#mem)*
 
 
-*Defined in [index.ts:641](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L641)*
+*Defined in [index.ts:641](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L641)*
 
 
 The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory.
 The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory.
 
 
@@ -75,7 +75,7 @@ ___
 
 
 • `Optional` **mtime**: Date \| string \| number
 • `Optional` **mtime**: Date \| string \| number
 
 
-*Defined in [index.ts:652](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L652)*
+*Defined in [index.ts:652](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L652)*
 
 
 When the file was last modified. Defaults to the current time.
 When the file was last modified. Defaults to the current time.
 Set this to 0 to avoid specifying a modification date entirely.
 Set this to 0 to avoid specifying a modification date entirely.

+ 2 - 2
docs/interfaces/zliboptions.md

@@ -23,7 +23,7 @@ Options for compressing data into a Zlib format
 
 
 *Inherited from [DeflateOptions](deflateoptions.md).[level](deflateoptions.md#level)*
 *Inherited from [DeflateOptions](deflateoptions.md).[level](deflateoptions.md#level)*
 
 
-*Defined in [index.ts:632](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L632)*
+*Defined in [index.ts:632](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L632)*
 
 
 The level of compression to use, ranging from 0-9.
 The level of compression to use, ranging from 0-9.
 
 
@@ -47,7 +47,7 @@ ___
 
 
 *Inherited from [DeflateOptions](deflateoptions.md).[mem](deflateoptions.md#mem)*
 *Inherited from [DeflateOptions](deflateoptions.md).[mem](deflateoptions.md#mem)*
 
 
-*Defined in [index.ts:641](https://github.com/101arrowz/fflate/blob/9ef7e32/src/index.ts#L641)*
+*Defined in [index.ts:641](https://github.com/101arrowz/fflate/blob/8a52440/src/index.ts#L641)*
 
 
 The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory.
 The memory level to use, ranging from 0-12. Increasing this increases speed and compression ratio at the cost of memory.
 
 

+ 6 - 2
package.json

@@ -1,10 +1,11 @@
 {
 {
   "name": "fflate",
   "name": "fflate",
-  "version": "0.0.2",
+  "version": "0.0.3",
   "description": "High performance (de)compression in an 8kB package",
   "description": "High performance (de)compression in an 8kB package",
   "main": "lib/index.js",
   "main": "lib/index.js",
   "module": "esm/index.js",
   "module": "esm/index.js",
   "types": "lib/index.d.ts",
   "types": "lib/index.d.ts",
+  "sideEffects": false,
   "repository": "https://github.com/101arrowz/fflate",
   "repository": "https://github.com/101arrowz/fflate",
   "author": "Arjun Barrett",
   "author": "Arjun Barrett",
   "license": "MIT",
   "license": "MIT",
@@ -16,7 +17,10 @@
     "compression",
     "compression",
     "decompression",
     "decompression",
     "zlib",
     "zlib",
-    "pako"
+    "pako",
+    "browser",
+    "node.js",
+    "tiny"
   ],
   ],
   "scripts": {
   "scripts": {
     "build": "tsc && tsc --project tsconfig.esm.json && typedoc --mode library --plugin typedoc-plugin-markdown --hideProjectName --hideBreadcrumbs --readme none",
     "build": "tsc && tsc --project tsconfig.esm.json && typedoc --mode library --plugin typedoc-plugin-markdown --hideProjectName --hideBreadcrumbs --readme none",

+ 7 - 7
src/index.ts

@@ -138,8 +138,8 @@ const bits16 = (d: Uint8Array, p: number) => {
 const inflt = (dat: Uint8Array, buf?: Uint8Array) => {
 const inflt = (dat: Uint8Array, buf?: Uint8Array) => {
   // have to estimate size
   // have to estimate size
   const noBuf = !buf;
   const noBuf = !buf;
-  // Slightly less than 2x - assumes ~60% compression ratio
-  if (noBuf) buf = new u8((dat.length >>> 2) << 3);
+  // 4x - assumes ~25% compression ratio
+  if (noBuf) buf = new u8(dat.length << 2);
   // ensure buffer can fit at least l elements
   // ensure buffer can fit at least l elements
   const cbuf = (l: number) => {
   const cbuf = (l: number) => {
     let bl = buf.length;
     let bl = buf.length;
@@ -166,13 +166,13 @@ const inflt = (dat: Uint8Array, buf?: Uint8Array) => {
     if (!type) {
     if (!type) {
       // go to end of byte boundary
       // go to end of byte boundary
       if (pos & 7) pos += 8 - (pos & 7);
       if (pos & 7) pos += 8 - (pos & 7);
-      const s = (pos >>> 3) + 4, l = dat[s - 4] | (dat[s - 3] << 8);
+      let s = (pos >>> 3) + 4, l = dat[s - 4] | (dat[s - 3] << 8);
       // ensure size
       // ensure size
       if (noBuf) cbuf(bt + l);
       if (noBuf) cbuf(bt + l);
       // Copy over uncompressed data
       // Copy over uncompressed data
-      buf.set(dat.subarray(s, s + l), bt);
+      for (let m = s + l; s < m; ++s) buf[bt++] = dat[s];
       // Get new bitpos, update byte count
       // Get new bitpos, update byte count
-      pos = (s + l) << 3, bt += l;
+      pos = s << 3;
       continue;
       continue;
     }
     }
     // Make sure the buffer can hold this + the largest possible addition
     // Make sure the buffer can hold this + the largest possible addition
@@ -488,7 +488,7 @@ const wblk = (dat: Uint8Array, out: Uint8Array, final: number, syms: Uint32Array
 }
 }
 
 
 // deflate options (nice << 13) | chain
 // deflate options (nice << 13) | chain
-const deo = new u32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
+const deo = /*#__PURE__*/new u32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
 
 
 // compresses data into a raw DEFLATE buffer
 // compresses data into a raw DEFLATE buffer
 const dflt = (dat: Uint8Array, lvl: number, plvl: number, pre: number, post: number) => {
 const dflt = (dat: Uint8Array, lvl: number, plvl: number, pre: number, post: number) => {
@@ -724,7 +724,7 @@ export function gunzip(data: Uint8Array, out?: Uint8Array) {
   let st = 10 + (flg & 2);
   let st = 10 + (flg & 2);
   if (flg & 4) st += data[10] | (data[11] << 8) + 2;
   if (flg & 4) st += data[10] | (data[11] << 8) + 2;
   for (let zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= (data[st++] == 0) as unknown as number);
   for (let zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= (data[st++] == 0) as unknown as number);
-  if (!out) out = new Uint8Array(data[l - 4] | data[l - 3] << 8 | data[l - 2] << 16 | data[l - 1] << 24);
+  if (!out) out = new u8(data[l - 4] | data[l - 3] << 8 | data[l - 2] << 16 | data[l - 1] << 24);
   return inflt(data.subarray(st, -8), out);
   return inflt(data.subarray(st, -8), out);
 }
 }