/* arrayqueue.vala * * Copyright (C) 2012-2014 Maciej Piechotka * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Author: * Maciej Piechotka */ /** * Resizable array implementation of the {@link Deque} interface. * * The storage array grows automatically when needed. * * This implementation is pretty good for lookups at the end or random. * Because they are stored in an array this structure does not fit for deleting * arbitrary elements. For an alternative implementation see {@link LinkedList}. * * @see LinkedList */ public class Gee.ArrayQueue : Gee.AbstractQueue, Deque { /** * Constructs a new, empty array queue. * * If not provided, the function parameter is requested to the * {@link Functions} function factory methods. * * @param equal_func an optional element equality testing function */ public ArrayQueue (owned EqualDataFunc? equal_func = null) { if (equal_func == null) { equal_func = Functions.get_equal_func_for (typeof (G)); } _equal_func = (owned)equal_func; this._items = new G[10]; } [CCode (notify = false)] public EqualDataFunc equal_func { private set {} get { return _equal_func; } } private EqualDataFunc _equal_func; /** * {@inheritDoc} */ public override int size { get { return _length; } } public bool is_empty { get { return _length == 0; } } /** * {@inheritDoc} */ public override bool read_only { get { return false; } } /** * {@inheritDoc} */ public override int capacity { get {return Queue.UNBOUNDED_CAPACITY;} } /** * {@inheritDoc} */ public override int remaining_capacity { get {return Queue.UNBOUNDED_CAPACITY;} } /** * {@inheritDoc} */ public override bool is_full { get { return false; } } /** * {@inheritDoc} */ public override Gee.Iterator iterator() { return new Iterator (this); } /** * {@inheritDoc} */ public override bool add (G element) { return offer_tail (element); } /** * {@inheritDoc} */ public override bool contains (G item) { return find_index(item) != -1; } /** * {@inheritDoc} */ public override bool remove (G item) { _stamp++; int index = find_index (item); if (index == -1) { return false; } else { remove_at (index); return true; } } /** * {@inheritDoc} */ public override void clear() { _stamp++; for (int i = 0; i < _length; i++) { _items[(_start + i) % _items.length] = null; } _start = _length = 0; } /** * {@inheritDoc} */ public override bool foreach (ForallFunc f) { for (int i = 0; i < _length; i++) { if (!f (_items[(_start + i) % _items.length])) { return false; } } return true; } /** * {@inheritDoc} */ public override G? peek () { return peek_head (); } /** * {@inheritDoc} */ public override G? poll () { return poll_head (); } /** * {@inheritDoc} */ public bool offer_head (G element) { grow_if_needed (); _start = (_items.length + _start - 1) % _items.length; _length++; _items[_start] = element; _stamp++; return true; } /** * {@inheritDoc} */ public G? peek_head () { return _items[_start]; } /** * {@inheritDoc} */ public G? poll_head () { _stamp++; if (_length == 0) { _start = 0; return null; } else { _length--; G result = (owned)_items[_start]; _start = (_start + 1) % _items.length; return (owned)result; } } /** * {@inheritDoc} */ public int drain_head (Collection recipient, int amount = -1) { return drain (recipient, amount); } /** * {@inheritDoc} */ public bool offer_tail (G element) { grow_if_needed(); _items[(_start + _length++) % _items.length] = element; _stamp++; return true; } /** * {@inheritDoc} */ public G? peek_tail () { return _items[(_items.length + _start + _length - 1) % _items.length]; } /** * {@inheritDoc} */ public G? poll_tail () { _stamp++; if (_length == 0) { _start = 0; return null; } else { return (owned)_items[(_items.length + _start + --_length) % _items.length]; } } /** * {@inheritDoc} */ public int drain_tail (Collection recipient, int amount = -1) { G? item = null; int drained = 0; while((amount == -1 || --amount >= 0) && (item = poll_tail ()) != null) { recipient.add(item); drained++; } return drained; } /** * {@inheritDoc} */ private void grow_if_needed () { if (_items.length < _length +1 ) { _items.resize (2 * _items.length); #if 0 _items.move (0, _length, _start); #else // See bug #667452 for(int i = 0; i < _start; i++) _items[_length + i] = (owned)_items[i]; #endif } } private int find_index (G item) { for (int i = _start; i < int.min(_items.length, _start + _length); i++) { if (equal_func(item, _items[i])) { return i; } } for (int i = 0; i < _start + _length - _items.length; i++) { if (equal_func(item, _items[i])) { return i; } } return -1; } private void remove_at (int index) { int end = (_items.length + _start + _length - 1) % _items.length + 1; if (index == _start) { _items[_start++] = null; _length--; return; } else if (index > _start && end <= _start) { _items[index] = null; _items.move (index + 1, index, _items.length - 1); _items[_items.length - 1] = (owned)_items[0]; _items.move (1, 0, end - 1); _length--; } else { _items[index] = null; _items.move (index + 1, index, end - (index + 1)); _length--; } } private class Iterator : GLib.Object, Traversable, Gee.Iterator { public Iterator (ArrayQueue queue) { _queue = queue; _stamp = _queue._stamp; } public Iterator.from_iterator (Iterator iter) { _queue = iter._queue; _stamp = iter._stamp; _offset = iter._offset; _removed = iter._removed; } public bool next () { assert (_queue._stamp == _stamp); if (has_next ()) { _offset++; _removed = false; return true; } else { return false; } } public bool has_next () { assert (_queue._stamp == _stamp); return _offset + 1 < _queue._length; } public new G get () { assert (_queue._stamp == _stamp); assert (_offset != -1); assert (!_removed); return _queue._items[(_queue._start + _offset) % _queue._items.length]; } public void remove () { assert (_queue._stamp++ == _stamp++); _queue.remove_at((_queue._start + _offset) % _queue._items.length); _offset--; _removed = true; } public bool valid { get {return _offset != -1 && !_removed;} } public bool read_only { get {return false;} } public bool foreach (ForallFunc f) { assert (_queue._stamp == _stamp); if (!valid) { _offset++; _removed = false; } for (int i = _offset; i < _queue._length; i++) { if (!f (_queue._items[(_queue._start + i) % _queue._items.length])) { _offset = i; return false; } } _offset = _queue._length - 1; return true; } public Gee.Iterator[] tee (uint forks) { if (forks == 0) { return new Gee.Iterator[0]; } else { Gee.Iterator[] result = new Gee.Iterator[forks]; result[0] = this; for (uint i = 1; i < forks; i++) { result[i] = new Iterator.from_iterator (this); } return result; } } protected ArrayQueue _queue; protected int _stamp; protected int _offset = -1; protected bool _removed = false; } private G[] _items; private int _start = 0; private int _length = 0; private int _stamp = 0; }