1. 12
    1. 2

      Just to give a flavor for the curious, it could look roughly like this in Nim:

      import core/macros, std/bitops
      
      macro makeSharFind(id; n: int) =
        let (x, e, n) = (ident("x"), ident("e"), n.intVal)
        let k = fastLog2(n); let k2 = 1 shl k
        result = quote do:
          proc `id`[T](`x`: openArray[T], `e`: T): int =
            result = if `x`[`k2`] <= `e`: `n` - `k2` else: 0
        for p in countdown(k - 1, 0):
          let p2 = 1 shl p
          result[^1].add quote do:
            if `x`[result + `p2`] <= `e`: result += `p2`
        result[^1].add quote do:
          if `x`[result] != `e`: result = -1
      
      const x = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
      makeSharFind(sharFind, x.len) # Non-const needs a fallback
      for i in -1..x.len: echo x.sharFind(i*10) # < x[0], >x[^1]
      for i in -1..<x.len: echo x.sharFind(i*10+5) # inside miss
      

      with just minimal testing at the end (so, yeah, maybe some bugs). Output of the above for me (pasted into 2 cols) is the expected:

      -1  -1
      0   -1
      1   -1
      2   -1
      3   -1
      4   -1
      5   -1
      6   -1
      7   -1
      8   -1
      9   -1
      -1
      

      and you can run nim c --expandMacro=makeSharFind to see generated code.