package simd import ( "fmt" "runtime" "sort" "sync" ) // Search finds the key using the naive way func Naive(xs []uint64, k uint64) int16 { var i int for i = 0; i < len(xs); i += 2 { x := xs[i] if x >= k { return int16(i / 2) } } return int16(i / 2) } func Clever(xs []uint64, k uint64) int16 { if len(xs) < 8 { return Naive(xs, k) } var twos, pk [4]uint64 pk[0] = k pk[1] = k pk[2] = k pk[3] = k for i := 0; i < len(xs); i += 8 { twos[0] = xs[i] twos[1] = xs[i+2] twos[2] = xs[i+4] twos[3] = xs[i+6] if twos[0] >= pk[0] { return int16(i / 2) } if twos[1] >= pk[1] { return int16((i + 2) / 2) } if twos[2] >= pk[2] { return int16((i + 4) / 2) } if twos[3] >= pk[3] { return int16((i + 6) / 2) } } return int16(len(xs) / 2) } func Parallel(xs []uint64, k uint64) int16 { cpus := runtime.NumCPU() if cpus%2 != 0 { panic(fmt.Sprintf("odd number of CPUs %v", cpus)) } sz := len(xs)/cpus + 1 var wg sync.WaitGroup retChan := make(chan int16, cpus) for i := 0; i < len(xs); i += sz { end := i + sz if end >= len(xs) { end = len(xs) } chunk := xs[i:end] wg.Add(1) go func(hd int16, xs []uint64, k uint64, wg *sync.WaitGroup, ch chan int16) { for i := 0; i < len(xs); i += 2 { if xs[i] >= k { ch <- (int16(i) + hd) / 2 break } } wg.Done() }(int16(i), chunk, k, &wg, retChan) } wg.Wait() close(retChan) var min int16 = (1 << 15) - 1 for i := range retChan { if i < min { min = i } } if min == (1<<15)-1 { return int16(len(xs) / 2) } return min } func Binary(keys []uint64, key uint64) int16 { return int16(sort.Search(len(keys), func(i int) bool { if i*2 >= len(keys) { return true } return keys[i*2] >= key })) } func cmp2_native(twos, pk [2]uint64) int16 { if twos[0] == pk[0] { return 0 } if twos[1] == pk[1] { return 1 } return 2 } func cmp4_native(fours, pk [4]uint64) int16 { for i := range fours { if fours[i] >= pk[i] { return int16(i) } } return 4 } func cmp8_native(a [8]uint64, pk [4]uint64) int16 { for i := range a { if a[i] >= pk[0] { return int16(i) } } return 8 }