Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This change modifies Gonum to support Slice in Struct #64

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 48 additions & 3 deletions cmem/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

package cmem

// #include "hdf5.h"
// #include <stdlib.h>
// #include <string.h>
import "C"

import (
"encoding/binary"
"fmt"
Expand All @@ -26,8 +31,16 @@ func init() {
// subsequently write an in memory object to a PacketTable using Append().
type Encoder struct {
// Buf contains the encoded data.
Buf []byte
offset int
Buf []byte
offset int
pointerSlice []unsafe.Pointer
}

// FreeMemory is to free memory from C
func (enc *Encoder) FreeMemory() {
for i := 0; i < len(enc.pointerSlice); i++ {
C.free(enc.pointerSlice[i])
}
}

// Encode encodes the value passed as data to binary form stored in []Buf. This
Expand Down Expand Up @@ -61,7 +74,39 @@ func (enc *Encoder) Encode(data interface{}) error {
rt := rv.Type()

switch rt.Kind() {
case reflect.Slice, reflect.Array:
case reflect.Slice:
length := C.size_t(reflect.ValueOf(data).Len())
msize := C.size_t(rv.Index(0).Type().Size() * uintptr(length))

// this is variable length data, it should follow hvl_t format
enc.Encode(length)
egachen marked this conversation as resolved.
Show resolved Hide resolved

pointer := C.malloc(msize)
enc.pointerSlice = append(enc.pointerSlice, pointer)

C.memset(pointer, 0, msize)

var tempBuf []byte
for i := 0; i < rv.Len(); i++ {
var myenc Encoder
if err := myenc.Encode(rv.Index(i).Interface()); err != nil {
return err
}
mypad := myenc.offset - len(myenc.Buf)
if mypad > 0 {
myenc.Buf = append(myenc.Buf, make([]byte, mypad)...)
}

tempBuf = append(tempBuf, myenc.Buf...)
}
// copy contents from temp buf to C memory
C.memcpy(pointer, unsafe.Pointer(&tempBuf[0]), msize)

enc.Encode(C.size_t(uintptr(pointer)))
egachen marked this conversation as resolved.
Show resolved Hide resolved

return nil

case reflect.Array:
for i := 0; i < rv.Len(); i++ {
if err := enc.Encode(rv.Index(i).Interface()); err != nil {
return err
Expand Down
83 changes: 41 additions & 42 deletions cmem/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,50 @@ package cmem

import (
"bytes"
"encoding/binary"
"strconv"
"testing"
"encoding/binary"
)

func TestEncode(t *testing.T) {
for i, tc := range []struct {
egachen marked this conversation as resolved.
Show resolved Hide resolved
v interface{}
want []byte
}{
{
v: struct {
V1 uint8
V2 uint64
V3 uint8
V4 uint16
}{1, 2, 3, 4},
want: []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |........|
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |........|
0x03, 0x00, 0x04, 0x00, /* */ // |....|
},
},
{
v: []int32{1, 20, 300, 4000, 50000, 600000, 7000000, 8000000},
want: []byte{
0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, // |........|
0x2c, 0x01, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, // |,.......|
0x50, 0xc3, 0x00, 0x00, 0xc0, 0x27, 0x09, 0x00, // |P....'..|
0xc0, 0xcf, 0x6a, 0x00, 0x00, 0x12, 0x7a, 0x00, // |..j...z.|
},
},
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
oldEndian := nativeEndian
nativeEndian = binary.LittleEndian
defer func() { nativeEndian = oldEndian }()
var enc Encoder
err := enc.Encode(tc.v)
if err != nil {
t.Fatalf("could not encode: %v", err)
}
if !bytes.Equal(enc.Buf, tc.want) {
t.Fatalf("encoding error:\ngot = %v\nwant= %v", enc.Buf, tc.want)
}
})
v := struct {
V1 uint8
V2 uint64
V3 uint8
V4 uint16
}{1, 2, 3, 4}
want := []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |........|
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |........|
0x03, 0x00, 0x04, 0x00, /* */ // |....|
}
var enc Encoder
err := enc.Encode(v)
if err != nil {
t.Fatalf("could not encode: %v", err)
}
if !bytes.Equal(enc.Buf, want) {
t.Fatalf("encoding error:\ngot = %v\nwant= %v", enc.Buf, want)
}
}

func TestEncodeSlice(t *testing.T) {
v := []int32{1, 20, 300, 4000, 50000, 600000, 7000000, 8000000}
want := []byte{
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |........|
egachen marked this conversation as resolved.
Show resolved Hide resolved
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |,.......|
}
var enc Encoder
err := enc.Encode(v)
if err != nil {
t.Fatalf("could not encode: %v", err)
}
pointer := enc.pointerSlice[0]
bs := make([]byte, 8)
binary.LittleEndian.PutUint64(bs, uint64(uintptr(pointer)))
copy(want[8:16], bs[:])

if !bytes.Equal(enc.Buf, want) {
t.Fatalf("encoding error:\ngot = %v\nwant= %v", enc.Buf, want)
}

}
3 changes: 3 additions & 0 deletions h5pt_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ func (t *Table) Append(args ...interface{}) error {
}

var enc cmem.Encoder
defer enc.FreeMemory()

for _, arg := range args {
if err := enc.Encode(arg); err != nil {
return err
Expand Down Expand Up @@ -167,6 +169,7 @@ func createTable(id C.hid_t, name string, dtype *Datatype, chunkSize, compressio
if err := checkID(hid); err != nil {
return nil, err
}

egachen marked this conversation as resolved.
Show resolved Hide resolved
return newPacketTable(hid), nil
}

Expand Down