"use strict"; /** * @author jdiaz5513 */ var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.Segment = void 0; const tslib_1 = require("tslib"); const debug_1 = tslib_1.__importDefault(require("debug")); const constants_1 = require("../constants"); const errors_1 = require("../errors"); const types_1 = require("../types"); const util_1 = require("../util"); const pointers_1 = require("./pointers"); const trace = debug_1.default("capnp:segment"); trace("load"); class Segment { constructor(id, message, buffer, byteLength = 0) { this[_a] = "Segment"; this.id = id; this.message = message; this.buffer = buffer; this._dv = new DataView(buffer); this.byteOffset = 0; this.byteLength = byteLength; } /** * Attempt to allocate the requested number of bytes in this segment. If this segment is full this method will return * a pointer to freshly allocated space in another segment from the same message. * * @param {number} byteLength The number of bytes to allocate, will be rounded up to the nearest word. * @returns {Pointer} A pointer to the newly allocated space. */ allocate(byteLength) { trace("allocate(%d)", byteLength); // eslint-disable-next-line @typescript-eslint/no-this-alias let segment = this; byteLength = util_1.padToWord(byteLength); if (byteLength > constants_1.MAX_SEGMENT_LENGTH - 8) { throw new Error(util_1.format(errors_1.SEG_SIZE_OVERFLOW, byteLength)); } if (!segment.hasCapacity(byteLength)) { segment = segment.message.allocateSegment(byteLength); } const byteOffset = segment.byteLength; segment.byteLength = segment.byteLength + byteLength; trace("Allocated %x bytes in %s (requested segment: %s).", byteLength, this, segment); return new pointers_1.Pointer(segment, byteOffset); } /** * Quickly copy a word (8 bytes) from `srcSegment` into this one at the given offset. * * @param {number} byteOffset The offset to write the word to. * @param {Segment} srcSegment The segment to copy the word from. * @param {number} srcByteOffset The offset from the start of `srcSegment` to copy from. * @returns {void} */ copyWord(byteOffset, srcSegment, srcByteOffset) { const value = srcSegment._dv.getFloat64(srcByteOffset, constants_1.NATIVE_LITTLE_ENDIAN); this._dv.setFloat64(byteOffset, value, constants_1.NATIVE_LITTLE_ENDIAN); } /** * Quickly copy words from `srcSegment` into this one. * * @param {number} byteOffset The offset to start copying into. * @param {Segment} srcSegment The segment to copy from. * @param {number} srcByteOffset The start offset to copy from. * @param {number} wordLength The number of words to copy. * @returns {void} */ copyWords(byteOffset, srcSegment, srcByteOffset, wordLength) { const dst = new Float64Array(this.buffer, byteOffset, wordLength); const src = new Float64Array(srcSegment.buffer, srcByteOffset, wordLength); dst.set(src); } /** * Quickly fill a number of words in the buffer with zeroes. * * @param {number} byteOffset The first byte to set to zero. * @param {number} wordLength The number of words (not bytes!) to zero out. * @returns {void} */ fillZeroWords(byteOffset, wordLength) { new Float64Array(this.buffer, byteOffset, wordLength).fill(0); } /** WARNING: This function is not yet implemented. */ getBigInt64(byteOffset, littleEndian) { throw new Error(util_1.format(errors_1.NOT_IMPLEMENTED, byteOffset, littleEndian)); } /** WARNING: This function is not yet implemented. */ getBigUint64(byteOffset, littleEndian) { throw new Error(util_1.format(errors_1.NOT_IMPLEMENTED, byteOffset, littleEndian)); } /** * Get the total number of bytes available in this segment (the size of its underlying buffer). * * @returns {number} The total number of bytes this segment can hold. */ getCapacity() { return this.buffer.byteLength; } /** * Read a float32 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getFloat32(byteOffset) { return this._dv.getFloat32(byteOffset, true); } /** * Read a float64 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getFloat64(byteOffset) { return this._dv.getFloat64(byteOffset, true); } /** * Read an int16 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getInt16(byteOffset) { return this._dv.getInt16(byteOffset, true); } /** * Read an int32 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getInt32(byteOffset) { return this._dv.getInt32(byteOffset, true); } /** * Read an int64 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getInt64(byteOffset) { return new types_1.Int64(new Uint8Array(this.buffer.slice(byteOffset, byteOffset + 8))); } /** * Read an int8 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getInt8(byteOffset) { return this._dv.getInt8(byteOffset); } /** * Read a uint16 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getUint16(byteOffset) { return this._dv.getUint16(byteOffset, true); } /** * Read a uint32 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getUint32(byteOffset) { return this._dv.getUint32(byteOffset, true); } /** * Read a uint8 value out of this segment. * NOTE: this does not copy the memory region, so updates to the underlying buffer will affect the Uint64 value! * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getUint64(byteOffset) { return new types_1.Uint64(new Uint8Array(this.buffer.slice(byteOffset, byteOffset + 8))); } /** * Read a uint8 value out of this segment. * * @param {number} byteOffset The offset in bytes to the value. * @returns {number} The value. */ getUint8(byteOffset) { return this._dv.getUint8(byteOffset); } hasCapacity(byteLength) { trace("hasCapacity(%d)", byteLength); // capacity - allocated >= requested return this.buffer.byteLength - this.byteLength >= byteLength; } /** * Quickly check the word at the given offset to see if it is equal to zero. * * PERF_V8: Fastest way to do this is by reading the whole word as a `number` (float64) in the _native_ endian format * and see if it's zero. * * Benchmark: http://jsben.ch/#/Pjooc * * @param {number} byteOffset The offset to the word. * @returns {boolean} `true` if the word is zero. */ isWordZero(byteOffset) { return this._dv.getFloat64(byteOffset, constants_1.NATIVE_LITTLE_ENDIAN) === 0; } /** * Swap out this segment's underlying buffer with a new one. It's assumed that the new buffer has the same content but * more free space, otherwise all existing pointers to this segment will be hilariously broken. * * @param {ArrayBuffer} buffer The new buffer to use. * @returns {void} */ replaceBuffer(buffer) { trace("replaceBuffer(%p)", buffer); if (this.buffer === buffer) return; if (buffer.byteLength < this.byteLength) { throw new Error(errors_1.SEG_REPLACEMENT_BUFFER_TOO_SMALL); } this._dv = new DataView(buffer); this.buffer = buffer; } /** WARNING: This function is not yet implemented. */ setBigInt64(byteOffset, value, littleEndian) { throw new Error(util_1.format(errors_1.NOT_IMPLEMENTED, byteOffset, value, littleEndian)); } /** WARNING: This function is not yet implemented. */ setBigUint64(byteOffset, value, littleEndian) { throw new Error(util_1.format(errors_1.NOT_IMPLEMENTED, byteOffset, value, littleEndian)); } /** * Write a float32 value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {number} val The value to store. * @returns {void} */ setFloat32(byteOffset, val) { this._dv.setFloat32(byteOffset, val, true); } /** * Write an float64 value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {number} val The value to store. * @returns {void} */ setFloat64(byteOffset, val) { this._dv.setFloat64(byteOffset, val, true); } /** * Write an int16 value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {number} val The value to store. * @returns {void} */ setInt16(byteOffset, val) { this._dv.setInt16(byteOffset, val, true); } /** * Write an int32 value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {number} val The value to store. * @returns {void} */ setInt32(byteOffset, val) { this._dv.setInt32(byteOffset, val, true); } /** * Write an int8 value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {number} val The value to store. * @returns {void} */ setInt8(byteOffset, val) { this._dv.setInt8(byteOffset, val); } /** * Write an int64 value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {Int64} val The value to store. * @returns {void} */ setInt64(byteOffset, val) { this._dv.setUint8(byteOffset, val.buffer[0]); this._dv.setUint8(byteOffset + 1, val.buffer[1]); this._dv.setUint8(byteOffset + 2, val.buffer[2]); this._dv.setUint8(byteOffset + 3, val.buffer[3]); this._dv.setUint8(byteOffset + 4, val.buffer[4]); this._dv.setUint8(byteOffset + 5, val.buffer[5]); this._dv.setUint8(byteOffset + 6, val.buffer[6]); this._dv.setUint8(byteOffset + 7, val.buffer[7]); } /** * Write a uint16 value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {number} val The value to store. * @returns {void} */ setUint16(byteOffset, val) { this._dv.setUint16(byteOffset, val, true); } /** * Write a uint32 value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {number} val The value to store. * @returns {void} */ setUint32(byteOffset, val) { this._dv.setUint32(byteOffset, val, true); } /** * Write a uint64 value to the specified offset. * TODO: benchmark other ways to perform this write operation. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {Uint64} val The value to store. * @returns {void} */ setUint64(byteOffset, val) { this._dv.setUint8(byteOffset + 0, val.buffer[0]); this._dv.setUint8(byteOffset + 1, val.buffer[1]); this._dv.setUint8(byteOffset + 2, val.buffer[2]); this._dv.setUint8(byteOffset + 3, val.buffer[3]); this._dv.setUint8(byteOffset + 4, val.buffer[4]); this._dv.setUint8(byteOffset + 5, val.buffer[5]); this._dv.setUint8(byteOffset + 6, val.buffer[6]); this._dv.setUint8(byteOffset + 7, val.buffer[7]); } /** * Write a uint8 (byte) value to the specified offset. * * @param {number} byteOffset The offset from the beginning of the buffer. * @param {number} val The value to store. * @returns {void} */ setUint8(byteOffset, val) { this._dv.setUint8(byteOffset, val); } /** * Write a zero word (8 bytes) to the specified offset. This is slightly faster than calling `setUint64` or * `setFloat64` with a zero value. * * Benchmark: http://jsben.ch/#/dUdPI * * @param {number} byteOffset The offset of the word to set to zero. * @returns {void} */ setWordZero(byteOffset) { this._dv.setFloat64(byteOffset, 0, constants_1.NATIVE_LITTLE_ENDIAN); } toString() { return util_1.format("Segment_id:%d,off:%a,len:%a,cap:%a", this.id, this.byteLength, this.byteOffset, this.buffer.byteLength); } } exports.Segment = Segment; _a = Symbol.toStringTag; //# sourceMappingURL=segment.js.map