001// Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 002// The Molly framework is freely distributable under the terms of an 003// MIT-style license. For details, see the molly pages web site at: 004// http://www.mollypages.org/. Use, modify, have fun ! 005 006package fc.util; 007 008import java.util.*; 009 010/** 011Misc Binary/bit operation related utility methods. 012 013All bit positions are 0-based. For example, to set a 8th logical bit (highest bit in a byte), say 014<tt>setBit(byte, 7)</tt>. 015*/ 016 017public class BitUtil 018{ 019/* 020we could only use the long version (all types get widened to long) but we won't be able 021to error check for the bit position number relevant to the type - so different methods. 022The spec says jvm will shift more than 31 or 63 bits anyway (even if larger value specified) 023but this allows us to catch bugs 024*/ 025 026/** 027returns <tt>true</tt> is specified bit in the specified byte is set. The num parameter is the bit 028position (0-based index). Set means the bit has value 1. 029 030@throws Runtime 031*/ 032public static boolean isBitSet(byte i, int num) 033 { 034 Argcheck.istrue(num >= 0 && num <= 7, "bit number must be between [0-7] for char, I got num=[" + num + "]"); 035 036 return ((i >> num) & 0x1) == 1; 037 } 038 039public static boolean isBitSet(short i, int num) 040 { 041 Argcheck.istrue(num >= 0 && num <= 15, "bit number must be between [0-15] for short, I got num=[" + num + "]"); 042 043 return ((i >> num) & 0x1) == 1; 044 } 045 046public static boolean isBitSet(char i, int num) 047 { 048 Argcheck.istrue(num >= 0 && num <= 15, "bit number must be between [0-15] for char, I got num=[" + num + "]"); 049 050 return ((i >> num) & 0x1) == 1; 051 } 052 053public static boolean isBitSet(int i, int num) 054 { 055 Argcheck.istrue(num >= 0 && num <= 31, "bit number must be between [0-31] for int, I got num=[" + num + "]"); 056 057 return ((i >> num) & 0x1) == 1; 058 } 059 060public static boolean isBitSet(long i, int num) 061 { 062 Argcheck.istrue(num >= 0 && num <= 63, "bit number must be between [0-63] for char, I got num=[" + num + "]"); 063 064 return ((i >> num) & 0x1L) == 1; 065 } 066 067public static byte setBit(byte i, int num) 068 { 069 Argcheck.istrue(num >= 0 && num <= 7, "bit number must be between [0-7] for byte, I got num=[" + num + "]"); 070 071 return (byte) (i | (1 << num)); 072 } 073 074public static short setBit(short i, int num) 075 { 076 Argcheck.istrue(num >= 0 && num <= 15, "bit number must be between [0-15] for short, I got num=[" + num + "]"); 077 078 return (short) (i | (1 << num)); 079 } 080 081public static char setBit(char i, int num) 082 { 083 Argcheck.istrue(num >= 0 && num <= 15, "bit number must be between [0-15] for char, I got num=[" + num + "]"); 084 085 return (char) (i | (1 << num)); 086 } 087 088public static int setBit(int i, int num) 089 { 090 Argcheck.istrue(num >= 0 && num <= 31, "bit number must be between [0-31] for int, I got num=[" + num + "]"); 091 092 return i | (1 << num); 093 } 094 095public static long setBit(long i, long num) 096 { 097 Argcheck.istrue(num >= 0 && num <= 63, "bit number must be between [0-63] for long, I got num=[" + num + "]"); 098 099 return i | (0x1L << num); //HAVE TO SAY 1L !!! 1 << num will only shift a max of 32 bits 100 //since num is constrained by spec to 0-31 max if lhs is int 101 //by default, all literals are int unless L specified. 102 //spent all day chasing this bug down. 103 } 104 105 106public static byte clearBit(byte i, int num) 107 { 108 Argcheck.istrue(num >= 0 && num <= 7, "bit number must be between [0-7] for byte, I got num=[" + num + "]"); 109 110 return (byte) (i & ~(1 << num)); 111 } 112 113public static short clearBit(short i, int num) 114 { 115 Argcheck.istrue(num >= 0 && num <= 15, "bit number must be between [0-15] for short, I got num=[" + num + "]"); 116 117 return (short) (i & ~(1 << num)); 118 } 119 120public static char clearBit(char i, int num) 121 { 122 Argcheck.istrue(num >= 0 && num <= 15, "bit number must be between [0-15] for char, I got num=[" + num + "]"); 123 124 return (char) (i & ~(1 << num)); 125 } 126 127public static int clearBit(int i, int num) 128 { 129 Argcheck.istrue(num >= 0 && num <= 31, "bit number must be between [0-31] for int, I got num=[" + num + "]"); 130 131 return i & ~(1 << num); 132 } 133 134public static long clearBit(long i, int num) 135 { 136 Argcheck.istrue(num >= 0 && num <= 63, "bit number must be between [0-63] for long, I got num=[" + num + "]"); 137 138 return i & ~(1L << num); 139 } 140 141 142//Integer.toBinaryString is doesn't left pad and the logic to do it is stupid so 143//just roll our own (faster this way anyway) 144 145public static String toBinaryString(byte i) 146 { 147 char[] buf = new char[8]; 148 for (int n = 0; n < 8; n++) { 149 buf[n] = ((i >> (7-n)) & 0x1) == 1 ? '1' : '0'; 150 } 151 return new String (buf); 152 } 153 154/** 155returns a 16 char binary digit string 156*/ 157public static String toBinaryString(short i) 158 { 159 char[] buf = new char[16]; 160 for (int n = 0; n < 16; n++) { 161 buf[n] = ((i >> (15-n)) & 0x1) == 1 ? '1' : '0'; 162 } 163 return new String (buf); 164 } 165 166/** 167returns a 16 char binary digit string 168*/ 169public static String toBinaryString(char i) 170 { 171 char[] buf = new char[16]; 172 for (int n = 0; n < 16; n++) { 173 buf[n] = ((i >> (15-n)) & 0x1) == 1 ? '1' : '0'; 174 } 175 return new String (buf); 176 } 177 178/** 179returns a 32 char binary digit string (Integer.toBinaryString is not padded, can be less than 32 180chars) 181*/ 182public static String toBinaryString(int i) 183 { 184 char[] buf = new char[32]; 185 for (int n = 0; n < 32; n++) { 186 buf[n] = ((i >> (31-n)) & 0x1) == 1 ? '1' : '0'; 187 } 188 return new String (buf); 189 } 190 191/** 192returns a 64 char binary digit string (Long.toBinaryString is not padded, can be less than 64 193chars)) 194*/ 195public static String toBinaryString(long i) 196 { 197 char[] buf = new char[64]; 198 for (int n = 0; n < 64; n++) { 199 buf[n] = ((i >> (63-n)) & 0x1L) == 1 ? '1' : '0'; 200 } 201 return new String (buf); 202 } 203 204 205static final int DEF_SEP_NUM = 4; 206static final char DEF_SEP_CHAR = ' '; 207 208private static Map getFormatMap(String formatstr) 209 { 210 int sep_num = DEF_SEP_NUM; 211 char sep_char = DEF_SEP_CHAR; 212 213 char[] arr = null; 214 215 if (formatstr != null) { 216 arr = formatstr.toCharArray(); 217 if (arr.length > 0) { 218 try { 219 sep_num = Integer.parseInt(String.valueOf(arr[0])); 220 } 221 catch (NumberFormatException e) { 222 sep_char = arr[0]; 223 } 224 } 225 if (arr.length > 1) { 226 sep_char = arr[1]; 227 } 228 } 229 Map m = new HashMap(); 230 m.put("sep_num", sep_num); 231 m.put("sep_char", sep_char); 232 return m; 233 } 234 235/** 236returns a 8 char binary digit string. 237<p>The format string has a number and separator, like "4 " which will print chunks of size <num> 238with the specified <separator>. The number must be between [1-9] and separator must be a single 239character, like: | or space. Errors in the format string are ignored and default values are used 240instead (4 and space). 241*/ 242public static String toBinaryString(byte i, String format) 243 { 244 String result = toBinaryString(i); 245 246 Map m = getFormatMap(format); 247 int sep_num = (Integer) m.get("sep_num"); 248 char sep_char = (Character) m.get("sep_char"); 249 250 StringBuilder builder = new StringBuilder(); 251 for (int n = 8, pos = 1; n > 0; n--, pos++) 252 { 253 builder.append(result.charAt(n-1)); 254 if ((pos % sep_num == 0) && n > 1) { 255 builder.append(sep_char); 256 } 257 } 258 return builder.reverse().toString(); 259 } 260 261/** 262returns a 16 char binary digit string. 263<p>The format string has a number and separator, like "4 " which will print chunks of size <num> 264with the specified <separator>. The number must be between [1-9] and separator must be a single 265character, like: | or space. Errors in the format string are ignored and default values are used 266instead (4 and space). 267*/ 268public static String toBinaryString(short i, String format) 269 { 270 String result = toBinaryString(i); 271 272 Map m = getFormatMap(format); 273 int sep_num = (Integer) m.get("sep_num"); 274 char sep_char = (Character) m.get("sep_char"); 275 276 StringBuilder builder = new StringBuilder(); 277 for (int n = 16, pos = 1; n > 0; n--, pos++) 278 { 279 builder.append(result.charAt(n-1)); 280 if ((pos % sep_num == 0) && n > 1) { 281 builder.append(sep_char); 282 } 283 } 284 return builder.reverse().toString(); 285 } 286 287/** 288returns a 16 char binary digit string. 289<p>The format string has a number and separator, like "4 " which will print chunks of size num with 290the specified separator. 291*/ 292public static String toBinaryString(char i, String format) 293 { 294 String result = toBinaryString(i); 295 296 Map m = getFormatMap(format); 297 int sep_num = (Integer) m.get("sep_num"); 298 char sep_char = (Character) m.get("sep_char"); 299 300 StringBuilder builder = new StringBuilder(); 301 for (int n = 16, pos = 1; n > 0; n--, pos++) 302 { 303 builder.append(result.charAt(n-1)); 304 if ((pos % sep_num == 0) && n > 1) { 305 builder.append(sep_char); 306 } 307 } 308 return builder.reverse().toString(); 309 } 310 311 312/** returns a 32char binary digit string (Long.toBinaryString is not padded, can be less than 31332 chars). 314<p>The format string has a number and separator, like "4 " which will print chunks of size <num> 315with the specified <separator>. The number must be between [1-9] and separator must be a single 316character, like: | or space. Errors in the format string are ignored and default values are used 317instead (4 and space). 318*/ 319public static String toBinaryString(int i, String format) 320 { 321 String result = toBinaryString(i); 322 323 Map m = getFormatMap(format); 324 int sep_num = (Integer) m.get("sep_num"); 325 char sep_char = (Character) m.get("sep_char"); 326 327 StringBuilder builder = new StringBuilder(); 328 for (int n = 32, pos = 1; n > 0; n--, pos++) 329 { 330 builder.append(result.charAt(n-1)); 331 if ((pos % sep_num == 0) && n > 1) { 332 builder.append(sep_char); 333 } 334 } 335 return builder.reverse().toString(); 336 } 337 338/** returns a 64 char binary digit string (Long.toBinaryString is not padded, can be less than 33964 chars). 340<p>The format string has a number and separator, like "4 " which will print chunks of size <num> 341with the specified <separator>. The number must be between [1-9] and separator must be a single 342character, like: | or space. Errors in the format string are ignored and default values are used 343instead (4 and space). 344*/ 345public static String toBinaryString(long i, String format) 346 { 347 String result = toBinaryString(i); 348 349 Map m = getFormatMap(format); 350 int sep_num = (Integer) m.get("sep_num"); 351 char sep_char = (Character) m.get("sep_char"); 352 353 StringBuilder builder = new StringBuilder(); 354 for (int n = 64, pos = 1; n > 0; n--, pos++) 355 { 356 builder.append(result.charAt(n-1)); 357 if ((pos % sep_num == 0) && n > 1) { 358 builder.append(sep_char); 359 } 360 } 361 return builder.reverse().toString(); 362 } 363 364public static void main (String args[]) 365 { 366 int i = Integer.parseInt("1000", 2); 367 System.out.println("[int]isBitSet('1000'/"+i+",3):"+isBitSet(i,3)); 368 369 i = Integer.parseInt("0000", 2); 370 System.out.println("[int]isBitSet('0000'/"+i+",3):"+isBitSet(i,3)); 371 372 i = Integer.parseInt("1001", 2); 373 System.out.println("[int]isBitSet('1001'/"+i+",2):"+isBitSet(i,2)); 374 375 i = Integer.parseInt("1001", 2); 376 System.out.println("[int]isBitSet('1001'/"+i+",0):"+isBitSet(i,0)); 377 378 i = Integer.parseInt("1000000000000000000000000000000", 2); 379 System.out.println("[int]isBitSet('1000000000000000000000000000000'/"+i+",2):"+isBitSet(i,2)); 380 381 i = Integer.parseInt("1001", 2); 382 try { 383 System.out.println("[int]isBitSet('1001'/"+i+",31):"+isBitSet(i,31)); 384 } 385 catch (Exception e) { 386 System.out.println(e); 387 } 388 389 long lng = Long.parseLong("11001100", 2); 390 System.out.println("[long]isBitSet('11001100'/"+lng+",3):"+isBitSet(lng,3)); 391 392 char c = (char) Integer.parseInt("1001000010010000", 2); 393 System.out.println("[char]isBitSet('1001000010010000'/"+c+",1):"+isBitSet(c,1)); 394 System.out.println("[char]isBitSet('1001000010010000'/"+c+",15):"+isBitSet(c,15)); 395 396 byte b = (byte) Integer.parseInt("00000100", 2); 397 398 System.out.println("[byte]isBitSet('00000100'/"+b+",1):"+isBitSet(b,0)); 399 System.out.println("[byte]isBitSet('00000100'/"+b+",3):"+isBitSet(b,2)); 400 401 short s = (short) Integer.parseInt("1000100010001000", 2); 402 System.out.println("[short]isBitSet('1000100010001000'/"+s+",1):"+isBitSet(s,0)); 403 System.out.println("[short]isBitSet('1000100010001000'/"+s+",3):"+isBitSet(s,15)); 404 405 System.out.println("------- set and clear bits ----------"); 406 System.out.println("------- char ----------"); 407 System.out.print("c="+toBinaryString(c)); 408 c = setBit(c, 0); 409 System.out.println("->setBit(c, 0)->"+toBinaryString(c)); 410 System.out.println("isBitSet(c, 0):"+isBitSet(c, 0)); 411 412 System.out.print("c="+toBinaryString(c)); 413 c = setBit(c, 1); 414 System.out.println("->setBit(c, 1)->"+toBinaryString(c)); 415 System.out.println("isBitSet(c, 1):"+isBitSet(c, 1)); 416 417 System.out.print("c="+toBinaryString(c)); 418 c = clearBit(c, 1); 419 System.out.println("->clearBit(c, 1)->"+toBinaryString(c)); 420 System.out.println("isBitSet(c, 1):"+isBitSet(c, 1)); 421 422 System.out.println("------- long ----------"); 423 System.out.println("lng="+toBinaryString(lng,",")); 424 lng = setBit(lng, 63); 425 System.out.println("->setBit(lng, 63)->\n "+toBinaryString(lng,",")); 426 System.out.println("isBitSet(lng, 63):"+isBitSet(lng, 63)); 427 lng = clearBit(lng, 63); 428 System.out.println("->clearBit(lng, 63)->\n "+toBinaryString(lng,",")); 429 System.out.println("isBitSet(lng, 63):"+isBitSet(lng, 63)); 430 431 System.out.println("------- int ----------"); 432 System.out.print("i="+toBinaryString(i,"|")); 433 i = setBit(i, 20); 434 System.out.println("->setBit(i, 20)-> "+toBinaryString(i,"|")); 435 System.out.println("isBitSet(i, 20):"+isBitSet(i, 20)); 436 System.out.print("i="+toBinaryString(i,"|")); 437 i = clearBit(i, 20); 438 System.out.println("->clearBit(i,20)->"+toBinaryString(i,"|")); 439 System.out.println("isBitSet(i, 20):"+isBitSet(i, 20)); 440 441 System.out.println("------- int ----------"); 442 System.out.print("i="+toBinaryString(i,"|")); 443 i = setBit(i, 31); 444 System.out.println("->setBit(i, 31)-> "+toBinaryString(i,"|")); 445 System.out.println("isBitSet(i, 31):"+isBitSet(i, 31)); 446 System.out.print("i="+toBinaryString(i,"|")); 447 i = clearBit(i, 31); 448 System.out.println("->clearBit(i,31)->"+toBinaryString(i,"|")); 449 System.out.println("isBitSet(i, 31):"+isBitSet(i, 31)); 450 451 System.out.println("------- byte ----------"); 452 System.out.println("b="+toBinaryString(b)); 453 b = setBit(b, 7); 454 System.out.println("->setBit(b, 7)->" + toBinaryString(b)); 455 System.out.println("isBitSet(b, 7):"+isBitSet(b, 7)); 456 System.out.print("b="+toBinaryString(b)); 457 b = clearBit(b, 7); 458 System.out.println("->clearBit(b, 7)->"+toBinaryString(b)); 459 System.out.println("isBitSet(b, 7):"+isBitSet(b, 7)); 460 461 System.out.println("------- short ----------"); 462 System.out.print("s="+toBinaryString(s,"|")); 463 s = setBit(s, 10); 464 System.out.println("->setBit(s, 10)->" + toBinaryString(s,"|")); 465 System.out.println("isBitSet(s, 10):"+isBitSet(s, 10)); 466 System.out.print("s="+toBinaryString(s,"|")); 467 s = clearBit(s, 10); 468 System.out.println("->clearBit(s, 10)->"+toBinaryString(s,"|")); 469 System.out.println("isBitSet(s, 10):"+isBitSet(s, 10)); 470 471 System.out.println("------- argument checks ----------"); 472 try { setBit(b, 8); } catch (RuntimeException e) { } 473 try { setBit(c, 16); } catch (RuntimeException e) { } 474 try { setBit(s, 16); } catch (RuntimeException e) { } 475 try { setBit(i, 32); } catch (RuntimeException e) { } 476 try { setBit(lng, 64); } catch (RuntimeException e) { } 477 478 try { setBit(b, 7); } catch (RuntimeException e) { } 479 try { setBit(c, 15); } catch (RuntimeException e) { } 480 try { setBit(s, 15); } catch (RuntimeException e) { } 481 try { setBit(i, 31); } catch (RuntimeException e) { } 482 try { setBit(lng, 63); } catch (RuntimeException e) { } 483 484 try { setBit(b, -1); } catch (RuntimeException e) { } 485 try { setBit(c, -1); } catch (RuntimeException e) { } 486 try { setBit(s, -1); } catch (RuntimeException e) { } 487 try { setBit(i, -1); } catch (RuntimeException e) { } 488 try { setBit(lng, -1); } catch (RuntimeException e) { } 489 490 System.out.println("done..."); 491 } 492} 493 494