avm2: Impl `Vector.insertAt`
This commit is contained in:
parent
e3ad30a0f7
commit
a053015558
|
@ -630,6 +630,33 @@ pub fn unshift<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Implements `Vector.insertAt`
|
||||
pub fn insert_at<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
this: Option<Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
if let Some(this) = this {
|
||||
if let Some(mut vs) = this.as_vector_storage_mut(activation.context.gc_context) {
|
||||
let index = args
|
||||
.get(0)
|
||||
.cloned()
|
||||
.unwrap_or(Value::Undefined)
|
||||
.coerce_to_i32(activation)?;
|
||||
let value_type = vs.value_type();
|
||||
let value = args
|
||||
.get(1)
|
||||
.cloned()
|
||||
.unwrap_or(Value::Undefined)
|
||||
.coerce_to_type(activation, value_type)?;
|
||||
|
||||
vs.insert(index, Some(value))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `Vector`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
let class = Class::new(
|
||||
|
@ -670,6 +697,7 @@ pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>
|
|||
("push", push),
|
||||
("shift", shift),
|
||||
("unshift", unshift),
|
||||
("insertAt", insert_at),
|
||||
];
|
||||
write.define_public_builtin_instance_methods(mc, PUBLIC_INSTANCE_METHODS);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::avm2::object::Object;
|
|||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::Collect;
|
||||
use std::cmp::max;
|
||||
|
||||
/// The vector storage portion of a vector object.
|
||||
///
|
||||
|
@ -224,6 +225,34 @@ impl<'gc> VectorStorage<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Insert a value at a specific position in the vector.
|
||||
///
|
||||
/// This function returns an error if the vector is fixed.
|
||||
///
|
||||
/// This function does no coercion as calling it requires mutably borrowing
|
||||
/// the vector (and thus it is unwise to reenter the AVM2 runtime to coerce
|
||||
/// things). You must use the associated `coerce` fn before storing things
|
||||
/// in the vector.
|
||||
pub fn insert(&mut self, position: i32, value: Option<Value<'gc>>) -> Result<(), Error> {
|
||||
if self.is_fixed {
|
||||
return Err("RangeError: Vector is fixed".into());
|
||||
}
|
||||
|
||||
let position = if position < 0 {
|
||||
max(position + self.storage.len() as i32, 0) as usize
|
||||
} else {
|
||||
position as usize
|
||||
};
|
||||
|
||||
if position >= self.storage.len() {
|
||||
self.storage.push(value);
|
||||
} else {
|
||||
self.storage.insert(position, value);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Iterate over vector values.
|
||||
pub fn iter<'a>(
|
||||
&'a self,
|
||||
|
|
|
@ -643,6 +643,7 @@ swf_tests! {
|
|||
(as3_vector_map, "avm2/vector_map", 1),
|
||||
(as3_vector_pushpop, "avm2/vector_pushpop", 1),
|
||||
(as3_vector_shiftunshift, "avm2/vector_shiftunshift", 1),
|
||||
(as3_vector_insertat, "avm2/vector_insertat", 1),
|
||||
}
|
||||
|
||||
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.
|
||||
|
|
|
@ -0,0 +1,272 @@
|
|||
package {
|
||||
public class Test {
|
||||
}
|
||||
}
|
||||
|
||||
function trace_vector(v: Vector.<*>) {
|
||||
trace(v.length, "elements");
|
||||
for (var i = 0; i < v.length; i += 1) {
|
||||
trace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
trace("/// var a_bool: Vector.<Boolean> = new <Boolean>[true, false];");
|
||||
var a_bool:Vector.<Boolean> = new <Boolean>[true, false];
|
||||
|
||||
trace("/// var b_bool: Vector.<Boolean> = new <Boolean>[false, true, false];");
|
||||
var b_bool:Vector.<Boolean> = new <Boolean>[false, true, false];
|
||||
|
||||
trace("/// a_bool.insertAt(3, false);");
|
||||
trace(a_bool.insertAt(3, false));
|
||||
|
||||
trace("/// (contents of a_bool...)");
|
||||
trace_vector(a_bool);
|
||||
|
||||
trace("/// a_bool.insertAt(0, false);");
|
||||
trace(a_bool.insertAt(0, false));
|
||||
|
||||
trace("/// (contents of a_bool...)");
|
||||
trace_vector(a_bool);
|
||||
|
||||
trace("/// b_bool.insertAt(-2, false);");
|
||||
trace(b_bool.insertAt(-2, false));
|
||||
|
||||
trace("/// (contents of b_bool...)");
|
||||
trace_vector(b_bool);
|
||||
|
||||
trace("/// b_bool.insertAt(-5, false);");
|
||||
trace(b_bool.insertAt(-5, false));
|
||||
|
||||
trace("/// (contents of b_bool...)");
|
||||
trace_vector(b_bool);
|
||||
|
||||
class Superclass {
|
||||
|
||||
}
|
||||
|
||||
class Subclass extends Superclass {
|
||||
|
||||
}
|
||||
|
||||
trace("/// var a0_class = new Superclass();");
|
||||
var a0_class = new Superclass();
|
||||
|
||||
trace("/// var a1_class = new Subclass();");
|
||||
var a1_class = new Subclass();
|
||||
|
||||
trace("/// var a_class: Vector.<Superclass> = new <Superclass>[a0_class, a1_class];");
|
||||
var a_class:Vector.<Superclass> = new <Superclass>[a0_class, a1_class];
|
||||
|
||||
trace("/// var b_class: Vector.<Subclass> = new <Subclass>[];");
|
||||
var b_class:Vector.<Subclass> = new <Subclass>[];
|
||||
|
||||
trace("/// b_class.length = 1;");
|
||||
b_class.length = 1;
|
||||
|
||||
trace("/// b_class[0] = new Subclass();");
|
||||
b_class[0] = new Subclass();
|
||||
|
||||
trace("/// a_class.insertAt(0, new Subclass());");
|
||||
trace(a_class.insertAt(0, new Subclass()));
|
||||
|
||||
trace("/// a0_class === a_class[1];");
|
||||
trace(a0_class === a_class[1]);
|
||||
|
||||
trace("/// a1_class === a_class[2];");
|
||||
trace(a1_class === a_class[2]);
|
||||
|
||||
trace("/// b_class.insertAt(-3, new Subclass());");
|
||||
trace(b_class.insertAt(-3, new Subclass()));
|
||||
|
||||
trace("/// (contents of b_class...)");
|
||||
trace_vector(b_class);
|
||||
|
||||
function trace_vector_int(v: Vector.<int>) {
|
||||
trace(v.length, "elements");
|
||||
for (var i = 0; i < v.length; i += 1) {
|
||||
trace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
trace("/// var a_int: Vector.<int> = new <int>[1,2];");
|
||||
var a_int:Vector.<int> = new <int>[1,2];
|
||||
|
||||
trace("/// var b_int: Vector.<int> = new <int>[5,16];");
|
||||
var b_int:Vector.<int> = new <int>[5,16];
|
||||
|
||||
trace("/// a_int.insertAt(1, 3);");
|
||||
trace(a_int.insertAt(1, 3));
|
||||
|
||||
trace("/// (contents of a_int)...");
|
||||
trace_vector_int(a_int);
|
||||
|
||||
trace("/// a_int.insertAt(6, 4);");
|
||||
trace(a_int.insertAt(6, 4));
|
||||
|
||||
trace("/// (contents of a_int)...");
|
||||
trace_vector_int(a_int);
|
||||
|
||||
trace("/// b_int.insertAt(-5, 3);");
|
||||
trace(b_int.insertAt(-5, 3));
|
||||
|
||||
trace("/// (contents of b_int)...");
|
||||
trace_vector_int(b_int);
|
||||
|
||||
trace("/// b_int.insertAt(-1, 3);");
|
||||
trace(b_int.insertAt(-1, 3));
|
||||
|
||||
trace("/// (contents of b_int)...");
|
||||
trace_vector_int(b_int);
|
||||
|
||||
function trace_vector_number(v: Vector.<Number>) {
|
||||
trace(v.length, "elements");
|
||||
for (var i = 0; i < v.length; i += 1) {
|
||||
trace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
trace("/// var a_number: Vector.<Number> = new <Number>[1,2,3,4];");
|
||||
var a_number:Vector.<Number> = new <Number>[1,2,3,4];
|
||||
|
||||
trace("/// var b_number: Vector.<Number> = new <Number>[5, NaN, -5, 0];");
|
||||
var b_number:Vector.<Number> = new <Number>[5, NaN, -5, 0];
|
||||
|
||||
trace("/// a_number.insertAt(1, 5);");
|
||||
trace(a_number.insertAt(1, 5));
|
||||
|
||||
trace("/// (contents of a_number...)");
|
||||
trace_vector_number(a_number);
|
||||
|
||||
trace("/// a_number.insertAt(9, 6);");
|
||||
trace(a_number.insertAt(9, 6));
|
||||
|
||||
trace("/// (contents of a_number...)");
|
||||
trace_vector_number(a_number);
|
||||
|
||||
trace("/// b_number.insertAt(-4, 23);");
|
||||
trace(b_number.insertAt(-4, 23));
|
||||
|
||||
trace("/// (contents of b_number...)");
|
||||
trace_vector_number(b_number);
|
||||
|
||||
trace("/// b_number.insertAt(-8, 99);");
|
||||
trace(b_number.insertAt(-8, 99));
|
||||
|
||||
trace("/// (contents of b_number...)");
|
||||
trace_vector_number(b_number);
|
||||
|
||||
function trace_vector_string(v: Vector.<String>) {
|
||||
trace(v.length, "elements");
|
||||
for (var i = 0; i < v.length; i += 1) {
|
||||
trace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
trace("/// var a_string: Vector.<String> = new <String>[\"a\",\"c\",\"d\",\"f\"];");
|
||||
var a_string:Vector.<String> = new <String>["a", "c", "d", "f"];
|
||||
|
||||
trace("/// var b_string: Vector.<String> = new <String>[\"986\",\"B4\",\"Q\",\"rrr\"];");
|
||||
var b_string:Vector.<String> = new <String>["986", "B4", "Q", "rrr"];
|
||||
|
||||
trace("/// a_string.insertAt(1, \"g\");");
|
||||
trace(a_string.insertAt(1, "g"));
|
||||
|
||||
trace("/// (contents of a_string...)");
|
||||
trace_vector_string(a_string);
|
||||
|
||||
trace("/// a_string.insertAt(8, \"h\");");
|
||||
trace(a_string.insertAt(8, "h"));
|
||||
|
||||
trace("/// (contents of a_string...)");
|
||||
trace_vector_string(a_string);
|
||||
|
||||
trace("/// b_string.insertAt(-9, \"i\");");
|
||||
trace(b_string.insertAt(-9, "i"));
|
||||
|
||||
trace("/// (contents of b_string...)");
|
||||
trace_vector_string(b_string);
|
||||
|
||||
trace("/// b_string.insertAt(-2, \"j\");");
|
||||
trace(b_string.insertAt(-2, "j"));
|
||||
|
||||
trace("/// (contents of b_string...)");
|
||||
trace_vector_string(b_string);
|
||||
|
||||
function trace_vector_uint(v: Vector.<uint>) {
|
||||
trace(v.length, "elements");
|
||||
for (var i = 0; i < v.length; i += 1) {
|
||||
trace(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
trace("/// var a_uint: Vector.<uint> = new <uint>[1,2];");
|
||||
var a_uint:Vector.<uint> = new <uint>[1,2];
|
||||
|
||||
trace("/// var b_uint: Vector.<uint> = new <uint>[5,16];");
|
||||
var b_uint:Vector.<uint> = new <uint>[5,16];
|
||||
|
||||
trace("/// a_uint.insertAt(1, 4);");
|
||||
trace(a_uint.insertAt(1, 4));
|
||||
|
||||
trace("/// (contents of a_uint...)");
|
||||
trace_vector_uint(a_uint);
|
||||
|
||||
trace("/// a_uint.insertAt(6, -4);");
|
||||
trace(a_uint.insertAt(6, -4));
|
||||
|
||||
trace("/// (contents of a_uint...)");
|
||||
trace_vector_uint(a_uint);
|
||||
|
||||
trace("/// b_uint.insertAt(-8, 9);");
|
||||
trace(b_uint.insertAt(-8, 9));
|
||||
|
||||
trace("/// (contents of b_uint...)");
|
||||
trace_vector_uint(b_uint);
|
||||
|
||||
trace("/// b_uint.insertAt(-2, 93);");
|
||||
trace(b_uint.insertAt(-2, 93));
|
||||
|
||||
trace("/// (contents of b_uint...)");
|
||||
trace_vector_uint(b_uint);
|
||||
|
||||
function trace_vector_vector(v) {
|
||||
trace(v.length, "elements");
|
||||
for (var i = 0; i < v.length; i += 1) {
|
||||
if (v[i] is Vector.<int>) {
|
||||
trace("/// (contents of index", i, ")");
|
||||
trace_vector_vector(v[i]);
|
||||
} else {
|
||||
trace(v[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trace("/// var a_vector:Vector.<Vector.<int>> = new <Vector.<int>>[new <int>[1,2], new <int>[4,3]];");
|
||||
var a_vector:Vector.<Vector.<int>> = new <Vector.<int>>[new <int>[1,2], new <int>[4,3]];
|
||||
|
||||
trace("/// var b_vector:Vector.<Vector.<int>> = new <Vector.<int>>[new <int>[5,16], new <int>[19,8]];");
|
||||
var b_vector:Vector.<Vector.<int>> = new <Vector.<int>>[new <int>[5,16], new <int>[19,8]];
|
||||
|
||||
trace("/// a_vector.insertAt(1, new <int>[5,6]);");
|
||||
trace(a_vector.insertAt(1, new <int>[5,6]));
|
||||
|
||||
trace("/// (contents of a_vector...)");
|
||||
trace_vector_vector(a_vector);
|
||||
|
||||
trace("/// a_vector.insertAt(5, new <int>[8,9]);");
|
||||
trace(a_vector.insertAt(5, new <int>[8,9]));
|
||||
|
||||
trace("/// (contents of a_vector...)");
|
||||
trace_vector_vector(a_vector);
|
||||
|
||||
trace("/// b_vector.insertAt(-6, new <int>[10,11]);");
|
||||
trace(b_vector.insertAt(-6, new <int>[10,11]));
|
||||
|
||||
trace("/// (contents of b_vector...)");
|
||||
trace_vector_vector(b_vector);
|
||||
|
||||
trace("/// b_vector.insertAt(-2, new <int>[12,13]);");
|
||||
trace(b_vector.insertAt(-2, new <int>[12,13]));
|
||||
|
||||
trace("/// (contents of b_vector...)");
|
||||
trace_vector_vector(b_vector);
|
|
@ -0,0 +1,270 @@
|
|||
/// var a_bool: Vector.<Boolean> = new <Boolean>[true, false];
|
||||
/// var b_bool: Vector.<Boolean> = new <Boolean>[false, true, false];
|
||||
/// a_bool.insertAt(3, false);
|
||||
undefined
|
||||
/// (contents of a_bool...)
|
||||
3 elements
|
||||
true
|
||||
false
|
||||
false
|
||||
/// a_bool.insertAt(0, false);
|
||||
undefined
|
||||
/// (contents of a_bool...)
|
||||
4 elements
|
||||
false
|
||||
true
|
||||
false
|
||||
false
|
||||
/// b_bool.insertAt(-2, false);
|
||||
undefined
|
||||
/// (contents of b_bool...)
|
||||
4 elements
|
||||
false
|
||||
false
|
||||
true
|
||||
false
|
||||
/// b_bool.insertAt(-5, false);
|
||||
undefined
|
||||
/// (contents of b_bool...)
|
||||
5 elements
|
||||
false
|
||||
false
|
||||
false
|
||||
true
|
||||
false
|
||||
/// var a0_class = new Superclass();
|
||||
/// var a1_class = new Subclass();
|
||||
/// var a_class: Vector.<Superclass> = new <Superclass>[a0_class, a1_class];
|
||||
/// var b_class: Vector.<Subclass> = new <Subclass>[];
|
||||
/// b_class.length = 1;
|
||||
/// b_class[0] = new Subclass();
|
||||
/// a_class.insertAt(0, new Subclass());
|
||||
undefined
|
||||
/// a0_class === a_class[1];
|
||||
true
|
||||
/// a1_class === a_class[2];
|
||||
true
|
||||
/// b_class.insertAt(-3, new Subclass());
|
||||
undefined
|
||||
/// (contents of b_class...)
|
||||
2 elements
|
||||
[object Subclass]
|
||||
[object Subclass]
|
||||
/// var a_int: Vector.<int> = new <int>[1,2];
|
||||
/// var b_int: Vector.<int> = new <int>[5,16];
|
||||
/// a_int.insertAt(1, 3);
|
||||
undefined
|
||||
/// (contents of a_int)...
|
||||
3 elements
|
||||
1
|
||||
3
|
||||
2
|
||||
/// a_int.insertAt(6, 4);
|
||||
undefined
|
||||
/// (contents of a_int)...
|
||||
4 elements
|
||||
1
|
||||
3
|
||||
2
|
||||
4
|
||||
/// b_int.insertAt(-5, 3);
|
||||
undefined
|
||||
/// (contents of b_int)...
|
||||
3 elements
|
||||
3
|
||||
5
|
||||
16
|
||||
/// b_int.insertAt(-1, 3);
|
||||
undefined
|
||||
/// (contents of b_int)...
|
||||
4 elements
|
||||
3
|
||||
5
|
||||
3
|
||||
16
|
||||
/// var a_number: Vector.<Number> = new <Number>[1,2,3,4];
|
||||
/// var b_number: Vector.<Number> = new <Number>[5, NaN, -5, 0];
|
||||
/// a_number.insertAt(1, 5);
|
||||
undefined
|
||||
/// (contents of a_number...)
|
||||
5 elements
|
||||
1
|
||||
5
|
||||
2
|
||||
3
|
||||
4
|
||||
/// a_number.insertAt(9, 6);
|
||||
undefined
|
||||
/// (contents of a_number...)
|
||||
6 elements
|
||||
1
|
||||
5
|
||||
2
|
||||
3
|
||||
4
|
||||
6
|
||||
/// b_number.insertAt(-4, 23);
|
||||
undefined
|
||||
/// (contents of b_number...)
|
||||
5 elements
|
||||
23
|
||||
5
|
||||
NaN
|
||||
-5
|
||||
0
|
||||
/// b_number.insertAt(-8, 99);
|
||||
undefined
|
||||
/// (contents of b_number...)
|
||||
6 elements
|
||||
99
|
||||
23
|
||||
5
|
||||
NaN
|
||||
-5
|
||||
0
|
||||
/// var a_string: Vector.<String> = new <String>["a","c","d","f"];
|
||||
/// var b_string: Vector.<String> = new <String>["986","B4","Q","rrr"];
|
||||
/// a_string.insertAt(1, "g");
|
||||
undefined
|
||||
/// (contents of a_string...)
|
||||
5 elements
|
||||
a
|
||||
g
|
||||
c
|
||||
d
|
||||
f
|
||||
/// a_string.insertAt(8, "h");
|
||||
undefined
|
||||
/// (contents of a_string...)
|
||||
6 elements
|
||||
a
|
||||
g
|
||||
c
|
||||
d
|
||||
f
|
||||
h
|
||||
/// b_string.insertAt(-9, "i");
|
||||
undefined
|
||||
/// (contents of b_string...)
|
||||
5 elements
|
||||
i
|
||||
986
|
||||
B4
|
||||
Q
|
||||
rrr
|
||||
/// b_string.insertAt(-2, "j");
|
||||
undefined
|
||||
/// (contents of b_string...)
|
||||
6 elements
|
||||
i
|
||||
986
|
||||
B4
|
||||
j
|
||||
Q
|
||||
rrr
|
||||
/// var a_uint: Vector.<uint> = new <uint>[1,2];
|
||||
/// var b_uint: Vector.<uint> = new <uint>[5,16];
|
||||
/// a_uint.insertAt(1, 4);
|
||||
undefined
|
||||
/// (contents of a_uint...)
|
||||
3 elements
|
||||
1
|
||||
4
|
||||
2
|
||||
/// a_uint.insertAt(6, -4);
|
||||
undefined
|
||||
/// (contents of a_uint...)
|
||||
4 elements
|
||||
1
|
||||
4
|
||||
2
|
||||
4294967292
|
||||
/// b_uint.insertAt(-8, 9);
|
||||
undefined
|
||||
/// (contents of b_uint...)
|
||||
3 elements
|
||||
9
|
||||
5
|
||||
16
|
||||
/// b_uint.insertAt(-2, 93);
|
||||
undefined
|
||||
/// (contents of b_uint...)
|
||||
4 elements
|
||||
9
|
||||
93
|
||||
5
|
||||
16
|
||||
/// var a_vector:Vector.<Vector.<int>> = new <Vector.<int>>[new <int>[1,2], new <int>[4,3]];
|
||||
/// var b_vector:Vector.<Vector.<int>> = new <Vector.<int>>[new <int>[5,16], new <int>[19,8]];
|
||||
/// a_vector.insertAt(1, new <int>[5,6]);
|
||||
undefined
|
||||
/// (contents of a_vector...)
|
||||
3 elements
|
||||
/// (contents of index 0 )
|
||||
2 elements
|
||||
1
|
||||
2
|
||||
/// (contents of index 1 )
|
||||
2 elements
|
||||
5
|
||||
6
|
||||
/// (contents of index 2 )
|
||||
2 elements
|
||||
4
|
||||
3
|
||||
/// a_vector.insertAt(5, new <int>[8,9]);
|
||||
undefined
|
||||
/// (contents of a_vector...)
|
||||
4 elements
|
||||
/// (contents of index 0 )
|
||||
2 elements
|
||||
1
|
||||
2
|
||||
/// (contents of index 1 )
|
||||
2 elements
|
||||
5
|
||||
6
|
||||
/// (contents of index 2 )
|
||||
2 elements
|
||||
4
|
||||
3
|
||||
/// (contents of index 3 )
|
||||
2 elements
|
||||
8
|
||||
9
|
||||
/// b_vector.insertAt(-6, new <int>[10,11]);
|
||||
undefined
|
||||
/// (contents of b_vector...)
|
||||
3 elements
|
||||
/// (contents of index 0 )
|
||||
2 elements
|
||||
10
|
||||
11
|
||||
/// (contents of index 1 )
|
||||
2 elements
|
||||
5
|
||||
16
|
||||
/// (contents of index 2 )
|
||||
2 elements
|
||||
19
|
||||
8
|
||||
/// b_vector.insertAt(-2, new <int>[12,13]);
|
||||
undefined
|
||||
/// (contents of b_vector...)
|
||||
4 elements
|
||||
/// (contents of index 0 )
|
||||
2 elements
|
||||
10
|
||||
11
|
||||
/// (contents of index 1 )
|
||||
2 elements
|
||||
12
|
||||
13
|
||||
/// (contents of index 2 )
|
||||
2 elements
|
||||
5
|
||||
16
|
||||
/// (contents of index 3 )
|
||||
2 elements
|
||||
19
|
||||
8
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue