@@ -318,43 +318,41 @@ private void addAndShiftAllRight(boolean bit, int longIndex, int indexInLong) {
318
318
int maxLongIndex = getLongIndex (elements );
319
319
// add the bit and save the LSB that was shifted out
320
320
int bitIntValue = Boolean .compare (bit , Boolean .FALSE );
321
- int rightmostBit = insertInLong (bitIntValue , longIndex ++, indexInLong );
321
+ long rightmostBit = insertInLong (bitIntValue , 1 , longIndex ++, indexInLong );
322
322
// keep inserting old LSB at 0 of next long and moving on with the new LSB
323
323
while (longIndex <= maxLongIndex ) {
324
- rightmostBit = insertInLong (rightmostBit , longIndex ++, 0 );
324
+ rightmostBit = insertInLong (rightmostBit , 1 , longIndex ++, 0 );
325
325
}
326
326
}
327
327
328
328
/**
329
- * Inserts the bit in the index of the long specified by the arguments and returns the previous LSB.
329
+ * Inserts the {@code lastLength} rightmost bits of lastValue in the position specified by {@code longIndex} and
330
+ * {@code indexInLong}, and then shifts every element with index >= {@code indexInLong} to the right. The bits that
331
+ * are shifted out are returned in the leftmost position
330
332
*
331
- * <p>
332
- * Inserting at any index is done by splitting the long word in two parts and rejoining them after shifting and
333
- * setting the new bit. The LSB that is shifted out is returned.
334
- * </p>
335
- *
336
- * @param bit the bit to be inserted
333
+ * @param lastValue bits to be inserted into the long
334
+ * @param lastLength length in bits of the last value
337
335
* @param longIndex index of the long in the {@code data} array
338
- * @param indexInLong index of the bit in the long
339
- * @return LSB of the long before insertion
336
+ * @param indexInLong index of the insertion bit in the long
337
+ * @return bits that were shifted out due to the insertion
340
338
*/
341
- private int insertInLong (int bit , int longIndex , int indexInLong ) {
342
- // get right side [indexInLong : ], can not be empty, will be shifted
339
+ private long insertInLong (long lastValue , int lastLength , int longIndex , int indexInLong ) {
340
+ // select the bits [indexInLong, (word end)] for the insertion
343
341
long rightSide = (data [longIndex ] << indexInLong ) >>> indexInLong ;
344
- // get left side [0 : indexInLong), can be empty, will remain intact
345
- long leftSide = data [longIndex ] - rightSide ;
346
-
347
- // save LSB
348
- long rightSideLSB = rightSide & 1L ;
349
- // unsigned shift to the right to make space for the new bit
350
- rightSide >>>= 1 ;
351
- // set the new bit
352
- rightSide |= ( long ) bit << (BITS_PER_LONG - 1 - indexInLong );
342
+ // separate the left part, this will remain intact
343
+ long leftSide = data [longIndex ] & ~ rightSide ;
344
+
345
+ // save the bits that will be shifted out
346
+ long rightSideShiftOut = selectBits ( rightSide , BITS_PER_LONG - lastLength , lastLength ) ;
347
+ // unsigned shift to the right to make space for the new bits
348
+ rightSide >>>= lastLength ;
349
+ // set the new bits
350
+ rightSide |= lastValue << (BITS_PER_LONG - lastLength - indexInLong );
353
351
// re-join the two parts
354
- data [longIndex ] = leftSide + rightSide ;
352
+ data [longIndex ] = leftSide ^ rightSide ;
355
353
356
- // return the LSB
357
- return ( int ) rightSideLSB ;
354
+ // return the discarded bits
355
+ return rightSideShiftOut ;
358
356
}
359
357
360
358
/**
@@ -366,47 +364,63 @@ private int insertInLong(int bit, int longIndex, int indexInLong) {
366
364
private void removeAndShiftAllLeft (int longIndex , int indexInLong ) {
367
365
// start at the end and work back to current long index
368
366
int currentLongIndex = getLongIndex (elements - 1 );
369
- int leftmostBit = 0 ; // dud value for first shift
367
+ long leftmostBit = 0 ; // dud value for first shift
370
368
// keep adding the old MSB as LSB of the previous long index and shifting the rest to the left
371
369
while (currentLongIndex > longIndex ) {
372
- leftmostBit = appendBitAndRemoveAtIndex (leftmostBit , currentLongIndex --, 0 );
370
+ leftmostBit = removeAtIndexAndAppend (leftmostBit , 1 , currentLongIndex --, 0 );
373
371
}
374
- // add the final MSB as LSB of {@code longIndex} and shift only the bits to the removed 's right
375
- appendBitAndRemoveAtIndex (leftmostBit , longIndex , indexInLong );
372
+ // add the final MSB as LSB of longIndex and shift only the bits to the popped bit 's right
373
+ removeAtIndexAndAppend (leftmostBit , 1 , longIndex , indexInLong );
376
374
}
377
375
378
376
/**
379
- * Appends the bit at the end of the long specified by the arguments and removes the bit at {@code indexInLong}.
380
- *
381
- * <p>
382
- * Since {@code indexInLong} can be at the middle of the long word, removing the bit is done by splitting the
383
- * long in two parts, clearing the desired bit and shifting once to restore the order of the previous bits.
384
- * </p>
377
+ * Removes the {@code lastLength} bits from the long specified by {@code longIndex} starting from {@code indexInLong}
378
+ * and then appends the same length of bits from {@code lastValue} at the end of the long. The
385
379
*
386
- * @param bit the bit to be appended to the long
380
+ * @param lastValue bits to be appended to the long
381
+ * @param lastLength length in bits of the last value
387
382
* @param longIndex index of the long in the {@code data} array
388
- * @param indexInLong index of the bit in the long
389
- * @return bit at {@code longIndex} that was popped out
383
+ * @param indexInLong index of the first removed bit in the long
384
+ * @return bits that were popped from the long
390
385
*/
391
- private int appendBitAndRemoveAtIndex ( int bit , int longIndex , int indexInLong ) {
386
+ private long removeAtIndexAndAppend ( long lastValue , int lastLength , int longIndex , int indexInLong ) {
392
387
// get right side [indexInLong : ], can not be empty, will be shifted
393
388
long rightSide = (data [longIndex ] << indexInLong ) >>> indexInLong ;
394
389
// get left side [0 : indexInLong), can be empty, will remain intact
395
- long leftSide = data [longIndex ] - rightSide ;
390
+ long leftSide = data [longIndex ] & ~rightSide ;
391
+
392
+ // save removed values
393
+ long poppedValues = selectBits (rightSide , indexInLong , lastLength ) >>> (BITS_PER_LONG - indexInLong - lastLength );
396
394
397
- // save MSB
398
- int rightSideMSB = getBitInLong (rightSide , indexInLong );
399
- // clear MSB and shift to the left to make it "disappear"
400
- rightSide &= ~singleBitMask (indexInLong );
401
- rightSide <<= 1 ;
402
- // append the previous bit
403
- rightSide += bit ;
395
+ // clear copied bits and shift to the left
396
+ rightSide = (rightSide << indexInLong + lastLength ) >>> indexInLong ;
397
+ // append the previous bits
398
+ rightSide |= lastValue ;
404
399
405
400
// re-join the two parts
406
- data [longIndex ] = leftSide + rightSide ;
401
+ data [longIndex ] = leftSide ^ rightSide ;
402
+
403
+ // return the popped bits
404
+ return poppedValues ;
405
+ }
407
406
408
- // return the MSB
409
- return rightSideMSB ;
407
+ /**
408
+ * Returns a long bit mask with ones only in the range [start, start + length)
409
+ *
410
+ * @param start start index of the selection
411
+ * @param length number of set bits in the result
412
+ * @return bit mask covering the range specified
413
+ * @implSpec <p>
414
+ * {@code start} should be in the range [0, 63]<br>
415
+ * {@code length} should be in the range [1, 64]<br>
416
+ * {@code start} and {@code length} should satisfy: start + length <= {@link #BITS_PER_LONG}
417
+ * </p>
418
+ */
419
+ private long selectBits (long aLong , int start , int length ) {
420
+ long mask = Long .MIN_VALUE >>> start ; // need at least the first bit
421
+ mask |= (Long .MIN_VALUE >>> start ) - 1 ; // make everything to the right ones
422
+ mask &= -(Long .MIN_VALUE >>> (start + length - 1 )); // make everything from end of length and forward 0
423
+ return aLong & mask ;
410
424
}
411
425
412
426
/**
@@ -503,7 +517,6 @@ private int longsRequiredForNBits(int nBits) {
503
517
(double ) nBits / BITS_PER_LONG );
504
518
}
505
519
506
-
507
520
/*
508
521
BitArray specific methods
509
522
*/
0 commit comments