namespace Invercargill.DataStructures { public class Vector : Enumerable, Lot, ReadOnlyCollection, ReadOnlyAddressable, Collection, Addressable { private T[] array; private int n_items = 0; private SafeReadFunc? safe_read; private SafeWriteFunc? safe_write; private const int INITIAL_SIZE = 2; public Vector() { array = new T[INITIAL_SIZE]; safe_read = get_safe_read_function_for(); safe_write = get_safe_write_function_for(); } public override Tracker get_tracker() { return new AddressableTracker(this); } public override T[] to_array () { lock(array) { var a2 = new T[n_items]; if(safe_write != null) { for(var i = 0; i < n_items; i++) { safe_write(a2, i, array_read(i)); } } else { for(var i = 0; i < n_items; i++) { a2[i] = array[i]; } } return a2; } } public void add(T item) { lock(array) { ensure_room(1); array_write(n_items, item); n_items++; } } public override void add_all(Enumerable items) { lock(array) { foreach (var item in items) { ensure_room(1); array_write(n_items, item); n_items++; } } } public new T @get(uint index) throws IndexError { IndexError? e = null; lock(array) { if(index < 0) { e = new IndexError.INDEX_EXCEEDS_LOWER_BOUNDS("Index is less than 0"); } else if(index >= n_items) { e = new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to access index $(index) on a vector with $(n_items) item(s)"); } else { return array_read(index); } } throw e; } public bool try_get(uint index, out T value) { lock(array) { if(index >= 0 && index < n_items) { value = array_read(index); return true; } } value = null; return false; } public new void @set(int index, T value) throws IndexError { IndexError? e = null; lock(array) { if(index < 0) { e = new IndexError.INDEX_EXCEEDS_LOWER_BOUNDS("Index is less than 0"); } else if(index >= n_items) { e = new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to set index $(index) on a vector with $(n_items) item(s)"); } else { array_write(index, value); return; } } throw e; } private void ensure_room(int items) { if(array.length <= n_items + items) { array.resize(array.length * 2); } } public override int count() { return n_items; } public void remove_at(int index) throws IndexError { var e = remove_internal(index); if(e != null) { throw e; } } private IndexError? remove_internal(uint index) { IndexError? e = null; lock(array) { if(index < 0) { e = new IndexError.INDEX_EXCEEDS_LOWER_BOUNDS("Index is less than 0"); } else if(index >= n_items) { e = new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to set index $(index) on a vector with $(n_items) item(s)"); } else { for(uint i = index; i < n_items; i++) { if(i+1 < n_items) { array_write(i, array_read(i+1)); continue; } array[i] = null; } n_items --; } } return e; } public override T last(owned PredicateDelegate? predicate = null) throws SequenceError { if(predicate != null) { return base.last((owned)predicate); } SequenceError? e = null; lock(array) { if(n_items == 0) { e = new SequenceError.NO_ELEMENTS("The sequence contains no elements"); } else { return array_read(n_items -1); } } throw e; } public override T? last_or_default(owned PredicateDelegate? predicate = null) { if(predicate != null) { return base.last_or_default((owned)predicate); } lock(array) { if(n_items == 0) { return null; } else { return array_read(n_items -1); } } } private void array_write(uint index, T item) { if(safe_write != null) { safe_write(array, index, item); return; } array[index] = item; } private T array_read(uint index) { if(safe_read != null) { return safe_read(array, index); } return array[index]; } public uint? first_index_of(PredicateDelegate predicate) { var i = -1; foreach (var item in this) { i++; if(predicate(item)) { return i; } } return null; } public void remove_first_where(Invercargill.PredicateDelegate predicate) { remove_internal(first_index_of(predicate)); } public void remove_all_where(Invercargill.PredicateDelegate predicate) { with_positions() .where(i => predicate(i.item)) .select(i => i.position) .iterate(i => remove_internal(i)); } public void clear() { n_items = 0; array = new T[INITIAL_SIZE]; } } }