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 }