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 }