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:
parent
de8aa1b17d
commit
65ca2d98af
4 changed files with 130 additions and 0 deletions
|
@ -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") \
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue