1 /*
2  * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license.
3  *
4  * Pixel Perfect Engine, AdvancedBitArray module
5  */
6 
7 module PixelPerfectEngine.system.advBitArray;
8 import std.stdio;
9 /**
10 * Mainly intended for collision detection, can be used for other purposes too.
11 */
12 public class AdvancedBitArray{
13 	private static const ubyte[8] maskData = [0b11111110,0b11111101,0b11111011,0b11110111,0b11101111,0b11011111,0b10111111,0b01111111];
14 	protected void[] rawData;
15 	protected int length;
16 
17 
18 	this(int length){
19 		setLength(length);
20 
21 	}
22 	this(void[] data, int l){
23 		rawData = data;
24 		rawData.length += 4;
25 		if(rawData.length % 4){
26 			rawData.length += 4 - (rawData.length % 4);
27 		}
28 		length = l;
29 	}
30 	//this(bool[] data){}
31 
32 	public int getLenght(){
33 		return length;
34 	}
35 
36 	public void setLength(int l){
37 		//test if resizing needed
38 		if(length == l) return;
39 		else if(length < l){
40 			if((l + 32) / 8 > rawData.length){
41 				rawData.length = (l + 32 + (32 - l%32)) / 8;
42 			}
43 		}else{
44 			for(int i = l ; i < length ; i++){
45 				this[i] = false;
46 			}
47 			rawData.length = (l + 32 + (32 - l%32)) / 8;
48 		}
49 		this.length = l;
50 	}
51 	bool opEquals()(auto ref const AdvancedBitArray o) {  
52 		for(int i ; i < rawData.length ; i += 4){
53 			if(cast(uint)rawData[i] != cast(uint)o.rawData[i]) return false;
54 		}
55 		return true;
56 	}
57 	AdvancedBitArray opBinary(string op)(int rhs){
58 		static if(op == ">>"){
59 			int byteShift = rhs / 8, bitShift = rhs % 8;
60 			AdvancedBitArray result = new AdvancedBitArray(this.length);
61 			//result.length = rawData.length;
62 			if(bitShift == 0){
63 				for(int i ; i < rawData.length - byteShift ; i+=4){
64 					*cast(uint*)(result.rawData.ptr + i + byteShift) = *cast(uint*)(rawData.ptr + i);
65 				}
66 			}else{
67 				for(int i ; i < rawData.length - byteShift ; i+=4){
68 					uint dA = *cast(uint*)(rawData.ptr + i), dB = i == 0 ? 0 : *cast(uint*)(rawData.ptr + i - 1);
69 					dA >>= bitShift;
70 					dB <<= (32-bitShift);
71 					*cast(uint*)(result.rawData.ptr + i + byteShift) = dA || dB;
72 				}
73 			}
74 			return result;
75 		}else static if(op == "<<"){
76 			int byteShift = rhs / 8, bitShift = rhs % 8;
77 			AdvancedBitArray result = new AdvancedBitArray(this.length);
78 			//result.length = rawData.length;
79 			if(bitShift == 0){
80 				for(int i ; i < rawData.length - byteShift ; i+=4){
81 					*cast(uint*)(result.rawData.ptr + i) = *cast(uint*)(rawData.ptr + i + byteShift);
82 				}
83 			}else{
84 				for(int i ; i < rawData.length - byteShift ; i+=4){
85 					uint dA = *cast(uint*)(rawData.ptr + i + byteShift), dB = *cast(uint*)(rawData.ptr + i + byteShift + 1);
86 					dA<<=bitShift;
87 					dB>>=(32-bitShift);
88 					*cast(uint*)(result.rawData.ptr + i + byteShift) = dA || dB;
89 				}
90 			}
91 			return result;
92 		}else static assert(0, "Operator "~op~" not implemented");
93 	}
94 	AdvancedBitArray opBinary(string op)(AdvancedBitArray rhs){
95 		static if(op == "&"){
96 			AdvancedBitArray result = new AdvancedBitArray(length);
97 			for(int i ; i < rawData.length ; i+=4){
98 				*cast(uint*)(result.rawData.ptr + i) = *cast(uint*)(rawData.ptr + i) & *cast(uint*)(rhs.rawData.ptr + i);
99 			}
100 			return result;
101 		}else static if(op == "|"){
102 			AdvancedBitArray result = new AdvancedBitArray(length);
103 			for(int i ; i < rawData.length ; i+=4){
104 				*cast(uint*)(result.rawData.ptr + i) = *cast(uint*)(rawData.ptr + i) | *cast(uint*)(rhs.rawData.ptr + i);
105 			}
106 			return result;
107 		}else static if(op == "^"){
108 			AdvancedBitArray result = new AdvancedBitArray(length);
109 			for(int i ; i < rawData.length ; i+=4){
110 				*cast(uint*)(result.rawData.ptr + i) = *cast(uint*)(rawData.ptr + i) ^ *cast(uint*)(rhs.rawData.ptr + i);
111 			}
112 			return result;
113 		}else static assert(0, "Operator "~op~" not implemented");
114 	}
115 
116 	public override string toString(){
117 		string result = "[";
118 		for(int i ; i < length ; i++){
119 			if(this[i]){
120 				result ~= "1";
121 			}else{
122 				result ~= "0";
123 			}
124 		}
125 		result ~= "]";
126 		return result;
127 	}
128 
129 	ref AdvancedBitArray opOPAssign(string op)(AdvancedBitArray rhs){
130 		static if(op == "&"){
131 			for(int i ; i < rawData.length ; i+=4){
132 				cast(uint)rawData[i] &= cast(uint)rhs.rawData[i];
133 			}
134 		}else static if(op == "|"){
135 			for(int i ; i < rawData.length ; i+=4){
136 				cast(uint)rawData[i] |= cast(uint)rhs.rawData[i];
137 			}
138 		}else static if(op == "^"){
139 			for(int i ; i < rawData.length ; i+=4){
140 				cast(uint)rawData[i] ^= cast(uint)rhs.rawData[i];
141 			}
142 		}else static if(op == "~"){
143 			/*int oldlength = length;
144 			this.setLength(length+rhs.length);*/
145 			if(length%8 == 0){
146 				rawData.length=length/8;
147 				rawData ~= rhs.rawData;
148 				this.setLength(length+rhs.length);
149 			}else{
150 
151 			}
152 		}else static assert(0, "Operator "~op~" not implemented");
153 	}
154 
155 	ref AdvancedBitArray opOPAssign(string op)(bool rhs){
156 		static if(op == "~"){
157 			this[length] = rhs;
158 			length++;
159 			if(length % 128 == 0){
160 				rawData.length += 16;
161 			}
162 		}else static assert(0, "Operator "~op~" not implemented");
163 	}
164 
165 	bool opIndexAssign(bool value, size_t i){
166 		int bytepos = i / 8, bitpos = i % 8;
167 		if(value){
168 			*cast(ubyte*)(rawData.ptr + bytepos) |= 0xFF - maskData[bitpos];
169 		}else{
170 			*cast(ubyte*)(rawData.ptr + bytepos) &= maskData[bitpos];
171 		}
172 		return value;
173 	}
174 
175 	bool opIndex(size_t i){
176 		int bytepos = i / 8, bitpos = i % 8;
177 		return (*cast(ubyte*)(rawData.ptr + bytepos) & (0xFF - maskData[bitpos])) != 0;
178 	}
179 	AdvancedBitArray opSlice(size_t i1, size_t i2){
180 		int bitShift = i1 % 8, bitShift2 = i2 % 8, byteShift = i1 / 8, byteShift2 = i2 / 8, l = i2 - i1, l2 = byteShift2 - byteShift;
181 		AdvancedBitArray result = new AdvancedBitArray(l);
182 		if(bitShift == 0){
183 			for(int i ; i < l2 ; i+=4){
184 				*cast(uint*)(result.rawData.ptr + i) = *cast(uint*)(rawData.ptr + i + byteShift);
185 			}
186 			if(l % 32 == 0){
187 				return result;
188 			}
189 		}else{
190 			for(int i ; i < l2 ; i+=4){
191 				*cast(uint*)(result.rawData.ptr + i) = *cast(uint*)(rawData.ptr + i + byteShift);
192 			}
193 		}
194 		return result;
195 	}
196 	/**
197 	* Tests multiple values at once. The intended algorithm didn't work as intended, replacement is coming in 0.9.2, in the meanwhile I'm using a slower but safer one.
198 	*/
199 	public bool test(int from, int length, AdvancedBitArray target, int tfrom){
200 		for(int i ; i < length ; i++){
201 			if(opIndex(from + i) && target[tfrom + i]){
202 				return true;
203 			}
204 		}
205 		/*int bitShiftA = from%8, bitShiftB = tfrom%8, bitlength = length%8, bitlength2 = length%32, byteShiftA = from/8, byteShiftB = tfrom/8, wordlength = length / 8;
206 		int i = -3;
207 		/*
208 		if(bitShiftA && bitShiftB){
209 			for(; i < wordlength; i++){
210 				int a = (*cast(ubyte*)(rawData.ptr + byteShiftA))<<bitShiftA | (*cast(ubyte*)(rawData.ptr + byteShiftA + 1))>>(8 - bitShiftA) & 0xff,
211 					b = (*cast(ubyte*)(target.rawData.ptr + byteShiftB))<<bitShiftB | (*cast(ubyte*)(target.rawData.ptr + byteShiftB + 1))>>(8 - bitShiftB) & 0xff;
212 				if(a & b){
213 					return true;
214 				}
215 			}
216 			if(bitlength){
217 				int a = (*cast(ubyte*)(rawData.ptr + byteShiftA))<<bitShiftA | (*cast(ubyte*)(rawData.ptr + byteShiftA + 1))>>(8 - bitShiftA) & 0xff,
218 					b = (*cast(ubyte*)(target.rawData.ptr + byteShiftB))<<bitShiftB | (*cast(ubyte*)(target.rawData.ptr + byteShiftB + 1))>>(8 - bitShiftB) & 0xff;
219 				a >>= bitlength;
220 				b >>= bitlength;
221 				if(a & b  & 0xff){
222 					return true;
223 				}
224 			}
225 		}else if(bitShiftB){
226 			for(; i < wordlength; i++){
227 				int a = (*cast(ubyte*)(rawData.ptr + byteShiftA)),
228 					b = (*cast(ubyte*)(target.rawData.ptr + byteShiftB))<<bitShiftB | (*cast(ubyte*)(target.rawData.ptr + byteShiftB + 1))>>(8 - bitShiftB) & 0xff;
229 				if(a & b){
230 					return true;
231 				}
232 			}
233 			if(bitlength){
234 				int a = (*cast(ubyte*)(rawData.ptr + byteShiftA)),
235 					b = (*cast(ubyte*)(target.rawData.ptr + byteShiftB))<<bitShiftB | (*cast(ubyte*)(target.rawData.ptr + byteShiftB + 1))>>(8 - bitShiftB) & 0xff;
236 				a >>= bitlength;
237 				b >>= bitlength;
238 				if(a & b  & 0xff){
239 					return true;
240 				}
241 			}
242 		}else if(bitShiftA){
243 			for(; i < wordlength; i++){
244 				int a = (*cast(ubyte*)(rawData.ptr + byteShiftA))<<bitShiftA | (*cast(ubyte*)(rawData.ptr + byteShiftA + 1))>>(8 - bitShiftA) & 0xff,
245 					b = (*cast(ubyte*)(target.rawData.ptr + byteShiftB));
246 				if(a & b){
247 					return true;
248 				}
249 			}
250 			if(bitlength){
251 				int a = (*cast(ubyte*)(rawData.ptr + byteShiftA))<<bitShiftA | (*cast(ubyte*)(rawData.ptr + byteShiftA + 1))>>(8 - bitShiftA) & 0xff,
252 					b = (*cast(ubyte*)(target.rawData.ptr + byteShiftB));
253 				a >>= bitlength;
254 				b >>= bitlength;
255 				if(a & b & 0xff){
256 					return true;
257 				}
258 			}
259 		}else{
260 			for(; i < wordlength; i++){
261 				int a = (*cast(ubyte*)(rawData.ptr + byteShiftA)),
262 					b = (*cast(ubyte*)(target.rawData.ptr + byteShiftB));
263 				if(a & b){
264 					return true;
265 				}
266 			}
267 			if(bitlength){
268 				int a = (*cast(ubyte*)(rawData.ptr + byteShiftA)),
269 					b = (*cast(ubyte*)(target.rawData.ptr + byteShiftB));
270 				a >>= bitlength;
271 				b >>= bitlength;
272 				if(a & b & 0xff){
273 					return true;
274 				}
275 			}
276 		}*/
277 
278 		/*if(bitShiftA && bitShiftB){
279 			for( ; i < wordlength - 7 ; i+=4){
280 				uint a = (*cast(uint*)(rawData.ptr + (byteShiftA)+i))<<bitShiftA | (*cast(uint*)(rawData.ptr + (byteShiftA)+1+i))>>(32-bitShiftA), 
281 					b = (*cast(uint*)(target.rawData.ptr + (byteShiftB)+i))<<bitShiftB | (*cast(uint*)(target.rawData.ptr + (byteShiftB)+1+i))>>(32-bitShiftB);
282 				//writeln(a,',',b);
283 				if((a & b)){
284 					return true;
285 				}
286 			}
287 			if(i < wordlength - 3 || bitlength){
288 				uint a = (*cast(uint*)(rawData.ptr + (byteShiftA)+i))<<bitShiftA | (*cast(uint*)(rawData.ptr + (byteShiftA)+3+i))>>(32-bitShiftA), 
289 					b = (*cast(uint*)(target.rawData.ptr + (byteShiftB)+i))<<bitShiftB | (*cast(uint*)(target.rawData.ptr + (byteShiftB)+1+i))>>(32-bitShiftB);
290 				a >>= 32 - bitlength2;
291 				b >>= 32 - bitlength2;
292 				//writeln(a,',',b);
293 			if((a & b)){
294 				return true;
295 			}
296 		}
297 		}else if(bitShiftB){
298 			for( ; i < wordlength - 7 ; i+=4){
299 				uint a = (*cast(uint*)(rawData.ptr + (byteShiftA)+i)<<bitShiftA) , 
300 					b = (*cast(uint*)(target.rawData.ptr + (byteShiftB)+i))<<bitShiftB | (*cast(uint*)(target.rawData.ptr + (byteShiftB)+3+i))>>(32-bitShiftB);
301 				//writeln(a,',',b);
302 				if(!(a & b)){
303 					return true;
304 				}
305 			}
306 			if(i < wordlength - 3 || bitlength){
307 				uint a = (*cast(uint*)(rawData.ptr + (byteShiftA)+i)<<bitShiftA) , 
308 					b = (*cast(uint*)(target.rawData.ptr + (byteShiftB)+i))<<bitShiftB | (*cast(uint*)(target.rawData.ptr + (byteShiftB)+3+i))>>(32-bitShiftB);
309 				a >>= 32 - bitlength2;
310 				b >>= 32 - bitlength2;
311 				//writeln(a,',',b);
312 				if((a & b)){
313 					return true;
314 				}
315 			}
316 		}else if(bitShiftA){
317 			for( ; i < wordlength - 7 ; i+=4){
318 				uint a = (*cast(uint*)(rawData.ptr + (byteShiftA)+i))<<bitShiftA | (*cast(uint*)(rawData.ptr + (byteShiftA)+4+i))>>(32-bitShiftA), 
319 					b = (*cast(uint*)(target.rawData.ptr + (byteShiftB)+i)<<bitShiftB) ;
320 				//writeln(a,',',b);
321 				if((a & b)){
322 					return true;
323 				}
324 			}
325 			if(i < wordlength - 3 || bitlength){
326 				uint a = (*cast(uint*)(rawData.ptr + (byteShiftA)+i))<<bitShiftA | (*cast(uint*)(rawData.ptr + (byteShiftA)+4+i))>>(32-bitShiftA), 
327 					b = (*cast(uint*)(target.rawData.ptr + (byteShiftB)+i)) ;
328 				a >>= 32 - bitlength2;
329 				b >>= 32 - bitlength2;
330 				//writeln(a,',',b);
331 				if((a & b)){
332 					return true;
333 				}
334 			}
335 		}else{
336 			for( ; i < wordlength - 7 ; i+=4){
337 				uint a = (*cast(uint*)(rawData.ptr + (byteShiftA)+i)) , 
338 					b = (*cast(uint*)(target.rawData.ptr + (byteShiftB)+i)) ;
339 				//writeln(a,',',b);
340 				if((a & b)){
341 					return true;
342 				}
343 			}
344 			if(i < wordlength - 3 || bitlength){
345 				uint a = (*cast(uint*)(rawData.ptr + (byteShiftA)+i)) , 
346 					b = (*cast(uint*)(target.rawData.ptr + (byteShiftB)+i)) ;
347 				//writeln(a,',',b);
348 				a >>= 32 - bitlength2;
349 				b >>= 32 - bitlength2;
350 				if((a & b)){
351 					return true;
352 				}
353 			}
354 		}/**/
355 		return false;
356 	}
357 	/*unittest{
358 		AdvancedBitArray a = new AdvancedBitArray([0b0,0b0,0b11111111,0b11111111,0b11111111,0b11111111,0b0,0b0],64);
359 		AdvancedBitArray b = new AdvancedBitArray([0b0,0b0,0b11111111,0b11111111,0b11111111,0b11111111,0b0,0b0],64);
360 
361 		assert(a.test(0,8,b,0) == false);
362 		assert(a.test(8,8,b,0) == false);
363 		assert(a.test(0,8,b,8) == false);
364 		assert(a.test(8,8,b,8) == false);
365 
366 		assert(a.test(0,16,b,0) == false);
367 
368 		assert(a.test(0,8,b,48) == false);
369 		assert(a.test(0,8,b,56) == false);
370 		assert(a.test(8,8,b,48) == false);
371 		assert(a.test(8,8,b,56) == false);
372 	}*/
373 }