Skip to content

Instantly share code, notes, and snippets.

@mattdesl
Last active February 16, 2021 18:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattdesl/3f4aff12a85182226bd654f56088ebe1 to your computer and use it in GitHub Desktop.
Save mattdesl/3f4aff12a85182226bd654f56088ebe1 to your computer and use it in GitHub Desktop.
simple expandable in-memory file utility, inspired by Emscripten's FS
export default function createFile(initialCapacity = 256) {
let cursor = 0;
let usedBytes = 0;
let contents = new Uint8Array(initialCapacity);
return {
contents: function () {
return contents.slice(0, usedBytes);
},
seek: function (offset) {
// offset in bytes
cursor = offset;
},
write: function (data) {
const size = data.byteLength;
expand(cursor + size);
contents.set(data, cursor);
cursor += size;
usedBytes = Math.max(usedBytes, cursor);
return size;
},
};
function expand(newCapacity) {
var prevCapacity = contents.length;
if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough.
// Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity.
// For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to
// avoid overshooting the allocation cap by a very large margin.
var CAPACITY_DOUBLING_MAX = 1024 * 1024;
newCapacity = Math.max(
newCapacity,
(prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>>
0
);
if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding.
const oldContents = contents;
contents = new Uint8Array(newCapacity); // Allocate new storage.
if (usedBytes > 0) contents.set(oldContents.subarray(0, usedBytes), 0);
}
}
import createFile from './createFile.js';
const file = createFile();
// write some data
file.write(new Uint8Array([ 1, 5, 2, 5 ]));
file.write(new Uint8Array([ 50, 25, 10 ]));
file.seek(0);
file.write(new Uint8Array([ 10, 20 ]));
// get the final file buffer
console.log(file.contents());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment