/* Monster - an advanced game scripting language Copyright (C) 2007, 2008 Nicolay Korslund Email: WWW: http://monster.snaptoad.com/ This file (growarray.d) is part of the Monster script language package. Monster is distributed as free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License version 3 along with this program. If not, see http://www.gnu.org/licenses/ . */ module monster.util.growarray; // Array that grows without reallocations. struct GrowArray(T) { const defSize = 128; private: uint listSize = defSize; // Size of new lists uint elements; // Current number of elements uint elemsAlloc; // Elements allocated uint begin; // At what element to start counting. Used for // slices. T[][] listList; // Make sure there is room for at least 'size' elements in total. void alloc(uint size) { // Do nothing if the list is large enough if(size <= elemsAlloc) return; // If this is a slice, we must always reallocate when // growing. Implement that later. if(begin) assert(0, "Cannot grow a slice"); // Number of lists we need uint lists = ((size-1) / listSize) + 1; // The number of needed elements should never decrease assert((listSize*lists) >= elemsAlloc); // Number of elements we need allocated elemsAlloc = listSize * lists; // Make sure the list of lists is large enough if(listList.length < lists) listList.length = lists+30; // Allocate the lists we need for(int i=0; i= begin && index < elements, "GrowArray index out of bounds"); return listList[index/listSize][index%listSize]; } T opIndexAssign(T value, int index) { index += begin; assert(index >= begin && index < elements, "GrowArray index out of bounds"); return (listList[index/listSize][index%listSize] = value); } T* getPtr(int index) { index += begin; assert(index >= begin && index < elements, "GrowArray index out of bounds"); return &listList[index/listSize][index%listSize]; } GrowArray opSlice(int start, int stop) { assert(start<=stop, "Illegal GrowArray slice"); GrowArray ga = *this; ga.begin = begin+start; ga.length = stop-start; return ga; } GrowArray opSlice() { return *this; } int opApply(int delegate(ref int, ref T) dg) { int res; int len = length; int pos = begin%listSize; int list = begin/listSize; for(int i; i= 1); // Setting and reading elements arr[0] = 1; arr[1] = 2; arr[2] = 3; assert(arr[0] == 1); assert(arr[1] == 2); assert(arr[2] == 3); assert(arr.listList[0][0] == 1); assert(arr.listList[0][1] == 2); assert(arr.listList[0][2] == 3); // Test opCatAssign arr ~= 4; assert(arr.length == 4); assert(arr[3] == 4); // Foreach int tmp = 0; foreach(int i, int v; arr) { assert(v==i+1); tmp++; } assert(tmp == 4); tmp = 1; foreach(int v; arr) assert(v == tmp++); assert(tmp == 5); // Slicing the entire array arr = arr[0..4]; assert(arr.length == 4); assert(arr[3] == 4); // Slicing part of the array auto arrS = arr[1..3]; assert(arrS.length == 2); assert(arrS[0] == 2); assert(arrS[1] == 3); arrS[0] = 10; assert(arr[1] == 10); // Slicing the slice arrS = arrS[1..2]; assert(arrS.length == 1); assert(arrS[0] == 3); // Empty slice arrS = arr[3..3]; assert(arrS.length == 0); // Custom list size, and more than one list auto arr2 = GrowArray!(byte)(3,2); assert(arr2.length == 3); assert(arr2.elements == 3); assert(arr2.listSize == 2); assert(arr2.elemsAlloc == 4); assert(arr2.listList.length >= 2); assert(arr2.listList[0].length == 2); assert(arr2[0] == 0); assert(arr2[1] == 0); assert(arr2[2] == 0); arr2[1]=2; arr2[2]=4; foreach(int i, byte v; arr2) assert(v == 2*i); // Check that boundry checking works (in non-release mode.) bool err = false; try{arr2[3];} catch { err = true; } assert(err == true); err = false; try{arr2[3] = 0;} catch { err = true; } assert(err == true); }