Files
narya/src/as/com/threerings/util/ArrayUtil.as
T
Ray Greenwell 9ce195b99d Made the Comparator optional.
Match the coding style already present in file (use ii for loop counter..)


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4991 542714f4-19e9-0310-aa3c-eee0fc999fb1
2008-04-08 19:37:00 +00:00

223 lines
7.1 KiB
ActionScript

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.util {
/**
* Contains methods that should be in Array, but aren't. Additionally
* contains methods that understand the interfaces in this package.
* So, for example, removeFirst() understands Equalable and will remove
* an element that is equals() to the specified element, rather than just
* === (strictly equals) to the specified element.
*/
public class ArrayUtil
{
/**
* Creates a shallow copy of the array.
*
* @internal TODO: add support for copy ranges and deep copies?
*/
public static function copyOf (arr :Array) :Array
{
return arr.slice();
}
/**
* Sort the specified array according to natural order- all elements
* must implement Comparable or be null.
*/
public static function sort (arr :Array) :void
{
arr.sort(Comparators.COMPARABLE);
}
/**
* Perform a stable sort on the specified array.
* @param comp a function that takes two objects in the array and returns -1 if the first
* object should appear before the second in the container, 1 if it should appear after,
* and 0 if the order does not matter. If omitted, Comparators.COMPARABLE is used and
* the array elements should be Comparable objects.
*/
public static function stableSort (arr :Array, comp :Function = null) :void
{
if (comp == null) {
comp = Comparators.COMPARABLE;
}
// insertion sort implementation
var nn :int = arr.length;
for (var ii :int = 1; ii < nn; ii++) {
var val :* = arr[ii];
var jj :int = ii - 1;
for (; jj >= 0; jj--) {
var compVal :* = arr[jj];
if (comp(val, compVal) < 0) {
break;
}
arr[jj + 1] = compVal;
}
arr[jj + 1] = val;
}
}
/**
* Randomly shuffle the elements in the specified array.
*
* @param rando a random number generator to use, or null if you don't care.
*/
public static function shuffle (arr :Array, rando :Random = null) :void
{
var randFunc :Function = (rando != null) ? rando.nextInt :
function (n :int) :int {
return int(Math.random() * n);
};
// starting from the end of the list, repeatedly swap the element in
// question with a random element previous to it up to and including
// itself
for (var ii :int = arr.length - 1; ii > 0; ii--) {
var idx :int = randFunc(ii + 1);
var tmp :Object = arr[idx];
arr[idx] = arr[ii];
arr[ii] = tmp;
}
}
/**
* Returns the index of the first item in the array for which the predicate function
* returns true, or -1 if no such item was found. The predicate function should be of type:
* function (element :*) :Boolean { }
*
* @return the zero-based index of the matching element, or -1 if none found.
*/
public static function indexIf (arr :Array, predicate :Function) :int
{
if (arr != null) {
for (var ii :int = 0; ii < arr.length; ii++) {
if (predicate(arr[ii])) {
return ii;
}
}
}
return -1; // never found
}
/**
* Returns the first index of the supplied element in the array. Note that if the element
* implements Equalable, an element that is equals() will have its index returned, instead
* of requiring the search element to be === (strictly equal) to an element in the array
* like Array.indexOf().
*
* @return the zero-based index of the matching element, or -1 if none found.
*/
public static function indexOf (arr :Array, element :Object) :int
{
if (arr != null) {
for (var ii :int = 0; ii < arr.length; ii++) {
if (Util.equals(arr[ii], element)) {
return ii;
}
}
}
return -1; // never found
}
/**
* @return true if the specified element, or one that is Equalable.equals() to it, is
* contained in the array.
*/
public static function contains (arr :Array, element :Object) :Boolean
{
return (indexOf(arr, element) != -1);
}
/**
* Remove the first instance of the specified element from the array.
*
* @return true if an element was removed, false otherwise.
*/
public static function removeFirst (arr :Array, element :Object) :Boolean
{
return removeImpl(arr, element, true);
}
/**
* Remove the last instance of the specified element from the array.
*
* @return true if an element was removed, false otherwise.
*/
public static function removeLast (arr :Array, element :Object) :Boolean
{
arr.reverse();
var removed :Boolean = removeFirst(arr, element);
arr.reverse();
return removed;
}
/**
* Removes all instances of the specified element from the array.
*
* @return true if at least one element was removed, false otherwise.
*/
public static function removeAll (arr :Array, element :Object) :Boolean
{
return removeImpl(arr, element, false);
}
/**
* Do the two arrays contain elements that are all equals()?
*/
public static function equals (ar1 :Array, ar2 :Array) :Boolean
{
if (ar1 === ar2) {
return true;
} else if (ar1 == null || ar2 == null || ar1.length != ar2.length) {
return false;
}
for (var jj :int = 0; jj < ar1.length; jj++) {
if (!Util.equals(ar1[jj], ar2[jj])) {
return false;
}
}
return true;
}
/**
* Implementation of remove methods.
*/
private static function removeImpl (
arr :Array, element :Object, firstOnly :Boolean) :Boolean
{
var removed :Boolean = false;
for (var ii :int = 0; ii < arr.length; ii++) {
if (Util.equals(arr[ii], element)) {
arr.splice(ii--, 1);
if (firstOnly) {
return true;
}
removed = true;
}
}
return removed;
}
}
}