Skip to content

Commit 06a2173

Browse files
IdanHolinusg
authored andcommitted
LibJS: Implement initializing a TypedArray from an array-like object
Used by twitch.tv and based on the following specification: https://tc39.es/ecma262/#sec-initializetypedarrayfromarraylike
1 parent c919699 commit 06a2173

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

Userland/Libraries/LibJS/Runtime/TypedArray.cpp

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,37 @@ static void initialize_typed_array_from_typed_array(GlobalObject& global_object,
135135
dest_array.put_by_index(i, v);
136136
}
137137
}
138+
template<typename T>
139+
static void initialize_typed_array_from_array_like(GlobalObject& global_object, TypedArray<T>& typed_array, const Object& array_like)
140+
{
141+
// 23.2.5.1.5 InitializeTypedArrayFromArrayLike, https://tc39.es/ecma262/#sec-initializetypedarrayfromarraylike
142+
143+
auto& vm = global_object.vm();
144+
auto length = length_of_array_like(global_object, array_like);
145+
if (vm.exception())
146+
return;
147+
148+
auto element_size = typed_array.element_size();
149+
if (Checked<size_t>::multiplication_would_overflow(element_size, length)) {
150+
vm.throw_exception<RangeError>(global_object, ErrorType::InvalidLength, "typed array");
151+
return;
152+
}
153+
auto byte_length = element_size * length;
154+
auto array_buffer = ArrayBuffer::create(global_object, byte_length);
155+
typed_array.set_viewed_array_buffer(array_buffer);
156+
typed_array.set_byte_length(byte_length);
157+
typed_array.set_byte_offset(0);
158+
typed_array.set_array_length(length);
159+
160+
for (size_t k = 0; k < length; k++) {
161+
auto value = array_like.get(k).value_or(js_undefined());
162+
if (vm.exception())
163+
return;
164+
typed_array.put_by_index(k, value);
165+
if (vm.exception())
166+
return;
167+
}
168+
}
138169

139170
void TypedArrayBase::visit_edges(Visitor& visitor)
140171
{
@@ -199,8 +230,17 @@ void TypedArrayBase::visit_edges(Visitor& visitor)
199230
if (vm.exception()) \
200231
return {}; \
201232
} else { \
202-
/* FIXME: Initialize from Iterator or Array-like object */ \
203-
TODO(); \
233+
auto iterator = first_argument.as_object().get(vm.well_known_symbol_iterator()); \
234+
if (vm.exception()) \
235+
return {}; \
236+
if (iterator.is_function()) { \
237+
/* FIXME: Initialize from Iterator */ \
238+
TODO(); \
239+
} else { \
240+
initialize_typed_array_from_array_like(global_object(), *typed_array, first_argument.as_object()); \
241+
} \
242+
if (vm.exception()) \
243+
return {}; \
204244
} \
205245
return typed_array; \
206246
} \

Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ test("typed array created from TypedArray do not share buffer", () => {
183183
expect(u8Array[1]).toBe(2);
184184
});
185185

186+
test("typed array from Array-Like", () => {
187+
TYPED_ARRAYS.forEach(T => {
188+
function func() {
189+
const newTypedArray = new T(arguments);
190+
expect(newTypedArray[0]).toBe(1);
191+
expect(newTypedArray[1]).toBe(2);
192+
expect(newTypedArray[2]).toBe(3);
193+
}
194+
func(1, 2, 3);
195+
});
196+
});
197+
186198
test("TypedArray is not exposed on the global object", () => {
187199
expect(globalThis.TypedArray).toBeUndefined();
188200
});

0 commit comments

Comments
 (0)