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