github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/longbits/bytestring.go (about)

     1  // Copyright 2020 Insolar Network Ltd.
     2  // All rights reserved.
     3  // This material is licensed under the Insolar License version 1.0,
     4  // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md.
     5  
     6  package longbits
     7  
     8  import (
     9  	"encoding/hex"
    10  	"io"
    11  	"math/bits"
    12  	"strings"
    13  )
    14  
    15  const EmptyByteString = ByteString("")
    16  
    17  func WrapStr(s string) ByteString {
    18  	return ByteString(s)
    19  }
    20  
    21  func CopyBytes(v []byte) ByteString {
    22  	return ByteString(v)
    23  }
    24  
    25  func Zero(len int) ByteString {
    26  	return Fill(len, 0)
    27  }
    28  
    29  func Fill(len int, fill byte) ByteString {
    30  	if len == 0 {
    31  		return EmptyByteString
    32  	}
    33  	b := make([]byte, len)
    34  	if fill != 0 {
    35  		for i := len - 1; i >= 0; i-- {
    36  			b[i] = fill
    37  		}
    38  	}
    39  	// lest hope for the compiler to optimize it
    40  	return ByteString(b)
    41  }
    42  
    43  var _ FoldableReader = EmptyByteString
    44  
    45  type ByteString string
    46  
    47  func (v ByteString) IsEmpty() bool {
    48  	return len(v) == 0
    49  }
    50  
    51  func (v ByteString) WriteTo(w io.Writer) (int64, error) {
    52  	n, err := w.Write([]byte(v))
    53  	return int64(n), err
    54  }
    55  
    56  func (v ByteString) CopyTo(b []byte) int {
    57  	return copy(b, v)
    58  }
    59  
    60  func (v ByteString) ReadAt(b []byte, off int64) (n int, err error) {
    61  	if n, err = VerifyReadAt(b, off, len(v)); err != nil || n == 0 {
    62  		return n, err
    63  	}
    64  	return copy(b, v[off:]), nil
    65  }
    66  
    67  func (v ByteString) AsByteString() ByteString {
    68  	return v
    69  }
    70  
    71  func (v ByteString) FixedByteSize() int {
    72  	return len(v)
    73  }
    74  
    75  func (v ByteString) CutOutUint64() uint64 {
    76  	folded := v.CutOutBits64()
    77  	return folded.FoldToUint64()
    78  }
    79  
    80  func (v ByteString) FoldToUint64() uint64 {
    81  	folded := v.FoldToBits64()
    82  	return folded.FoldToUint64()
    83  }
    84  
    85  func (v ByteString) BitMasked(index int) (value byte, mask uint8) {
    86  	bytePos, bitPos := v.BitPos(index)
    87  	mask = 1 << bitPos
    88  	return v[bytePos] & mask, mask
    89  }
    90  
    91  func (v ByteString) BitBool(index int) bool {
    92  	if b, _ := v.BitMasked(index); b != 0 {
    93  		return true
    94  	}
    95  	return false
    96  }
    97  
    98  func (v ByteString) BitValue(index int) byte {
    99  	if b, _ := v.BitMasked(index); b != 0 {
   100  		return 1
   101  	}
   102  	return 0
   103  }
   104  
   105  func (v ByteString) Byte(index int) byte {
   106  	return v[index]
   107  }
   108  
   109  func (v ByteString) BitPos(index int) (bytePos int, bitPos uint8) {
   110  	bytePos, bitPos = BitPos(index)
   111  	if bytePos >= len(v) {
   112  		panic("out of bounds")
   113  	}
   114  	return bytePos, bitPos
   115  }
   116  
   117  func (v ByteString) BitLen() int {
   118  	return len(v) << 3
   119  }
   120  
   121  func (v ByteString) SearchBit(startAt int, bit bool) int {
   122  	if startAt < 0 {
   123  		panic("illegal value")
   124  	}
   125  	if startAt>>3 >= len(v) {
   126  		return -1
   127  	}
   128  
   129  	if bit {
   130  		return v.searchBit1(startAt)
   131  	}
   132  	return v.searchBit0(startAt)
   133  }
   134  
   135  func (v ByteString) searchBit1(startAt int) int {
   136  	bytePos := startAt >> 3
   137  	bitPos := byte(startAt & 0x7)
   138  
   139  	b := v[bytePos] >> bitPos
   140  	if b != 0 {
   141  		return bytePos<<3 + int(bitPos) + bits.TrailingZeros8(b)
   142  	}
   143  
   144  	for bytePos++; bytePos < len(v); bytePos++ {
   145  		b := v[bytePos]
   146  		if b != 0 {
   147  			return bytePos<<3 + bits.TrailingZeros8(b)
   148  		}
   149  	}
   150  	return -1
   151  }
   152  
   153  func (v ByteString) searchBit0(startAt int) int {
   154  	bytePos := startAt >> 3
   155  	bitPos := byte(startAt & 0x7)
   156  
   157  	b := (^v[bytePos]) >> bitPos
   158  	if b != 0 {
   159  		return bytePos<<3 + int(bitPos) + bits.TrailingZeros8(b)
   160  	}
   161  
   162  	for bytePos++; bytePos < len(v); bytePos++ {
   163  		b := v[bytePos]
   164  		if b != 0xFF {
   165  			return bytePos<<3 + bits.TrailingZeros8(^b)
   166  		}
   167  	}
   168  	return -1
   169  }
   170  
   171  func (v ByteString) CutOutBits64() (folded Bits64) {
   172  	if len(v) <= len(folded) {
   173  		copy(folded[:], v)
   174  		return folded
   175  	}
   176  
   177  	for i := range folded {
   178  		folded[i] = v[i*(len(v)-1)/(len(folded)-1)]
   179  	}
   180  	return folded
   181  }
   182  
   183  func (v ByteString) FoldToBits64() (folded Bits64) {
   184  	if len(v) == 0 {
   185  		return folded
   186  	}
   187  
   188  	alignedLen := len(v)
   189  	alignedLen &^= len(folded) - 1
   190  	copy(folded[:], v[alignedLen:])
   191  
   192  	for i := 0; i < alignedLen; i += len(folded) {
   193  		folded[0] ^= v[i+0]
   194  		folded[1] ^= v[i+1]
   195  		folded[2] ^= v[i+2]
   196  		folded[3] ^= v[i+3]
   197  		folded[4] ^= v[i+4]
   198  		folded[5] ^= v[i+5]
   199  		folded[6] ^= v[i+6]
   200  		folded[7] ^= v[i+7]
   201  	}
   202  	return folded
   203  }
   204  
   205  func (v ByteString) String() string {
   206  	return bitsToStringDefault(&v)
   207  }
   208  
   209  func (v ByteString) NewIoReader() io.Reader {
   210  	return strings.NewReader(string(v))
   211  }
   212  
   213  func (v ByteString) Hex() string {
   214  	if v == "" {
   215  		return ""
   216  	}
   217  	b := make([]byte, hex.EncodedLen(len(v)))
   218  	hex.Encode(b, []byte(v))
   219  	return string(b)
   220  }
   221  
   222  func (v ByteString) Equal(other FixedReader) bool {
   223  	if other == nil {
   224  		return false
   225  	}
   226  	if s, ok := other.(ByteString); ok {
   227  		return s == v
   228  	}
   229  	return Equal(v, other)
   230  }