/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.nashorn.internal.runtime.arrays;

import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;

Array index computation helpers. that both throw exceptions or return invalid values.
/** * Array index computation helpers. that both throw exceptions or return * invalid values. * */
public final class ArrayIndex { private static final int INVALID_ARRAY_INDEX = -1; private static final long MAX_ARRAY_INDEX = 0xfffffffeL; private ArrayIndex() { }
Fast conversion of non-negative integer string to long.
Params:
  • key – Key as a string.
Returns:long value of string or -1 if string does not represent a valid index.
/** * Fast conversion of non-negative integer string to long. * @param key Key as a string. * @return long value of string or {@code -1} if string does not represent a valid index. */
private static long fromString(final String key) { long value = 0; final int length = key.length(); // Check for empty string or leading 0 if (length == 0 || (length > 1 && key.charAt(0) == '0')) { return INVALID_ARRAY_INDEX; } // Fast toNumber. for (int i = 0; i < length; i++) { final char digit = key.charAt(i); // If not a digit. if (digit < '0' || digit > '9') { return INVALID_ARRAY_INDEX; } // Insert digit. value = value * 10 + digit - '0'; // Check for overflow (need to catch before wrap around.) if (value > MAX_ARRAY_INDEX) { return INVALID_ARRAY_INDEX; } } return value; }
Returns a valid array index in an int, if the object represents one. This routine needs to perform quickly since all keys are tested with it.

The key parameter must be a JavaScript primitive type, i.e. one of String, Number, Boolean, null, or undefined. ScriptObject instances should be converted to primitive with String.class hint before being passed to this method.

Params:
  • key – key to check for array index.
Returns:the array index, or -1 if key does not represent a valid index. Note that negative return values other than -1 are considered valid and can be converted to the actual index using toLongIndex(int).
/** * Returns a valid array index in an int, if the object represents one. This * routine needs to perform quickly since all keys are tested with it. * * <p>The {@code key} parameter must be a JavaScript primitive type, i.e. one of * {@code String}, {@code Number}, {@code Boolean}, {@code null}, or {@code undefined}. * {@code ScriptObject} instances should be converted to primitive with * {@code String.class} hint before being passed to this method.</p> * * @param key key to check for array index. * @return the array index, or {@code -1} if {@code key} does not represent a valid index. * Note that negative return values other than {@code -1} are considered valid and can be converted to * the actual index using {@link #toLongIndex(int)}. */
public static int getArrayIndex(final Object key) { if (key instanceof Integer) { return getArrayIndex(((Integer) key).intValue()); } else if (key instanceof Double) { return getArrayIndex(((Double) key).doubleValue()); } else if (key instanceof String) { return (int)fromString((String) key); } else if (key instanceof Long) { return getArrayIndex(((Long) key).longValue()); } else if (key instanceof ConsString) { return (int)fromString(key.toString()); } assert !(key instanceof ScriptObject); return INVALID_ARRAY_INDEX; }
Returns a valid array index in an int, if key represents one.
Params:
  • key – key to check
Returns:the array index, or -1 if key is not a valid array index.
/** * Returns a valid array index in an int, if {@code key} represents one. * * @param key key to check * @return the array index, or {@code -1} if {@code key} is not a valid array index. */
public static int getArrayIndex(final int key) { return (key >= 0) ? key : INVALID_ARRAY_INDEX; }
Returns a valid array index in an int, if the long represents one.
Params:
  • key – key to check
Returns:the array index, or -1 if long is not a valid array index. Note that negative return values other than -1 are considered valid and can be converted to the actual index using toLongIndex(int).
/** * Returns a valid array index in an int, if the long represents one. * * @param key key to check * @return the array index, or {@code -1} if long is not a valid array index. * Note that negative return values other than {@code -1} are considered valid and can be converted to * the actual index using {@link #toLongIndex(int)}. */
public static int getArrayIndex(final long key) { if (key >= 0 && key <= MAX_ARRAY_INDEX) { return (int)key; } return INVALID_ARRAY_INDEX; }
Return a valid index for this double, if it represents one. Doubles that aren't representable exactly as longs/ints aren't working array indexes, however, array[1.1] === array["1.1"] in JavaScript.
Params:
  • key – the key to check
Returns:the array index this double represents or -1 if this isn't a valid index. Note that negative return values other than -1 are considered valid and can be converted to the actual index using toLongIndex(int).
/** * Return a valid index for this double, if it represents one. * * Doubles that aren't representable exactly as longs/ints aren't working * array indexes, however, array[1.1] === array["1.1"] in JavaScript. * * @param key the key to check * @return the array index this double represents or {@code -1} if this isn't a valid index. * Note that negative return values other than {@code -1} are considered valid and can be converted to * the actual index using {@link #toLongIndex(int)}. */
public static int getArrayIndex(final double key) { if (JSType.isRepresentableAsInt(key)) { return getArrayIndex((int) key); } else if (JSType.isRepresentableAsLong(key)) { return getArrayIndex((long) key); } return INVALID_ARRAY_INDEX; }
Return a valid array index for this string, if it represents one.
Params:
  • key – the key to check
Returns:the array index this string represents or -1 if this isn't a valid index. Note that negative return values other than -1 are considered valid and can be converted to the actual index using toLongIndex(int).
/** * Return a valid array index for this string, if it represents one. * * @param key the key to check * @return the array index this string represents or {@code -1} if this isn't a valid index. * Note that negative return values other than {@code -1} are considered valid and can be converted to * the actual index using {@link #toLongIndex(int)}. */
public static int getArrayIndex(final String key) { return (int)fromString(key); }
Check whether an index is valid as an array index. This check only tests if it is the special "invalid array index" type, not if it is e.g. less than zero or corrupt in some other way
Params:
  • index – index to test
Returns:true if index is not the special invalid array index type
/** * Check whether an index is valid as an array index. This check only tests if * it is the special "invalid array index" type, not if it is e.g. less than zero * or corrupt in some other way * * @param index index to test * @return true if {@code index} is not the special invalid array index type */
public static boolean isValidArrayIndex(final int index) { return index != INVALID_ARRAY_INDEX; }
Convert an index to a long value. This basically amounts to converting it into a JSType.toUint32(int) uint32} as the maximum array index in JavaScript is 0xfffffffe
Params:
  • index – index to convert to long form
Returns:index as uint32 in a long
/** * Convert an index to a long value. This basically amounts to converting it into a * {@link JSType#toUint32(int)} uint32} as the maximum array index in JavaScript * is 0xfffffffe * * @param index index to convert to long form * @return index as uint32 in a long */
public static long toLongIndex(final int index) { return JSType.toUint32(index); }
Convert an index to a key string. This is the same as calling toLongIndex(int) and converting the result to String.
Params:
  • index – index to convert
Returns:index as string
/** * Convert an index to a key string. This is the same as calling {@link #toLongIndex(int)} * and converting the result to String. * * @param index index to convert * @return index as string */
public static String toKey(final int index) { return Long.toString(JSType.toUint32(index)); } }