|
- // +build 386 amd64,!appengine
-
- package roaring
-
- import (
- "errors"
- "io"
- "reflect"
- "runtime"
- "unsafe"
- )
-
- func (ac *arrayContainer) writeTo(stream io.Writer) (int, error) {
- buf := uint16SliceAsByteSlice(ac.content)
- return stream.Write(buf)
- }
-
- func (bc *bitmapContainer) writeTo(stream io.Writer) (int, error) {
- if bc.cardinality <= arrayDefaultMaxSize {
- return 0, errors.New("refusing to write bitmap container with cardinality of array container")
- }
- buf := uint64SliceAsByteSlice(bc.bitmap)
- return stream.Write(buf)
- }
-
- func uint64SliceAsByteSlice(slice []uint64) []byte {
- // make a new slice header
- header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
-
- // update its capacity and length
- header.Len *= 8
- header.Cap *= 8
-
- // instantiate result and use KeepAlive so data isn't unmapped.
- result := *(*[]byte)(unsafe.Pointer(&header))
- runtime.KeepAlive(&slice)
-
- // return it
- return result
- }
-
- func uint16SliceAsByteSlice(slice []uint16) []byte {
- // make a new slice header
- header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
-
- // update its capacity and length
- header.Len *= 2
- header.Cap *= 2
-
- // instantiate result and use KeepAlive so data isn't unmapped.
- result := *(*[]byte)(unsafe.Pointer(&header))
- runtime.KeepAlive(&slice)
-
- // return it
- return result
- }
-
- func (bc *bitmapContainer) asLittleEndianByteSlice() []byte {
- return uint64SliceAsByteSlice(bc.bitmap)
- }
-
- // Deserialization code follows
-
- ////
- // These methods (byteSliceAsUint16Slice,...) do not make copies,
- // they are pointer-based (unsafe). The caller is responsible to
- // ensure that the input slice does not get garbage collected, deleted
- // or modified while you hold the returned slince.
- ////
- func byteSliceAsUint16Slice(slice []byte) (result []uint16) { // here we create a new slice holder
- if len(slice)%2 != 0 {
- panic("Slice size should be divisible by 2")
- }
- // reference: https://go101.org/article/unsafe.html
-
- // make a new slice header
- bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
- rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
-
- // transfer the data from the given slice to a new variable (our result)
- rHeader.Data = bHeader.Data
- rHeader.Len = bHeader.Len / 2
- rHeader.Cap = bHeader.Cap / 2
-
- // instantiate result and use KeepAlive so data isn't unmapped.
- runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
-
- // return result
- return
- }
-
- func byteSliceAsUint64Slice(slice []byte) (result []uint64) {
- if len(slice)%8 != 0 {
- panic("Slice size should be divisible by 8")
- }
- // reference: https://go101.org/article/unsafe.html
-
- // make a new slice header
- bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
- rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
-
- // transfer the data from the given slice to a new variable (our result)
- rHeader.Data = bHeader.Data
- rHeader.Len = bHeader.Len / 8
- rHeader.Cap = bHeader.Cap / 8
-
- // instantiate result and use KeepAlive so data isn't unmapped.
- runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
-
- // return result
- return
- }
-
- func byteSliceAsInterval16Slice(slice []byte) (result []interval16) {
- if len(slice)%4 != 0 {
- panic("Slice size should be divisible by 4")
- }
- // reference: https://go101.org/article/unsafe.html
-
- // make a new slice header
- bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
- rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
-
- // transfer the data from the given slice to a new variable (our result)
- rHeader.Data = bHeader.Data
- rHeader.Len = bHeader.Len / 4
- rHeader.Cap = bHeader.Cap / 4
-
- // instantiate result and use KeepAlive so data isn't unmapped.
- runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
-
- // return result
- return
- }
|