reign
Version:
A persistent, typed-objects implementation.
220 lines (195 loc) • 6.69 kB
JavaScript
;
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() + ">";
}
};
};
});
};