merge conflicts

This commit is contained in:
Todd Gruben 2018-02-20 10:41:02 -06:00
parent 6374fedd7a
commit 2d458b98a1
6 changed files with 73 additions and 499 deletions

View file

@ -1,68 +0,0 @@
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package roaring
// bit population count, take from
// https://code.google.com/p/go/issues/detail?id=4988#c11
// credit: https://code.google.com/u/arnehormann/
func popcntGo(x uint64) (n uint64) {
x -= (x >> 1) & 0x5555555555555555
x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
x += x >> 4
x &= 0x0f0f0f0f0f0f0f0f
x *= 0x0101010101010101
return x >> 56
}
func popcntSliceGo(s []uint64) uint64 {
cnt := uint64(0)
for _, x := range s {
cnt += popcntGo(x)
}
return cnt
}
func popcntMaskSliceGo(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcntGo(s[i] &^ m[i])
}
return cnt
}
func popcntAndSliceGo(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcntGo(s[i] & m[i])
}
return cnt
}
func popcntOrSliceGo(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcntGo(s[i] | m[i])
}
return cnt
}
func popcntXorSliceGo(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcntGo(s[i] ^ m[i])
}
return cnt
}

View file

@ -1,122 +0,0 @@
#include "textflag.h"
TEXT ·hasAsm(SB),4,$0-1
MOVQ $1, AX
CPUID
SHRQ $23, CX
ANDQ $1, CX
MOVB CX, ret+0(FP)
RET
TEXT ·POPCNTQ(SB),NOSPLIT,$0-16
MOVQ memory+0(FP), BP
POPCNTQ BP, BX
MOVQ BX, ret+8(FP)
RET
TEXT ·BSFQ(SB),NOSPLIT,$0-16
MOVQ memory+0(FP), BP
BSFQ BP, BX
MOVQ BX, ret+8(FP)
RET
#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2
TEXT ·popcntSliceAsm(SB),4,$0-32
XORQ AX, AX
MOVQ s_base+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntSliceEnd
popcntSliceLoop:
BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX
ADDQ DX, AX
ADDQ $8, SI
LOOP popcntSliceLoop
popcntSliceEnd:
MOVQ AX, ret+24(FP)
RET
TEXT ·popcntMaskSliceAsm(SB),4,$0-56
XORQ AX, AX
MOVQ s_base+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntMaskSliceEnd
MOVQ m+24(FP), DI
popcntMaskSliceLoop:
MOVQ (DI), DX
NOTQ DX
ANDQ (SI), DX
POPCNTQ_DX_DX
ADDQ DX, AX
ADDQ $8, SI
ADDQ $8, DI
LOOP popcntMaskSliceLoop
popcntMaskSliceEnd:
MOVQ AX, ret+48(FP)
RET
TEXT ·popcntAndSliceAsm(SB),4,$0-56
XORQ AX, AX
MOVQ s_base+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntAndSliceEnd
MOVQ m+24(FP), DI
popcntAndSliceLoop:
MOVQ (DI), DX
ANDQ (SI), DX
POPCNTQ_DX_DX
ADDQ DX, AX
ADDQ $8, SI
ADDQ $8, DI
LOOP popcntAndSliceLoop
popcntAndSliceEnd:
MOVQ AX, ret+48(FP)
RET
TEXT ·popcntOrSliceAsm(SB),4,$0-56
XORQ AX, AX
MOVQ s_base+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntOrSliceEnd
MOVQ m+24(FP), DI
popcntOrSliceLoop:
MOVQ (DI), DX
ORQ (SI), DX
POPCNTQ_DX_DX
ADDQ DX, AX
ADDQ $8, SI
ADDQ $8, DI
LOOP popcntOrSliceLoop
popcntOrSliceEnd:
MOVQ AX, ret+48(FP)
RET
TEXT ·popcntXorSliceAsm(SB),4,$0-56
XORQ AX, AX
MOVQ s_base+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntXorSliceEnd
MOVQ m+24(FP), DI
popcntXorSliceLoop:
MOVQ (DI), DX
XORQ (SI), DX
POPCNTQ_DX_DX
ADDQ DX, AX
ADDQ $8, SI
ADDQ $8, DI
LOOP popcntXorSliceLoop
popcntXorSliceEnd:
MOVQ AX, ret+48(FP)
RET
TEXT ·popcntAsm(SB),4,$0-16
MOVQ x+0(FP), DX
POPCNTQ_DX_DX
MOVQ DX, ret+8(FP)
RET

View file

@ -1,87 +0,0 @@
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build amd64
package roaring
func hasAsm() bool
func BSFQ(memory uint64) int
func POPCNTQ(memory uint64) int
//go:noescape
var useAsm = hasAsm()
//go:noescape
func popcntSliceAsm(s []uint64) uint64
//go:noescape
func popcntMaskSliceAsm(s, m []uint64) uint64
//go:noescape
func popcntAndSliceAsm(s, m []uint64) uint64
//go:noescape
func popcntOrSliceAsm(s, m []uint64) uint64
//go:noescape
func popcntXorSliceAsm(s, m []uint64) uint64
//go:noescape
func popcntAsm(x uint64) uint64
func popcntSlice(s []uint64) uint64 {
if useAsm {
return popcntSliceAsm(s)
}
return popcntSliceGo(s)
}
func popcntMaskSlice(s, m []uint64) uint64 {
if useAsm {
return popcntMaskSliceAsm(s, m)
}
return popcntMaskSliceGo(s, m)
}
func popcntAndSlice(s, m []uint64) uint64 {
if useAsm {
return popcntAndSliceAsm(s, m)
}
return popcntAndSliceGo(s, m)
}
func popcntOrSlice(s, m []uint64) uint64 {
if useAsm {
return popcntOrSliceAsm(s, m)
}
return popcntOrSliceGo(s, m)
}
func popcntXorSlice(s, m []uint64) uint64 {
if useAsm {
return popcntXorSliceAsm(s, m)
}
return popcntXorSliceGo(s, m)
}
func popcnt(x uint64) uint64 {
if useAsm {
return popcntAsm(x)
}
return popcntGo(x)
}

View file

@ -1,27 +0,0 @@
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !amd64
package roaring
func hasAsm() bool {return false}
func popcntSlice(s []uint64) uint64 { return popcntSliceGo(s) }
func popcntMaskSlice(s, m []uint64) uint64 { return popcntMaskSliceGo(s, m) }
func popcntAndSlice(s, m []uint64) uint64 { return popcntAndSliceGo(s, m) }
func popcntOrSlice(s, m []uint64) uint64 { return popcntOrSliceGo(s, m) }
func popcntXorSlice(s, m []uint64) uint64 { return popcntXorSliceGo(s, m) }
func popcnt(s uint64) uint64 { return popcntGo(s) }

View file

@ -1,139 +0,0 @@
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package roaring
import "testing"
func TestBSFQ(t *testing.T) {
result := BSFQ(2)
if result != 1 {
t.Fatalf("BSF INCORRECT: %d", result)
}
}
func TestBSFQ_CompareGo(t *testing.T) {
v := uint64(1)
for i := 0; i < 64; i++ {
if BSFQ(v) != trailingZeroN(v) {
t.Fatalf("BSF INCORRECT: %d %d", BSFQ(v), trailingZeroN(v))
}
if v == 0 {
v = 1
} else {
v *= 2
}
}
/*
if bsfq(0) != trailingZeroN(0) {
fmt.Println(bsfq(0))
t.Fatalf("BSF INCORRECT")
}
*/
}
func BenchmarkBSF(b *testing.B) {
for i := 0; i < b.N; i++ {
BSFQ(uint64(i))
}
}
func BenchmarkTrailingZeroN(b *testing.B) {
for i := 0; i < b.N; i++ {
trailingZeroN(uint64(i))
}
}
func BenchmarkPOPCNTQ(b *testing.B) {
for i := 0; i < b.N; i++ {
POPCNTQ(uint64(i))
}
}
func BenchmarkPopcount(b *testing.B) {
for i := 0; i < b.N; i++ {
popcount(uint64(i))
}
}
func BenchmarkPopcntAsm(b *testing.B) {
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
popcntAsm(0xdeadbeef)
}
}
func BenchmarkPopcntGo(b *testing.B) {
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
popcntGo(0xdeadbeef)
}
}
func getData() []uint64 {
return []uint64{
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
0xdeadbeef,
}
}
func BenchmarkPopcntSliceGo(b *testing.B) {
d := getData()
for n := 0; n < b.N; n++ {
popcntSliceGo(d)
}
}
func BenchmarkPopcntSliceAsm(b *testing.B) {
d := getData()
for n := 0; n < b.N; n++ {
popcntSliceAsm(d)
}
}
func BenchmarkPopcntSlice(b *testing.B) {
d := getData()
for n := 0; n < b.N; n++ {
popcntSlice(d)
}
}

View file

@ -21,6 +21,7 @@ import (
"fmt"
"hash/fnv"
"io"
"math/bits"
"sort"
"unsafe"
)
@ -1274,10 +1275,10 @@ func (c *container) contains(v uint16) bool {
func (c *container) bitmapCountRuns() (r int) {
for i := 0; i < 1023; i++ {
v, v1 := c.bitmap[i], c.bitmap[i+1]
r = r + int(popcnt((v<<1)&^v)+((v>>63)&^v1))
r = r + int(popcount((v<<1)&^v)+((v>>63)&^v1))
}
vl := c.bitmap[len(c.bitmap)-1]
r = r + int(popcnt((vl<<1)&^vl)+vl>>63)
r = r + int(popcount((vl<<1)&^vl)+vl>>63)
return r
}
@ -1918,7 +1919,7 @@ func intersectionCountArrayBitmap(a, b *container) (n int) {
}
func intersectionCountBitmapBitmap(a, b *container) (n int) {
return int(popcntAndSlice(a.bitmap, b.bitmap))
return int(popcountAndSlice(a.bitmap, b.bitmap))
}
func intersect(a, b *container) *container {
@ -2061,22 +2062,22 @@ func intersectBitmapRun(a, b *container) *container {
for valast >= vb.start && vastart <= vb.last && i < bitmapN {
if vastart >= vb.start && valast <= vb.last { // a within b
output.bitmap[i] = a.bitmap[i]
output.n += int(popcnt(a.bitmap[i]))
output.n += int(popcount(a.bitmap[i]))
} else if vb.start >= vastart && vb.last <= valast { // b within a
var mask uint64 = ((1 << (vb.last - vb.start + 1)) - 1) << (vb.start - vastart)
bits := a.bitmap[i] & mask
output.bitmap[i] |= bits
output.n += int(popcnt(bits))
output.n += int(popcount(bits))
} else if vastart < vb.start { // a overlaps front of b
offset := 64 - (1 + valast - vb.start)
bits := (a.bitmap[i] >> offset) << offset
output.bitmap[i] |= bits
output.n += int(popcnt(bits))
output.n += int(popcount(bits))
} else if vb.start < vastart { // b overlaps front of a
offset := 64 - (1 + vb.last - vastart)
bits := (a.bitmap[i] << offset) >> offset
output.bitmap[i] |= bits
output.n += int(popcnt(bits))
output.n += int(popcount(bits))
}
// update loop vars
i++
@ -2293,19 +2294,19 @@ func (c *container) bitmapSetRange(i, j uint64) {
y := (j - 1) >> 6
var X uint64 = maxBitmap << (i % 64)
var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64))
xcnt := popcnt(X)
ycnt := popcnt(Y)
xcnt := popcount(X)
ycnt := popcount(Y)
if x == y {
c.n += int((j - i) - popcnt(c.bitmap[x]&(X&Y)))
c.n += int((j - i) - popcount(c.bitmap[x]&(X&Y)))
c.bitmap[x] |= (X & Y)
} else {
c.n += int(xcnt - popcnt(c.bitmap[x]&X))
c.n += int(xcnt - popcount(c.bitmap[x]&X))
c.bitmap[x] |= X
for i := x + 1; i < y; i++ {
c.n += int(64 - popcnt(c.bitmap[i]))
c.n += int(64 - popcount(c.bitmap[i]))
c.bitmap[i] = maxBitmap
}
c.n += int(ycnt - popcnt(c.bitmap[y]&Y))
c.n += int(ycnt - popcount(c.bitmap[y]&Y))
c.bitmap[y] |= Y
}
}
@ -2317,21 +2318,21 @@ func (c *container) bitmapXorRange(i, j uint64) {
var X uint64 = maxBitmap << (i % 64)
var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64))
if x == y {
cnt := popcnt(c.bitmap[x])
cnt := popcount(c.bitmap[x])
c.bitmap[x] ^= (X & Y) //// flip
c.n += int(popcnt(c.bitmap[x]) - cnt)
c.n += int(popcount(c.bitmap[x]) - cnt)
} else {
cnt := popcnt(c.bitmap[x])
cnt := popcount(c.bitmap[x])
c.bitmap[x] ^= X
c.n += int(popcnt(c.bitmap[x]) - cnt)
c.n += int(popcount(c.bitmap[x]) - cnt)
for i := x + 1; i < y; i++ {
cnt = popcnt(c.bitmap[i])
cnt = popcount(c.bitmap[i])
c.bitmap[i] ^= maxBitmap
c.n += int(popcnt(c.bitmap[i]) - cnt)
c.n += int(popcount(c.bitmap[i]) - cnt)
}
cnt = popcnt(c.bitmap[y])
cnt = popcount(c.bitmap[y])
c.bitmap[y] ^= Y
c.n += int(popcnt(c.bitmap[y]) - cnt)
c.n += int(popcount(c.bitmap[y]) - cnt)
}
}
@ -2342,16 +2343,16 @@ func (c *container) bitmapZeroRange(i, j uint64) {
var X uint64 = maxBitmap << (i % 64)
var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64))
if x == y {
c.n -= int(popcnt(c.bitmap[x] & (X & Y)))
c.n -= int(popcount(c.bitmap[x] & (X & Y)))
c.bitmap[x] &= ^(X & Y)
} else {
c.n -= int(popcnt(c.bitmap[x] & X))
c.n -= int(popcount(c.bitmap[x] & X))
c.bitmap[x] &= ^X
for i := x + 1; i < y; i++ {
c.n -= int(popcnt(c.bitmap[i]))
c.n -= int(popcount(c.bitmap[i]))
c.bitmap[i] = 0
}
c.n -= int(popcnt(c.bitmap[y] & Y))
c.n -= int(popcount(c.bitmap[y] & Y))
c.bitmap[y] &= ^Y
}
}
@ -2376,7 +2377,7 @@ func unionBitmapBitmap(a, b *container) *container {
for i := 0; i < bitmapN; i++ {
v := a.bitmap[i] | b.bitmap[i]
output.bitmap[i] = v
output.n += int(popcnt(v))
output.n += int(popcount(v))
}
return output
@ -2812,7 +2813,7 @@ func xorBitmapBitmap(a, b *container) *container {
for i := 0; i < bitmapN; i++ {
v := a.bitmap[i] ^ b.bitmap[i]
output.bitmap[i] = v
output.n += int(popcnt(v))
output.n += int(popcount(v))
}
if output.count() < ArrayMaxSize {
@ -2975,35 +2976,7 @@ func search64(a []uint64, value uint64) int {
// trailingZeroN returns the number of trailing zeros in v.
// v must be greater than zero.
func trailingZeroN(v uint64) int {
n := int64(63)
if y := v << 32; y != 0 {
n, v = n-32, y
}
if y := v << 16; y != 0 {
n, v = n-16, y
}
if y := v << 8; y != 0 {
n, v = n-8, y
}
if y := v << 4; y != 0 {
n, v = n-4, y
}
if y := v << 2; y != 0 {
n, v = n-2, y
}
return int(n - int64(v<<1>>63))
}
// bit population count, taken from
// https://code.google.com/p/go/issues/detail?id=4988#c11
// credit: https://code.google.com/u/arnehormann/
func popcount(x uint64) (n uint64) {
x -= (x >> 1) & 0x5555555555555555
x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
x += x >> 4
x &= 0x0f0f0f0f0f0f0f0f
x *= 0x0101010101010101
return x >> 56
return bits.TrailingZeros64(v)
}
// ErrorList represents a list of errors.
@ -3265,3 +3238,47 @@ func xorBitmapRun(a, b *container) *container {
}
return output
}
func popcount(x uint64) uint64 {
return uint64(bits.OnesCount64(x))
}
func popcountSlice(s []uint64) uint64 {
cnt := uint64(0)
for _, x := range s {
cnt += popcount(x)
}
return cnt
}
func popcountMaskSlice(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcount(s[i] &^ m[i])
}
return cnt
}
func popcountAndSlice(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcount(s[i] & m[i])
}
return cnt
}
func popcountOrSlice(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcount(s[i] | m[i])
}
return cnt
}
func popcountXorSlice(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcount(s[i] ^ m[i])
}
return cnt
}