internal/generic_inequality_search.go (141 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 internal import ( "github.com/apache/datasketches-go/common" ) type Inequality int64 const ( InequalityLT Inequality = iota InequalityLE InequalityGE InequalityGT ) func FindWithInequality[C comparable](arr []C, low int, high int, v C, crit Inequality, comparator common.CompareFn[C]) int { if len(arr) == 0 { return -1 } lo := low hi := high for lo <= hi { if hi-lo <= 1 { return resolve(arr, lo, hi, v, crit, comparator) } mid := lo + (hi-lo)/2 ret := compare(arr, mid, mid+1, v, crit, comparator) if ret == -1 { hi = mid } else if ret == 1 { lo = mid + 1 } else { return getIndex(arr, mid, mid+1, v, crit, comparator) } } return -1 } func resolve[C comparable](arr []C, lo int, hi int, v C, crit Inequality, compareFn common.CompareFn[C]) int { result := 0 switch crit { case InequalityLT: if lo == hi { if compareFn(v, arr[hi]) == false && v != arr[hi] { result = lo } else { result = -1 } } else { if compareFn(v, arr[hi]) == false && v != arr[hi] { result = hi } else if compareFn(v, arr[lo]) == false && v != arr[lo] { result = lo } else { result = -1 } } case InequalityLE: if lo == hi { if compareFn(v, arr[lo]) == false { result = lo } else { result = -1 } } else { if compareFn(v, arr[hi]) == false { result = hi } else if compareFn(v, arr[lo]) == false { result = lo } else { result = -1 } } case InequalityGE: if lo == hi { if compareFn(v, arr[lo]) || v == arr[lo] { result = lo } else { result = -1 } } else { if compareFn(v, arr[lo]) || v == arr[lo] { result = lo } else if compareFn(v, arr[hi]) || v == arr[hi] { result = hi } else { result = -1 } } case InequalityGT: if lo == hi { if compareFn(v, arr[lo]) { result = lo } else { result = -1 } } else { if compareFn(v, arr[lo]) { result = lo } else if compareFn(v, arr[hi]) { result = hi } else { result = -1 } } default: panic("invalid inequality") } return result } func compare[C comparable](arr []C, a int, b int, v C, crit Inequality, compareFn common.CompareFn[C]) int { result := 0 switch crit { case InequalityLT, InequalityGE: if compareFn(v, arr[a]) || arr[a] == v { result = -1 } else if compareFn(arr[b], v) { result = 1 } else { result = 0 } case InequalityLE, InequalityGT: if compareFn(v, arr[a]) { result = -1 } else if compareFn(arr[b], v) || arr[b] == v { result = 1 } else { result = 0 } default: panic("invalid inequality") } return result } func getIndex[C comparable](arr []C, a int, b int, v C, crit Inequality, compareFn common.CompareFn[C]) int { result := 0 switch crit { case InequalityLT, InequalityLE: result = a case InequalityGE, InequalityGT: result = b default: panic("invalid inequality") } return result }