Skip to content

Commit

Permalink
Implement efficient copies of bytes.
Browse files Browse the repository at this point in the history
  • Loading branch information
NoamK-CR committed Dec 13, 2023
1 parent d520eb6 commit e6a14f8
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 0 deletions.
33 changes: 33 additions & 0 deletions _examples/gobytes/gobytes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2017 The go-python Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gobytes

func HashBytes(b []byte) [4]byte {
result := [4]byte{0, 0, 0, 0}
full_blocks := len(b) / 4
for i := 0; i < full_blocks; i++ {
for j := 0; j < 4; j++ {
result[j] ^= b[4*i+j]
}
}
if full_blocks*4 < len(b) {
for j := 0; j < 4; j++ {
if full_blocks*4+j < len(b) {
result[j] ^= b[full_blocks*4+j]
} else {
result[j] ^= 0x55
}
}
}
return result
}

func CreateBytes(len byte) []byte {
res := make([]byte, len)
for i := (byte)(0); i < len; i++ {
res[i] = i
}
return res
}
18 changes: 18 additions & 0 deletions _examples/gobytes/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2017 The go-python Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

from __future__ import print_function
import gobytes, go

a = bytes([0, 1, 2, 3])
b = gobytes.CreateBytes(10)
print ("Python bytes:", a)
print ("Go slice: ", b)

print ("gobytes.HashBytes from Go bytes:", gobytes.HashBytes(b))

print("Python bytes to Go: ", go.Slice_byte.from_bytes(a))
print("Go bytes to Python: ", bytes(go.Slice_byte([3, 4, 5])))

print("OK")
46 changes: 46 additions & 0 deletions bind/gen_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,25 @@ otherwise parameter is a python list that we copy from
g.pywrap.Outdent()
g.pywrap.Outdent()
}

if slNm == "Slice_byte" {
g.pywrap.Printf("@staticmethod\n")
g.pywrap.Printf("def from_bytes(value):\n")
g.pywrap.Indent()
g.pywrap.Printf(`"""Create a Go []byte object from a Python bytes object"""
`)
g.pywrap.Printf("handle = _%s_from_bytes(value)\n", qNm)
g.pywrap.Printf("return Slice_byte(handle=handle)\n")
g.pywrap.Outdent()
g.pywrap.Printf("def __bytes__(self):\n")
g.pywrap.Indent()
g.pywrap.Printf(`"""Convert the slice to a bytes object."""
`)
g.pywrap.Printf("return _%s_to_bytes(self.handle)\n", qNm)
g.pywrap.Outdent()
g.pywrap.Outdent()

}
}

if !extTypes || !pyWrapOnly {
Expand Down Expand Up @@ -367,6 +386,33 @@ otherwise parameter is a python list that we copy from

g.pybuild.Printf("mod.add_function('%s_append', None, [param('%s', 'handle'), param('%s', 'value'%s)])\n", slNm, PyHandle, esym.cpyname, transfer_ownership)
}

if slNm == "Slice_byte" {
g.gofile.Printf("//export Slice_byte_from_bytes\n")
g.gofile.Printf("func Slice_byte_from_bytes(o *C.PyObject) CGoHandle {\n")
g.gofile.Indent()
g.gofile.Printf("size := C.PyBytes_Size(o)\n")
g.gofile.Printf("ptr := unsafe.Pointer(C.PyBytes_AsString(o))\n")
g.gofile.Printf("data := make([]byte, size)\n")
g.gofile.Printf("tmp := unsafe.Slice((*byte)(ptr), size)\n")
g.gofile.Printf("copy(data, tmp)\n")
g.gofile.Printf("return handleFromPtr_Slice_byte(&data)\n")
g.gofile.Outdent()
g.gofile.Printf("}\n\n")

g.gofile.Printf("//export Slice_byte_to_bytes\n")
g.gofile.Printf("func Slice_byte_to_bytes(handle CGoHandle) *C.PyObject {\n")
g.gofile.Indent()
g.gofile.Printf("s := deptrFromHandle_Slice_byte(handle)\n")
g.gofile.Printf("ptr := unsafe.Pointer(&s[0])\n")
g.gofile.Printf("size := len(s)\n")
g.gofile.Printf("return C.PyBytes_FromStringAndSize((*C.char)(ptr), C.long(size))\n")
g.gofile.Outdent()
g.gofile.Printf("}\n\n")

g.pybuild.Printf("mod.add_function('Slice_byte_from_bytes', retval('%s'%s), [param('PyObject*', 'o', transfer_ownership=False)])\n", PyHandle, caller_owns_ret)
g.pybuild.Printf("mod.add_function('Slice_byte_to_bytes', retval('PyObject*', caller_owns_return=True), [param('%s', 'handle')])\n", PyHandle)
}
}
}

Expand Down
20 changes: 20 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var (
testBackends = map[string]string{}
features = map[string][]string{
"_examples/hi": []string{"py3"},
"_examples/gobytes": []string{"py3"},
"_examples/funcs": []string{"py3"},
"_examples/sliceptr": []string{"py3"},
"_examples/simple": []string{"py3"},
Expand Down Expand Up @@ -267,6 +268,25 @@ OK

}

func TestBytes(t *testing.T) {
// t.Parallel()
path := "_examples/gobytes"
testPkg(t, pkg{
path: path,
lang: features[path],
cmd: "build",
extras: nil,
want: []byte(`Python bytes: b'\x00\x01\x02\x03'
Go slice: go.Slice_byte len: 10 handle: 1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
gobytes.HashBytes from Go bytes: gobytes.Array_4_byte len: 4 handle: 2 [12, 13, 81, 81]
Python bytes to Go: go.Slice_byte len: 4 handle: 3 [0, 1, 2, 3]
Go bytes to Python: b'\x03\x04\x05'
OK
`),
})

}

func TestBindFuncs(t *testing.T) {
// t.Parallel()
path := "_examples/funcs"
Expand Down

0 comments on commit e6a14f8

Please sign in to comment.