8023026: Array.prototype iterator functions like forEach, reduce should work for Java arrays, lists

Reviewed-by: jlaskey, lagergren
This commit is contained in:
Athijegannathan Sundararajan 2013-08-14 20:51:53 +05:30
parent bf29c2ec49
commit a28b8a61dc
11 changed files with 417 additions and 14 deletions

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime.arrays;
import java.util.Iterator;
import java.util.List;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
@ -49,7 +50,7 @@ abstract public class ArrayLikeIterator<T> implements Iterator<T> {
*
* @param includeUndefined should undefined elements be included in the iteration?
*/
protected ArrayLikeIterator(final boolean includeUndefined) {
ArrayLikeIterator(final boolean includeUndefined) {
this.includeUndefined = includeUndefined;
this.index = 0;
}
@ -118,18 +119,26 @@ abstract public class ArrayLikeIterator<T> implements Iterator<T> {
Object obj = object;
if (ScriptObject.isArray(obj)) {
return new ArrayIterator((ScriptObject) obj, includeUndefined);
return new ScriptArrayIterator((ScriptObject) obj, includeUndefined);
}
obj = JSType.toScriptObject(obj);
if (obj instanceof ScriptObject) {
return new MapIterator((ScriptObject)obj, includeUndefined);
return new ScriptObjectIterator((ScriptObject)obj, includeUndefined);
}
if (obj instanceof ScriptObjectMirror) {
return new ScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined);
}
if (obj instanceof List) {
return new JavaListIterator((List)obj, includeUndefined);
}
if (obj != null && obj.getClass().isArray()) {
return new JavaArrayIterator(obj, includeUndefined);
}
return new EmptyArrayLikeIterator();
}
@ -143,19 +152,25 @@ abstract public class ArrayLikeIterator<T> implements Iterator<T> {
Object obj = object;
if (ScriptObject.isArray(obj)) {
return new ReverseArrayIterator((ScriptObject) obj, includeUndefined);
return new ReverseScriptArrayIterator((ScriptObject) obj, includeUndefined);
}
obj = JSType.toScriptObject(obj);
if (obj instanceof ScriptObject) {
return new ReverseMapIterator((ScriptObject)obj, includeUndefined);
return new ReverseScriptObjectIterator((ScriptObject)obj, includeUndefined);
}
if (obj instanceof ScriptObjectMirror) {
return new ReverseScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined);
}
assert !obj.getClass().isArray();
if (obj instanceof List) {
return new ReverseJavaListIterator((List)obj, includeUndefined);
}
if (obj != null && obj.getClass().isArray()) {
return new ReverseJavaArrayIterator(obj, includeUndefined);
}
return new EmptyArrayLikeIterator();
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime.arrays;
import java.lang.reflect.Array;
/**
* Iterator over a Java List.
*/
class JavaArrayIterator extends ArrayLikeIterator<Object> {
/** Array to iterate over */
protected final Object array;
/** length of array */
protected final long length;
/**
* Constructor
* @param array array to iterate over
* @param includeUndefined should undefined elements be included in iteration
*/
protected JavaArrayIterator(final Object array, final boolean includeUndefined) {
super(includeUndefined);
assert array.getClass().isArray() : "expecting Java array object";
this.array = array;
this.length = Array.getLength(array);
}
/**
* Is the current index still inside the array
* @return true if inside the array
*/
protected boolean indexInArray() {
return index < length;
}
@Override
public Object next() {
return Array.get(array, (int)bumpIndex());
}
@Override
public long getLength() {
return length;
}
@Override
public boolean hasNext() {
return indexInArray();
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime.arrays;
import java.util.List;
/**
* Iterator over a Java List.
*/
class JavaListIterator extends ArrayLikeIterator<Object> {
/** {@link java.util.List} to iterate over */
protected final List<?> list;
/** length of array */
protected final long length;
/**
* Constructor
* @param list list to iterate over
* @param includeUndefined should undefined elements be included in iteration
*/
protected JavaListIterator(final List<?> list, final boolean includeUndefined) {
super(includeUndefined);
this.list = list;
this.length = list.size();
}
/**
* Is the current index still inside the array
* @return true if inside the array
*/
protected boolean indexInArray() {
return index < length;
}
@Override
public Object next() {
return list.get((int)bumpIndex());
}
@Override
public long getLength() {
return length;
}
@Override
public boolean hasNext() {
return indexInArray();
}
@Override
public void remove() {
list.remove(index);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime.arrays;
import java.lang.reflect.Array;
/**
* Reverse iterator over a array
*/
final class ReverseJavaArrayIterator extends JavaArrayIterator {
/**
* Constructor
* @param array array to iterate over
* @param includeUndefined should undefined elements be included in iteration
*/
public ReverseJavaArrayIterator(final Object array, final boolean includeUndefined) {
super(array, includeUndefined);
this.index = Array.getLength(array) - 1;
}
@Override
public boolean isReverse() {
return true;
}
@Override
protected boolean indexInArray() {
return index >= 0;
}
@Override
protected long bumpIndex() {
return index--;
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime.arrays;
import java.util.List;
/**
* Reverse iterator over a List
*/
final class ReverseJavaListIterator extends JavaListIterator {
/**
* Constructor
* @param list list to iterate over
* @param includeUndefined should undefined elements be included in iteration
*/
public ReverseJavaListIterator(final List<?> list, final boolean includeUndefined) {
super(list, includeUndefined);
this.index = list.size() - 1;
}
@Override
public boolean isReverse() {
return true;
}
@Override
protected boolean indexInArray() {
return index >= 0;
}
@Override
protected long bumpIndex() {
return index--;
}
}

View File

@ -30,14 +30,14 @@ import jdk.nashorn.internal.runtime.ScriptObject;
/**
* Reverse iterator over a NativeArray
*/
final class ReverseArrayIterator extends ArrayIterator {
final class ReverseScriptArrayIterator extends ScriptArrayIterator {
/**
* Constructor
* @param array array to iterate over
* @param includeUndefined should undefined elements be included in iteration
*/
public ReverseArrayIterator(final ScriptObject array, final boolean includeUndefined) {
public ReverseScriptArrayIterator(final ScriptObject array, final boolean includeUndefined) {
super(array, includeUndefined);
this.index = array.getArray().length() - 1;
}

View File

@ -31,9 +31,9 @@ import jdk.nashorn.internal.runtime.ScriptObject;
/**
* Reverse iterator over a map
*/
final class ReverseMapIterator extends MapIterator {
final class ReverseScriptObjectIterator extends ScriptObjectIterator {
ReverseMapIterator(final ScriptObject obj, final boolean includeUndefined) {
ReverseScriptObjectIterator(final ScriptObject obj, final boolean includeUndefined) {
super(obj, includeUndefined);
this.index = JSType.toUint32(obj.getLength()) - 1;
}

View File

@ -30,7 +30,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
/**
* Iterator over a NativeArray
*/
class ArrayIterator extends ArrayLikeIterator<Object> {
class ScriptArrayIterator extends ArrayLikeIterator<Object> {
/** Array {@link ScriptObject} to iterate over */
protected final ScriptObject array;
@ -43,7 +43,7 @@ class ArrayIterator extends ArrayLikeIterator<Object> {
* @param array array to iterate over
* @param includeUndefined should undefined elements be included in iteration
*/
protected ArrayIterator(final ScriptObject array, final boolean includeUndefined) {
protected ScriptArrayIterator(final ScriptObject array, final boolean includeUndefined) {
super(includeUndefined);
this.array = array;
this.length = array.getArray().length();

View File

@ -32,12 +32,12 @@ import jdk.nashorn.internal.runtime.ScriptObject;
/**
* Iterator over a map
*/
class MapIterator extends ArrayLikeIterator<Object> {
class ScriptObjectIterator extends ArrayLikeIterator<Object> {
protected final ScriptObject obj;
private final long length;
MapIterator(final ScriptObject obj, final boolean includeUndefined) {
ScriptObjectIterator(final ScriptObject obj, final boolean includeUndefined) {
super(includeUndefined);
this.obj = obj;
this.length = JSType.toUint32(obj.getLength());

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8023026: Array.prototype iterator functions like forEach, reduce should work for Java arrays, lists
*
* @test
* @run
*/
function checkIterations(obj) {
if (typeof obj.getClass == 'function') {
print("iterating on an object of " + obj.getClass());
} else {
print("iterating on " + String(obj));
}
Array.prototype.forEach.call(obj,
function(x) { print("forEach " + x); });
print("left sum " + Array.prototype.reduce.call(obj,
function(x, y) { print("reduce", x, y); return x + y; }));
print("right sum " + Array.prototype.reduceRight.call(obj,
function(x, y) { print("reduceRight", x, y); return x + y; }));
print("squared " + Array.prototype.map.call(obj,
function(x) x*x));
}
var array = new (Java.type("[I"))(4);
for (var i in array) {
array[i] = i;
}
checkIterations(array);
var list = new java.util.ArrayList();
list.add(1);
list.add(3);
list.add(5);
list.add(7);
checkIterations(list);
var mirror = loadWithNewGlobal({
name: "test",
script: "[2, 4, 6, 8]"
});
checkIterations(mirror);

View File

@ -0,0 +1,42 @@
iterating on an object of class [I
forEach 0
forEach 1
forEach 2
forEach 3
reduce 0 1
reduce 1 2
reduce 3 3
left sum 6
reduceRight 3 2
reduceRight 5 1
reduceRight 6 0
right sum 6
squared 0,1,4,9
iterating on an object of class java.util.ArrayList
forEach 1
forEach 3
forEach 5
forEach 7
reduce 1 3
reduce 4 5
reduce 9 7
left sum 16
reduceRight 7 5
reduceRight 12 3
reduceRight 15 1
right sum 16
squared 1,9,25,49
iterating on [object Array]
forEach 2
forEach 4
forEach 6
forEach 8
reduce 2 4
reduce 6 6
reduce 12 8
left sum 20
reduceRight 8 6
reduceRight 14 4
reduceRight 18 2
right sum 20
squared 4,16,36,64