github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/istructsmem/internal/utils/bytes.go (about)

     1  /*
     2   * Copyright (c) 2021-present Sigma-Soft, Ltd.
     3   * @author: Nikolay Nikitin
     4   */
     5  
     6  package utils
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"io"
    13  	"math"
    14  )
    15  
    16  // Copies bytes from src
    17  func CopyBytes(src []byte) []byte {
    18  	result := make([]byte, len(src))
    19  	copy(result, src)
    20  	return result
    21  }
    22  
    23  // Write int8 to buf
    24  func WriteInt8(buf *bytes.Buffer, value int8) {
    25  	buf.Write([]byte{byte(value)})
    26  }
    27  
    28  // Write byte to buf
    29  func WriteByte(buf *bytes.Buffer, value byte) {
    30  	buf.Write([]byte{value})
    31  }
    32  
    33  // Write bool to buf
    34  func WriteBool(buf *bytes.Buffer, value bool) {
    35  	s := []byte{0}
    36  	if value {
    37  		s[0] = 1
    38  	}
    39  	buf.Write(s)
    40  }
    41  
    42  // Write int16 to buf
    43  func WriteInt16(buf *bytes.Buffer, value int16) {
    44  	s := []byte{0, 0}
    45  	binary.BigEndian.PutUint16(s, uint16(value))
    46  	buf.Write(s)
    47  }
    48  
    49  // Write uint16 to buf
    50  func WriteUint16(buf *bytes.Buffer, value uint16) {
    51  	s := []byte{0, 0}
    52  	binary.BigEndian.PutUint16(s, value)
    53  	buf.Write(s)
    54  }
    55  
    56  // Write int32 to buf
    57  func WriteInt32(buf *bytes.Buffer, value int32) {
    58  	s := []byte{0, 0, 0, 0}
    59  	binary.BigEndian.PutUint32(s, uint32(value))
    60  	buf.Write(s)
    61  }
    62  
    63  // Write uint32 to buf
    64  func WriteUint32(buf *bytes.Buffer, value uint32) {
    65  	s := []byte{0, 0, 0, 0}
    66  	binary.BigEndian.PutUint32(s, value)
    67  	buf.Write(s)
    68  }
    69  
    70  // Write int64 to buf
    71  func WriteInt64(buf *bytes.Buffer, value int64) {
    72  	s := []byte{0, 0, 0, 0, 0, 0, 0, 0}
    73  	binary.BigEndian.PutUint64(s, uint64(value))
    74  	buf.Write(s)
    75  }
    76  
    77  // Write uint64 to buf
    78  func WriteUint64(buf *bytes.Buffer, value uint64) {
    79  	s := []byte{0, 0, 0, 0, 0, 0, 0, 0}
    80  	binary.BigEndian.PutUint64(s, value)
    81  	buf.Write(s)
    82  }
    83  
    84  // Write float32 to buf
    85  func WriteFloat32(buf *bytes.Buffer, value float32) {
    86  	s := []byte{0, 0, 0, 0}
    87  
    88  	binary.BigEndian.PutUint32(s, math.Float32bits(value))
    89  	buf.Write(s)
    90  }
    91  
    92  // Write float64 to buf
    93  func WriteFloat64(buf *bytes.Buffer, value float64) {
    94  	s := []byte{0, 0, 0, 0, 0, 0, 0, 0}
    95  
    96  	binary.BigEndian.PutUint64(s, math.Float64bits(value))
    97  	buf.Write(s)
    98  }
    99  
   100  // Writes short (< 64K) string into a buffer
   101  func WriteShortString(buf *bytes.Buffer, str string) {
   102  	const maxLen uint16 = 0xFFFF
   103  
   104  	var l uint16
   105  	line := str
   106  
   107  	if len(line) < int(maxLen) {
   108  		l = uint16(len(line))
   109  	} else {
   110  		l = maxLen
   111  		line = line[0:maxLen]
   112  	}
   113  
   114  	WriteUint16(buf, l)
   115  	buf.WriteString(line)
   116  }
   117  
   118  // Writes data to buffer.
   119  //
   120  // # Hints:
   121  //   - To exclude slow write through binary.Write() cast user types to go-types as possible.
   122  //   - To avoid escaping values to heap during interface conversion use Write××× routines as possible.
   123  func SafeWriteBuf(b *bytes.Buffer, data any) {
   124  	var err error
   125  	switch v := data.(type) {
   126  	case nil:
   127  	case int8:
   128  		WriteInt8(b, v)
   129  	case uint8:
   130  		WriteByte(b, v)
   131  	case int16:
   132  		WriteInt16(b, v)
   133  	case uint16:
   134  		WriteUint16(b, v)
   135  	case int32:
   136  		WriteInt32(b, v)
   137  	case uint32:
   138  		WriteUint32(b, v)
   139  	case int64:
   140  		WriteInt64(b, v)
   141  	case uint64:
   142  		WriteUint64(b, v)
   143  	case bool:
   144  		WriteBool(b, v)
   145  	case float32:
   146  		WriteFloat32(b, v)
   147  	case float64:
   148  		WriteFloat64(b, v)
   149  	case []byte:
   150  		_, err = b.Write(v)
   151  	case string:
   152  		_, err = b.WriteString(v)
   153  	default:
   154  		err = binary.Write(b, binary.BigEndian, v)
   155  	}
   156  	if err != nil {
   157  		panic(err)
   158  	}
   159  }
   160  
   161  // Returns error if buf shorter than len bytes
   162  func checkBufLen(buf *bytes.Buffer, length int) error {
   163  	if l := buf.Len(); l < length {
   164  		return fmt.Errorf("error read data from byte buffer, expected %d bytes, but only %d bytes is available: %w", length, l, io.ErrUnexpectedEOF)
   165  	}
   166  	return nil
   167  }
   168  
   169  // Reads int8 from buf
   170  func ReadInt8(buf *bytes.Buffer) (int8, error) {
   171  	i, e := buf.ReadByte()
   172  	if e == io.EOF {
   173  		e = io.ErrUnexpectedEOF
   174  	}
   175  	return int8(i), e
   176  }
   177  
   178  // Reads byte from buf
   179  func ReadByte(buf *bytes.Buffer) (byte, error) {
   180  	i, e := buf.ReadByte()
   181  	if e == io.EOF {
   182  		e = io.ErrUnexpectedEOF
   183  	}
   184  	return i, e
   185  }
   186  
   187  // Reads bool from buf
   188  func ReadBool(buf *bytes.Buffer) (bool, error) {
   189  	i, e := ReadByte(buf)
   190  	return i != 0, e
   191  }
   192  
   193  // Reads int16 from buf
   194  func ReadInt16(buf *bytes.Buffer) (int16, error) {
   195  	const size = 2
   196  	if err := checkBufLen(buf, size); err != nil {
   197  		return 0, err
   198  	}
   199  	return int16(binary.BigEndian.Uint16(buf.Next(size))), nil
   200  }
   201  
   202  // Reads uint16 from buf
   203  func ReadUInt16(buf *bytes.Buffer) (uint16, error) {
   204  	const size = 2
   205  	if err := checkBufLen(buf, size); err != nil {
   206  		return 0, err
   207  	}
   208  	return binary.BigEndian.Uint16(buf.Next(size)), nil
   209  }
   210  
   211  // Reads int32 from buf
   212  func ReadInt32(buf *bytes.Buffer) (int32, error) {
   213  	const size = 4
   214  	if err := checkBufLen(buf, size); err != nil {
   215  		return 0, err
   216  	}
   217  	return int32(binary.BigEndian.Uint32(buf.Next(size))), nil
   218  }
   219  
   220  // Reads uint32 from buf
   221  func ReadUInt32(buf *bytes.Buffer) (uint32, error) {
   222  	const size = 4
   223  	if err := checkBufLen(buf, size); err != nil {
   224  		return 0, err
   225  	}
   226  	return binary.BigEndian.Uint32(buf.Next(size)), nil
   227  }
   228  
   229  // Reads int64 from buf
   230  func ReadInt64(buf *bytes.Buffer) (int64, error) {
   231  	const size = 8
   232  	if err := checkBufLen(buf, size); err != nil {
   233  		return 0, err
   234  	}
   235  	return int64(binary.BigEndian.Uint64(buf.Next(size))), nil
   236  }
   237  
   238  // Reads uint64 from buf
   239  func ReadUInt64(buf *bytes.Buffer) (uint64, error) {
   240  	const size = 8
   241  	if err := checkBufLen(buf, size); err != nil {
   242  		return 0, err
   243  	}
   244  	return binary.BigEndian.Uint64(buf.Next(size)), nil
   245  }
   246  
   247  // Reads float32 from buf
   248  func ReadFloat32(buf *bytes.Buffer) (float32, error) {
   249  	const size = 4
   250  	if err := checkBufLen(buf, size); err != nil {
   251  		return 0, err
   252  	}
   253  	return math.Float32frombits(binary.BigEndian.Uint32(buf.Next(size))), nil
   254  }
   255  
   256  // Reads float64 from buf
   257  func ReadFloat64(buf *bytes.Buffer) (float64, error) {
   258  	const size = 8
   259  	if err := checkBufLen(buf, size); err != nil {
   260  		return 0, err
   261  	}
   262  	return math.Float64frombits(binary.BigEndian.Uint64(buf.Next(size))), nil
   263  }
   264  
   265  // Reads short (< 64K) string from a buffer
   266  func ReadShortString(buf *bytes.Buffer) (string, error) {
   267  	const size = 2
   268  	if err := checkBufLen(buf, size); err != nil {
   269  		return "", err
   270  	}
   271  	strLen := int(binary.BigEndian.Uint16(buf.Next(size)))
   272  	if strLen == 0 {
   273  		return "", nil
   274  	}
   275  	if err := checkBufLen(buf, strLen); err != nil {
   276  		return "", err
   277  	}
   278  	return string(buf.Next(strLen)), nil
   279  }
   280  
   281  // Returns a slice of bytes built from the specified values, written from left to right
   282  func ToBytes(value ...interface{}) []byte {
   283  	buf := new(bytes.Buffer)
   284  	for _, p := range value {
   285  		SafeWriteBuf(buf, p)
   286  	}
   287  	return buf.Bytes()
   288  }
   289  
   290  // Returns is all bytes is max (0xFF)
   291  func FullBytes(b []byte) bool {
   292  	for _, e := range b {
   293  		if e != math.MaxUint8 {
   294  			return false
   295  		}
   296  	}
   297  	return true
   298  }
   299  
   300  // Increments by one bit low byte and returns the result.
   301  //
   302  // Useful to obtain right margin of half-open range of partially filled clustering columns
   303  func IncBytes(cur []byte) (next []byte) {
   304  	if FullBytes(cur) {
   305  		return nil
   306  	}
   307  
   308  	var incByte func(i int)
   309  	incByte = func(i int) {
   310  		if next[i] != math.MaxUint8 {
   311  			next[i]++
   312  			return
   313  		}
   314  		next[i] = 0
   315  		incByte(i - 1)
   316  	}
   317  	next = make([]byte, len(cur))
   318  	copy(next, cur)
   319  	incByte(len(cur) - 1)
   320  	return next
   321  }