1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 11:57:35 +00:00

LibJS: Add %TypedArray%.prototype.every

This commit is contained in:
Luke 2021-06-18 03:56:57 +01:00 committed by Linus Groh
parent de8aa1b17d
commit 65ca2d98af
4 changed files with 130 additions and 0 deletions

View file

@ -156,6 +156,7 @@
M(TypedArrayInvalidByteOffset, "Invalid byte offset for {}: must be a multiple of {}, got {}") \ M(TypedArrayInvalidByteOffset, "Invalid byte offset for {}: must be a multiple of {}, got {}") \
M(TypedArrayOutOfRangeByteOffset, "Typed array byte offset {} is out of range for buffer with length {}") \ M(TypedArrayOutOfRangeByteOffset, "Typed array byte offset {} is out of range for buffer with length {}") \
M(TypedArrayOutOfRangeByteOffsetOrLength, "Typed array range {}:{} is out of range for buffer with length {}") \ M(TypedArrayOutOfRangeByteOffsetOrLength, "Typed array range {}:{} is out of range for buffer with length {}") \
M(TypedArrayPrototypeOneArg, "TypedArray.prototype.{}() requires at least one argument") \
M(TypedArrayFailedSettingIndex, "Failed setting value of index {} of typed array") \ M(TypedArrayFailedSettingIndex, "Failed setting value of index {} of typed array") \
M(UnknownIdentifier, "'{}' is not defined") \ M(UnknownIdentifier, "'{}' is not defined") \
M(URIMalformed, "URI malformed") \ M(URIMalformed, "URI malformed") \

View file

@ -26,6 +26,7 @@ void TypedArrayPrototype::initialize(GlobalObject& object)
define_native_accessor(vm.names.byteLength, byte_length_getter, nullptr, Attribute::Configurable); define_native_accessor(vm.names.byteLength, byte_length_getter, nullptr, Attribute::Configurable);
define_native_accessor(vm.names.byteOffset, byte_offset_getter, nullptr, Attribute::Configurable); define_native_accessor(vm.names.byteOffset, byte_offset_getter, nullptr, Attribute::Configurable);
define_native_function(vm.names.at, at, 1, attr); define_native_function(vm.names.at, at, 1, attr);
define_native_function(vm.names.every, every, 1, attr);
} }
TypedArrayPrototype::~TypedArrayPrototype() TypedArrayPrototype::~TypedArrayPrototype()
@ -44,6 +45,49 @@ static TypedArrayBase* typed_array_from(VM& vm, GlobalObject& global_object)
return static_cast<TypedArrayBase*>(this_object); return static_cast<TypedArrayBase*>(this_object);
} }
static Function* callback_from_args(GlobalObject& global_object, const String& name)
{
auto& vm = global_object.vm();
if (vm.argument_count() < 1) {
vm.throw_exception<TypeError>(global_object, ErrorType::TypedArrayPrototypeOneArg, name);
return nullptr;
}
auto callback = vm.argument(0);
if (!callback.is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, callback.to_string_without_side_effects());
return nullptr;
}
return &callback.as_function();
}
static void for_each_item(VM& vm, GlobalObject& global_object, const String& name, AK::Function<IterationDecision(size_t index, Value value, Value callback_result)> callback)
{
auto* typed_array = typed_array_from(vm, global_object);
if (!typed_array)
return;
auto initial_length = typed_array->array_length();
auto* callback_function = callback_from_args(global_object, name);
if (!callback_function)
return;
auto this_value = vm.argument(1);
for (size_t i = 0; i < initial_length; ++i) {
auto value = typed_array->get(i);
if (vm.exception())
return;
auto callback_result = vm.call(*callback_function, this_value, value, Value((i32)i), typed_array);
if (vm.exception())
return;
if (callback(i, value, callback_result) == IterationDecision::Break)
break;
}
}
// 23.2.3.18 get %TypedArray%.prototype.length, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.length // 23.2.3.18 get %TypedArray%.prototype.length, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.length
JS_DEFINE_NATIVE_GETTER(TypedArrayPrototype::length_getter) JS_DEFINE_NATIVE_GETTER(TypedArrayPrototype::length_getter)
{ {
@ -81,6 +125,20 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::at)
return typed_array->get(index.value()); return typed_array->get(index.value());
} }
// 23.2.3.7 %TypedArray%.prototype.every ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.every
JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::every)
{
auto result = true;
for_each_item(vm, global_object, "every", [&](auto, auto, auto callback_result) {
if (!callback_result.to_boolean()) {
result = false;
return IterationDecision::Break;
}
return IterationDecision::Continue;
});
return Value(result);
}
// 23.2.3.1 get %TypedArray%.prototype.buffer, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.buffer // 23.2.3.1 get %TypedArray%.prototype.buffer, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.buffer
JS_DEFINE_NATIVE_GETTER(TypedArrayPrototype::buffer_getter) JS_DEFINE_NATIVE_GETTER(TypedArrayPrototype::buffer_getter)
{ {

View file

@ -25,6 +25,7 @@ private:
JS_DECLARE_NATIVE_GETTER(byte_offset_getter); JS_DECLARE_NATIVE_GETTER(byte_offset_getter);
JS_DECLARE_NATIVE_FUNCTION(at); JS_DECLARE_NATIVE_FUNCTION(at);
JS_DECLARE_NATIVE_FUNCTION(every);
}; };
} }

View file

@ -0,0 +1,70 @@
const TYPED_ARRAYS = [
Uint8Array,
Uint16Array,
Uint32Array,
Int8Array,
Int16Array,
Int32Array,
Float32Array,
Float64Array,
];
const BIGINT_TYPED_ARRAYS = [BigUint64Array, BigInt64Array];
test("length is 1", () => {
TYPED_ARRAYS.forEach(T => {
expect(T.prototype.every).toHaveLength(1);
});
BIGINT_TYPED_ARRAYS.forEach(T => {
expect(T.prototype.every).toHaveLength(1);
});
});
describe("errors", () => {
function errorTests(T) {
test(`requires at least one argument (${T.name})`, () => {
expect(() => {
new T().every();
}).toThrowWithMessage(
TypeError,
"TypedArray.prototype.every() requires at least one argument"
);
});
test(`callback must be a function (${T.name})`, () => {
expect(() => {
new T().every(undefined);
}).toThrowWithMessage(TypeError, "undefined is not a function");
});
}
TYPED_ARRAYS.forEach(T => errorTests(T));
BIGINT_TYPED_ARRAYS.forEach(T => errorTests(T));
});
test("basic functionality", () => {
TYPED_ARRAYS.forEach(T => {
const typedArray = new T([2, 4, 6]);
expect(typedArray.every(value => value === 2)).toBeFalse();
expect(typedArray.every(value => value === 4)).toBeFalse();
expect(typedArray.every(value => value === 6)).toBeFalse();
expect(typedArray.every(value => value % 2 === 0)).toBeTrue();
expect(typedArray.every(value => value % 2 === 1)).toBeFalse();
expect(typedArray.every(value => value < 2)).toBeFalse();
expect(typedArray.every(value => value > 2)).toBeFalse();
expect(typedArray.every(value => value >= 2)).toBeTrue();
});
BIGINT_TYPED_ARRAYS.forEach(T => {
const typedArray = new T([2n, 4n, 6n]);
expect(typedArray.every(value => value === 2n)).toBeFalse();
expect(typedArray.every(value => value === 4n)).toBeFalse();
expect(typedArray.every(value => value === 6n)).toBeFalse();
expect(typedArray.every(value => value % 2n === 0n)).toBeTrue();
expect(typedArray.every(value => value % 2n === 1n)).toBeFalse();
expect(typedArray.every(value => value < 2n)).toBeFalse();
expect(typedArray.every(value => value > 2n)).toBeFalse();
expect(typedArray.every(value => value >= 2n)).toBeTrue();
});
});