github.com/tunabay/go-bitarray@v1.3.1/bitarray_shift.go (about)

     1  // Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved.
     2  // Use of this source code is governed by the MIT license that can be found in
     3  // the LICENSE file.
     4  
     5  package bitarray
     6  
     7  import (
     8  	"math/bits"
     9  )
    10  
    11  // Reverse returns the bit array with its bits in reversed order.
    12  func (ba *BitArray) Reverse() *BitArray {
    13  	switch {
    14  	case ba.IsZero():
    15  		return zeroBitArray
    16  	case ba.Len() == 1, ba.b == nil:
    17  		return ba
    18  	}
    19  	buf := make([]byte, len(ba.b))
    20  	for i, o := range ba.b {
    21  		buf[len(ba.b)-1-i] = bits.Reverse8(o)
    22  	}
    23  
    24  	return NewFromBytes(buf, ba.NumPadding(), ba.nBits)
    25  }
    26  
    27  // ShiftLeft returns the bit array of shifted left by k bits.
    28  // To shift to right, call ShiftLeft(-k).
    29  func (ba *BitArray) ShiftLeft(k int) *BitArray {
    30  	switch {
    31  	case ba.IsZero():
    32  		return zeroBitArray
    33  	case ba.b == nil:
    34  		return ba
    35  	case ba.nBits <= k, ba.nBits <= -k:
    36  		return &BitArray{nBits: ba.nBits}
    37  	case 0 < k:
    38  		return ba.shiftLeft(k)
    39  	case k < 0:
    40  		return ba.shiftRight(-k)
    41  	}
    42  
    43  	return ba
    44  }
    45  
    46  func (ba *BitArray) shiftLeft(k int) *BitArray {
    47  	if k&7 == 0 {
    48  		buf := allocByteSlice(len(ba.b))
    49  		copy(buf, ba.b[k>>3:])
    50  		return &BitArray{b: buf, nBits: ba.nBits}
    51  	}
    52  
    53  	return ba.Slice(k, ba.nBits).append1(&BitArray{nBits: k})
    54  }
    55  
    56  func (ba *BitArray) shiftRight(k int) *BitArray {
    57  	if k&7 == 0 {
    58  		buf := allocByteSlice(len(ba.b))
    59  		copy(buf[k>>3:], ba.b)
    60  		if npad := ba.NumPadding(); npad != 0 {
    61  			mask := byte(0xff) << npad
    62  			buf[len(buf)-1] &= mask
    63  		}
    64  		return &BitArray{b: buf, nBits: ba.nBits}
    65  	}
    66  
    67  	return (&BitArray{nBits: k}).append1(ba.Slice(0, ba.nBits-k))
    68  }
    69  
    70  // RotateLeft returns the bit array of rotated left by k bits.
    71  // To rotate to right, call RotateLeft(-k).
    72  func (ba *BitArray) RotateLeft(k int) *BitArray {
    73  	switch {
    74  	case ba.IsZero():
    75  		return zeroBitArray
    76  	case ba.b == nil:
    77  		return ba
    78  	case 0 < k:
    79  		return ba.rotateLeft(k)
    80  	case k < 0:
    81  		return ba.rotateRight(-k)
    82  	}
    83  
    84  	return ba
    85  }
    86  
    87  func (ba *BitArray) rotateLeft(k int) *BitArray {
    88  	k %= ba.nBits
    89  	switch {
    90  	case k == 0:
    91  		return ba
    92  	case k&7 == 0 && ba.nBits&7 == 0:
    93  		buf := allocByteSlice(len(ba.b))
    94  		nbs := k >> 3
    95  		copy(buf, ba.b[nbs:])
    96  		copy(buf[len(buf)-nbs:], ba.b)
    97  		return &BitArray{b: buf, nBits: ba.nBits}
    98  	}
    99  
   100  	return ba.Slice(k, ba.nBits).append1(ba.Slice(0, k))
   101  }
   102  
   103  func (ba *BitArray) rotateRight(k int) *BitArray {
   104  	k %= ba.nBits
   105  	switch {
   106  	case k == 0:
   107  		return ba
   108  	case k&7 == 0 && ba.nBits&7 == 0:
   109  		buf := allocByteSlice(len(ba.b))
   110  		nbs := k >> 3
   111  		copy(buf[nbs:], ba.b)
   112  		copy(buf, ba.b[len(ba.b)-nbs:])
   113  		return &BitArray{b: buf, nBits: ba.nBits}
   114  	}
   115  
   116  	return ba.Slice(ba.nBits-k, ba.nBits).append1(ba.Slice(0, ba.nBits-k))
   117  }