Files
narya/src/as/com/threerings/util/RingBuffer.as
T
Tom Conkling 6dee96bb15 use Function.call(), not Function.apply()
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4941 542714f4-19e9-0310-aa3c-eee0fc999fb1
2008-02-20 00:55:28 +00:00

227 lines
6.6 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 {
public class RingBuffer
{
/** Creates a new RingBuffer with the specified capacity. */
public function RingBuffer (capacity :uint = 1)
{
_capacity = capacity;
_array.length = _capacity;
}
/** Returns the capacity of the RingBuffer. */
public function get capacity () :uint
{
return _capacity;
}
/**
* Sets the capacity of the RingBuffer.
* If the new capacity is less than the RingBuffer's length,
* elements will be removed from the end of the RingBuffer
* to accommodate the smaller capacity.
*/
public function set capacity (newCapacity :uint) :void
{
// Copy all the elements to a new array.
var newArray :Array = new Array();
var newLength :uint = Math.min(_length, newCapacity);
newArray.length = newCapacity;
for (var i :uint = 0; i < newLength; ++i) {
newArray[i] = this.at(i);
}
_capacity = newCapacity;
_length = newLength;
_array = newArray;
_firstIndex = 0;
}
/** Returns the number of elements currently stored in the RingBuffer. */
public function get length () :uint
{
return _length;
}
/** Returns true if the RingBuffer contains 0 elements. */
public function get empty () :Boolean
{
return (0 == _length);
}
/**
* Adds the specified elements to the front of the RingBuffer.
* If the RingBuffer's length is equal to its capacity, this
* will cause elements to be removed from the back of
* the RingBuffer.
* Returns the new length of the RingBuffer.
*/
public function unshift (...args) :uint
{
for (var i :int = args.length - 1; i >= 0; --i) {
var index :uint = (_firstIndex > 0 ? _firstIndex - 1 : _capacity - 1);
_array[index] = args[i];
_length = Math.min(_length + 1, _capacity);
_firstIndex = index;
}
return _length;
}
/**
* Adds the specified elements to the back of the RingBuffer.
* If the RingBuffer's length is equal to its capacity, this
* will cause a elements to be removed from the front of
* the RingBuffer.
* Returns the new length of the RingBuffer.
*/
public function push (...args) :uint
{
for (var i :uint = 0; i < args.length; ++i) {
var index :uint = ((_firstIndex + _length) % _capacity);
_array[index] = args[i];
_length = Math.min(_length + 1, _capacity);
// did we overwrite the first index?
if (index == _firstIndex && _length == _capacity) {
_firstIndex = (_firstIndex < _capacity - 1 ? _firstIndex + 1 : 0);
}
}
return _length;
}
/**
* Removes the first element from the RingBuffer and returns it.
* If the RingBuffer is empty, shift() will return undefined.
*/
public function shift () :*
{
if (this.empty) {
return undefined;
}
var obj :* = _array[_firstIndex];
_array[_firstIndex] = undefined;
_firstIndex = (_firstIndex < _capacity - 1 ? _firstIndex + 1 : 0);
--_length;
return obj;
}
/**
* Removes the last element from the RingBuffer and returns it.
* If the RingBuffer is empty, pop() will return undefined.
*/
public function pop () :*
{
if (this.empty) {
return undefined;
}
var lastIndex :uint = ((_firstIndex + _length - 1) % _capacity);
var obj :* = _array[lastIndex];
_array[lastIndex] = undefined;
--_length;
return obj;
}
/** Removes all elements from the RingBuffer. */
public function clear () :void
{
_array = new Array();
_array.length = _capacity;
_length = 0;
_firstIndex = 0;
}
/**
* Returns the element at the specified index.
* If index >= length, at() will return undefined.
*/
public function at (index :uint) :*
{
if (index >= _length) {
return undefined;
} else {
var index :uint = ((_firstIndex + index) % _capacity);
return _array[index];
}
}
/**
* Executes a test function on each item in the ring buffer
* until an item is reached that returns false for the specified
* function.
*
* Returns a Boolean value of true if all items in the buffer return
* true for the specified function; otherwise, false.
*/
public function every (callback :Function, thisObject :* = null) :Boolean
{
for (var i :int = 0; i < _length; ++i) {
if (!callback.call(thisObject, this.at(i))) {
return false;
}
}
return true;
}
/**
* Executes a function on each item in the ring buffer.
*/
public function forEach (callback :Function, thisObject :* = null) :void
{
for (var i :int = 0; i < _length; ++i) {
callback.call(thisObject, this.at(i));
}
}
/**
* Searches for an item in the ring buffer by using strict equality
* (===) and returns the index position of the item, or -1
* if the item is not found.
*/
public function indexOf (searchElement :*, fromIndex :int = 0) :int
{
for (var i :int = 0; i < _length; ++i) {
if (this.at(i) === searchElement) {
return i;
}
}
return -1;
}
protected var _array :Array = new Array();
protected var _capacity :uint;
protected var _length :uint;
protected var _firstIndex :uint;
}
}