1 module mutils.container.vector;
2 
3 import core.bitop;
4 import core.stdc.stdlib : malloc,free;
5 import core.stdc.string : memset,memcpy;
6 
7 import std.traits:Unqual;
8 
9 @nogc @safe nothrow pure size_t nextPow2(size_t num){
10 	return 1<< bsr(num)+1;
11 }
12 
13 
14 struct Vector(T){
15 	T[] array;
16 	size_t used;
17 public:
18 
19 	this(T t){
20 		add(t);
21 	}
22 
23 	this(T[] t){
24 		add(t);
25 	}
26 
27 	this(size_t numElements){
28 		assert(numElements>0);
29 		extend(numElements);
30 	}
31 	
32 	void clear(){
33 		removeAll();
34 	}
35 	
36 	void removeAll(){
37 		if(array !is null){
38 			freeData(cast(void[])array);
39 		}
40 		array=T[].init;
41 		used=0;
42 	}
43 	
44 	bool empty(){
45 		return (used==0);
46 	}
47 	
48 	size_t length(){
49 		return used;
50 	}	
51 
52 	void length(size_t newLength){
53 		assert(newLength>=used);
54 		reserve(newLength);
55 		foreach(ref el;array[used..newLength]){
56 			el=T.init;
57 		}
58 		used=newLength;
59 	}
60 	
61 	void reset(){
62 		used=0;
63 	}
64 
65 	
66 	void reserve(size_t numElements){
67 		if(numElements>array.length){
68 			extend(numElements);
69 		}
70 	}
71 
72 	size_t capacity(){
73 		return array.length-used;
74 	}
75 	
76 	void extend(size_t newNumOfElements){
77 		auto oldArray=manualExtend(newNumOfElements);
78 		if(oldArray !is null){
79 			freeData(oldArray);
80 		}
81 	}
82 	
83 	@nogc void freeData(void[] data){
84 		// 0xFFFFFF probably invalid value for pointers and other types
85 		memset(data.ptr,0xFFFFFFFF,data.length);// Makes bugs show up xD 
86 		free(data.ptr);
87 	}
88 	
89 	void[] manualExtend(size_t newNumOfElements=0){
90 		if(newNumOfElements==0)newNumOfElements=2;
91 		T[] oldArray=array;
92 		size_t oldSize=oldArray.length*T.sizeof;
93 		size_t newSize=newNumOfElements*T.sizeof;
94 		T* memory=cast(T*)malloc(newSize);
95 		memcpy(cast(void*)memory,cast(void*)oldArray.ptr,oldSize);
96 		array=memory[0..newNumOfElements];
97 		return cast(void[])oldArray;		
98 	}
99 	
100 	Vector!T copy(){
101 		Vector!T duplicate;
102 		duplicate.reserve(used);
103 		duplicate~=array[0..used];
104 		return duplicate;
105 	}
106 
107 	bool canAddWithoutRealloc(uint elemNum=1){
108 		return used+elemNum<=array.length;
109 	}
110 	
111 	void add(T  t) {
112 		if(used>=array.length){
113 			extend(nextPow2(used+1));
114 		}
115 		array[used]=t;
116 		used++;
117 	}
118 
119 	/// Add element at given position moving others
120 	void add(T t, size_t pos){
121 		assert(pos<=used);
122 		if(used>=array.length){
123 			extend(array.length*2);
124 		}
125 		foreach_reverse(size_t i;pos..used){
126 			array[i+1]=array[i];
127 		}
128 		array[pos]=t;
129 		used++;
130 	}
131 	
132 	void add(T[]  t){
133 		if(used+t.length>array.length){
134 			extend(nextPow2(used+t.length));
135 		}
136 		foreach(i;0..t.length){
137 			array[used+i]=t[i];
138 		}
139 		used+=t.length;
140 	}
141 	
142 	
143 	void remove(size_t elemNum){
144 		array[elemNum]=array[used-1];
145 		used--;
146 	}
147 	
148 	bool tryRemoveElement(T elem){
149 		foreach(i,ref el;array[0..used]){
150 			if(el==elem){
151 				remove(i);
152 				return true;
153 			}
154 		}
155 		return false;
156 	}
157 	
158 	void removeElement(T elem){
159 		assert(tryRemoveElement(elem));
160 	}
161 	
162 	ref T opIndex(size_t elemNum){
163 		pragma(inline, true);
164 		assert(elemNum<used);
165 		return array.ptr[elemNum];
166 	}
167 	
168 	auto opSlice(){
169 		return array.ptr[0..used];
170 	}
171 	
172 	T[] opSlice(size_t x, size_t y){
173 		assert(y<=used);
174 		return array.ptr[x..y];
175 	}
176 	
177 	size_t opDollar(){
178 		return used;
179 	}
180 	
181 	void opOpAssign(string op)(T obj){
182 		static assert(op=="~");
183 		add(obj);
184 	}
185 	
186 	void opOpAssign(string op)(T[] obj){
187 		static assert(op=="~");
188 		add(obj);
189 	}
190 	
191 	void opIndexAssign(T obj, size_t elemNum){
192 		assert(elemNum<used, "Range viloation");
193 		array[elemNum]=obj;		
194 	}
195 
196 	void opSliceAssign(T obj, size_t a, size_t b){
197 		assert(b<used && a<=b, "Range viloation");
198 		array.ptr[a..b]=obj;		
199 	}
200 
201 	bool opEquals()(auto ref const Vector!T r) const { 
202 		return used==r.used && array.ptr[0..used]==r.array.ptr[0..r.used];
203 	}
204 
205 	size_t toHash() const nothrow @trusted
206 	{
207 		return hashOf(cast( Unqual!(T)[])array.ptr[0..used]);
208 	}
209 
210 
211 	import std.format:FormatSpec,formatValue;
212 	/**
213 	 * Preety print
214 	 */
215 	void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt)
216 	{
217 		static if(__traits(compiles,formatValue(sink, array[0..used], fmt))){
218 			formatValue(sink, array[0..used], fmt);
219 		}
220 	}
221 	
222 }
223 
224 // Helper to avoid GC
225 private T[n] s(T, size_t n)(auto ref T[n] array) pure nothrow @nogc @safe{return array;}
226 
227 @nogc nothrow unittest{
228 	Vector!int vec;
229 	assert(vec.empty);
230 	vec.add(0);
231 	vec.add(1);
232 	vec.add(2);
233 	vec.add(3);
234 	vec.add(4);
235 	vec.add(5);
236 	assert(vec.length==6);
237 	assert(vec[3]==3);
238 	assert(vec[5]==5);
239 	assert(vec[]==[0,1,2,3,4,5].s);
240 	assert(!vec.empty);
241 	vec.remove(3);
242 	assert(vec.length==5);
243 	assert(vec[]==[0,1,2,5,4].s);//unstable remove
244 	
245 }
246 
247 @nogc nothrow unittest{
248 	Vector!int vec;
249 	assert(vec.empty);
250 	vec~=[0,1,2,3,4,5].s;
251 	assert(vec[]==[0,1,2,3,4,5].s);
252 	assert(vec.length==6);
253 	vec~=6;
254 	assert(vec[]==[0,1,2,3,4,5,6].s);
255 	
256 }
257 
258 
259 @nogc nothrow unittest{
260 	Vector!int vec;
261 	vec~=[0,1,2,3,4,5].s;
262 	vec[3]=33;
263 	assert(vec[3]==33);
264 	
265 }