code: def create_binary_string_func(binary_func, retty):
      """
      Provide a wrapper around numba's low-level extension API which
      produces the boilerplate needed to implement a binary function
      of two strings.
      """
  
      def deco(cuda_func):
          @cuda_lower(binary_func, string_view, string_view)
          def binary_func_impl(context, builder, sig, args):
              lhs_ptr = builder.alloca(args[0].type)
              rhs_ptr = builder.alloca(args[1].type)
              builder.store(args[0], lhs_ptr)
              builder.store(args[1], rhs_ptr)
  
              # these conditional statements should compile out
              if retty != udf_string:
                  # binary function of two strings yielding a fixed-width type
                  # example: str.startswith(other) -> bool
                  # shim functions can return the value through nb_retval
                  result = context.compile_internal(
                      builder,
                      cuda_func,
                      nb_signature(retty, _STR_VIEW_PTR, _STR_VIEW_PTR),
                      (lhs_ptr, rhs_ptr),
                  )
                  return result
              else:
                  # binary function of two strings yielding a new string
                  # example: str.strip(other) -> str
                  # shim functions can not return a struct due to C linkage
                  # so we create a new udf_string and pass a pointer to it
                  # for the shim function to write the output to. The return
                  # value of compile_internal is therefore discarded (although
                  # this may change in the future if we need to return error
                  # codes, for instance).
                  udf_str_ptr = builder.alloca(
                      default_manager[udf_string].get_value_type()
                  )
                  _ = context.compile_internal(
                      builder,
                      cuda_func,
                      size_type(
                          _UDF_STRING_PTR, _STR_VIEW_PTR, _STR_VIEW_PTR
                      ),
                      (udf_str_ptr, lhs_ptr, rhs_ptr),
                  )
                  result = cgutils.create_struct_proxy(udf_string)(
                      context, builder, value=builder.load(udf_str_ptr)
                  )
                  return result._getvalue()
  
          # binary_func can be attribute-like: str.binary_func
          # or operator-like: binary_func(str, other)
          if isinstance(binary_func, str):
              binary_func_impl = cuda_lower(
                  f"StringView.{binary_func}", string_view, string_view
              )(binary_func_impl)
              binary_func_impl = cuda_lower(
                  f"UDFString.{binary_func}", string_view, string_view
              )(binary_func_impl)
          else:
              binary_func_impl = cuda_lower(
                  binary_func, string_view, string_view
              )(binary_func_impl)
  
          return binary_func_impl
  
      return deco
  
imports: import operator
  from functools import partial
  from numba import cuda, types
  from numba.core import cgutils
  from numba.core.datamodel import default_manager
  from numba.core.typing import signature
  from numba.cuda.cudaimpl import lower, registry
  from cudf._lib.strings_udf import get_character_cases_table_ptr, get_character_flags_table_ptr, get_special_case_mapping_table_ptr
  from cudf.core.udf.masked_typing import MaskedType
  from cudf.core.udf.strings_typing import size_type, string_view, udf_string
label_desc: Use image node_id 15 for calling a global function with example usage: create_binary_string_func(binary_func, retty) and returns: deco, binary_func_impl, result, result