text: //------------------------------------------------------------------------------
  // GB_context.h: definitions for the internal context
  //------------------------------------------------------------------------------
  
  // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
  // SPDX-License-Identifier: Apache-2.0
  
  //------------------------------------------------------------------------------
  
  #ifndef GB_CONTEXT_H
  #define GB_CONTEXT_H
  
  //------------------------------------------------------------------------------
  // GB_context: error logging, thread control, and Werk space
  //------------------------------------------------------------------------------
  
  // Error messages are logged in Context->logger_handle, on the stack which is
  // handle to the input/output matrix/vector (typically C).  If the user-defined
  // data types, operators, etc have really long names, the error messages are
  // safely truncated (via snprintf).  This is intentional, but gcc with
  // -Wformat-truncation will print a warning (see pragmas above).  Ignore the
  // warning.
  
  // Threading control is described in GB_nthreads.h.
  
  // GB_WERK_SIZE is the size of a small fixed-sized array in the Context, used
  // for small werkspace allocations (typically O(# of threads or # tasks)).
  // GB_WERK_SIZE must be a multiple of 8.  The Werk array is placed first in the
  // GB_Context struct, to ensure proper alignment.
  
  #define GB_WERK_SIZE 16384
  
  typedef struct
  {
      GB_void Werk [GB_WERK_SIZE] ;   // werkspace stack
      double chunk ;                  // chunk size for small problems
      const char *where ;             // GraphBLAS function where error occurred
      char **logger_handle ;          // error report
      size_t *logger_size_handle ;
      int nthreads_max ;              // max # of threads to use
      int pwerk ;                     // top of Werk stack, initially zero
  }
  GB_Context_struct ;
  
  typedef GB_Context_struct *GB_Context ;
  
  // GB_WHERE keeps track of the currently running user-callable function.
  // User-callable functions in this implementation are written so that they do
  // not call other unrelated user-callable functions (except for GrB_*free).
  // Related user-callable functions can call each other since they all report
  // the same type-generic name.  Internal functions can be called by many
  // different user-callable functions, directly or indirectly.  It would not be
  // helpful to report the name of an internal function that flagged an error
  // condition.  Thus, each time a user-callable function is entered, it logs the
  // name of the function with the GB_WHERE macro.
  
  #define GB_CONTEXT(where_string)                                    \
      /* construct the Context */                                     \
      GB_Context_struct Context_struct ;                              \
      GB_Context Context = &Context_struct ;                          \
      /* set Context->where so GrB_error can report it if needed */   \
      Context->where = where_string ;                                 \
      /* get the default max # of threads and default chunk size */   \
      Context->nthreads_max = GB_Global_nthreads_max_get ( ) ;        \
      Context->chunk = GB_Global_chunk_get ( ) ;                      \
      /* get the pointer to where any error will be logged */         \
      Context->logger_handle = NULL ;                                 \
      Context->logger_size_handle = NULL ;                            \
      /* initialize the Werk stack */                                 \
      Context->pwerk = 0 ;
  
  // C is a matrix, vector, scalar, or descriptor
  #define GB_WHERE(C,where_string)                                    \
      if (!GB_Global_GrB_init_called_get ( ))                         \
      {                                                               \
          return (GrB_PANIC) ; /* GrB_init not called */              \
      }                                                               \
      GB_CONTEXT (where_string)                                       \
      if (C != NULL)                                                  \
      {                                                               \
          /* free any prior error logged in the object */             \
          GB_FREE (&(C->logger), C->logger_size) ;                    \
          Context->logger_handle = &(C->logger) ;                     \
          Context->logger_size_handle = &(C->logger_size) ;           \
      }
  
  // create the Context, with no error logging
  #define GB_WHERE1(where_string)                                     \
      if (!GB_Global_GrB_init_called_get ( ))                         \
      {                                                               \
          return (GrB_PANIC) ; /* GrB_init not called */              \
      }                                                               \
      GB_CONTEXT (where_string)
  
  //------------------------------------------------------------------------------
  // error logging
  //------------------------------------------------------------------------------
  
  // The GB_ERROR macro logs an error in the logger error string.
  //
  //  if (i >= nrows)
  //  {
  //      GB_ERROR (GrB_INDEX_OUT_OF_BOUNDS,
  //          "Row index %d out of bounds; must be < %d", i, nrows) ;
  //  }
  //
  // The user can then do:
  //
  //  const char *error ;
  //  GrB_error (&error, A) ;
  //  printf ("%s", error) ;
  
  GB_PUBLIC
  const char *GB_status_code (GrB_Info info) ;
  
  // maximum size of the error logger string
  #define GB_LOGGER_LEN 384
  
  // log an error in the error logger string and return the error
  #define GB_ERROR(info,format,...)                                           \
  {                                                                           \
      if (Context != NULL)                                                    \
      {                                                                       \
          char **logger_handle = Context->logger_handle ;                     \
          if (logger_handle != NULL)                                          \
          {                                                                   \
              size_t *logger_size_handle = Context->logger_size_handle ;      \
              (*logger_handle) = GB_CALLOC (GB_LOGGER_LEN+1, char,            \
                  logger_size_handle) ;                                       \
              if ((*logger_handle) != NULL)                                   \
              {                                                               \
                  snprintf ((*logger_handle), GB_LOGGER_LEN,                  \
                      "GraphBLAS error: %s\nfunction: %s\n" format,           \
                      GB_status_code (info), Context->where, __VA_ARGS__) ;   \
              }                                                               \
          }                                                                   \
      }                                                                       \
      return (info) ;                                                         \
  }
  
  #endif
  
  