tile38/internal/collection/item/unpacked.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
}