mirror of https://github.com/tidwall/tile38.git
Binary objects
This commit is contained in:
parent
def9c173bf
commit
4b71083fae
|
@ -1,23 +1,73 @@
|
||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/tidwall/geojson"
|
"github.com/tidwall/geojson"
|
||||||
"github.com/tidwall/geojson/geometry"
|
"github.com/tidwall/geojson/geometry"
|
||||||
"github.com/tidwall/tile38/internal/field"
|
"github.com/tidwall/tile38/internal/field"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Object struct {
|
type pointObject struct {
|
||||||
id string
|
base Object
|
||||||
|
pt geojson.SimplePoint
|
||||||
|
}
|
||||||
|
|
||||||
|
type geoObject struct {
|
||||||
|
base Object
|
||||||
geo geojson.Object
|
geo geojson.Object
|
||||||
expires int64 // unix nano expiration
|
}
|
||||||
|
|
||||||
|
const opoint = 1
|
||||||
|
const ogeo = 2
|
||||||
|
|
||||||
|
type Object struct {
|
||||||
|
head string // tuple (kind,expires,id)
|
||||||
fields field.List
|
fields field.List
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Object) geo() geojson.Object {
|
||||||
|
if o != nil {
|
||||||
|
switch o.head[0] {
|
||||||
|
case opoint:
|
||||||
|
return &(*pointObject)(unsafe.Pointer(o)).pt
|
||||||
|
case ogeo:
|
||||||
|
return (*geoObject)(unsafe.Pointer(o)).geo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// uvarint is a slightly modified version of binary.Uvarint, and it's a little
|
||||||
|
// faster. But it lacks overflow checks which are not needed for our use.
|
||||||
|
func uvarint(s string) (uint64, int) {
|
||||||
|
var x uint64
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
b := s[i]
|
||||||
|
if b < 0x80 {
|
||||||
|
return x | uint64(b)<<(i*7), i + 1
|
||||||
|
}
|
||||||
|
x |= uint64(b&0x7f) << (i * 7)
|
||||||
|
}
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func varint(s string) (int64, int) {
|
||||||
|
ux, n := uvarint(s)
|
||||||
|
x := int64(ux >> 1)
|
||||||
|
if ux&1 != 0 {
|
||||||
|
x = ^x
|
||||||
|
}
|
||||||
|
return x, n
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Object) ID() string {
|
func (o *Object) ID() string {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return o.id
|
_, n := varint(o.head[1:])
|
||||||
|
return o.head[1+n:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Object) Fields() field.List {
|
func (o *Object) Fields() field.List {
|
||||||
|
@ -31,32 +81,32 @@ func (o *Object) Expires() int64 {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return o.expires
|
ex, _ := varint(o.head[1:])
|
||||||
|
return ex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Object) Rect() geometry.Rect {
|
func (o *Object) Rect() geometry.Rect {
|
||||||
if o == nil || o.geo == nil {
|
ogeo := o.geo()
|
||||||
|
if ogeo == nil {
|
||||||
return geometry.Rect{}
|
return geometry.Rect{}
|
||||||
}
|
}
|
||||||
return o.geo.Rect()
|
return ogeo.Rect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Object) Geo() geojson.Object {
|
func (o *Object) Geo() geojson.Object {
|
||||||
if o == nil || o.geo == nil {
|
return o.geo()
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return o.geo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Object) String() string {
|
func (o *Object) String() string {
|
||||||
if o == nil || o.geo == nil {
|
ogeo := o.geo()
|
||||||
|
if ogeo == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return o.geo.String()
|
return ogeo.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Object) IsSpatial() bool {
|
func (o *Object) IsSpatial() bool {
|
||||||
_, ok := o.geo.(geojson.Spatial)
|
_, ok := o.geo().(geojson.Spatial)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +125,47 @@ func (o *Object) Weight() int {
|
||||||
return weight
|
return weight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeHead(kind byte, id string, expires int64) string {
|
||||||
|
var exb [20]byte
|
||||||
|
exn := binary.PutVarint(exb[:], expires)
|
||||||
|
n := 1 + exn + len(id)
|
||||||
|
head := make([]byte, n)
|
||||||
|
head[0] = kind
|
||||||
|
copy(head[1:], exb[:exn])
|
||||||
|
copy(head[1+exn:], id)
|
||||||
|
return *(*string)(unsafe.Pointer(&head))
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPoint(id string, pt geometry.Point, expires int64, fields field.List,
|
||||||
|
) *Object {
|
||||||
|
return (*Object)(unsafe.Pointer(&pointObject{
|
||||||
|
Object{
|
||||||
|
head: makeHead(opoint, id, expires),
|
||||||
|
fields: fields,
|
||||||
|
},
|
||||||
|
geojson.SimplePoint{Point: pt},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
func newGeo(id string, geo geojson.Object, expires int64, fields field.List,
|
||||||
|
) *Object {
|
||||||
|
return (*Object)(unsafe.Pointer(&geoObject{
|
||||||
|
Object{
|
||||||
|
head: makeHead(ogeo, id, expires),
|
||||||
|
fields: fields,
|
||||||
|
},
|
||||||
|
geo,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
func New(id string, geo geojson.Object, expires int64, fields field.List,
|
func New(id string, geo geojson.Object, expires int64, fields field.List,
|
||||||
) *Object {
|
) *Object {
|
||||||
return &Object{
|
switch p := geo.(type) {
|
||||||
id: id,
|
case *geojson.SimplePoint:
|
||||||
geo: geo,
|
return newPoint(id, p.Base(), expires, fields)
|
||||||
expires: expires,
|
case *geojson.Point:
|
||||||
fields: fields,
|
if p.IsSimple() {
|
||||||
|
return newPoint(id, p.Base(), expires, fields)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return newGeo(id, geo, expires, fields)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue