Skip to content

chore(ecmascript): refactor reverse and copy_within #682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ impl TypedArrayPrototype {
agent: &mut Agent,
this_value: Value,
arguments: ArgumentsList,
mut gc: GcScope<'gc, '_>,
gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Value<'gc>> {
let this_value = this_value.bind(gc.nogc());
let target = arguments.get(0).bind(gc.nogc());
Expand All @@ -776,80 +776,24 @@ impl TypedArrayPrototype {
};
// 1. Let O be the this value.
let o = this_value;

// 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
let ta_record = validate_typed_array(agent, o, Ordering::SeqCst, gc.nogc())
.unbind()?
.bind(gc.nogc());
let o = ta_record.object;
let scoped_o = o.scope(agent, gc.nogc());
// 3. Let len be TypedArrayLength(taRecord).
let len = with_typed_array_viewable!(
scoped_o.get(agent),
typed_array_length::<T>(agent, &ta_record, gc.nogc())
)
.to_i64()
.unwrap();
let end = end.map(|e| e.scope(agent, gc.nogc()));
let start = start.scope(agent, gc.nogc());
let target = target.scope(agent, gc.nogc());

// 4. Let relativeTarget be ? ToIntegerOrInfinity(target).
// SAFETY: target has not been shared.
let relative_target =
to_integer_or_infinity(agent, unsafe { target.take(agent) }, gc.reborrow()).unbind()?;
// 5. If relativeTarget = -∞, let targetIndex be 0.
let target_index = if relative_target.is_neg_infinity() {
0
} else if relative_target.is_negative() {
// 6. Else if relativeTarget < 0, let targetIndex be max(len + relativeTarget, 0).
(len + relative_target.into_i64()).max(0)
} else {
// 7. Else, let targetIndex be min(relativeTarget, len).
relative_target.into_i64().min(len)
};
// 8. Let relativeStart be ? ToIntegerOrInfinity(start).
// SAFETY: start has not been shared.
let relative_start =
to_integer_or_infinity(agent, unsafe { start.take(agent) }, gc.reborrow()).unbind()?;
let start_index = if relative_start.is_neg_infinity() {
// 9. If relativeStart = -∞, let startIndex be 0
0
} else if relative_start.is_negative() {
// 10. Else if relativeStart < 0, let startIndex be max(len + relativeStart, 0).
(len + relative_start.into_i64()).max(0)
} else {
// 11. Else, let startIndex be min(relativeStart, len).
relative_start.into_i64().min(len)
};
// 12. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
let end = end.map(|e| unsafe { e.take(agent) }.bind(gc.nogc()));
let end_index = if end.is_none() || end.unwrap().is_undefined() {
len
} else {
let relative_end =
to_integer_or_infinity(agent, end.unwrap().unbind(), gc.reborrow()).unbind()?;
// 13. If relativeEnd = -∞, let endIndex be 0.
if relative_end.is_neg_infinity() {
0
} else if relative_end.is_negative() {
// 14. Else if relativeEnd < 0, let endIndex be max(len + relativeEnd, 0).
(len + relative_end.into_i64()).max(0)
} else {
// 15. Else, let endIndex be min(relativeEnd, len).
relative_end.into_i64().min(len)
}
};
let gc = gc.into_nogc();
let o = scoped_o.get(agent).bind(gc);

with_typed_array_viewable!(
let o = with_typed_array_viewable!(
o,
copy_within_typed_array::<T>(agent, o, target_index, start_index, end_index, len, gc,)?
copy_within_typed_array::<T>(
agent,
ta_record.unbind(),
target.unbind(),
start.unbind(),
end.unbind(),
gc,
)
);

// 18. Return O.
Ok(o.into_value())
o.map(|o| o.into_value())
}

/// ### [23.2.3.7 %TypedArray%.prototype.entries ( )](https://tc39.es/ecma262/#sec-%typedarray%.prototype.entries)
Expand Down Expand Up @@ -1010,10 +954,10 @@ impl TypedArrayPrototype {
this_arg.unbind(),
ta_record.unbind(),
gc,
)?
)
);

Ok(a.into_value())
a.map(|a| a.into_value())
}

/// ### 23.2.3.11 %TypedArray%.prototype.find ( predicate [ , thisArg ] )(https://tc39.es/ecma262/multipage/indexed-collections.html#sec-%typedarray%.prototype.find)
Expand Down Expand Up @@ -1838,23 +1782,8 @@ impl TypedArrayPrototype {
let ta_record = validate_typed_array(agent, o, Ordering::SeqCst, gc)
.unbind()?
.bind(gc);
// 3. Let len be TypedArrayLength(taRecord).
let o = ta_record.object;
let len =
with_typed_array_viewable!(o, typed_array_length::<T>(agent, &ta_record, gc)) as i64;
// 4. Let middle be floor(len / 2).
// 5. Let lower be 0.
let len = len as usize;
// 6. Repeat, while lower ≠ middle,
// a. Let upper be len - lower - 1.
// b. Let upperP be ! ToString(𝔽(upper)).
// c. Let lowerP be ! ToString(𝔽(lower)).
// d. Let lowerValue be ! Get(O, lowerP).
// e. Let upperValue be ! Get(O, upperP).
// f. Perform ! Set(O, lowerP, upperValue, true).
// g. Perform ! Set(O, upperP, lowerValue, true).
// h. Set lower to lower + 1.
with_typed_array_viewable!(o, reverse_typed_array::<T>(agent, o, len, gc)?);
with_typed_array_viewable!(o, reverse_typed_array::<T>(agent, ta_record, o, gc)?);
// 7. Return O.
Ok(o.into_value())
}
Expand Down Expand Up @@ -2393,10 +2322,23 @@ fn search_typed_element<'a, T: Viewable + std::fmt::Debug, const ASCENDING: bool

fn reverse_typed_array<'a, T: Viewable + Copy + std::fmt::Debug>(
agent: &mut Agent,
ta_record: TypedArrayWithBufferWitnessRecords<'_>,
ta: TypedArray,
len: usize,
gc: NoGcScope<'a, '_>,
) -> JsResult<'a, ()> {
// 3. Let len be TypedArrayLength(taRecord).
let len = typed_array_length::<T>(agent, &ta_record, gc);
// 4. Let middle be floor(len / 2).
// 5. Let lower be 0.
// 6. Repeat, while lower ≠ middle,
// a. Let upper be len - lower - 1.
// b. Let upperP be ! ToString(𝔽(upper)).
// c. Let lowerP be ! ToString(𝔽(lower)).
// d. Let lowerValue be ! Get(O, lowerP).
// e. Let upperValue be ! Get(O, upperP).
// f. Perform ! Set(O, lowerP, upperValue, true).
// g. Perform ! Set(O, upperP, lowerValue, true).
// h. Set lower to lower + 1.
let slice = viewable_slice_mut::<T>(agent, ta, gc).unwrap();
let slice = &mut slice[..len];
slice.reverse();
Expand All @@ -2405,16 +2347,74 @@ fn reverse_typed_array<'a, T: Viewable + Copy + std::fmt::Debug>(

fn copy_within_typed_array<'a, T: Viewable + std::fmt::Debug>(
agent: &mut Agent,
ta: TypedArray,
target_index: i64,
start_index: i64,
end_index: i64,
before_len: i64,
gc: NoGcScope<'a, '_>,
) -> JsResult<'a, ()> {
let end_bound = (end_index - start_index)
.max(0)
.min(before_len - target_index) as usize;
ta_record: TypedArrayWithBufferWitnessRecords,
target: Value,
start: Value,
end: Option<Value>,
mut gc: GcScope<'a, '_>,
) -> JsResult<'a, TypedArray<'a>> {
let ta_record = ta_record.bind(gc.nogc());
let o = ta_record.object;
let scoped_o = o.scope(agent, gc.nogc());
let target = target.bind(gc.nogc());
let start = start.bind(gc.nogc());
let end = end.bind(gc.nogc());
// 3. Let len be TypedArrayLength(taRecord).
let len = typed_array_length::<T>(agent, &ta_record, gc.nogc())
.to_i64()
.unwrap();
let end = end.map(|e| e.scope(agent, gc.nogc()));
let start = start.scope(agent, gc.nogc());
let target = target.scope(agent, gc.nogc());
// 4. Let relativeTarget be ? ToIntegerOrInfinity(target).
// SAFETY: target has not been shared.
let relative_target =
to_integer_or_infinity(agent, unsafe { target.take(agent) }, gc.reborrow()).unbind()?;
// 5. If relativeTarget = -∞, let targetIndex be 0.
let target_index = if relative_target.is_neg_infinity() {
0
} else if relative_target.is_negative() {
// 6. Else if relativeTarget < 0, let targetIndex be max(len + relativeTarget, 0).
(len + relative_target.into_i64()).max(0)
} else {
// 7. Else, let targetIndex be min(relativeTarget, len).
relative_target.into_i64().min(len)
};
// 8. Let relativeStart be ? ToIntegerOrInfinity(start).
// SAFETY: start has not been shared.
let relative_start =
to_integer_or_infinity(agent, unsafe { start.take(agent) }, gc.reborrow()).unbind()?;
let start_index = if relative_start.is_neg_infinity() {
// 9. If relativeStart = -∞, let startIndex be 0
0
} else if relative_start.is_negative() {
// 10. Else if relativeStart < 0, let startIndex be max(len + relativeStart, 0).
(len + relative_start.into_i64()).max(0)
} else {
// 11. Else, let startIndex be min(relativeStart, len).
relative_start.into_i64().min(len)
};
// 12. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
let end = end.map(|e| unsafe { e.take(agent) }.bind(gc.nogc()));
let end_index = if end.is_none() || end.unwrap().is_undefined() {
len
} else {
let relative_end =
to_integer_or_infinity(agent, end.unwrap().unbind(), gc.reborrow()).unbind()?;
// 13. If relativeEnd = -∞, let endIndex be 0.
if relative_end.is_neg_infinity() {
0
} else if relative_end.is_negative() {
// 14. Else if relativeEnd < 0, let endIndex be max(len + relativeEnd, 0).
(len + relative_end.into_i64()).max(0)
} else {
// 15. Else, let endIndex be min(relativeEnd, len).
relative_end.into_i64().min(len)
}
};
let gc = gc.into_nogc();
let ta = scoped_o.get(agent).bind(gc);
let end_bound = (end_index - start_index).max(0).min(len - target_index) as usize;
let ta_record = make_typed_array_with_buffer_witness_record(agent, ta, Ordering::SeqCst, gc);
if is_typed_array_out_of_bounds::<T>(agent, &ta_record, gc) {
return Err(agent.throw_exception_with_static_message(
Expand All @@ -2423,21 +2423,23 @@ fn copy_within_typed_array<'a, T: Viewable + std::fmt::Debug>(
gc,
));
}
let len = typed_array_length::<T>(agent, &ta_record, gc) as usize;
let after_len = typed_array_length::<T>(agent, &ta_record, gc) as usize;
let slice = viewable_slice_mut::<T>(agent, ta, gc).unwrap();
let slice = &mut slice[..len];
let slice = &mut slice[..after_len];
let start_bound = start_index as usize;
let target_index = target_index as usize;
let before_len = before_len as usize;
let before_len = len as usize;
if before_len != slice.len() {
let end_bound = (len - target_index).max(0).min(before_len - target_index);
let end_bound = (after_len - target_index)
.max(0)
.min(before_len - target_index);
slice.copy_within(start_bound..end_bound, target_index);
return Ok(());
return Ok(ta);
}
if end_bound > 0 {
slice.copy_within(start_bound..start_bound + end_bound, target_index);
}
Ok(())
Ok(ta)
}

fn fill_typed_array<'a, T: Viewable>(
Expand Down
Loading