diff --git a/cmem/encoder.go b/cmem/encoder.go index dc7d00a..b4fef1c 100644 --- a/cmem/encoder.go +++ b/cmem/encoder.go @@ -4,6 +4,10 @@ package cmem +// #include +// #include +import "C" + import ( "encoding/binary" "fmt" @@ -26,8 +30,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 @@ -61,7 +73,38 @@ func (enc *Encoder) Encode(data interface{}) error { rt := rv.Type() switch rt.Kind() { - case reflect.Slice, reflect.Array: + case reflect.Slice: + 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...) + } + + arraySize := C.size_t(len(tempBuf)) + vlArray := C.malloc(arraySize) + C.bzero(vlArray, arraySize) + C.memcpy(vlArray, unsafe.Pointer(&tempBuf[0]), C.size_t(arraySize)) + enc.pointerSlice = append(enc.pointerSlice, vlArray) + + // this is variable length data, it should follow hvl_t format + if err := enc.Encode(C.size_t(rv.Len())); err != nil { + return err + } + if err := enc.Encode(C.size_t(uintptr(vlArray))); err != nil { + return err + } + + return nil + + case reflect.Array: for i := 0; i < rv.Len(); i++ { if err := enc.Encode(rv.Index(i).Interface()); err != nil { return err diff --git a/cmem/encoder_test.go b/cmem/encoder_test.go index 9180ab1..eafba2f 100644 --- a/cmem/encoder_test.go +++ b/cmem/encoder_test.go @@ -6,51 +6,50 @@ package cmem import ( "bytes" - "encoding/binary" - "strconv" "testing" + "encoding/binary" ) func TestEncode(t *testing.T) { - for i, tc := range []struct { - 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, // |........| + 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) + } + } diff --git a/h5pt_table.go b/h5pt_table.go index b94d772..287d02f 100644 --- a/h5pt_table.go +++ b/h5pt_table.go @@ -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