mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 05:47: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(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(TypedArrayPrototypeOneArg, "TypedArray.prototype.{}() requires at least one argument") \
|
||||
M(TypedArrayFailedSettingIndex, "Failed setting value of index {} of typed array") \
|
||||
M(UnknownIdentifier, "'{}' is not defined") \
|
||||
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.byteOffset, byte_offset_getter, nullptr, Attribute::Configurable);
|
||||
define_native_function(vm.names.at, at, 1, attr);
|
||||
define_native_function(vm.names.every, every, 1, attr);
|
||||
}
|
||||
|
||||
TypedArrayPrototype::~TypedArrayPrototype()
|
||||
|
@ -44,6 +45,49 @@ static TypedArrayBase* typed_array_from(VM& vm, GlobalObject& global_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
|
||||
JS_DEFINE_NATIVE_GETTER(TypedArrayPrototype::length_getter)
|
||||
{
|
||||
|
@ -81,6 +125,20 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::at)
|
|||
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
|
||||
JS_DEFINE_NATIVE_GETTER(TypedArrayPrototype::buffer_getter)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@ private:
|
|||
JS_DECLARE_NATIVE_GETTER(byte_offset_getter);
|
||||
|
||||
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