UNPKG

reign

Version:

A persistent, typed-objects implementation.

257 lines (228 loc) 7.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.STRING_DATA_OFFSET = exports.STRING_HEADER_SIZE = exports.STRING_HASH_OFFSET = exports.STRING_LENGTH_OFFSET = undefined; exports.make = make; var _performance = require("../../performance"); var _string = require("../../random/string"); var _string2 = _interopRequireDefault(_string); var _backing = require("backing"); var _backing2 = _interopRequireDefault(_backing); var _ = require("../.."); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } var STRING_LENGTH_OFFSET = exports.STRING_LENGTH_OFFSET = 0; var STRING_HASH_OFFSET = exports.STRING_HASH_OFFSET = 4; var STRING_HEADER_SIZE = exports.STRING_HEADER_SIZE = 8; var STRING_DATA_OFFSET = exports.STRING_DATA_OFFSET = STRING_HEADER_SIZE; /** * Make a simple string type for the given realm. */ function make(realm) { var StringType = realm.StringType; var RawString = new StringType({ name: 'String', byteLength: 8, // Pointer byteAlignment: 8, constructor: function constructor(input) { if (this instanceof RawString) { throw new TypeError("String is not a constructor."); } else { return input == null ? '' : '' + input; } }, cast: function cast(input) { return input == null ? '' : '' + input; }, accepts: function accepts(input) { return typeof input === 'string'; }, initialize: function initialize(backing, pointerAddress, initialInput) { if (!initialInput) { backing.setFloat64(pointerAddress, 0); } else { backing.setFloat64(pointerAddress, createRawString(backing, initialInput)); } }, store: function store(backing, pointerAddress, input) { var existing = backing.getFloat64(pointerAddress); if (!input) { if (existing !== 0) { backing.gc.unref(existing); backing.setFloat64(pointerAddress, 0); } } else { var address = createRawString(backing, input); if (address !== existing) { if (existing !== 0) { backing.gc.unref(existing); } backing.setFloat64(pointerAddress, address); } } }, load: function load(backing, address) { return getString(backing, backing.getFloat64(address)); }, clear: function clear(backing, address) { var existing = backing.getFloat64(address); if (existing !== 0) { backing.gc.unref(existing); backing.setFloat64(address, 0); } }, randomValue: _string2.default, emptyValue: function emptyValue() { return ''; }, hashValue: hashString, equal: function equal(valueA, valueB) { return valueA === valueB; }, flowType: function flowType() { return "string"; } }); return RawString; } /** * Store the given raw string and return the address. * The string will NOT be interned. */ function createRawString(backing, input) { var hash = 0x811c9dc5; var allAscii = true; var length = input.length; for (var i = 0; i < length; i++) { var code = input.charCodeAt(i); if (code > 127) { allAscii = false; } hash ^= code; hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); } hash = hash >>> 0; return storeString(backing, input, hash, allAscii); } (0, _performance.forceInline)(createRawString); /** * Store a string and return its address. */ function storeString(backing, input, hash, allAscii) { if (allAscii) { return storeAsciiString(backing, input, hash); } else { return storeMultibyteString(backing, input, hash); } } (0, _performance.forceInline)(storeString); function storeAsciiString(backing, input, hash) { var length = input.length; var byteLength = length + STRING_HEADER_SIZE; var address = backing.gc.alloc(byteLength, 0, 1); backing.setInt32(address, length); backing.setUint32(address + STRING_HASH_OFFSET, hash); var offset = backing.offsetFor(address + STRING_DATA_OFFSET); var chars = backing.arenaFor(address).uint8Array; for (var i = 0; i < length; i++) { chars[offset + i] = input.charCodeAt(i); } return address; } (0, _performance.forceInline)(storeAsciiString); function storeMultibyteString(backing, input, hash) { var length = input.length; var byteLength = length + length + STRING_HEADER_SIZE; var address = backing.gc.alloc(byteLength, 0, 1); backing.setInt32(address, -length); backing.setUint32(address + STRING_HASH_OFFSET, hash); var offset = backing.offsetFor(address + STRING_DATA_OFFSET) >> 1; var chars = backing.arenaFor(address).uint16Array; for (var i = 0; i < length; i++) { chars[offset + i] = input.charCodeAt(i); } return address; } (0, _performance.forceInline)(storeMultibyteString); /** * Returns the hash for the given string. */ function hashString(input) { var hash = 0x811c9dc5; for (var i = 0; i < input.length; i++) { hash ^= input.charCodeAt(i); hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); } return hash >>> 0; } (0, _performance.forceInline)(hashString); /** * Check that the string stored at the given address matches the given input + hash. */ function checkEqual(backing, address, input, hash, allAscii) { if (getStringHash(backing, address) !== hash) { return false; } var length = backing.getInt32(address); if (length < 0) { if (allAscii) { return false; } length = -length; if (length !== input.length) { return false; } var arena = backing.arenaFor(address); var chars = arena.uint16Array; var offset = backing.offsetFor(address + STRING_HEADER_SIZE) >> 1; for (var i = 0; i < length; i++) { if (input.charCodeAt(i) !== chars[offset + i]) { return false; } } return true; } else { if (!allAscii) { return false; } else if (length !== input.length) { return false; } var _arena = backing.arenaFor(address); var _chars = _arena.uint8Array; var _offset = backing.offsetFor(address + STRING_HEADER_SIZE); for (var _i = 0; _i < length; _i++) { if (input.charCodeAt(_i) !== _chars[_offset + _i]) { return false; } } return true; } } (0, _performance.forceInline)(checkEqual); /** * Read the string at the given address. */ function getString(backing, address) { if (address === 0) { return ''; } var arena = backing.arenaFor(address); var offset = backing.offsetFor(address); var length = arena.int32Array[offset >> 2]; if (length < 0) { offset = offset + STRING_DATA_OFFSET >> 1; return String.fromCharCode.apply(String, _toConsumableArray(arena.uint16Array.slice(offset, offset + Math.abs(length)))); } else { offset = offset + STRING_DATA_OFFSET; return String.fromCharCode.apply(String, _toConsumableArray(arena.uint8Array.slice(offset, offset + Math.abs(length)))); } } (0, _performance.forceInline)(getString); /** * Read the hash for the given string. */ function getStringHash(backing, address) { return backing.getUint32(address + STRING_HASH_OFFSET); } (0, _performance.forceInline)(getStringHash);