From 98d311e4187997b92826186dee0239c42b81c1b0 Mon Sep 17 00:00:00 2001 From: Kevin Klues Date: Mon, 22 Mar 2021 10:54:29 +0000 Subject: [PATCH] Add pkg/bytes as a direct port from mig-parted/internal/bytes Signed-off-by: Kevin Klues --- pkg/bytes/bytes.go | 87 ++++++++++++++++++++ pkg/bytes/bytes_test.go | 178 ++++++++++++++++++++++++++++++++++++++++ pkg/bytes/native.go | 78 ++++++++++++++++++ pkg/bytes/swapbo.go | 112 +++++++++++++++++++++++++ 4 files changed, 455 insertions(+) create mode 100644 pkg/bytes/bytes.go create mode 100644 pkg/bytes/bytes_test.go create mode 100644 pkg/bytes/native.go create mode 100644 pkg/bytes/swapbo.go diff --git a/pkg/bytes/bytes.go b/pkg/bytes/bytes.go new file mode 100644 index 0000000..daa94a7 --- /dev/null +++ b/pkg/bytes/bytes.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bytes + +import ( + "encoding/binary" + "unsafe" +) + +type Raw interface { + Raw() *[]byte +} + +type Reader interface { + Read8(pos int) uint8 + Read16(pos int) uint16 + Read32(pos int) uint32 + Read64(pos int) uint64 + Len() int +} + +type Writer interface { + Write8(pos int, value uint8) + Write16(pos int, value uint16) + Write32(pos int, value uint32) + Write64(pos int, value uint64) + Len() int +} + +type Bytes interface { + Raw + Reader + Writer + Slice(offset int, size int) Bytes + LittleEndian() Bytes + BigEndian() Bytes +} + +var nativeByteOrder binary.ByteOrder + +func init() { + buf := [2]byte{} + *(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0x00FF) + + switch buf { + case [2]byte{0xFF, 0x00}: + nativeByteOrder = binary.LittleEndian + case [2]byte{0x00, 0xFF}: + nativeByteOrder = binary.BigEndian + default: + panic("Unable to infer byte order") + } +} + +func New(data *[]byte) Bytes { + return (*native)(data) +} + +func NewLittleEndian(data *[]byte) Bytes { + if nativeByteOrder == binary.LittleEndian { + return (*native)(data) + } else { + return (*swapbo)(data) + } +} + +func NewBigEndian(data *[]byte) Bytes { + if nativeByteOrder == binary.BigEndian { + return (*native)(data) + } else { + return (*swapbo)(data) + } +} diff --git a/pkg/bytes/bytes_test.go b/pkg/bytes/bytes_test.go new file mode 100644 index 0000000..3c8403e --- /dev/null +++ b/pkg/bytes/bytes_test.go @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bytes + +import ( + "encoding/binary" + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNew(t *testing.T) { + source := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + + bytes := New(&source) + require.IsType(t, (*native)(&source), bytes) + + bytes = NewLittleEndian(&source) + if nativeByteOrder == binary.LittleEndian { + require.IsType(t, (*native)(&source), bytes) + } else { + require.IsType(t, (*swapbo)(&source), bytes) + + } + + bytes = NewBigEndian(&source) + if nativeByteOrder == binary.BigEndian { + require.IsType(t, (*native)(&source), bytes) + } else { + require.IsType(t, (*swapbo)(&source), bytes) + } +} + +func TestRead(t *testing.T) { + source := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + + type testCase struct { + Description string + New func(*[]byte) Bytes + ByteOrder binary.ByteOrder + Offset int + } + testCases := func() []testCase { + var testCases []testCase + for i := 0; i < len(source)/2; i++ { + tc1 := testCase{ + fmt.Sprintf("LittleEndian offset: %v", i), + NewLittleEndian, + binary.LittleEndian, + i, + } + + tc2 := testCase{ + fmt.Sprintf("BigEndian offset: %v", i), + NewBigEndian, + binary.BigEndian, + i, + } + + testCases = append(testCases, tc1, tc2) + } + return testCases + }() + + for _, tc := range testCases { + t.Run(tc.Description, func(t *testing.T) { + bytes := tc.New(&source) + + r8 := bytes.Read8(tc.Offset) + require.Equal(t, r8, source[tc.Offset]) + + r16 := bytes.Read16(tc.Offset) + require.Equal(t, r16, tc.ByteOrder.Uint16(source[tc.Offset:tc.Offset+2])) + + r32 := bytes.Read32(tc.Offset) + require.Equal(t, r32, tc.ByteOrder.Uint32(source[tc.Offset:tc.Offset+4])) + + r64 := bytes.Read64(tc.Offset) + require.Equal(t, r64, tc.ByteOrder.Uint64(source[tc.Offset:tc.Offset+8])) + }) + } +} + +func TestWrite(t *testing.T) { + source := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + + type testCase struct { + Description string + New func(*[]byte) Bytes + ByteOrder binary.ByteOrder + Offset int + } + testCases := func() []testCase { + var testCases []testCase + for i := 0; i < len(source)/2; i++ { + tc1 := testCase{ + fmt.Sprintf("LittleEndian offset: %v", i), + NewLittleEndian, + binary.LittleEndian, + i, + } + + tc2 := testCase{ + fmt.Sprintf("BigEndian offset: %v", i), + NewBigEndian, + binary.BigEndian, + i, + } + + testCases = append(testCases, tc1, tc2) + } + return testCases + }() + + for _, tc := range testCases { + t.Run(tc.Description, func(t *testing.T) { + bytes := tc.New(&source) + + r8 := bytes.Read8(tc.Offset) + require.Equal(t, r8, source[tc.Offset]) + bytes.Write8(tc.Offset, (1<<8)-1) + r8 = bytes.Read8(tc.Offset) + require.Equal(t, r8, uint8((1<<8)-1)) + require.Equal(t, r8, source[tc.Offset]) + bytes.Write8(tc.Offset, uint8(tc.Offset)) + + r16 := bytes.Read16(tc.Offset) + require.Equal(t, r16, tc.ByteOrder.Uint16(source[tc.Offset:tc.Offset+2])) + bytes.Write16(tc.Offset, (1<<16)-1) + r16 = bytes.Read16(tc.Offset) + require.Equal(t, r16, uint16((1<<16)-1)) + require.Equal(t, r16, tc.ByteOrder.Uint16(source[tc.Offset:tc.Offset+2])) + bytes.Write8(tc.Offset+0, uint8(tc.Offset+0)) + bytes.Write8(tc.Offset+1, uint8(tc.Offset+1)) + + r32 := bytes.Read32(tc.Offset) + require.Equal(t, r32, tc.ByteOrder.Uint32(source[tc.Offset:tc.Offset+4])) + bytes.Write32(tc.Offset, (1<<32)-1) + r32 = bytes.Read32(tc.Offset) + require.Equal(t, r32, uint32((1<<32)-1)) + require.Equal(t, r32, tc.ByteOrder.Uint32(source[tc.Offset:tc.Offset+4])) + bytes.Write8(tc.Offset+0, uint8(tc.Offset+0)) + bytes.Write8(tc.Offset+1, uint8(tc.Offset+1)) + bytes.Write8(tc.Offset+2, uint8(tc.Offset+2)) + bytes.Write8(tc.Offset+3, uint8(tc.Offset+3)) + + r64 := bytes.Read64(tc.Offset) + require.Equal(t, r64, tc.ByteOrder.Uint64(source[tc.Offset:tc.Offset+8])) + bytes.Write64(tc.Offset, (1<<64)-1) + r64 = bytes.Read64(tc.Offset) + require.Equal(t, r64, uint64((1<<64)-1)) + require.Equal(t, r64, tc.ByteOrder.Uint64(source[tc.Offset:tc.Offset+8])) + bytes.Write8(tc.Offset+0, uint8(tc.Offset+0)) + bytes.Write8(tc.Offset+1, uint8(tc.Offset+1)) + bytes.Write8(tc.Offset+2, uint8(tc.Offset+2)) + bytes.Write8(tc.Offset+3, uint8(tc.Offset+3)) + bytes.Write8(tc.Offset+4, uint8(tc.Offset+4)) + bytes.Write8(tc.Offset+5, uint8(tc.Offset+5)) + bytes.Write8(tc.Offset+6, uint8(tc.Offset+6)) + bytes.Write8(tc.Offset+7, uint8(tc.Offset+7)) + }) + } +} diff --git a/pkg/bytes/native.go b/pkg/bytes/native.go new file mode 100644 index 0000000..3c79e68 --- /dev/null +++ b/pkg/bytes/native.go @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bytes + +import ( + "unsafe" +) + +type native []byte + +var _ Bytes = (*native)(nil) + +func (b *native) Read8(pos int) uint8 { + return (*b)[pos] +} + +func (b *native) Read16(pos int) uint16 { + return *(*uint16)(unsafe.Pointer(&((*b)[pos]))) +} + +func (b *native) Read32(pos int) uint32 { + return *(*uint32)(unsafe.Pointer(&((*b)[pos]))) +} + +func (b *native) Read64(pos int) uint64 { + return *(*uint64)(unsafe.Pointer(&((*b)[pos]))) +} + +func (b *native) Write8(pos int, value uint8) { + (*b)[pos] = value +} + +func (b *native) Write16(pos int, value uint16) { + *(*uint16)(unsafe.Pointer(&((*b)[pos]))) = value +} + +func (b *native) Write32(pos int, value uint32) { + *(*uint32)(unsafe.Pointer(&((*b)[pos]))) = value +} + +func (b *native) Write64(pos int, value uint64) { + *(*uint64)(unsafe.Pointer(&((*b)[pos]))) = value +} + +func (b *native) Slice(offset int, size int) Bytes { + nb := (*b)[offset : offset+size] + return &nb +} + +func (b *native) LittleEndian() Bytes { + return NewLittleEndian((*[]byte)(b)) +} + +func (b *native) BigEndian() Bytes { + return NewBigEndian((*[]byte)(b)) +} + +func (b *native) Raw() *[]byte { + return (*[]byte)(b) +} + +func (b *native) Len() int { + return len(*b) +} diff --git a/pkg/bytes/swapbo.go b/pkg/bytes/swapbo.go new file mode 100644 index 0000000..278c67d --- /dev/null +++ b/pkg/bytes/swapbo.go @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bytes + +import ( + "unsafe" +) + +type swapbo []byte + +var _ Bytes = (*swapbo)(nil) + +func (b *swapbo) Read8(pos int) uint8 { + return (*b)[pos] +} + +func (b *swapbo) Read16(pos int) uint16 { + buf := [2]byte{} + buf[0] = (*b)[pos+1] + buf[1] = (*b)[pos+0] + return *(*uint16)(unsafe.Pointer(&buf[0])) +} + +func (b *swapbo) Read32(pos int) uint32 { + buf := [4]byte{} + buf[0] = (*b)[pos+3] + buf[1] = (*b)[pos+2] + buf[2] = (*b)[pos+1] + buf[3] = (*b)[pos+0] + return *(*uint32)(unsafe.Pointer(&buf[0])) +} + +func (b *swapbo) Read64(pos int) uint64 { + buf := [8]byte{} + buf[0] = (*b)[pos+7] + buf[1] = (*b)[pos+6] + buf[2] = (*b)[pos+5] + buf[3] = (*b)[pos+4] + buf[4] = (*b)[pos+3] + buf[5] = (*b)[pos+2] + buf[6] = (*b)[pos+1] + buf[7] = (*b)[pos+0] + return *(*uint64)(unsafe.Pointer(&buf[0])) +} + +func (b *swapbo) Write8(pos int, value uint8) { + (*b)[pos] = value +} + +func (b *swapbo) Write16(pos int, value uint16) { + buf := [2]byte{} + *(*uint16)(unsafe.Pointer(&buf[0])) = value + (*b)[pos+0] = buf[1] + (*b)[pos+1] = buf[0] +} + +func (b *swapbo) Write32(pos int, value uint32) { + buf := [4]byte{} + *(*uint32)(unsafe.Pointer(&buf[0])) = value + (*b)[pos+0] = buf[3] + (*b)[pos+1] = buf[2] + (*b)[pos+2] = buf[1] + (*b)[pos+3] = buf[0] +} + +func (b *swapbo) Write64(pos int, value uint64) { + buf := [8]byte{} + *(*uint64)(unsafe.Pointer(&buf[0])) = value + (*b)[pos+0] = buf[7] + (*b)[pos+1] = buf[6] + (*b)[pos+2] = buf[5] + (*b)[pos+3] = buf[4] + (*b)[pos+4] = buf[3] + (*b)[pos+5] = buf[2] + (*b)[pos+6] = buf[1] + (*b)[pos+7] = buf[0] +} + +func (b *swapbo) Slice(offset int, size int) Bytes { + nb := (*b)[offset : offset+size] + return &nb +} + +func (b *swapbo) LittleEndian() Bytes { + return NewLittleEndian((*[]byte)(b)) +} + +func (b *swapbo) BigEndian() Bytes { + return NewBigEndian((*[]byte)(b)) +} + +func (b *swapbo) Raw() *[]byte { + return (*[]byte)(b) +} + +func (b *swapbo) Len() int { + return len(*b) +}