summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go')
-rw-r--r--vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go99
1 files changed, 60 insertions, 39 deletions
diff --git a/vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go b/vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go
index c1d3ad3046..818a06c80b 100644
--- a/vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go
+++ b/vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go
@@ -3,8 +3,10 @@
package roaring
import (
+ "errors"
"io"
"reflect"
+ "runtime"
"unsafe"
)
@@ -14,26 +16,13 @@ func (ac *arrayContainer) writeTo(stream io.Writer) (int, error) {
}
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)
}
-// readFrom reads an arrayContainer from stream.
-// PRE-REQUISITE: you must size the arrayContainer correctly (allocate b.content)
-// *before* you call readFrom. We can't guess the size in the stream
-// by this point.
-func (ac *arrayContainer) readFrom(stream io.Reader) (int, error) {
- buf := uint16SliceAsByteSlice(ac.content)
- return io.ReadFull(stream, buf)
-}
-
-func (bc *bitmapContainer) readFrom(stream io.Reader) (int, error) {
- buf := uint64SliceAsByteSlice(bc.bitmap)
- n, err := io.ReadFull(stream, buf)
- bc.computeCardinality()
- return n, err
-}
-
func uint64SliceAsByteSlice(slice []uint64) []byte {
// make a new slice header
header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
@@ -42,8 +31,12 @@ func uint64SliceAsByteSlice(slice []uint64) []byte {
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 *(*[]byte)(unsafe.Pointer(&header))
+ return result
}
func uint16SliceAsByteSlice(slice []uint16) []byte {
@@ -54,8 +47,12 @@ func uint16SliceAsByteSlice(slice []uint16) []byte {
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 *(*[]byte)(unsafe.Pointer(&header))
+ return result
}
func (bc *bitmapContainer) asLittleEndianByteSlice() []byte {
@@ -64,50 +61,74 @@ func (bc *bitmapContainer) asLittleEndianByteSlice() []byte {
// Deserialization code follows
-func byteSliceAsUint16Slice(slice []byte) []uint16 {
+////
+// 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
- header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
+ bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
+ rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
- // update its capacity and length
- header.Len /= 2
- header.Cap /= 2
+ // 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
- // return it
- return *(*[]uint16)(unsafe.Pointer(&header))
+ // 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) []uint64 {
+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
- header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
+ bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
+ rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
- // update its capacity and length
- header.Len /= 8
- header.Cap /= 8
+ // 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
- // return it
- return *(*[]uint64)(unsafe.Pointer(&header))
+ // 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) []interval16 {
+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
- header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
+ bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
+ rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
- // update its capacity and length
- header.Len /= 4
- header.Cap /= 4
+ // 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
- // return it
- return *(*[]interval16)(unsafe.Pointer(&header))
+ // instantiate result and use KeepAlive so data isn't unmapped.
+ runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
+
+ // return result
+ return
}