class_docstr: Generates and executes code that performs prefix sums ("scans") on
  arbitrary types, with many possible tweaks.
  
  Usage example::
  
      from pyopencl.scan import GenericScanKernel
      knl = GenericScanKernel(
              context, np.int32,
              arguments="__global int *ary",
              input_expr="ary[i]",
              scan_expr="a+b", neutral="0",
              output_statement="ary[i+1] = item;")
  
      a = cl.array.arange(queue, 10000, dtype=np.int32)
      knl(a, queue=queue)
  
  .. automethod:: __init__
  .. automethod:: __call__
class_docstr_tok: ["Generates","and","executes","code","that","performs","prefix","sums","(","``","scans","''",")","on","arbitrary","types",",","with","many","possible","tweaks",".","Usage","example",":",":","from","pyopencl.scan","import","GenericScanKernel","knl","=","GenericScanKernel","(","context",",","np.int32",",","arguments=","''","__global","int","*","ary","''",",","input_expr=","''","ary","[","i","]","''",",","scan_expr=","''","a+b","''",",","neutral=","''","0","''",",","output_statement=","''","ary","[","i+1","]","=","item",";","''",")","a","=","cl.array.arange","(","queue",",","10000",",","dtype=np.int32",")","knl","(","a",",","queue=queue",")","..","automethod",":",":","__init__","..","automethod",":",":","__call__"]
code: def generate_scan_kernel(
      self,
      max_wg_size: int,
      arguments: List[DtypedArgument],
      input_expr: str,
      is_segment_start_expr: Optional[str],
      input_fetch_exprs: List[Tuple[str, str, int]],
      is_first_level: bool,
      store_segment_start_flags: bool,
      k_group_size: int,
      use_bank_conflict_avoidance: bool,
  ) -> _GeneratedScanKernelInfo:
      scalar_arg_dtypes = get_arg_list_scalar_arg_dtypes(arguments)
  
      # Empirically found on Nv hardware: no need to be bigger than this size
      wg_size = _round_down_to_power_of_2(min(max_wg_size, 256))
  
      kernel_name = self.code_variables["name_prefix"]
      if is_first_level:
          kernel_name += "_lev1"
      else:
          kernel_name += "_lev2"
  
      scan_tpl = _make_template(SCAN_INTERVALS_SOURCE)
      scan_src = str(
          scan_tpl.render(
              wg_size=wg_size,
              input_expr=input_expr,
              k_group_size=k_group_size,
              arg_offset_adjustment=get_arg_offset_adjuster_code(
                  arguments
              ),
              argument_signature=", ".join(
                  arg.declarator() for arg in arguments
              ),
              is_segment_start_expr=is_segment_start_expr,
              input_fetch_exprs=input_fetch_exprs,
              is_first_level=is_first_level,
              store_segment_start_flags=store_segment_start_flags,
              use_bank_conflict_avoidance=use_bank_conflict_avoidance,
              kernel_name=kernel_name,
              **self.code_variables,
          )
      )
  
      scalar_arg_dtypes.extend(
          (None, self.index_dtype, self.index_dtype)
      )
      if is_first_level:
          scalar_arg_dtypes.append(None)  # interval_results
      if self.is_segmented and is_first_level:
          scalar_arg_dtypes.append(
              None
          )  # g_first_segment_start_in_interval
      if store_segment_start_flags:
          scalar_arg_dtypes.append(None)  # g_segment_start_flags
  
      return _GeneratedScanKernelInfo(
          scan_src=scan_src,
          kernel_name=kernel_name,
          scalar_arg_dtypes=scalar_arg_dtypes,
          wg_size=wg_size,
          k_group_size=k_group_size,
      )
  
imports: from abc import ABC, abstractmethod
  from dataclasses import dataclass
  from typing import Any, Dict, List, Optional, Set, Tuple, Union
  import numpy
  import pyopencl
  import pyopencl.array
  from pyopencl.tools import KernelTemplateBase, DtypedArgument, bitlog2, context_dependent_memoize, dtype_to_ctype, get_arg_list_scalar_arg_dtypes, get_arg_offset_adjuster_code, _process_code_for_macro, _NumpyTypesKeyBuilder
  import pyopencl._mymako
  from pyopencl._cluda import CLUDA_PREAMBLE
  from pytools.persistent_dict import WriteOncePersistentDict
  import logging
label_desc: Use image node_id 4 for calling the GenericScanKernel obj's underlying member method code with example usage: obj.generate_scan_kernel(max_wg_size, arguments, input_expr, is_segment_start_expr, input_fetch_exprs, is_first_level, store_segment_start_flags, k_group_size, use_bank_conflict_avoidance) and returns: _GeneratedScanKernelInfo