UNPKG

reign

Version:

A persistent, typed-objects implementation.

220 lines (195 loc) 6.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MIN_TYPE_ID = undefined; exports.make = make; var _ = require("../"); var _2 = require("../../"); var _backing = require("backing"); var _backing2 = _interopRequireDefault(_backing); var _symbols = require("../../symbols"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var MIN_TYPE_ID = exports.MIN_TYPE_ID = Math.pow(2, 20) * 3; /** * Makes a ReferenceType type class for the given realm. */ function make(realm) { var TypeClass = realm.TypeClass; var typeCounter = 0; return new TypeClass('ReferenceType', function (Target) { return function (Reference) { typeCounter++; var name = typeof Target.name === 'string' && Target.name.length > 0 ? "Reference<" + Target.name + ">" : "%Reference<0x" + typeCounter.toString(16) + ">"; var id = MIN_TYPE_ID + typeCounter; Reference[_symbols.$CanBeEmbedded] = true; Reference[_symbols.$CanBeReferenced] = false; Reference[_symbols.$CanContainReferences] = true; if (!Target[_symbols.$CanBeReferenced]) { throw new TypeError("Type " + Target.name + " cannot be referenced."); } var ReferenceArray = void 0; // Issue 285 Object.defineProperties(Reference, { Array: { get: function get() { if (ReferenceArray === undefined) { ReferenceArray = new realm.ArrayType(Reference); } return ReferenceArray; } } }); /** * Initialize a reference to the given object at the given address. */ function initializeReference(backing, pointerAddress, value) { if (value == null) { backing.setFloat64(pointerAddress, 0); } else if (value instanceof Target) { if (!value[_symbols.$CanBeReferenced]) { throw new ReferenceError("Cannot reference value of type " + Target.name); } var address = value[_symbols.$Address]; backing.gc.ref(address); backing.setFloat64(pointerAddress, address); } else { var _address = backing.gc.alloc(Target.byteLength, Target.id, 1); Target.initialize(backing, _address, value); backing.setFloat64(pointerAddress, _address); } } /** * Store a reference to the given object at the given address. */ function storeReference(backing, pointerAddress, value) { var existing = backing.getFloat64(pointerAddress); if (value == null) { if (existing !== 0) { backing.setFloat64(pointerAddress, 0); } return; } else if (existing !== 0) { backing.gc.unref(existing); } if (value instanceof Target) { if (!value[_symbols.$CanBeReferenced]) { throw new ReferenceError("Cannot reference value of type " + Target.name); } var address = value[_symbols.$Address]; backing.gc.ref(address); backing.setFloat64(pointerAddress, address); } else { var _address2 = backing.gc.alloc(Target.byteLength, Target.id, 1); Target.initialize(backing, _address2, value); backing.setFloat64(pointerAddress, _address2); } } /** * Load an object based on the reference stored at the given address. */ function loadReference(backing, pointerAddress) { var address = backing.getFloat64(pointerAddress); if (address === 0) { return null; } else { return Target.load(backing, address); } } /** * Remove a reference at the given address. */ function clearReference(backing, pointerAddress) { var address = backing.getFloat64(pointerAddress); if (address !== 0) { backing.setFloat64(pointerAddress, 0); backing.gc.unref(address); } } /** * Destroy a reference at the given address. */ function referenceDestructor(backing, pointerAddress) { var address = backing.getFloat64(pointerAddress); if (address !== 0) { backing.setFloat64(pointerAddress, 0); backing.gc.unref(address); } } return { id: id, name: name, byteLength: 8, byteAlignment: 8, initialize: initializeReference, store: storeReference, load: loadReference, clear: clearReference, destructor: referenceDestructor, emptyValue: function emptyValue() { return null; }, equal: function equal(valueA, valueB) { if (valueA === valueB) { return true; } else if (!valueA || !valueB) { return false; } else { return Target.equal(valueA, valueB); } }, compareValues: function compareValues(valueA, valueB) { return Target.compareValues(valueA, valueB); }, compareAddresses: function compareAddresses(backing, addressA, addressB) { if (addressA === addressB) { return 0; } else if (addressA === 0) { return -1; } else if (addressB === 0) { return 1; } var pointerA = backing.getFloat64(addressA); var pointerB = backing.getFloat64(addressB); if (pointerA === pointerB) { return 0; } else if (pointerA === 0) { return -1; } else if (pointerB === 0) { return 1; } else { return Target.compareAddresses(backing, pointerA, pointerB); } }, compareAddressValue: function compareAddressValue(backing, address, value) { var pointer = backing.getFloat64(address); if (pointer === 0) { if (value == null) { return 0; } else { return -1; } } return Target.compareAddressValue(backing, pointer, value); }, randomValue: function randomValue() { if (Math.random() < 0.5) { return null; } else { return Target.randomValue(); } }, hashValue: function hashValue(input) { if (input == null) { return 4; } else { return Target.hashValue(input); } }, flowType: function flowType() { return "Reference<" + Target.flowType() + ">"; } }; }; }); };