269 lines
5.2 KiB
Go
269 lines
5.2 KiB
Go
// Copyright 2014 The Go 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 seq
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"runtime"
|
|
"unsafe"
|
|
)
|
|
|
|
// Buffer is a set of arguments or return values from a function call
|
|
// across the language boundary. Encoding is machine-dependent.
|
|
type Buffer struct {
|
|
Data []byte
|
|
Offset int // position of next read/write from Data
|
|
}
|
|
|
|
func (b *Buffer) String() string {
|
|
// Debugging.
|
|
var buf bytes.Buffer
|
|
fmt.Fprintf(&buf, "seq{Off=%d, Len=%d Data=", b.Offset, len(b.Data))
|
|
const hextable = "0123456789abcdef"
|
|
for i, v := range b.Data {
|
|
if i > 0 {
|
|
buf.WriteByte(':')
|
|
}
|
|
buf.WriteByte(hextable[v>>4])
|
|
buf.WriteByte(hextable[v&0x0f])
|
|
}
|
|
buf.WriteByte('}')
|
|
return buf.String()
|
|
}
|
|
|
|
func (b *Buffer) panic(need int) {
|
|
panic(fmt.Sprintf("need %d bytes: %s", need, b))
|
|
}
|
|
|
|
func (b *Buffer) grow(need int) {
|
|
size := len(b.Data)
|
|
if size == 0 {
|
|
size = 2
|
|
}
|
|
for size < need {
|
|
size *= 2
|
|
}
|
|
data := make([]byte, size+len(b.Data))
|
|
copy(data, b.Data[:b.Offset])
|
|
b.Data = data
|
|
}
|
|
|
|
// align returns the aligned offset.
|
|
func align(offset, alignment int) int {
|
|
pad := offset % alignment
|
|
if pad > 0 {
|
|
pad = alignment - pad
|
|
}
|
|
return pad + offset
|
|
}
|
|
|
|
func (b *Buffer) ReadInt8() int8 {
|
|
offset := b.Offset
|
|
if len(b.Data)-offset < 1 {
|
|
b.panic(1)
|
|
}
|
|
v := *(*int8)(unsafe.Pointer(&b.Data[offset]))
|
|
b.Offset++
|
|
return v
|
|
}
|
|
|
|
func (b *Buffer) ReadInt16() int16 {
|
|
offset := align(b.Offset, 2)
|
|
if len(b.Data)-offset < 2 {
|
|
b.panic(2)
|
|
}
|
|
v := *(*int16)(unsafe.Pointer(&b.Data[offset]))
|
|
b.Offset = offset + 2
|
|
return v
|
|
}
|
|
|
|
func (b *Buffer) ReadInt32() int32 {
|
|
offset := align(b.Offset, 4)
|
|
if len(b.Data)-offset < 4 {
|
|
b.panic(4)
|
|
}
|
|
v := *(*int32)(unsafe.Pointer(&b.Data[offset]))
|
|
b.Offset = offset + 4
|
|
return v
|
|
}
|
|
|
|
func (b *Buffer) ReadInt64() int64 {
|
|
offset := align(b.Offset, 8)
|
|
if len(b.Data)-offset < 8 {
|
|
b.panic(8)
|
|
}
|
|
v := *(*int64)(unsafe.Pointer(&b.Data[offset]))
|
|
b.Offset = offset + 8
|
|
return v
|
|
}
|
|
|
|
func (b *Buffer) ReadBool() bool {
|
|
return b.ReadInt8() != 0
|
|
}
|
|
|
|
func (b *Buffer) ReadInt() int {
|
|
return int(b.ReadInt64())
|
|
}
|
|
|
|
func (b *Buffer) ReadFloat32() float32 {
|
|
offset := align(b.Offset, 4)
|
|
if len(b.Data)-offset < 4 {
|
|
b.panic(4)
|
|
}
|
|
v := *(*float32)(unsafe.Pointer(&b.Data[offset]))
|
|
b.Offset = offset + 4
|
|
return v
|
|
}
|
|
|
|
func (b *Buffer) ReadFloat64() float64 {
|
|
offset := align(b.Offset, 8)
|
|
if len(b.Data)-offset < 8 {
|
|
b.panic(8)
|
|
}
|
|
v := *(*float64)(unsafe.Pointer(&b.Data[offset]))
|
|
b.Offset = offset + 8
|
|
return v
|
|
}
|
|
|
|
func (b *Buffer) ReadByteArray() []byte {
|
|
sz := b.ReadInt64()
|
|
if sz == 0 {
|
|
return nil
|
|
}
|
|
|
|
ptr := b.ReadInt64()
|
|
org := (*[1 << 30]byte)(unsafe.Pointer(uintptr(ptr)))[:sz]
|
|
|
|
// Make a copy managed by Go, so the returned byte array can be
|
|
// used safely in Go.
|
|
slice := make([]byte, sz)
|
|
copy(slice, org)
|
|
return slice
|
|
}
|
|
|
|
func (b *Buffer) ReadRef() *Ref {
|
|
ref := &Ref{b.ReadInt32()}
|
|
if ref.Num > 0 {
|
|
// This is a foreign object reference.
|
|
// Track its lifetime with a finalizer.
|
|
runtime.SetFinalizer(ref, FinalizeRef)
|
|
}
|
|
return ref
|
|
}
|
|
|
|
func (b *Buffer) ReadString() string {
|
|
return DecString(b)
|
|
}
|
|
|
|
func (b *Buffer) WriteInt8(v int8) {
|
|
offset := b.Offset
|
|
if len(b.Data)-offset < 1 {
|
|
b.grow(offset + 1 - len(b.Data))
|
|
}
|
|
*(*int8)(unsafe.Pointer(&b.Data[offset])) = v
|
|
b.Offset++
|
|
}
|
|
|
|
func (b *Buffer) WriteInt16(v int16) {
|
|
offset := align(b.Offset, 2)
|
|
if len(b.Data)-offset < 2 {
|
|
b.grow(offset + 2 - len(b.Data))
|
|
}
|
|
*(*int16)(unsafe.Pointer(&b.Data[offset])) = v
|
|
b.Offset = offset + 2
|
|
}
|
|
|
|
func (b *Buffer) WriteInt32(v int32) {
|
|
offset := align(b.Offset, 4)
|
|
if len(b.Data)-offset < 4 {
|
|
b.grow(offset + 4 - len(b.Data))
|
|
}
|
|
*(*int32)(unsafe.Pointer(&b.Data[offset])) = v
|
|
b.Offset = offset + 4
|
|
}
|
|
|
|
func (b *Buffer) WriteInt64(v int64) {
|
|
offset := align(b.Offset, 8)
|
|
if len(b.Data)-offset < 8 {
|
|
b.grow(offset + 8 - len(b.Data))
|
|
}
|
|
*(*int64)(unsafe.Pointer(&b.Data[offset])) = v
|
|
b.Offset = offset + 8
|
|
}
|
|
|
|
func (b *Buffer) WriteBool(v bool) {
|
|
if v {
|
|
b.WriteInt8(1)
|
|
} else {
|
|
b.WriteInt8(0)
|
|
}
|
|
}
|
|
|
|
func (b *Buffer) WriteInt(v int) {
|
|
b.WriteInt64(int64(v))
|
|
}
|
|
|
|
func (b *Buffer) WriteFloat32(v float32) {
|
|
offset := align(b.Offset, 4)
|
|
if len(b.Data)-offset < 4 {
|
|
b.grow(offset + 4 - len(b.Data))
|
|
}
|
|
*(*float32)(unsafe.Pointer(&b.Data[offset])) = v
|
|
b.Offset = offset + 4
|
|
}
|
|
|
|
func (b *Buffer) WriteFloat64(v float64) {
|
|
offset := align(b.Offset, 8)
|
|
if len(b.Data)-offset < 8 {
|
|
b.grow(offset + 8 - len(b.Data))
|
|
}
|
|
*(*float64)(unsafe.Pointer(&b.Data[offset])) = v
|
|
b.Offset = offset + 8
|
|
}
|
|
|
|
func (b *Buffer) WriteByteArray(byt []byte) {
|
|
sz := len(byt)
|
|
if sz == 0 {
|
|
b.WriteInt64(int64(sz))
|
|
return
|
|
}
|
|
|
|
ptr := uintptr(unsafe.Pointer(&byt[0]))
|
|
b.WriteInt64(int64(sz))
|
|
b.WriteInt64(int64(ptr))
|
|
return
|
|
}
|
|
|
|
func (b *Buffer) WriteString(v string) {
|
|
EncString(b, v)
|
|
}
|
|
|
|
func (b *Buffer) WriteGoRef(obj interface{}) {
|
|
refs.Lock()
|
|
num := refs.refs[obj]
|
|
if num != 0 {
|
|
s := refs.objs[num]
|
|
refs.objs[num] = countedObj{s.obj, s.cnt + 1}
|
|
} else {
|
|
num = refs.next
|
|
refs.next--
|
|
if refs.next > 0 {
|
|
panic("refs.next underflow")
|
|
}
|
|
refs.refs[obj] = num
|
|
refs.objs[num] = countedObj{obj, 1}
|
|
}
|
|
refs.Unlock()
|
|
|
|
b.WriteInt32(int32(num))
|
|
}
|
|
|
|
/* TODO: Will we need it?
|
|
func (b *Buffer) WriteRef(ref *Ref) {
|
|
b.WriteInt32(ref.Num)
|
|
}
|
|
*/
|