@@ -318,43 +318,41 @@ private void addAndShiftAllRight(boolean bit, int longIndex, int indexInLong) {
318318 int maxLongIndex = getLongIndex (elements );
319319 // add the bit and save the LSB that was shifted out
320320 int bitIntValue = Boolean .compare (bit , Boolean .FALSE );
321- int rightmostBit = insertInLong (bitIntValue , longIndex ++, indexInLong );
321+ long rightmostBit = insertInLong (bitIntValue , 1 , longIndex ++, indexInLong );
322322 // keep inserting old LSB at 0 of next long and moving on with the new LSB
323323 while (longIndex <= maxLongIndex ) {
324- rightmostBit = insertInLong (rightmostBit , longIndex ++, 0 );
324+ rightmostBit = insertInLong (rightmostBit , 1 , longIndex ++, 0 );
325325 }
326326 }
327327
328328 /**
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
330332 *
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
337335 * @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
340338 */
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
343341 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 );
353351 // re-join the two parts
354- data [longIndex ] = leftSide + rightSide ;
352+ data [longIndex ] = leftSide ^ rightSide ;
355353
356- // return the LSB
357- return ( int ) rightSideLSB ;
354+ // return the discarded bits
355+ return rightSideShiftOut ;
358356 }
359357
360358 /**
@@ -366,47 +364,63 @@ private int insertInLong(int bit, int longIndex, int indexInLong) {
366364 private void removeAndShiftAllLeft (int longIndex , int indexInLong ) {
367365 // start at the end and work back to current long index
368366 int currentLongIndex = getLongIndex (elements - 1 );
369- int leftmostBit = 0 ; // dud value for first shift
367+ long leftmostBit = 0 ; // dud value for first shift
370368 // keep adding the old MSB as LSB of the previous long index and shifting the rest to the left
371369 while (currentLongIndex > longIndex ) {
372- leftmostBit = appendBitAndRemoveAtIndex (leftmostBit , currentLongIndex --, 0 );
370+ leftmostBit = removeAtIndexAndAppend (leftmostBit , 1 , currentLongIndex --, 0 );
373371 }
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 );
376374 }
377375
378376 /**
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
385379 *
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
387382 * @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
390385 */
391- private int appendBitAndRemoveAtIndex ( int bit , int longIndex , int indexInLong ) {
386+ private long removeAtIndexAndAppend ( long lastValue , int lastLength , int longIndex , int indexInLong ) {
392387 // get right side [indexInLong : ], can not be empty, will be shifted
393388 long rightSide = (data [longIndex ] << indexInLong ) >>> indexInLong ;
394389 // 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 );
396394
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 ;
404399
405400 // 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+ }
407406
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 ;
410424 }
411425
412426 /**
@@ -503,7 +517,6 @@ private int longsRequiredForNBits(int nBits) {
503517 (double ) nBits / BITS_PER_LONG );
504518 }
505519
506-
507520 /*
508521 BitArray specific methods
509522 */
0 commit comments