001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3.util; 018 019import java.io.Serializable; 020import java.util.BitSet; 021import java.util.Objects; 022import java.util.stream.IntStream; 023 024/** 025 * A fluent {@link BitSet} with additional operations. 026 * <p> 027 * Originally from Apache Commons VFS with more added to act as a fluent replacement for {@link java.util.BitSet}. 028 * </p> 029 * @since 3.13.0 030 */ 031public final class FluentBitSet implements Cloneable, Serializable { 032 033 private static final long serialVersionUID = 1L; 034 035 /** 036 * Working BitSet. 037 */ 038 private final BitSet bitSet; 039 040 /** 041 * Creates a new bit set. All bits are initially {@code false}. 042 */ 043 public FluentBitSet() { 044 this(new BitSet()); 045 } 046 047 /** 048 * Creates a new instance for the given bit set. 049 * 050 * @param set The bit set to wrap. 051 */ 052 public FluentBitSet(final BitSet set) { 053 this.bitSet = Objects.requireNonNull(set, "set"); 054 } 055 056 /** 057 * Creates a bit set whose initial size is large enough to explicitly represent bits with indices in the range {@code 0} 058 * through {@code nbits-1}. All bits are initially {@code false}. 059 * 060 * @param nbits the initial size of the bit set. 061 * @throws NegativeArraySizeException if the specified initial size is negative. 062 */ 063 public FluentBitSet(final int nbits) { 064 this(new BitSet(nbits)); 065 } 066 067 /** 068 * Performs a logical <b>AND</b> of this target bit set with the argument bit set. This bit set is modified so that each 069 * bit in it has the value {@code true} if and only if it both initially had the value {@code true} and the 070 * corresponding bit in the bit set argument also had the value {@code true}. 071 * 072 * @param set a bit set. 073 * @return {@code this} instance. 074 */ 075 public FluentBitSet and(final BitSet set) { 076 bitSet.and(set); 077 return this; 078 } 079 080 /** 081 * Performs a logical <b>AND</b> of this target bit set with the argument bit set. This bit set is modified so that each 082 * bit in it has the value {@code true} if and only if it both initially had the value {@code true} and the 083 * corresponding bit in the bit set argument also had the value {@code true}. 084 * 085 * @param set a bit set. 086 * @return {@code this} instance. 087 */ 088 public FluentBitSet and(final FluentBitSet set) { 089 bitSet.and(set.bitSet); 090 return this; 091 } 092 093 /** 094 * Clears all of the bits in this {@link BitSet} whose corresponding bit is set in the specified {@link BitSet}. 095 * 096 * @param set the {@link BitSet} with which to mask this {@link BitSet}. 097 * @return {@code this} instance. 098 */ 099 public FluentBitSet andNot(final BitSet set) { 100 bitSet.andNot(set); 101 return this; 102 } 103 104 /** 105 * Clears all of the bits in this {@link BitSet} whose corresponding bit is set in the specified {@link BitSet}. 106 * 107 * @param set the {@link BitSet} with which to mask this {@link BitSet}. 108 * @return {@code this} instance. 109 */ 110 public FluentBitSet andNot(final FluentBitSet set) { 111 this.bitSet.andNot(set.bitSet); 112 return this; 113 } 114 115 /** 116 * Gets the wrapped bit set. 117 * 118 * @return the wrapped bit set. 119 */ 120 public BitSet bitSet() { 121 return bitSet; 122 } 123 124 /** 125 * Returns the number of bits set to {@code true} in this {@link BitSet}. 126 * 127 * @return the number of bits set to {@code true} in this {@link BitSet}. 128 */ 129 public int cardinality() { 130 return bitSet.cardinality(); 131 } 132 133 /** 134 * Sets all of the bits in this BitSet to {@code false}. 135 * 136 * @return {@code this} instance. 137 */ 138 public FluentBitSet clear() { 139 bitSet.clear(); 140 return this; 141 } 142 143 /** 144 * Sets the bits specified by the indexes to {@code false}. 145 * 146 * @param bitIndexArray the index of the bit to be cleared. 147 * @throws IndexOutOfBoundsException if the specified index is negative. 148 * @return {@code this} instance. 149 */ 150 public FluentBitSet clear(final int... bitIndexArray) { 151 for (final int e : bitIndexArray) { 152 this.bitSet.clear(e); 153 } 154 return this; 155 } 156 157 /** 158 * Sets the bit specified by the index to {@code false}. 159 * 160 * @param bitIndex the index of the bit to be cleared. 161 * @throws IndexOutOfBoundsException if the specified index is negative. 162 * @return {@code this} instance. 163 */ 164 public FluentBitSet clear(final int bitIndex) { 165 bitSet.clear(bitIndex); 166 return this; 167 } 168 169 /** 170 * Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to 171 * {@code false}. 172 * 173 * @param fromIndex index of the first bit to be cleared. 174 * @param toIndex index after the last bit to be cleared. 175 * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or 176 * {@code fromIndex} is larger than {@code toIndex}. 177 * @return {@code this} instance. 178 */ 179 public FluentBitSet clear(final int fromIndex, final int toIndex) { 180 bitSet.clear(fromIndex, toIndex); 181 return this; 182 } 183 184 /** 185 * Cloning this {@link BitSet} produces a new {@link BitSet} that is equal to it. The clone of the bit set is another 186 * bit set that has exactly the same bits set to {@code true} as this bit set. 187 * 188 * @return a clone of this bit set 189 * @see #size() 190 */ 191 @Override 192 public Object clone() { 193 return new FluentBitSet((BitSet) bitSet.clone()); 194 } 195 196 @Override 197 public boolean equals(final Object obj) { 198 if (this == obj) { 199 return true; 200 } 201 if (!(obj instanceof FluentBitSet)) { 202 return false; 203 } 204 final FluentBitSet other = (FluentBitSet) obj; 205 return Objects.equals(bitSet, other.bitSet); 206 } 207 208 /** 209 * Sets the bit at the specified index to the complement of its current value. 210 * 211 * @param bitIndex the index of the bit to flip. 212 * @throws IndexOutOfBoundsException if the specified index is negative. 213 * @return {@code this} instance. 214 */ 215 public FluentBitSet flip(final int bitIndex) { 216 bitSet.flip(bitIndex); 217 return this; 218 } 219 220 /** 221 * Sets each bit from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to the 222 * complement of its current value. 223 * 224 * @param fromIndex index of the first bit to flip. 225 * @param toIndex index after the last bit to flip. 226 * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or 227 * {@code fromIndex} is larger than {@code toIndex}. 228 * @return {@code this} instance. 229 */ 230 public FluentBitSet flip(final int fromIndex, final int toIndex) { 231 bitSet.flip(fromIndex, toIndex); 232 return this; 233 } 234 235 /** 236 * Returns the value of the bit with the specified index. The value is {@code true} if the bit with the index 237 * {@code bitIndex} is currently set in this {@link BitSet}; otherwise, the result is {@code false}. 238 * 239 * @param bitIndex the bit index. 240 * @return the value of the bit with the specified index. 241 * @throws IndexOutOfBoundsException if the specified index is negative. 242 */ 243 public boolean get(final int bitIndex) { 244 return bitSet.get(bitIndex); 245 } 246 247 /** 248 * Returns a new {@link BitSet} composed of bits from this {@link BitSet} from {@code fromIndex} (inclusive) to 249 * {@code toIndex} (exclusive). 250 * 251 * @param fromIndex index of the first bit to include. 252 * @param toIndex index after the last bit to include. 253 * @return a new {@link BitSet} from a range of this {@link BitSet}. 254 * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or 255 * {@code fromIndex} is larger than {@code toIndex}. 256 */ 257 public FluentBitSet get(final int fromIndex, final int toIndex) { 258 return new FluentBitSet(bitSet.get(fromIndex, toIndex)); 259 } 260 261 @Override 262 public int hashCode() { 263 return bitSet.hashCode(); 264 } 265 266 /** 267 * Returns true if the specified {@link BitSet} has any bits set to {@code true} that are also set to {@code true} in 268 * this {@link BitSet}. 269 * 270 * @param set {@link BitSet} to intersect with. 271 * @return boolean indicating whether this {@link BitSet} intersects the specified {@link BitSet}. 272 */ 273 public boolean intersects(final BitSet set) { 274 return bitSet.intersects(set); 275 } 276 277 /** 278 * Returns true if the specified {@link BitSet} has any bits set to {@code true} that are also set to {@code true} in 279 * this {@link BitSet}. 280 * 281 * @param set {@link BitSet} to intersect with. 282 * @return boolean indicating whether this {@link BitSet} intersects the specified {@link BitSet}. 283 */ 284 public boolean intersects(final FluentBitSet set) { 285 return bitSet.intersects(set.bitSet); 286 } 287 288 /** 289 * Returns true if this {@link BitSet} contains no bits that are set to {@code true}. 290 * 291 * @return boolean indicating whether this {@link BitSet} is empty. 292 */ 293 public boolean isEmpty() { 294 return bitSet.isEmpty(); 295 } 296 297 /** 298 * Returns the "logical size" of this {@link BitSet}: the index of the highest set bit in the {@link BitSet} plus one. 299 * Returns zero if the {@link BitSet} contains no set bits. 300 * 301 * @return the logical size of this {@link BitSet}. 302 */ 303 public int length() { 304 return bitSet.length(); 305 } 306 307 /** 308 * Returns the index of the first bit that is set to {@code false} that occurs on or after the specified starting index. 309 * 310 * @param fromIndex the index to start checking from (inclusive). 311 * @return the index of the next clear bit. 312 * @throws IndexOutOfBoundsException if the specified index is negative. 313 */ 314 public int nextClearBit(final int fromIndex) { 315 return bitSet.nextClearBit(fromIndex); 316 } 317 318 /** 319 * Returns the index of the first bit that is set to {@code true} that occurs on or after the specified starting index. 320 * If no such bit exists then {@code -1} is returned. 321 * <p> 322 * To iterate over the {@code true} bits in a {@link BitSet}, use the following loop: 323 * </p> 324 * 325 * <pre> 326 * {@code 327 * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { 328 * // operate on index i here 329 * if (i == Integer.MAX_VALUE) { 330 * break; // or (i+1) would overflow 331 * } 332 * }} 333 * </pre> 334 * 335 * @param fromIndex the index to start checking from (inclusive). 336 * @return the index of the next set bit, or {@code -1} if there is no such bit. 337 * @throws IndexOutOfBoundsException if the specified index is negative. 338 */ 339 public int nextSetBit(final int fromIndex) { 340 return bitSet.nextSetBit(fromIndex); 341 } 342 343 /** 344 * Performs a logical <b>OR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it 345 * has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in 346 * the bit set argument has the value {@code true}. 347 * 348 * @param set a bit set. 349 * @return {@code this} instance. 350 */ 351 public FluentBitSet or(final BitSet set) { 352 bitSet.or(set); 353 return this; 354 } 355 356 /** 357 * Performs a logical <b>OR</b> of this bit set with the bit set arguments. This bit set is modified so that a bit in it 358 * has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in 359 * the bit set argument has the value {@code true}. 360 * 361 * @param set a bit set. 362 * @return {@code this} instance. 363 */ 364 public FluentBitSet or(final FluentBitSet... set) { 365 for (final FluentBitSet e : set) { 366 this.bitSet.or(e.bitSet); 367 } 368 return this; 369 } 370 371 /** 372 * Performs a logical <b>OR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it 373 * has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in 374 * the bit set argument has the value {@code true}. 375 * 376 * @param set a bit set. 377 * @return {@code this} instance. 378 */ 379 public FluentBitSet or(final FluentBitSet set) { 380 this.bitSet.or(set.bitSet); 381 return this; 382 } 383 384 /** 385 * Returns the index of the nearest bit that is set to {@code false} that occurs on or before the specified starting 386 * index. If no such bit exists, or if {@code -1} is given as the starting index, then {@code -1} is returned. 387 * 388 * @param fromIndex the index to start checking from (inclusive). 389 * @return the index of the previous clear bit, or {@code -1} if there is no such bit. 390 * @throws IndexOutOfBoundsException if the specified index is less than {@code -1}. 391 */ 392 public int previousClearBit(final int fromIndex) { 393 return bitSet.previousClearBit(fromIndex); 394 } 395 396 /** 397 * Returns the index of the nearest bit that is set to {@code true} that occurs on or before the specified starting 398 * index. If no such bit exists, or if {@code -1} is given as the starting index, then {@code -1} is returned. 399 * 400 * <p> 401 * To iterate over the {@code true} bits in a {@link BitSet}, use the following loop: 402 * 403 * <pre> 404 * {@code 405 * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) { 406 * // operate on index i here 407 * }} 408 * </pre> 409 * 410 * @param fromIndex the index to start checking from (inclusive) 411 * @return the index of the previous set bit, or {@code -1} if there is no such bit 412 * @throws IndexOutOfBoundsException if the specified index is less than {@code -1} 413 */ 414 public int previousSetBit(final int fromIndex) { 415 return bitSet.previousSetBit(fromIndex); 416 } 417 418 /** 419 * Sets the bit at the specified indexes to {@code true}. 420 * 421 * @param bitIndexArray a bit index array. 422 * @throws IndexOutOfBoundsException if the specified index is negative. 423 * @return {@code this} instance. 424 */ 425 public FluentBitSet set(final int... bitIndexArray) { 426 for (final int e : bitIndexArray) { 427 bitSet.set(e); 428 } 429 return this; 430 } 431 432 /** 433 * Sets the bit at the specified index to {@code true}. 434 * 435 * @param bitIndex a bit index 436 * @throws IndexOutOfBoundsException if the specified index is negative 437 * @return {@code this} instance. 438 */ 439 public FluentBitSet set(final int bitIndex) { 440 bitSet.set(bitIndex); 441 return this; 442 } 443 444 /** 445 * Sets the bit at the specified index to the specified value. 446 * 447 * @param bitIndex a bit index. 448 * @param value a boolean value to set. 449 * @throws IndexOutOfBoundsException if the specified index is negative. 450 * @return {@code this} instance. 451 */ 452 public FluentBitSet set(final int bitIndex, final boolean value) { 453 bitSet.set(bitIndex, value); 454 return this; 455 } 456 457 /** 458 * Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to 459 * {@code true}. 460 * 461 * @param fromIndex index of the first bit to be set. 462 * @param toIndex index after the last bit to be set. 463 * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or 464 * {@code fromIndex} is larger than {@code toIndex}. 465 * @return {@code this} instance. 466 */ 467 public FluentBitSet set(final int fromIndex, final int toIndex) { 468 bitSet.set(fromIndex, toIndex); 469 return this; 470 } 471 472 /** 473 * Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to the 474 * specified value. 475 * 476 * @param fromIndex index of the first bit to be set. 477 * @param toIndex index after the last bit to be set. 478 * @param value value to set the selected bits to. 479 * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or 480 * {@code fromIndex} is larger than {@code toIndex}. 481 * @return {@code this} instance. 482 */ 483 public FluentBitSet set(final int fromIndex, final int toIndex, final boolean value) { 484 bitSet.set(fromIndex, toIndex, value); 485 return this; 486 } 487 488 /** 489 * Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (inclusive) to 490 * {@code true}. 491 * 492 * @param fromIndex index of the first bit to be set 493 * @param toIndex index of the last bit to be set 494 * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or 495 * {@code fromIndex} is larger than {@code toIndex} 496 * @return {@code this} instance. 497 */ 498 public FluentBitSet setInclusive(final int fromIndex, final int toIndex) { 499 bitSet.set(fromIndex, toIndex + 1); 500 return this; 501 } 502 503 /** 504 * Returns the number of bits of space actually in use by this {@link BitSet} to represent bit values. The maximum 505 * element in the set is the size - 1st element. 506 * 507 * @return the number of bits currently in this bit set. 508 */ 509 public int size() { 510 return bitSet.size(); 511 } 512 513 /** 514 * Returns a stream of indices for which this {@link BitSet} contains a bit in the set state. The indices are returned 515 * in order, from lowest to highest. The size of the stream is the number of bits in the set state, equal to the value 516 * returned by the {@link #cardinality()} method. 517 * 518 * <p> 519 * The bit set must remain constant during the execution of the terminal stream operation. Otherwise, the result of the 520 * terminal stream operation is undefined. 521 * </p> 522 * 523 * @return a stream of integers representing set indices. 524 * @since 1.8 525 */ 526 public IntStream stream() { 527 return bitSet.stream(); 528 } 529 530 /** 531 * Returns a new byte array containing all the bits in this bit set. 532 * 533 * <p> 534 * More precisely, if: 535 * </p> 536 * <ol> 537 * <li>{@code byte[] bytes = s.toByteArray();}</li> 538 * <li>then {@code bytes.length == (s.length()+7)/8} and</li> 539 * <li>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}</li> 540 * <li>for all {@code n < 8 * bytes.length}.</li> 541 * </ol> 542 * 543 * @return a byte array containing a little-endian representation of all the bits in this bit set 544 */ 545 public byte[] toByteArray() { 546 return bitSet.toByteArray(); 547 } 548 549 /** 550 * Returns a new byte array containing all the bits in this bit set. 551 * 552 * <p> 553 * More precisely, if: 554 * </p> 555 * <ol> 556 * <li>{@code long[] longs = s.toLongArray();}</li> 557 * <li>then {@code longs.length == (s.length()+63)/64} and</li> 558 * <li>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}</li> 559 * <li>for all {@code n < 64 * longs.length}.</li> 560 * </ol> 561 * 562 * @return a byte array containing a little-endian representation of all the bits in this bit set 563 */ 564 public long[] toLongArray() { 565 return bitSet.toLongArray(); 566 } 567 568 @Override 569 public String toString() { 570 return bitSet.toString(); 571 } 572 573 /** 574 * Performs a logical <b>XOR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it 575 * has the value {@code true} if and only if one of the following statements holds: 576 * <ul> 577 * <li>The bit initially has the value {@code true}, and the corresponding bit in the argument has the value 578 * {@code false}. 579 * <li>The bit initially has the value {@code false}, and the corresponding bit in the argument has the value 580 * {@code true}. 581 * </ul> 582 * 583 * @param set a bit set 584 * @return {@code this} instance. 585 */ 586 public FluentBitSet xor(final BitSet set) { 587 bitSet.xor(set); 588 return this; 589 } 590 591 /** 592 * Performs a logical <b>XOR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it 593 * has the value {@code true} if and only if one of the following statements holds: 594 * <ul> 595 * <li>The bit initially has the value {@code true}, and the corresponding bit in the argument has the value 596 * {@code false}. 597 * <li>The bit initially has the value {@code false}, and the corresponding bit in the argument has the value 598 * {@code true}. 599 * </ul> 600 * 601 * @param set a bit set 602 * @return {@code this} instance. 603 */ 604 public FluentBitSet xor(final FluentBitSet set) { 605 bitSet.xor(set.bitSet); 606 return this; 607 } 608 609}