1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 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.arrays; 27 28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 29 30 import jdk.nashorn.api.scripting.ScriptObjectMirror; 31 import jdk.nashorn.internal.runtime.Context; 32 import jdk.nashorn.internal.runtime.ScriptFunction; 33 import jdk.nashorn.internal.runtime.ScriptRuntime; 34 35 /** 36 * Helper class for the various map/apply functions in {@link jdk.nashorn.internal.objects.NativeArray}. 37 * @param <T> element type of results from application callback 38 */ 39 public abstract class IteratorAction<T> { 40 /** Self object */ 41 protected final Object self; 42 43 /** This for the callback invocation */ 44 protected Object thisArg; 45 46 /** Callback function to be applied to elements */ 47 protected final Object callbackfn; 48 49 /** Result of array iteration */ 50 protected T result; 51 52 /** Current array index of iterator */ 53 protected long index; 54 55 /** Iterator object */ 56 private final ArrayLikeIterator<Object> iter; 57 58 /** 59 * Constructor 60 * 61 * @param self self reference to array object 62 * @param callbackfn callback function for each element 63 * @param thisArg the reference 64 * @param initialResult result accumulator initialization 65 */ 66 public IteratorAction(final Object self, final Object callbackfn, final Object thisArg, final T initialResult) { 67 this(self, callbackfn, thisArg, initialResult, ArrayLikeIterator.arrayLikeIterator(self)); 68 } 69 70 /** 71 * Constructor 72 * 73 * @param self self reference to array object 74 * @param callbackfn callback function for each element 75 * @param thisArg the reference 76 * @param initialResult result accumulator initialization 77 * @param iter custom element iterator 78 */ 79 public IteratorAction(final Object self, final Object callbackfn, final Object thisArg, final T initialResult, final ArrayLikeIterator<Object> iter) { 80 this.self = self; 81 this.callbackfn = callbackfn; 82 this.result = initialResult; 83 this.iter = iter; 84 this.thisArg = thisArg; 85 } 86 87 /** 88 * An action to be performed once at the start of the apply loop 89 * @param iterator array element iterator 90 */ 91 protected void applyLoopBegin(final ArrayLikeIterator<Object> iterator) { 92 //empty 93 } 94 95 /** 96 * Apply action main loop. 97 * @return result of apply 98 */ 99 public final T apply() { 100 final boolean strict; 101 if (callbackfn instanceof ScriptFunction) { 102 strict = ((ScriptFunction)callbackfn).isStrict(); 103 } else if (callbackfn instanceof ScriptObjectMirror && 104 ((ScriptObjectMirror)callbackfn).isFunction()) { 105 strict = ((ScriptObjectMirror)callbackfn).isStrictFunction(); 106 } else { 107 throw typeError("not.a.function", ScriptRuntime.safeToString(callbackfn)); 108 } 109 110 // for non-strict callback, need to translate undefined thisArg to be global object 111 thisArg = (thisArg == ScriptRuntime.UNDEFINED && !strict)? Context.getGlobal() : thisArg; 112 113 applyLoopBegin(iter); 114 final boolean reverse = iter.isReverse(); 115 while (iter.hasNext()) { 116 117 final Object val = iter.next(); 118 index = iter.nextIndex() + (reverse ? 1 : -1); 119 120 try { 121 if (!forEach(val, index)) { 122 return result; 123 } 124 } catch (final RuntimeException | Error e) { 125 throw e; 126 } catch (final Throwable t) { 127 throw new RuntimeException(t); 128 } 129 } 130 131 return result; 132 } 133 134 /** 135 * For each callback 136 * 137 * @param val value 138 * @param i position of value 139 * 140 * @return true if callback invocation return true 141 * 142 * @throws Throwable if invocation throws an exception/error 143 */ 144 protected abstract boolean forEach(final Object val, final long i) throws Throwable; 145 146 }