github.com/tunabay/go-bitarray@v1.3.1/util.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  	"fmt"
     9  	"unsafe"
    10  )
    11  
    12  // dstOff < 8, srcOff < 8, nBits < 8, dstOff + nBits <= 8
    13  func copyBits7(dst *byte, src []byte, dstOff, srcOff, nBits int) bool {
    14  	nBits0, srcBits0 := nBits, 8-srcOff
    15  	if srcBits0 < nBits {
    16  		nBits0 = srcBits0
    17  	}
    18  	mask := byte(0xff) << (8 - nBits0) >> dstOff
    19  	*dst &= ^mask
    20  	*dst |= mask & (src[0] << srcOff >> dstOff)
    21  
    22  	zf := src[0] == 0
    23  	if nBits0 < nBits {
    24  		zf2 := copyBits7(dst, src[1:], dstOff+nBits0, 0, nBits-nBits0)
    25  		zf = zf && zf2
    26  	}
    27  
    28  	return zf
    29  }
    30  
    31  func copyBits(dst, src []byte, dstOff, srcOff, nBits int) bool {
    32  	dst, src = dst[dstOff>>3:], src[srcOff>>3:]
    33  	dstOff, srcOff = dstOff&7, srcOff&7
    34  
    35  	zf := true
    36  	if dstOff != 0 {
    37  		nBits0 := 8 - dstOff
    38  		if nBits <= nBits0 {
    39  			zf2 := copyBits7(&dst[0], src, dstOff, srcOff, nBits)
    40  			return zf2
    41  		}
    42  		zf2 := copyBits7(&dst[0], src, dstOff, srcOff, nBits0)
    43  		zf = zf && zf2
    44  
    45  		nBits -= nBits0
    46  		dst = dst[1:]
    47  		srcOff += nBits0
    48  		src = src[srcOff>>3:]
    49  		srcOff &= 7
    50  	}
    51  
    52  	if nBytes1 := nBits >> 3; 0 < nBytes1 {
    53  		if srcOff == 0 {
    54  			copy(dst, src[:nBytes1])
    55  			zf = false
    56  		} else {
    57  			rsh := 8 - srcOff
    58  			for i := 0; i < nBytes1; i++ {
    59  				dst[i] = src[i]<<srcOff | src[i+1]>>rsh
    60  				zf = zf && dst[i] == 0
    61  			}
    62  		}
    63  		nBits &= 7
    64  		if nBits == 0 {
    65  			return zf
    66  		}
    67  		dst = dst[nBytes1:]
    68  		src = src[nBytes1:]
    69  	}
    70  
    71  	zf2 := copyBits7(&dst[0], src, 0, srcOff, nBits)
    72  
    73  	return zf && zf2
    74  }
    75  
    76  func clearBits(b []byte, off, nBits int) {
    77  	b = b[off>>3:]
    78  	off &= 7
    79  
    80  	if off != 0 {
    81  		nBits0 := 8 - off
    82  		if nBits <= nBits0 {
    83  			b[0] &^= byte(0xff) << (8 - nBits) >> off
    84  			return
    85  		}
    86  		b[0] &= byte(0xff) << nBits0
    87  		nBits -= nBits0
    88  		b = b[1:]
    89  	}
    90  
    91  	if nBytes1 := nBits >> 3; 0 < nBytes1 {
    92  		for i := 0; i < nBits>>3; i++ {
    93  			b[i] = 0
    94  		}
    95  		nBits &= 7
    96  		b = b[nBytes1:]
    97  	}
    98  
    99  	if nBits != 0 {
   100  		b[0] &= byte(0xff) >> nBits
   101  	}
   102  }
   103  
   104  func setBits(b []byte, off, nBits int) {
   105  	b = b[off>>3:]
   106  	off &= 7
   107  
   108  	if off != 0 {
   109  		nBits0 := 8 - off
   110  		if nBits <= nBits0 {
   111  			b[0] |= byte(0xff) << (8 - nBits) >> off
   112  			return
   113  		}
   114  		b[0] |= byte(0xff) >> off
   115  		nBits -= nBits0
   116  		b = b[1:]
   117  	}
   118  
   119  	if nBytes1 := nBits >> 3; 0 < nBytes1 {
   120  		for i := 0; i < nBits>>3; i++ {
   121  			b[i] = 0xff
   122  		}
   123  		nBits &= 7
   124  		b = b[nBytes1:]
   125  	}
   126  
   127  	if nBits != 0 {
   128  		b[0] |= byte(0xff) << (8 - nBits)
   129  	}
   130  }
   131  
   132  func toggleBits(b []byte, off, nBits int) {
   133  	b = b[off>>3:]
   134  	off &= 7
   135  
   136  	if off != 0 {
   137  		nBits0 := 8 - off
   138  		if nBits <= nBits0 {
   139  			b[0] ^= byte(0xff) << (8 - nBits) >> off
   140  			return
   141  		}
   142  		b[0] ^= byte(0xff) >> off
   143  		nBits -= nBits0
   144  		b = b[1:]
   145  	}
   146  
   147  	if nBytes1 := nBits >> 3; 0 < nBytes1 {
   148  		for i := 0; i < nBits>>3; i++ {
   149  			b[i] ^= 0xff
   150  		}
   151  		nBits &= 7
   152  		b = b[nBytes1:]
   153  	}
   154  
   155  	if nBits != 0 {
   156  		b[0] ^= byte(0xff) << (8 - nBits)
   157  	}
   158  }
   159  
   160  // dstOff < 8, srcOff < 8, nBits < 8, dstOff + nBits <= 8
   161  func andBits7(dst *byte, src []byte, dstOff, srcOff, nBits int) {
   162  	nBits0, srcBits0 := nBits, 8-srcOff
   163  	if srcBits0 < nBits {
   164  		nBits0 = srcBits0
   165  	}
   166  	mask := byte(0xff) << (8 - nBits0) >> dstOff
   167  	*dst &= ^mask | (src[0] << srcOff >> dstOff)
   168  
   169  	if nBits0 < nBits {
   170  		andBits7(dst, src[1:], dstOff+nBits0, 0, nBits-nBits0)
   171  	}
   172  }
   173  
   174  func andBits(dst, src []byte, dstOff, srcOff, nBits int) {
   175  	dst, src = dst[dstOff>>3:], src[srcOff>>3:]
   176  	dstOff, srcOff = dstOff&7, srcOff&7
   177  
   178  	if dstOff != 0 {
   179  		nBits0 := 8 - dstOff
   180  		if nBits <= nBits0 {
   181  			andBits7(&dst[0], src, dstOff, srcOff, nBits)
   182  			return
   183  		}
   184  		andBits7(&dst[0], src, dstOff, srcOff, nBits0)
   185  
   186  		nBits -= nBits0
   187  		dst = dst[1:]
   188  		srcOff += nBits0
   189  		src = src[srcOff>>3:]
   190  		srcOff &= 7
   191  	}
   192  
   193  	// TODO: maybe can be optimized using asUint64Slice()
   194  	if nBytes1 := nBits >> 3; 0 < nBytes1 {
   195  		if srcOff == 0 {
   196  			for i := 0; i < nBytes1; i++ {
   197  				dst[i] &= src[i]
   198  			}
   199  		} else {
   200  			rsh := 8 - srcOff
   201  			for i := 0; i < nBytes1; i++ {
   202  				dst[i] &= src[i]<<srcOff | src[i+1]>>rsh
   203  			}
   204  		}
   205  		nBits &= 7
   206  		if nBits == 0 {
   207  			return
   208  		}
   209  		dst = dst[nBytes1:]
   210  		src = src[nBytes1:]
   211  	}
   212  
   213  	andBits7(&dst[0], src, 0, srcOff, nBits)
   214  }
   215  
   216  // dstOff < 8, srcOff < 8, nBits < 8, dstOff + nBits <= 8
   217  func orBits7(dst *byte, src []byte, dstOff, srcOff, nBits int) {
   218  	nBits0, srcBits0 := nBits, 8-srcOff
   219  	if srcBits0 < nBits {
   220  		nBits0 = srcBits0
   221  	}
   222  	mask := byte(0xff) << (8 - nBits0) >> dstOff
   223  	*dst |= mask & (src[0] << srcOff >> dstOff)
   224  
   225  	if nBits0 < nBits {
   226  		orBits7(dst, src[1:], dstOff+nBits0, 0, nBits-nBits0)
   227  	}
   228  }
   229  
   230  func orBits(dst, src []byte, dstOff, srcOff, nBits int) {
   231  	dst, src = dst[dstOff>>3:], src[srcOff>>3:]
   232  	dstOff, srcOff = dstOff&7, srcOff&7
   233  
   234  	if dstOff != 0 {
   235  		nBits0 := 8 - dstOff
   236  		if nBits <= nBits0 {
   237  			orBits7(&dst[0], src, dstOff, srcOff, nBits)
   238  			return
   239  		}
   240  		orBits7(&dst[0], src, dstOff, srcOff, nBits0)
   241  
   242  		nBits -= nBits0
   243  		dst = dst[1:]
   244  		srcOff += nBits0
   245  		src = src[srcOff>>3:]
   246  		srcOff &= 7
   247  	}
   248  
   249  	// TODO: maybe can be optimized using asUint64Slice()
   250  	if nBytes1 := nBits >> 3; 0 < nBytes1 {
   251  		if srcOff == 0 {
   252  			for i := 0; i < nBytes1; i++ {
   253  				dst[i] |= src[i]
   254  			}
   255  		} else {
   256  			rsh := 8 - srcOff
   257  			for i := 0; i < nBytes1; i++ {
   258  				dst[i] |= src[i]<<srcOff | src[i+1]>>rsh
   259  			}
   260  		}
   261  		nBits &= 7
   262  		if nBits == 0 {
   263  			return
   264  		}
   265  		dst = dst[nBytes1:]
   266  		src = src[nBytes1:]
   267  	}
   268  
   269  	orBits7(&dst[0], src, 0, srcOff, nBits)
   270  }
   271  
   272  // dstOff < 8, srcOff < 8, nBits < 8, dstOff + nBits <= 8
   273  func xorBits7(dst *byte, src []byte, dstOff, srcOff, nBits int) {
   274  	nBits0, srcBits0 := nBits, 8-srcOff
   275  	if srcBits0 < nBits {
   276  		nBits0 = srcBits0
   277  	}
   278  	mask := byte(0xff) << (8 - nBits0) >> dstOff
   279  	*dst ^= mask & (src[0] << srcOff >> dstOff)
   280  
   281  	if nBits0 < nBits {
   282  		xorBits7(dst, src[1:], dstOff+nBits0, 0, nBits-nBits0)
   283  	}
   284  }
   285  
   286  func xorBits(dst, src []byte, dstOff, srcOff, nBits int) {
   287  	dst, src = dst[dstOff>>3:], src[srcOff>>3:]
   288  	dstOff, srcOff = dstOff&7, srcOff&7
   289  
   290  	if dstOff != 0 {
   291  		nBits0 := 8 - dstOff
   292  		if nBits <= nBits0 {
   293  			xorBits7(&dst[0], src, dstOff, srcOff, nBits)
   294  			return
   295  		}
   296  		xorBits7(&dst[0], src, dstOff, srcOff, nBits0)
   297  
   298  		nBits -= nBits0
   299  		dst = dst[1:]
   300  		srcOff += nBits0
   301  		src = src[srcOff>>3:]
   302  		srcOff &= 7
   303  	}
   304  
   305  	// TODO: maybe can be optimized using asUint64Slice()
   306  	if nBytes1 := nBits >> 3; 0 < nBytes1 {
   307  		if srcOff == 0 {
   308  			for i := 0; i < nBytes1; i++ {
   309  				dst[i] ^= src[i]
   310  			}
   311  		} else {
   312  			rsh := 8 - srcOff
   313  			for i := 0; i < nBytes1; i++ {
   314  				dst[i] ^= src[i]<<srcOff | src[i+1]>>rsh
   315  			}
   316  		}
   317  		nBits &= 7
   318  		if nBits == 0 {
   319  			return
   320  		}
   321  		dst = dst[nBytes1:]
   322  		src = src[nBytes1:]
   323  	}
   324  
   325  	xorBits7(&dst[0], src, 0, srcOff, nBits)
   326  }
   327  
   328  func allBytesZero(b []byte) bool {
   329  	for _, u64 := range asUint64Slice(b) {
   330  		if u64 != 0 {
   331  			return false
   332  		}
   333  	}
   334  	return true
   335  }
   336  
   337  func panicf(format string, v ...interface{}) {
   338  	panic("bitarray: " + fmt.Sprintf(format, v...))
   339  }
   340  
   341  func allocByteSlice(nBytes int) []byte {
   342  	return make([]byte, nBytes, (nBytes+7) & ^7)
   343  }
   344  
   345  func asUint64Slice(b []byte) []uint64 {
   346  	return unsafe.Slice((*uint64)(unsafe.Pointer(&b[0])), (len(b)+7)>>3)
   347  }
   348  
   349  func fill00(b []byte) {
   350  	// This seems to get optimized into a memclr.
   351  	for i := range b {
   352  		b[i] = 0
   353  	}
   354  	// copy(b, []byte{0, 0, 0, 0, 0, 0, 0, 0})
   355  	// for n := 8; n < len(b); n <<= 1 {
   356  	// 	copy(b[n:], b[:n])
   357  	// }
   358  }
   359  
   360  func fillFF(b []byte) {
   361  	copy(b, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
   362  	for n := 8; n < len(b); n <<= 1 {
   363  		copy(b[n:], b[:n])
   364  	}
   365  }
   366  
   367  func fill30(b []byte) {
   368  	copy(b, []byte{0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30})
   369  	for n := 8; n < len(b); n <<= 1 {
   370  		copy(b[n:], b[:n])
   371  	}
   372  }
   373  
   374  // ba != nil
   375  func (ba *BitArray) bits8() []byte {
   376  	b8 := make([]byte, ba.nBits)
   377  	if ba.b == nil {
   378  		return b8
   379  	}
   380  	for i := 0; i < ba.nBits; i++ {
   381  		b8[i] = ba.b[i>>3] >> (7 - i&7) & 1
   382  	}
   383  	return b8
   384  }