50 * array, while in Java {@code Deque} they operate on the front of the queue and as such the Java dequeue |
50 * array, while in Java {@code Deque} they operate on the front of the queue and as such the Java dequeue |
51 * {@link #push(Object)} and {@link #pop()} operations will translate to {@code unshift} and {@code shift} script |
51 * {@link #push(Object)} and {@link #pop()} operations will translate to {@code unshift} and {@code shift} script |
52 * operations respectively, while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and |
52 * operations respectively, while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and |
53 * {@code pop}. |
53 * {@code pop}. |
54 */ |
54 */ |
55 public final class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> { |
55 public class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> { |
56 // Invoker creator for methods that add to the start or end of the list: PUSH and UNSHIFT. Takes fn, this, and value, returns void. |
56 // Invoker creator for methods that add to the start or end of the list: PUSH and UNSHIFT. Takes fn, this, and value, returns void. |
57 private static final Callable<MethodHandle> ADD_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, Object.class); |
57 private static final Callable<MethodHandle> ADD_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, Object.class); |
58 |
58 |
59 // PUSH adds to the start of the list |
59 // PUSH adds to the start of the list |
60 private static final Object PUSH = new Object(); |
60 private static final Object PUSH = new Object(); |
76 // SPLICE can also be used to remove values from the middle of the list. |
76 // SPLICE can also be used to remove values from the middle of the list. |
77 private static final Object SPLICE_REMOVE = new Object(); |
77 private static final Object SPLICE_REMOVE = new Object(); |
78 private static final Callable<MethodHandle> SPLICE_REMOVE_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, int.class, int.class); |
78 private static final Callable<MethodHandle> SPLICE_REMOVE_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, int.class, int.class); |
79 |
79 |
80 /** wrapped object */ |
80 /** wrapped object */ |
81 private final JSObject obj; |
81 final JSObject obj; |
82 private final Global global; |
82 private final Global global; |
83 |
83 |
84 // allow subclasses only in this package |
84 // allow subclasses only in this package |
85 ListAdapter(final JSObject obj) { |
85 ListAdapter(final JSObject obj, final Global global) { |
|
86 if (global == null) { |
|
87 throw new IllegalStateException(ECMAErrors.getMessage("list.adapter.null.global")); |
|
88 } |
|
89 |
86 this.obj = obj; |
90 this.obj = obj; |
87 this.global = getGlobalNonNull(); |
91 this.global = global; |
88 } |
|
89 |
|
90 private static Global getGlobalNonNull() { |
|
91 final Global global = Context.getGlobal(); |
|
92 if (global != null) { |
|
93 return global; |
|
94 } |
|
95 throw new IllegalStateException(ECMAErrors.getMessage("list.adapter.null.global")); |
|
96 } |
92 } |
97 |
93 |
98 /** |
94 /** |
99 * Factory to create a ListAdapter for a given script object. |
95 * Factory to create a ListAdapter for a given script object. |
100 * |
96 * |
101 * @param obj script object to wrap as a ListAdapter |
97 * @param obj script object to wrap as a ListAdapter |
102 * @return A ListAdapter wrapper object |
98 * @return A ListAdapter wrapper object |
103 */ |
99 */ |
104 public static ListAdapter create(final Object obj) { |
100 public static ListAdapter create(final Object obj) { |
105 return new ListAdapter(getJSObject(obj)); |
101 final Global global = Context.getGlobal(); |
106 } |
102 return new ListAdapter(getJSObject(obj, global), global); |
107 |
103 } |
108 private static JSObject getJSObject(final Object obj) { |
104 |
|
105 private static JSObject getJSObject(final Object obj, final Global global) { |
109 if (obj instanceof ScriptObject) { |
106 if (obj instanceof ScriptObject) { |
110 return (JSObject)ScriptObjectMirror.wrap(obj, Context.getGlobal()); |
107 return (JSObject)ScriptObjectMirror.wrap(obj, global); |
111 } else if (obj instanceof JSObject) { |
108 } else if (obj instanceof JSObject) { |
112 return (JSObject)obj; |
109 return (JSObject)obj; |
113 } |
110 } |
114 throw new IllegalArgumentException("ScriptObject or JSObject expected"); |
111 throw new IllegalArgumentException("ScriptObject or JSObject expected"); |
115 } |
112 } |