mirror of https://github.com/tidwall/tile38.git
96 lines
2.3 KiB
Go
96 lines
2.3 KiB
Go
|
package item
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
func getFieldAt(data unsafe.Pointer, index int) float64 {
|
||
|
return *(*float64)(unsafe.Pointer(uintptr(data) + uintptr(index*8)))
|
||
|
}
|
||
|
|
||
|
func setFieldAt(data unsafe.Pointer, index int, value float64) {
|
||
|
*(*float64)(unsafe.Pointer(uintptr(data) + uintptr(index*8))) = value
|
||
|
}
|
||
|
|
||
|
func (item *Item) dataBytes() []byte {
|
||
|
return *(*[]byte)((unsafe.Pointer)(&reflect.SliceHeader{
|
||
|
Data: uintptr(unsafe.Pointer(item.data)),
|
||
|
Len: item.fieldsDataSize() + item.idDataSize(),
|
||
|
Cap: item.fieldsDataSize() + item.idDataSize(),
|
||
|
}))
|
||
|
}
|
||
|
|
||
|
func bytesToFloats(f []byte) []float64 {
|
||
|
return *(*[]float64)((unsafe.Pointer)(&reflect.SliceHeader{
|
||
|
Data: ((*reflect.SliceHeader)(unsafe.Pointer(&f))).Data,
|
||
|
Len: len(f) / 8,
|
||
|
Cap: len(f) / 8,
|
||
|
}))
|
||
|
}
|
||
|
|
||
|
func (item *Item) unpackedGenerateFieldBytes(values []float64) []byte {
|
||
|
return *(*[]byte)((unsafe.Pointer)(&reflect.SliceHeader{
|
||
|
Data: ((*reflect.SliceHeader)(unsafe.Pointer(&values))).Data,
|
||
|
Len: len(values) * 8,
|
||
|
Cap: len(values) * 8,
|
||
|
}))
|
||
|
}
|
||
|
|
||
|
func (item *Item) unpackedSetField(index int, value float64) (updated bool) {
|
||
|
numFields := item.fieldsDataSize() / 8
|
||
|
if index < numFields {
|
||
|
// field exists
|
||
|
if getFieldAt(item.data, index) == value {
|
||
|
return false
|
||
|
}
|
||
|
} else if value == 0 {
|
||
|
return false
|
||
|
} else {
|
||
|
|
||
|
// make room for new field
|
||
|
oldBytes := item.dataBytes()
|
||
|
newData := make([]byte, (index+1)*8+item.idDataSize())
|
||
|
// copy the existing fields
|
||
|
copy(newData, oldBytes[:item.fieldsDataSize()])
|
||
|
// copy the id
|
||
|
copy(newData[(index+1)*8:], oldBytes[item.fieldsDataSize():])
|
||
|
// update the fields length
|
||
|
item.setFieldsDataSize((index + 1) * 8)
|
||
|
// update the raw data
|
||
|
item.data = unsafe.Pointer(&newData[0])
|
||
|
}
|
||
|
// set the new field
|
||
|
setFieldAt(item.data, index, value)
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (item *Item) unpackedForEachField(
|
||
|
count int, iter func(value float64) bool,
|
||
|
) {
|
||
|
fields := bytesToFloats(item.fieldsBytes())
|
||
|
var n int
|
||
|
if count < 0 {
|
||
|
n = len(fields)
|
||
|
} else {
|
||
|
n = count
|
||
|
}
|
||
|
for i := 0; i < n; i++ {
|
||
|
var field float64
|
||
|
if i < len(fields) {
|
||
|
field = fields[i]
|
||
|
}
|
||
|
if !iter(field) {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (item *Item) unpackedGetField(index int) float64 {
|
||
|
numFields := item.fieldsDataSize() / 8
|
||
|
if index < numFields {
|
||
|
return getFieldAt(item.data, index)
|
||
|
}
|
||
|
return 0
|
||
|
}
|