github.com/fiatjaf/generic-ristretto@v0.0.1/z/simd/baseline.go (about)

     1  package simd
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  	"sort"
     7  	"sync"
     8  )
     9  
    10  // Search finds the key using the naive way
    11  func Naive(xs []uint64, k uint64) int16 {
    12  	var i int
    13  	for i = 0; i < len(xs); i += 2 {
    14  		x := xs[i]
    15  		if x >= k {
    16  			return int16(i / 2)
    17  		}
    18  	}
    19  	return int16(i / 2)
    20  }
    21  
    22  func Clever(xs []uint64, k uint64) int16 {
    23  	if len(xs) < 8 {
    24  		return Naive(xs, k)
    25  	}
    26  	var twos, pk [4]uint64
    27  	pk[0] = k
    28  	pk[1] = k
    29  	pk[2] = k
    30  	pk[3] = k
    31  	for i := 0; i < len(xs); i += 8 {
    32  		twos[0] = xs[i]
    33  		twos[1] = xs[i+2]
    34  		twos[2] = xs[i+4]
    35  		twos[3] = xs[i+6]
    36  		if twos[0] >= pk[0] {
    37  			return int16(i / 2)
    38  		}
    39  		if twos[1] >= pk[1] {
    40  			return int16((i + 2) / 2)
    41  		}
    42  		if twos[2] >= pk[2] {
    43  			return int16((i + 4) / 2)
    44  		}
    45  		if twos[3] >= pk[3] {
    46  			return int16((i + 6) / 2)
    47  		}
    48  
    49  	}
    50  	return int16(len(xs) / 2)
    51  }
    52  
    53  func Parallel(xs []uint64, k uint64) int16 {
    54  	cpus := runtime.NumCPU()
    55  	if cpus%2 != 0 {
    56  		panic(fmt.Sprintf("odd number of CPUs %v", cpus))
    57  	}
    58  	sz := len(xs)/cpus + 1
    59  	var wg sync.WaitGroup
    60  	retChan := make(chan int16, cpus)
    61  	for i := 0; i < len(xs); i += sz {
    62  		end := i + sz
    63  		if end >= len(xs) {
    64  			end = len(xs)
    65  		}
    66  		chunk := xs[i:end]
    67  		wg.Add(1)
    68  		go func(hd int16, xs []uint64, k uint64, wg *sync.WaitGroup, ch chan int16) {
    69  			for i := 0; i < len(xs); i += 2 {
    70  				if xs[i] >= k {
    71  					ch <- (int16(i) + hd) / 2
    72  					break
    73  				}
    74  			}
    75  			wg.Done()
    76  		}(int16(i), chunk, k, &wg, retChan)
    77  	}
    78  	wg.Wait()
    79  	close(retChan)
    80  	var min int16 = (1 << 15) - 1
    81  	for i := range retChan {
    82  		if i < min {
    83  			min = i
    84  		}
    85  	}
    86  	if min == (1<<15)-1 {
    87  		return int16(len(xs) / 2)
    88  	}
    89  	return min
    90  }
    91  
    92  func Binary(keys []uint64, key uint64) int16 {
    93  	return int16(sort.Search(len(keys), func(i int) bool {
    94  		if i*2 >= len(keys) {
    95  			return true
    96  		}
    97  		return keys[i*2] >= key
    98  	}))
    99  }
   100  
   101  func cmp2_native(twos, pk [2]uint64) int16 {
   102  	if twos[0] == pk[0] {
   103  		return 0
   104  	}
   105  	if twos[1] == pk[1] {
   106  		return 1
   107  	}
   108  	return 2
   109  }
   110  
   111  func cmp4_native(fours, pk [4]uint64) int16 {
   112  	for i := range fours {
   113  		if fours[i] >= pk[i] {
   114  			return int16(i)
   115  		}
   116  	}
   117  	return 4
   118  }
   119  
   120  func cmp8_native(a [8]uint64, pk [4]uint64) int16 {
   121  	for i := range a {
   122  		if a[i] >= pk[0] {
   123  			return int16(i)
   124  		}
   125  	}
   126  	return 8
   127  }