17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.runtime; 27 28 import java.util.AbstractList; 29 import java.util.Deque; 30 import java.util.Iterator; 31 import java.util.ListIterator; 32 import java.util.NoSuchElementException; 33 import java.util.RandomAccess; 34 import java.util.concurrent.Callable; 35 import jdk.nashorn.api.scripting.JSObject; 36 import jdk.nashorn.api.scripting.ScriptObjectMirror; 37 import jdk.nashorn.internal.runtime.linker.Bootstrap; 38 import jdk.nashorn.internal.runtime.linker.InvokeByName; 39 40 /** 41 * An adapter that can wrap any ECMAScript Array-like object (that adheres to the array rules for the property 42 * {@code length} and having conforming {@code push}, {@code pop}, {@code shift}, {@code unshift}, and {@code splice} 43 * methods) and expose it as both a Java list and double-ended queue. While script arrays aren't necessarily efficient 44 * as dequeues, it's still slightly more efficient to be able to translate dequeue operations into pushes, pops, shifts, 45 * and unshifts, than to blindly translate all list's add/remove operations into splices. Also, it is conceivable that a 46 * custom script object that implements an Array-like API can have a background data representation that is optimized 47 * for dequeue-like access. Note that with ECMAScript arrays, {@code push} and {@code pop} operate at the end of the 48 * array, while in Java {@code Deque} they operate on the front of the queue and as such the Java dequeue 49 * {@link #push(Object)} and {@link #pop()} operations will translate to {@code unshift} and {@code shift} script 50 * operations respectively, while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and 51 * {@code pop}. 52 */ 53 public abstract class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> { 54 // These add to the back and front of the list 55 private static final Object PUSH = new Object(); 56 private static InvokeByName getPUSH() { 57 return ((GlobalObject)Context.getGlobal()).getInvokeByName(PUSH, 58 new Callable<InvokeByName>() { 59 @Override 60 public InvokeByName call() { 61 return new InvokeByName("push", Object.class, void.class, Object.class); 62 } 63 }); 64 } 65 66 private static final Object UNSHIFT = new Object(); 67 private static InvokeByName getUNSHIFT() { 68 return ((GlobalObject)Context.getGlobal()).getInvokeByName(UNSHIFT, 69 new Callable<InvokeByName>() { 70 @Override 71 public InvokeByName call() { 72 return new InvokeByName("unshift", Object.class, void.class, Object.class); 73 } 74 }); 75 } 76 77 // These remove from the back and front of the list 78 private static final Object POP = new Object(); 79 private static InvokeByName getPOP() { 80 return ((GlobalObject)Context.getGlobal()).getInvokeByName(POP, 81 new Callable<InvokeByName>() { 82 @Override 83 public InvokeByName call() { 84 return new InvokeByName("pop", Object.class, Object.class); 85 } 86 }); 87 } 88 89 private static final Object SHIFT = new Object(); 90 private static InvokeByName getSHIFT() { 91 return ((GlobalObject)Context.getGlobal()).getInvokeByName(SHIFT, 92 new Callable<InvokeByName>() { 93 @Override 94 public InvokeByName call() { 95 return new InvokeByName("shift", Object.class, Object.class); 96 } 97 }); 98 } 99 100 // These insert and remove in the middle of the list 101 private static final Object SPLICE_ADD = new Object(); 102 private static InvokeByName getSPLICE_ADD() { 103 return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_ADD, 104 new Callable<InvokeByName>() { 105 @Override 106 public InvokeByName call() { 107 return new InvokeByName("splice", Object.class, void.class, int.class, int.class, Object.class); 108 } 109 }); 110 } 111 112 private static final Object SPLICE_REMOVE = new Object(); 113 private static InvokeByName getSPLICE_REMOVE() { 114 return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_REMOVE, 115 new Callable<InvokeByName>() { 116 @Override 117 public InvokeByName call() { 118 return new InvokeByName("splice", Object.class, void.class, int.class, int.class); 119 } 120 }); 121 } 122 123 /** wrapped object */ 124 protected final Object obj; 125 126 // allow subclasses only in this package 127 ListAdapter(final Object obj) { 128 this.obj = obj; 129 } 130 131 /** 132 * Factory to create a ListAdapter for a given script object. 133 * 134 * @param obj script object to wrap as a ListAdapter | 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.runtime; 27 28 import java.util.AbstractList; 29 import java.util.Deque; 30 import java.util.Iterator; 31 import java.util.ListIterator; 32 import java.util.NoSuchElementException; 33 import java.util.RandomAccess; 34 import java.util.concurrent.Callable; 35 import jdk.nashorn.api.scripting.JSObject; 36 import jdk.nashorn.api.scripting.ScriptObjectMirror; 37 import jdk.nashorn.internal.objects.Global; 38 import jdk.nashorn.internal.runtime.linker.Bootstrap; 39 import jdk.nashorn.internal.runtime.linker.InvokeByName; 40 41 /** 42 * An adapter that can wrap any ECMAScript Array-like object (that adheres to the array rules for the property 43 * {@code length} and having conforming {@code push}, {@code pop}, {@code shift}, {@code unshift}, and {@code splice} 44 * methods) and expose it as both a Java list and double-ended queue. While script arrays aren't necessarily efficient 45 * as dequeues, it's still slightly more efficient to be able to translate dequeue operations into pushes, pops, shifts, 46 * and unshifts, than to blindly translate all list's add/remove operations into splices. Also, it is conceivable that a 47 * custom script object that implements an Array-like API can have a background data representation that is optimized 48 * for dequeue-like access. Note that with ECMAScript arrays, {@code push} and {@code pop} operate at the end of the 49 * array, while in Java {@code Deque} they operate on the front of the queue and as such the Java dequeue 50 * {@link #push(Object)} and {@link #pop()} operations will translate to {@code unshift} and {@code shift} script 51 * operations respectively, while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and 52 * {@code pop}. 53 */ 54 public abstract class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> { 55 // These add to the back and front of the list 56 private static final Object PUSH = new Object(); 57 private static InvokeByName getPUSH() { 58 return Context.getGlobal().getInvokeByName(PUSH, 59 new Callable<InvokeByName>() { 60 @Override 61 public InvokeByName call() { 62 return new InvokeByName("push", Object.class, void.class, Object.class); 63 } 64 }); 65 } 66 67 private static final Object UNSHIFT = new Object(); 68 private static InvokeByName getUNSHIFT() { 69 return Context.getGlobal().getInvokeByName(UNSHIFT, 70 new Callable<InvokeByName>() { 71 @Override 72 public InvokeByName call() { 73 return new InvokeByName("unshift", Object.class, void.class, Object.class); 74 } 75 }); 76 } 77 78 // These remove from the back and front of the list 79 private static final Object POP = new Object(); 80 private static InvokeByName getPOP() { 81 return Context.getGlobal().getInvokeByName(POP, 82 new Callable<InvokeByName>() { 83 @Override 84 public InvokeByName call() { 85 return new InvokeByName("pop", Object.class, Object.class); 86 } 87 }); 88 } 89 90 private static final Object SHIFT = new Object(); 91 private static InvokeByName getSHIFT() { 92 return Context.getGlobal().getInvokeByName(SHIFT, 93 new Callable<InvokeByName>() { 94 @Override 95 public InvokeByName call() { 96 return new InvokeByName("shift", Object.class, Object.class); 97 } 98 }); 99 } 100 101 // These insert and remove in the middle of the list 102 private static final Object SPLICE_ADD = new Object(); 103 private static InvokeByName getSPLICE_ADD() { 104 return Context.getGlobal().getInvokeByName(SPLICE_ADD, 105 new Callable<InvokeByName>() { 106 @Override 107 public InvokeByName call() { 108 return new InvokeByName("splice", Object.class, void.class, int.class, int.class, Object.class); 109 } 110 }); 111 } 112 113 private static final Object SPLICE_REMOVE = new Object(); 114 private static InvokeByName getSPLICE_REMOVE() { 115 return Context.getGlobal().getInvokeByName(SPLICE_REMOVE, 116 new Callable<InvokeByName>() { 117 @Override 118 public InvokeByName call() { 119 return new InvokeByName("splice", Object.class, void.class, int.class, int.class); 120 } 121 }); 122 } 123 124 /** wrapped object */ 125 protected final Object obj; 126 127 // allow subclasses only in this package 128 ListAdapter(final Object obj) { 129 this.obj = obj; 130 } 131 132 /** 133 * Factory to create a ListAdapter for a given script object. 134 * 135 * @param obj script object to wrap as a ListAdapter |