text: //------------------------------------------------------------------------------
  // GB_ek_slice.h: slice the entries and vectors of a matrix
  //------------------------------------------------------------------------------
  
  // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
  // SPDX-License-Identifier: Apache-2.0
  
  //------------------------------------------------------------------------------
  
  #ifndef GB_EK_SLICE_H
  #define GB_EK_SLICE_H
  #include "GB.h"
  
  //------------------------------------------------------------------------------
  // GB_SLICE_MATRIX: slice a single matrix using GB_ek_slice
  //------------------------------------------------------------------------------
  
  #define GB_SLICE_MATRIX(X,NTASKS_PER_THREAD)                                   \
  {                                                                              \
      X ## _nthreads = GB_nthreads (GB_NNZ (X) + X->nvec, chunk, nthreads_max) ; \
      X ## _ntasks = (X ## _nthreads == 1) ? 1 :                                 \
          ((NTASKS_PER_THREAD) * (X ## _nthreads)) ;                             \
      if (!GB_ek_slice (&(pstart_ ## X ## slice), &(kfirst_ ## X ## slice),      \
          &(klast_ ## X ## slice), X, &(X ## _ntasks)))                          \
      {                                                                          \
          /* out of memory */                                                    \
          GB_FREE_ALL ;                                                          \
          return (GrB_OUT_OF_MEMORY) ;                                           \
      }                                                                          \
  }
  
  //------------------------------------------------------------------------------
  // GB_ek_slice prototypes
  //------------------------------------------------------------------------------
  
  // Slice the entries of a matrix or vector into ntasks slices.
  
  // Task t does entries pstart_slice [t] to pstart_slice [t+1]-1 and
  // vectors kfirst_slice [t] to klast_slice [t].  The first and last vectors
  // may be shared with prior slices and subsequent slices.
  
  // On input, ntasks must be <= nnz (A), unless nnz (A) is zero.  In that
  // case, ntasks must be 1.
  
  bool GB_ek_slice        // true if successful, false if out of memory
  (
      // output:
      int64_t *GB_RESTRICT *pstart_slice_handle, // size ntasks+1
      int64_t *GB_RESTRICT *kfirst_slice_handle, // size ntasks
      int64_t *GB_RESTRICT *klast_slice_handle,  // size ntasks
      // input:
      GrB_Matrix A,                   // matrix to slize
      // input/output:
      int *ntasks_handle              // # of tasks (may be modified)
  ) ;
  
  void GB_ek_slice_free
  (
      int64_t *GB_RESTRICT *pstart_slice_handle,
      int64_t *GB_RESTRICT *kfirst_slice_handle,
      int64_t *GB_RESTRICT *klast_slice_handle
  ) ;
  
  // define the static inline function GB_search_for_vector
  #include "GB_search_for_vector_template.c"
  
  //------------------------------------------------------------------------------
  // GB_get_pA_and_pC: find the part of A(:,k) and C(:,k) for this task
  //------------------------------------------------------------------------------
  
  // The tasks were generated by GB_ek_slice.
  
  static inline void GB_get_pA_and_pC
  (
      // output
      int64_t *pA_start,
      int64_t *pA_end,
      int64_t *pC,
      // input
      int tid,            // task id
      int64_t k,          // current vector
      int64_t kfirst,     // first vector for this slice
      int64_t klast,      // last vector for this slice
      const int64_t *GB_RESTRICT pstart_slice,   // start of each slice in A
      const int64_t *GB_RESTRICT C_pstart_slice, // start of each slice in C
      const int64_t *GB_RESTRICT Cp,             // vector pointers for C
      int64_t cvlen,                             // C->vlen
      const int64_t *GB_RESTRICT Ap,             // vector pointers for A
      int64_t avlen                              // A->vlen
  )
  {
  
      int64_t p0 = GBP (Ap, k, avlen) ;
      int64_t p1 = GBP (Ap, k+1, avlen) ;
  
      if (k == kfirst)
      { 
          // First vector for task tid; may only be partially owned.
          (*pA_start) = pstart_slice [tid] ;
          (*pA_end  ) = GB_IMIN (p1, pstart_slice [tid+1]) ;
          (*pC) = C_pstart_slice [tid] ;
      }
      else if (k == klast)
      { 
          // Last vector for task tid; may only be partially owned.
          (*pA_start) = p0 ;
          (*pA_end  ) = pstart_slice [tid+1] ;
          (*pC) = GBP (Cp, k, cvlen) ;
      }
      else
      { 
          // task tid entirely owns this vector A(:,k).
          (*pA_start) = p0 ;
          (*pA_end  ) = p1 ;
          (*pC) = GBP (Cp, k, cvlen) ;
      }
  }
  
  //------------------------------------------------------------------------------
  // GB_get_pA: find the part of A(:,k) to be operated on by this task
  //------------------------------------------------------------------------------
  
  // The tasks were generated by GB_ek_slice.
  
  static inline void GB_get_pA
  (
      // output
      int64_t *pA_start,
      int64_t *pA_end,
      // input
      int tid,            // task id
      int64_t k,          // current vector
      int64_t kfirst,     // first vector for this slice
      int64_t klast,      // last vector for this slice
      const int64_t *GB_RESTRICT pstart_slice,   // start of each slice in A
      const int64_t *GB_RESTRICT Ap,             // vector pointers for A
      int64_t avlen                              // A->vlen
  )
  {
  
      int64_t p0 = GBP (Ap, k, avlen) ;
      int64_t p1 = GBP (Ap, k+1, avlen) ;
  
      if (k == kfirst)
      { 
          // First vector for task tid; may only be partially owned.
          (*pA_start) = pstart_slice [tid] ;
          (*pA_end  ) = GB_IMIN (p1, pstart_slice [tid+1]) ;
      }
      else if (k == klast)
      { 
          // Last vector for task tid; may only be partially owned.
          (*pA_start) = p0 ;
          (*pA_end  ) = pstart_slice [tid+1] ;
      }
      else
      { 
          // task tid entirely owns this vector A(:,k).
          (*pA_start) = p0 ;
          (*pA_end  ) = p1 ;
      }
  }
  
  #endif
  