mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:37:43 +00:00
LibJS: ArrayBuffer.prototype.slice
Implements the aforementioned native Javascript function, following the specification's [1] implementation. [1] https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
This commit is contained in:
parent
b50de19cd3
commit
01187e58f2
4 changed files with 82 additions and 1 deletions
|
@ -34,12 +34,23 @@ ArrayBuffer* ArrayBuffer::create(GlobalObject& global_object, size_t byte_size)
|
||||||
return global_object.heap().allocate<ArrayBuffer>(global_object, byte_size, *global_object.array_buffer_prototype());
|
return global_object.heap().allocate<ArrayBuffer>(global_object, byte_size, *global_object.array_buffer_prototype());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayBuffer* ArrayBuffer::create(GlobalObject& global_object, ByteBuffer& buffer)
|
||||||
|
{
|
||||||
|
return global_object.heap().allocate<ArrayBuffer>(global_object, buffer, *global_object.array_buffer_prototype());
|
||||||
|
}
|
||||||
|
|
||||||
ArrayBuffer::ArrayBuffer(size_t byte_size, Object& prototype)
|
ArrayBuffer::ArrayBuffer(size_t byte_size, Object& prototype)
|
||||||
: Object(prototype)
|
: Object(prototype)
|
||||||
, m_buffer(ByteBuffer::create_zeroed(byte_size))
|
, m_buffer(ByteBuffer::create_zeroed(byte_size))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayBuffer::ArrayBuffer(ByteBuffer& buffer, Object& prototype)
|
||||||
|
: Object(prototype)
|
||||||
|
, m_buffer(buffer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ArrayBuffer::~ArrayBuffer()
|
ArrayBuffer::~ArrayBuffer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,10 @@ class ArrayBuffer : public Object {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ArrayBuffer* create(GlobalObject&, size_t);
|
static ArrayBuffer* create(GlobalObject&, size_t);
|
||||||
|
static ArrayBuffer* create(GlobalObject&, ByteBuffer&);
|
||||||
|
|
||||||
ArrayBuffer(size_t, Object& prototype);
|
ArrayBuffer(size_t, Object& prototype);
|
||||||
|
ArrayBuffer(ByteBuffer& buffer, Object& prototype);
|
||||||
virtual ~ArrayBuffer() override;
|
virtual ~ArrayBuffer() override;
|
||||||
|
|
||||||
size_t byte_length() const { return m_buffer.size(); }
|
size_t byte_length() const { return m_buffer.size(); }
|
||||||
|
|
|
@ -66,12 +66,51 @@ static ArrayBuffer* array_buffer_object_from(VM& vm, GlobalObject& global_object
|
||||||
return static_cast<ArrayBuffer*>(&this_object);
|
return static_cast<ArrayBuffer*>(&this_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 25.1.5.3 ArrayBuffer.prototype.slice, https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::slice)
|
JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::slice)
|
||||||
{
|
{
|
||||||
|
const auto start = vm.argument(0);
|
||||||
|
const auto end = vm.argument(1);
|
||||||
|
|
||||||
auto array_buffer_object = array_buffer_object_from(vm, global_object);
|
auto array_buffer_object = array_buffer_object_from(vm, global_object);
|
||||||
if (!array_buffer_object)
|
if (!array_buffer_object)
|
||||||
return {};
|
return {};
|
||||||
TODO();
|
|
||||||
|
// FIXME: Check for shared buffer
|
||||||
|
// FIXME: Check for detached buffer
|
||||||
|
|
||||||
|
const auto len = array_buffer_object->byte_length();
|
||||||
|
|
||||||
|
const auto relative_start = start.is_negative_infinity()
|
||||||
|
? 0
|
||||||
|
: start.to_integer_or_infinity(global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto first = relative_start < 0
|
||||||
|
? max(len + relative_start, 0.0)
|
||||||
|
: min(relative_start, static_cast<double>(len));
|
||||||
|
|
||||||
|
const auto relative_end = end.is_undefined()
|
||||||
|
? len
|
||||||
|
: end.to_integer_or_infinity(global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
double final_;
|
||||||
|
if (end.is_negative_infinity())
|
||||||
|
final_ = 0;
|
||||||
|
else if (relative_end < 0)
|
||||||
|
final_ = max(len + relative_end, 0.0);
|
||||||
|
else
|
||||||
|
final_ = min(relative_end, static_cast<double>(len));
|
||||||
|
|
||||||
|
const auto new_len = max(final_ - first, 0.0);
|
||||||
|
|
||||||
|
// FIXME: this is a bit more involved in the specification
|
||||||
|
auto sliced = array_buffer_object->buffer().slice(first, new_len);
|
||||||
|
auto buffer = ArrayBuffer::create(global_object, sliced);
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_GETTER(ArrayBufferPrototype::byte_length_getter)
|
JS_DEFINE_NATIVE_GETTER(ArrayBufferPrototype::byte_length_getter)
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
test("single parameter", () => {
|
||||||
|
const buffer = new ArrayBuffer(16);
|
||||||
|
const fullView = new Int32Array(buffer);
|
||||||
|
|
||||||
|
// modify some value that we can check in the sliced buffer
|
||||||
|
fullView[3] = 7;
|
||||||
|
|
||||||
|
// slice the buffer and use a new int32 view to perform basic checks
|
||||||
|
const slicedBuffer = buffer.slice(12);
|
||||||
|
const slicedView = new Int32Array(slicedBuffer);
|
||||||
|
|
||||||
|
expect(slicedView).toHaveLength(1);
|
||||||
|
expect(slicedView[0]).toBe(7);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("both parameters", () => {
|
||||||
|
const buffer = new ArrayBuffer(16);
|
||||||
|
const fullView = new Int32Array(buffer);
|
||||||
|
|
||||||
|
// modify some value that we can check in the sliced buffer
|
||||||
|
fullView[1] = 12;
|
||||||
|
|
||||||
|
// slice the buffer and use a new int32 view to perform basic checks
|
||||||
|
const slicedBuffer = buffer.slice(4, 8);
|
||||||
|
const slicedView = new Int32Array(slicedBuffer);
|
||||||
|
|
||||||
|
expect(slicedView).toHaveLength(1);
|
||||||
|
expect(slicedView[0]).toBe(12);
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue