From 148766903ef5908667168362cc8caf8e74aa8901 Mon Sep 17 00:00:00 2001 From: Tom Conkling Date: Fri, 21 Dec 2007 01:57:26 +0000 Subject: [PATCH] created RingBuffer collection class git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4917 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- src/as/com/threerings/util/RingBuffer.as | 181 +++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 src/as/com/threerings/util/RingBuffer.as diff --git a/src/as/com/threerings/util/RingBuffer.as b/src/as/com/threerings/util/RingBuffer.as new file mode 100644 index 000000000..8d1b9b547 --- /dev/null +++ b/src/as/com/threerings/util/RingBuffer.as @@ -0,0 +1,181 @@ +// +// $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]; + } + } + + protected var _array :Array = new Array(); + protected var _capacity :uint; + protected var _length :uint; + protected var _firstIndex :uint; +} + +}