src/jdk/nashorn/internal/runtime/ListAdapter.java

Print this page




  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