All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.stjs.javascript.Array Maven / Gradle / Ivy

/**
 *  Copyright 2011 Alexandru Craciun, Eyal Kaspi
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.stjs.javascript;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import org.stjs.javascript.annotation.ServerSide;
import org.stjs.javascript.annotation.Template;
import org.stjs.javascript.functions.Callback1;

/**
 * This interface represents an array from Javascript.The value may be typed. The iteration is done on the indexes to have the javascript
 * equivalent of 
* for(var key in array)
* The methods are prefixed with $ to let the generator know that is should generate braket access instead, i.e
* array.$get(key) => array[key]
* array.$set(key, value) => array[key]=value It is generally a bad idea for code written in ST-JS to create subclasses of Array, as that will * not be translated properly. However, it may be useful for some bridges. * @author acraciun */ public class Array implements Iterable { private final List array; public Array() { this(new ArrayList()); } private Array(List elements) { array = elements; } public Array(Number size) { this(); this.$length(size.intValue()); } @SuppressWarnings("unchecked") public Array(V first, V second, V... others) { this(); this.push(first); this.push(second); this.push(others); } /** * constructors used on the server side only. It only wraps the given list, no copy is done * @param list * @return */ @ServerSide public static Array wrap(List list) { return new Array(list); } /** * constructors used on the server side only. It copies the given parameter * @param list * @return */ @ServerSide public static Array copyOf(List list) { return new Array(new ArrayList(list)); } /** * this gives access to the java implementation. used on the server side only * @return */ @ServerSide public List java() { return array; } @Override public Iterator iterator() { return new Iterator() { private int current = 0; @Override public boolean hasNext() { return current < array.size(); } @Override public String next() { if (!hasNext()) { throw new NoSuchElementException(); } return Integer.toString(current++); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Template("get") public V $get(int index) { if (index < 0 || index >= array.size()) { return null; } return array.get(index); } @Template("get") public V $get(String index) { return $get(Integer.valueOf(index)); } @Template("set") public void $set(int index, V value) { if (index < 0) { return; } if (index >= array.size()) { $length(index + 1); } array.set(index, value); } @Template("set") public void $set(String index, V value) { $set(Integer.valueOf(index), value); } @Template("toProperty") public int $length() { return array.size(); } @Template("toProperty") public void $length(int newLength) { if (newLength < array.size()) { splice(newLength, array.size() - newLength); } else { while (array.size() < newLength) { array.add(null); } } } public Array concat(Array... arrays) { Array ret = new Array(); ret.array.addAll(this.array); for (Array a : arrays) { for (int i = 0; i < a.$length(); ++i) { ret.array.add(a.$get(i)); } } return ret; } public int indexOf(V element) { return array.indexOf(element); } public int indexOf(V element, int aStart) { int start = aStart >= 0 ? aStart : array.size() + aStart; if (start >= array.size()) { return -1; } int pos = array.subList(start, array.size()).indexOf(element); if (pos < 0) { return pos; } return pos + start; } public String join() { return join(","); } public String join(String separator) { StringBuilder sb = new StringBuilder(); for (V value : array) { if (sb.length() != 0) { sb.append(separator); } sb.append(value != null ? value.toString() : ""); } return sb.toString(); } public V pop() { if (array.size() == 0) { return null; } return array.remove(array.size() - 1); } public int push(V... values) { for (V value : values) { array.add(value); } return array.size(); } public Array reverse() { Collections.reverse(array); return this; } public V shift() { if (array.size() == 0) { return null; } return array.remove(0); } // If start is positive, use min(start, length). // If start is negative, use max(start + length, 0). // If end is positive, use min(end, length) // If end is negative, use max(end + length, 0) private int fixIndex(int idx) { if (idx >= 0) { return java.lang.Math.min(idx, array.size()); } return java.lang.Math.max(0, array.size() + idx); } public Array slice(int start) { return slice(fixIndex(start), array.size()); } public Array slice(int start, int end) { int s = fixIndex(start); int e = fixIndex(end); if (s > e) { return new Array(); } Array ret = new Array(); ret.array.addAll(array.subList(s, e)); return ret; } public Array splice(int start) { return splice(start, array.size() - start); } public Array splice(int start, int howMany) { int s = fixIndex(start); Array ret = new Array(); for (int i = 0; i < howMany; ++i) { if (s >= array.size()) { break; } ret.array.add(array.remove(s)); } return ret; } public Array splice(int start, int howMany, V... values) { int s = fixIndex(start); Array removed = splice(start, howMany); array.addAll(s, Arrays.asList(values)); return removed; } private SortFunction defaultSortFunction() { return new SortFunction() { @Override public int $invoke(V a, V b) { if (a == null) { return 1; } if (b == null) { return -1; } return a.toString().compareTo(b.toString()); } }; } public void sort() { sort(defaultSortFunction()); } public void sort(final SortFunction aFunction) { final SortFunction function = aFunction != null ? aFunction : defaultSortFunction(); Collections.sort(array, new Comparator() { @Override public int compare(V a, V b) { return function.$invoke(a, b); } }); } public int unshift(V... values) { array.addAll(0, Arrays.asList(values)); return array.size(); } public void forEach(Callback1 callback) { for (V value : array) { callback.$invoke(value); } } /** * this method does exactly as {@link #forEach(Callback1)}, but allows in java 8 the usage of lambda easily as the forEach method overloads * the method from the new Iterable interface. The generated code is, as expected, forEach * @param callback */ @Template("prefix") public void $forEach(Callback1 callback) { forEach(callback); } @Override public String toString() { // ArrayList.toString() look like this "[1, 2, 3, 4, 5]" (with spaces // between elements and enclosed in [] // but in Array.toString() must actually look like "1,2,3,4,5" (no spaces, // no []) StringBuilder builder = new StringBuilder(); boolean first = true; for (V item : array) { if (!first) { builder.append(","); } else { first = false; } if (item == null) { builder.append("null"); } else { builder.append(item.toString()); } } return builder.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy