github.com/tidwall/pair@v0.0.0-20170418221434-1140497fc57a/pair.go (about) 1 package pair 2 3 import ( 4 "encoding/binary" 5 "reflect" 6 "unsafe" 7 ) 8 9 const maxInt = int(^uint(0) >> 1) 10 11 // Pair is a tightly packed key/value pair 12 type Pair struct { 13 ptr unsafe.Pointer 14 } 15 16 // New returns a Pair 17 func New(key, value []byte) Pair { 18 slice := makenz(8 + len(value) + len(key)) 19 binary.LittleEndian.PutUint32(slice, uint32(len(value))) 20 binary.LittleEndian.PutUint32(slice[4:], uint32(len(key))) 21 copy(slice[8:], value) 22 copy(slice[8+len(value):], key) 23 return Pair{unsafe.Pointer(&slice[0])} 24 } 25 func (pair Pair) getSlice() []byte { 26 if uintptr(pair.ptr) == 0 { 27 return nil 28 } 29 return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ 30 Data: uintptr(pair.ptr), 31 Len: maxInt, 32 Cap: maxInt, 33 })) 34 } 35 36 // Value returns the value 37 func (pair Pair) Value() []byte { 38 slice := pair.getSlice() 39 if slice == nil { 40 return nil 41 } 42 valuesz := binary.LittleEndian.Uint32(slice) 43 return slice[8 : 8+valuesz : 8+valuesz] 44 } 45 46 // Key returns the key portion of the key 47 func (pair Pair) Key() []byte { 48 slice := pair.getSlice() 49 if slice == nil { 50 return nil 51 } 52 valuesz := binary.LittleEndian.Uint32(slice) 53 keysz := binary.LittleEndian.Uint32(slice[4:]) 54 return slice[8+valuesz : 8+valuesz+keysz : 8+valuesz+keysz] 55 } 56 57 // Size returns the size of the allocation 58 func (pair Pair) Size() int { 59 slice := pair.getSlice() 60 if slice == nil { 61 return 0 62 } 63 valuesz := binary.LittleEndian.Uint32(slice) 64 keysz := binary.LittleEndian.Uint32(slice[4:]) 65 return int(8 + valuesz + keysz) 66 } 67 68 // Zero return true if the pair is unallocated 69 func (pair Pair) Zero() bool { 70 return uintptr(pair.ptr) == 0 71 } 72 73 //go:linkname mallocgc runtime.mallocgc 74 func mallocgc(size, typ uintptr, needzero bool) uintptr 75 76 // makenz returns a byte slice that is not zero filled. This can provide a big 77 // performance boost for large pairs. 78 func makenz(count int) []byte { 79 return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ 80 Data: mallocgc(uintptr(count), 0, false), 81 Len: count, 82 Cap: count, 83 })) 84 } 85 86 // Pointer returns the underlying pointer 87 func (pair Pair) Pointer() unsafe.Pointer { 88 return pair.ptr 89 } 90 91 // FromPointer returns a pair that uses the memory at the pointer. 92 func FromPointer(ptr unsafe.Pointer) Pair { 93 return Pair{ptr} 94 }