diff --git a/README.md b/README.md index 0965859..0903374 100644 --- a/README.md +++ b/README.md @@ -40,13 +40,15 @@ The [OCapN](https://ocapn.org/) network protocol treats strings and byte-arrays ## Solution -This proposal introduces additional methods and read-only accessor properties to `ArrayBuffer.prototype` that fit naturally into those explained above. Just as a buffer can be resizable or not, or detached or not, this proposal enables buffers to be immutable or not. Just as `transferToFixedSize` moves the contents of a original buffer into a newly created non-resizable buffer, this proposal provides a transfer operation that moves the contents of an original original buffer into a newly created immutable buffer. Altogether, this proposal only adds to `ArrayBuffer.prototype` one method +This proposal introduces additional methods and read-only accessor properties to `ArrayBuffer.prototype` that fit naturally into those explained above. Just as a buffer can be resizable or not, and detached or not, this proposal enables buffers to be immutable or not. Just as `transferToFixedSize` moves the contents of a original buffer into a newly created non-resizable buffer, this proposal provides a transfer operation that moves the contents of an original original buffer into a newly created immutable buffer. Altogether, this proposal only adds to `ArrayBuffer.prototype` one method - `transferToImmutable() :ArrayBuffer` -- move the contents of the original buffer into a new immutable buffer, detach the original buffer, and return the new buffer. and one read-only accessor - `immutable: boolean` -- is this buffer immutable, or can its contents be changed? -An immutable buffer cannot be detached or resized. Its `maxByteLength` is the same as its `byteLength`. A `DataView` or `TypedArray` using an immutable buffer as its backing store can be frozen and immutable. `ArrayBuffer`s, `DataView`s, and `TypedArray`s that are frozen and immutable could be placed in ROM without going beyond JavaScript's official semantics. +An immutable buffer cannot be detached, resized, or further transferred. Its `maxByteLength` is the same as its `byteLength`. A `DataView` or `TypedArray` using an immutable buffer as its backing store can be frozen and immutable. `ArrayBuffer`s, `DataView`s, and `TypedArray`s that are frozen and immutable could be placed in ROM without going beyond JavaScript's official semantics. + +The ArrayBuffer `slice` method and TypedArray methods that create new ArrayBuffers (`filter`, `map`, `slice`, `toReversed`, etc.) make no effort to preserve immutability, just like they make no effort to preserve resizability (although use of SpeciesConstructor in those methods means that _lack_ of resizability/immutability in the result cannot be guaranteed for the latter). ## Implementations diff --git a/spec.emu b/spec.emu index e8fecc4..c07e0c1 100644 --- a/spec.emu +++ b/spec.emu @@ -495,6 +495,68 @@ contributors: Mark S. Miller, Richard Gibson + +

ArrayBuffer.prototype.resize ( _newLength_ )

+

This method performs the following steps when called:

+ + 1. Let _O_ be the *this* value. + 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferMaxByteLength]]). + 1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception. + 1. Let _newByteLength_ be ? ToIndex(_newLength_). + 1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception. + 1. If IsImmutableBuffer(_O_) is *true*, throw a *TypeError* exception. + 1. If _newByteLength_ > _O_.[[ArrayBufferMaxByteLength]], throw a *RangeError* exception. + 1. Let _hostHandled_ be ? HostResizeArrayBuffer(_O_, _newByteLength_). + 1. If _hostHandled_ is ~handled~, return *undefined*. + 1. Let _oldBlock_ be _O_.[[ArrayBufferData]]. + 1. Let _newBlock_ be ? CreateByteDataBlock(_newByteLength_). + 1. Let _copyLength_ be min(_newByteLength_, _O_.[[ArrayBufferByteLength]]). + 1. Perform CopyDataBlockBytes(_newBlock_, 0, _oldBlock_, 0, _copyLength_). + 1. NOTE: Neither creation of the new Data Block nor copying from the old Data Block are observable. Implementations may implement this method as in-place growth or shrinkage. + 1. Set _O_.[[ArrayBufferData]] to _newBlock_. + 1. Set _O_.[[ArrayBufferByteLength]] to _newByteLength_. + 1. Return *undefined*. + +
+ + +

ArrayBuffer.prototype.slice ( _start_, _end_ )

+

This method performs the following steps when called:

+ + 1. Let _O_ be the *this* value. + 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]). + 1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception. + 1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception. + 1. Let _len_ be _O_.[[ArrayBufferByteLength]]. + 1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_). + 1. If _relativeStart_ = -∞, let _first_ be 0. + 1. Else if _relativeStart_ < 0, let _first_ be max(_len_ + _relativeStart_, 0). + 1. Else, let _first_ be min(_relativeStart_, _len_). + 1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_). + 1. If _relativeEnd_ = -∞, let _final_ be 0. + 1. Else if _relativeEnd_ < 0, let _final_ be max(_len_ + _relativeEnd_, 0). + 1. Else, let _final_ be min(_relativeEnd_, _len_). + 1. Let _newLen_ be max(_final_ - _first_, 0). + 1. Let _ctor_ be ? SpeciesConstructor(_O_, %ArrayBuffer%). + 1. Let _new_ be ? Construct(_ctor_, « 𝔽(_newLen_) »). + 1. Perform ? RequireInternalSlot(_new_, [[ArrayBufferData]]). + 1. If IsSharedArrayBuffer(_new_) is *true*, throw a *TypeError* exception. + 1. If IsDetachedBuffer(_new_) is *true*, throw a *TypeError* exception. + 1. If IsImmutableBuffer(_new_) is *true*, throw a *TypeError* exception. + 1. If SameValue(_new_, _O_) is *true*, throw a *TypeError* exception. + 1. If _new_.[[ArrayBufferByteLength]] < _newLen_, throw a *TypeError* exception. + 1. NOTE: Side-effects of the above steps may have detached or resized _O_. + 1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception. + 1. Let _fromBuf_ be _O_.[[ArrayBufferData]]. + 1. Let _toBuf_ be _new_.[[ArrayBufferData]]. + 1. Let _currentLen_ be _O_.[[ArrayBufferByteLength]]. + 1. If _first_ < _currentLen_, then + 1. Let _count_ be min(_newLen_, _currentLen_ - _first_). + 1. Perform CopyDataBlockBytes(_toBuf_, 0, _fromBuf_, _first_, _count_). + 1. Return _new_. + +
+