#define _POSIX_C_SOURCE 200112
#include <ceed-impl.h>
#include <ceed.h>
#include <ceed/backend.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static CeedRequest ceed_request_immediate;
static CeedRequest ceed_request_ordered;
static struct {
char prefix[CEED_MAX_RESOURCE_LEN];
int (*init)(const char *resource, Ceed f);
unsigned int priority;
} backends[32];
static size_t num_backends;
#define CEED_FTABLE_ENTRY(class, method) \
{ #class #method, offsetof(struct class##_private, method) }
CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
int CeedRequestWait(CeedRequest *req) {
if (!*req) return CEED_ERROR_SUCCESS;
return CeedError(NULL, CEED_ERROR_UNSUPPORTED, "CeedRequestWait not implemented");
}
int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
int ierr = 0;
CeedPragmaCritical(CeedRegisterImpl) {
if (num_backends < sizeof(backends) / sizeof(backends[0])) {
strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN - 1] = 0;
backends[num_backends].init = init;
backends[num_backends].priority = priority;
num_backends++;
} else {
ierr = 1;
}
}
CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "Too many backends");
return CEED_ERROR_SUCCESS;
}
bool CeedDebugFlag(const Ceed ceed) { return ceed->is_debug; }
bool CeedDebugFlagEnv(void) { return getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG"); }
void CeedDebugImpl256(const unsigned char color, const char *format, ...) {
va_list args;
va_start(args, format);
fflush(stdout);
if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[38;5;%dm", color);
vfprintf(stdout, format, args);
if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[m");
fprintf(stdout, "\n");
fflush(stdout);
va_end(args);
}
int CeedMallocArray(size_t n, size_t unit, void *p) {
int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit);
CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
return CEED_ERROR_SUCCESS;
}
int CeedCallocArray(size_t n, size_t unit, void *p) {
*(void **)p = calloc(n, unit);
CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit);
return CEED_ERROR_SUCCESS;
}
int CeedReallocArray(size_t n, size_t unit, void *p) {
*(void **)p = realloc(*(void **)p, n * unit);
CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit);
return CEED_ERROR_SUCCESS;
}
int CeedStringAllocCopy(const char *source, char **copy) {
size_t len = strlen(source);
CeedCall(CeedCalloc(len + 1, copy));
memcpy(*copy, source, len);
return CEED_ERROR_SUCCESS;
}
int CeedFree(void *p) {
free(*(void **)p);
*(void **)p = NULL;
return CEED_ERROR_SUCCESS;
}
int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
CeedDebugEnv("Backend Register: %s", prefix);
CeedRegisterImpl(prefix, init, priority);
return CEED_ERROR_SUCCESS;
}
int CeedIsDebug(Ceed ceed, bool *is_debug) {
*is_debug = ceed->is_debug;
return CEED_ERROR_SUCCESS;
}
int CeedGetResourceRoot(Ceed ceed, const char *resource, const char *delineator, char **resource_root) {
char *device_spec = strstr(resource, delineator);
size_t resource_root_len = device_spec ? (size_t)(device_spec - resource) + 1 : strlen(resource) + 1;
CeedCall(CeedCalloc(resource_root_len, resource_root));
memcpy(*resource_root, resource, resource_root_len - 1);
return CEED_ERROR_SUCCESS;
}
int CeedGetParent(Ceed ceed, Ceed *parent) {
if (ceed->parent) {
CeedCall(CeedGetParent(ceed->parent, parent));
return CEED_ERROR_SUCCESS;
}
*parent = ceed;
return CEED_ERROR_SUCCESS;
}
int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
*delegate = ceed->delegate;
return CEED_ERROR_SUCCESS;
}
int CeedSetDelegate(Ceed ceed, Ceed delegate) {
ceed->delegate = delegate;
delegate->parent = ceed;
return CEED_ERROR_SUCCESS;
}
int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) {
for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) {
if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) {
*delegate = ceed->obj_delegates->delegate;
return CEED_ERROR_SUCCESS;
}
}
CeedCall(CeedGetDelegate(ceed, delegate));
return CEED_ERROR_SUCCESS;
}
int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) {
CeedInt count = ceed->obj_delegate_count;
if (count) {
CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates));
} else {
CeedCall(CeedCalloc(1, &ceed->obj_delegates));
}
ceed->obj_delegate_count++;
ceed->obj_delegates[count].delegate = delegate;
CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name));
delegate->parent = ceed;
return CEED_ERROR_SUCCESS;
}
int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) {
*resource = (const char *)ceed->op_fallback_resource;
return CEED_ERROR_SUCCESS;
}
int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) {
if (ceed->has_valid_op_fallback_resource) {
CeedDebug256(ceed, CEED_DEBUG_COLOR_SUCCESS, "---------- CeedOperator Fallback ----------\n");
CeedDebug(ceed, "Getting fallback from %s to %s\n", ceed->resource, ceed->op_fallback_resource);
}
if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) {
CeedDebug(ceed, "Creating fallback Ceed");
Ceed fallback_ceed;
const char *fallback_resource;
CeedCall(CeedGetOperatorFallbackResource(ceed, &fallback_resource));
CeedCall(CeedInit(fallback_resource, &fallback_ceed));
fallback_ceed->op_fallback_parent = ceed;
fallback_ceed->Error = ceed->Error;
ceed->op_fallback_ceed = fallback_ceed;
}
*fallback_ceed = ceed->op_fallback_ceed;
return CEED_ERROR_SUCCESS;
}
int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) {
CeedCall(CeedFree(&ceed->op_fallback_resource));
CeedCall(CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource));
ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && ceed->resource && strcmp(ceed->op_fallback_resource, ceed->resource);
return CEED_ERROR_SUCCESS;
}
int CeedSetDeterministic(Ceed ceed, bool is_deterministic) {
ceed->is_deterministic = is_deterministic;
return CEED_ERROR_SUCCESS;
}
int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, const char *func_name, int (*f)()) {
char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = "";
if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN);
strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN);
strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN);
for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) {
if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) {
size_t offset = ceed->f_offsets[i].offset;
int (**fpointer)(void) = (int (**)(void))((char *)object + offset);
*fpointer = f;
return CEED_ERROR_SUCCESS;
}
}
return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type);
}
int CeedGetData(Ceed ceed, void *data) {
*(void **)data = ceed->data;
return CEED_ERROR_SUCCESS;
}
int CeedSetData(Ceed ceed, void *data) {
ceed->data = data;
return CEED_ERROR_SUCCESS;
}
int CeedReference(Ceed ceed) {
ceed->ref_count++;
return CEED_ERROR_SUCCESS;
}
int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) {
*n = 0;
*resources = malloc(num_backends * sizeof(**resources));
CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "malloc() failure");
if (priorities) {
*priorities = malloc(num_backends * sizeof(**priorities));
CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "malloc() failure");
}
for (size_t i = 0; i < num_backends; i++) {
if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) {
*resources[i] = backends[i].prefix;
if (priorities) *priorities[i] = backends[i].priority;
*n += 1;
}
}
CeedCheck(*n, NULL, CEED_ERROR_MAJOR, "No backends installed");
*resources = realloc(*resources, *n * sizeof(**resources));
CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "realloc() failure");
if (priorities) {
*priorities = realloc(*priorities, *n * sizeof(**priorities));
CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "realloc() failure");
}
return CEED_ERROR_SUCCESS;
}
int CeedInit(const char *resource, Ceed *ceed) {
size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority;
CeedCheck(resource, NULL, CEED_ERROR_MAJOR, "No resource provided");
CeedCall(CeedRegisterAll());
const char *help_prefix = "help";
size_t match_help = 0;
while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++;
if (match_help == 4) {
fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH,
CEED_VERSION_RELEASE ? "" : "+development");
fprintf(stderr, "Available backend resources:\n");
for (size_t i = 0; i < num_backends; i++) {
if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) fprintf(stderr, " %s\n", backends[i].prefix);
}
fflush(stderr);
match_help = 5; } else {
match_help = 0;
}
size_t stem_length = 0;
while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++;
for (size_t i = 0; i < num_backends; i++) {
size_t n = 0;
const char *prefix = backends[i].prefix;
while (prefix[n] && prefix[n] == resource[n + match_help]) n++;
priority = backends[i].priority;
if (n > match_len || (n == match_len && match_priority > priority)) {
match_len = n;
match_priority = priority;
match_index = i;
}
}
if (match_len <= 1 || match_len != stem_length) {
size_t lev_dis = UINT_MAX;
size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY;
for (size_t i = 0; i < num_backends; i++) {
const char *prefix = backends[i].prefix;
size_t prefix_length = strlen(backends[i].prefix);
size_t min_len = (prefix_length < stem_length) ? prefix_length : stem_length;
size_t column[min_len + 1];
for (size_t j = 0; j <= min_len; j++) column[j] = j;
for (size_t j = 1; j <= min_len; j++) {
column[0] = j;
for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) {
size_t old_diag = column[k];
size_t min_1 = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1;
size_t min_2 = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1);
column[k] = (min_1 < min_2) ? min_1 : min_2;
last_diag = old_diag;
}
}
size_t n = column[min_len];
priority = backends[i].priority;
if (n < lev_dis || (n == lev_dis && lev_priority > priority)) {
lev_dis = n;
lev_priority = priority;
lev_index = i;
}
}
const char *prefix_lev = backends[lev_index].prefix;
size_t lev_length = 0;
while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++;
size_t m = (lev_length < stem_length) ? lev_length : stem_length;
if (lev_dis + 1 >= m) return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource);
else return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\nClosest match: %s", resource, backends[lev_index].prefix);
}
CeedCall(CeedCalloc(1, ceed));
CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots));
const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
if (!ceed_error_handler) ceed_error_handler = "abort";
if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit;
else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore;
else (*ceed)->Error = CeedErrorAbort;
memcpy((*ceed)->err_msg, "No error message stored", 24);
(*ceed)->ref_count = 1;
(*ceed)->data = NULL;
FOffset f_offsets[] = {
CEED_FTABLE_ENTRY(Ceed, Error),
CEED_FTABLE_ENTRY(Ceed, SetStream),
CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
CEED_FTABLE_ENTRY(Ceed, Destroy),
CEED_FTABLE_ENTRY(Ceed, VectorCreate),
CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateAtPoints),
CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv),
CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl),
CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate),
CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
CEED_FTABLE_ENTRY(CeedVector, HasValidArray),
CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType),
CEED_FTABLE_ENTRY(CeedVector, SetArray),
CEED_FTABLE_ENTRY(CeedVector, TakeArray),
CEED_FTABLE_ENTRY(CeedVector, SetValue),
CEED_FTABLE_ENTRY(CeedVector, SyncArray),
CEED_FTABLE_ENTRY(CeedVector, GetArray),
CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite),
CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
CEED_FTABLE_ENTRY(CeedVector, Norm),
CEED_FTABLE_ENTRY(CeedVector, Scale),
CEED_FTABLE_ENTRY(CeedVector, AXPY),
CEED_FTABLE_ENTRY(CeedVector, AXPBY),
CEED_FTABLE_ENTRY(CeedVector, PointwiseMult),
CEED_FTABLE_ENTRY(CeedVector, Reciprocal),
CEED_FTABLE_ENTRY(CeedVector, Destroy),
CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned),
CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnoriented),
CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyAtPointsInElement),
CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets),
CEED_FTABLE_ENTRY(CeedElemRestriction, GetOrientations),
CEED_FTABLE_ENTRY(CeedElemRestriction, GetCurlOrientations),
CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
CEED_FTABLE_ENTRY(CeedBasis, Apply),
CEED_FTABLE_ENTRY(CeedBasis, ApplyAtPoints),
CEED_FTABLE_ENTRY(CeedBasis, Destroy),
CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
CEED_FTABLE_ENTRY(CeedQFunction, Apply),
CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction),
CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction),
CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData),
CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType),
CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData),
CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData),
CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData),
CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead),
CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData),
CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead),
CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy),
CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble),
CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle),
CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse),
CEED_FTABLE_ENTRY(CeedOperator, Apply),
CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite),
CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd),
CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite),
CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
CEED_FTABLE_ENTRY(CeedOperator, Destroy),
{NULL, 0} };
CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets));
memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets));
const char fallback_resource[] = "";
CeedCall(CeedSetOperatorFallbackResource(*ceed, fallback_resource));
(*ceed)->is_debug = getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG");
CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource));
CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault));
CeedCall(backends[match_index].init(&resource[match_help], *ceed));
return CEED_ERROR_SUCCESS;
}
int CeedSetStream(Ceed ceed, void *handle) {
CeedCheck(handle, ceed, CEED_ERROR_INCOMPATIBLE, "Stream handle must be non-null");
if (ceed->SetStream) {
CeedCall(ceed->SetStream(ceed, handle));
} else {
Ceed delegate;
CeedCall(CeedGetDelegate(ceed, &delegate));
if (delegate) CeedCall(CeedSetStream(delegate, handle));
else return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support setting stream");
}
return CEED_ERROR_SUCCESS;
}
int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) {
CeedCall(CeedReference(ceed));
CeedCall(CeedDestroy(ceed_copy));
*ceed_copy = ceed;
return CEED_ERROR_SUCCESS;
}
int CeedGetResource(Ceed ceed, const char **resource) {
*resource = (const char *)ceed->resource;
return CEED_ERROR_SUCCESS;
}
int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) {
if (ceed->GetPreferredMemType) {
CeedCall(ceed->GetPreferredMemType(mem_type));
} else {
Ceed delegate;
CeedCall(CeedGetDelegate(ceed, &delegate));
if (delegate) {
CeedCall(CeedGetPreferredMemType(delegate, mem_type));
} else {
*mem_type = CEED_MEM_HOST;
}
}
return CEED_ERROR_SUCCESS;
}
int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) {
*is_deterministic = ceed->is_deterministic;
return CEED_ERROR_SUCCESS;
}
int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) {
Ceed ceed_parent;
CeedCall(CeedGetParent(ceed, &ceed_parent));
CeedInt index = ceed_parent->num_jit_source_roots;
size_t path_length = strlen(jit_source_root);
CeedCall(CeedRealloc(index + 1, &ceed_parent->jit_source_roots));
CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index]));
memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length);
ceed_parent->num_jit_source_roots++;
return CEED_ERROR_SUCCESS;
}
int CeedView(Ceed ceed, FILE *stream) {
CeedMemType mem_type;
CeedCall(CeedGetPreferredMemType(ceed, &mem_type));
fprintf(stream,
"Ceed\n"
" Ceed Resource: %s\n"
" Preferred MemType: %s\n",
ceed->resource, CeedMemTypes[mem_type]);
return CEED_ERROR_SUCCESS;
}
int CeedDestroy(Ceed *ceed) {
if (!*ceed || --(*ceed)->ref_count > 0) {
*ceed = NULL;
return CEED_ERROR_SUCCESS;
}
if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate));
if ((*ceed)->obj_delegate_count > 0) {
for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) {
CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate)));
CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name));
}
CeedCall(CeedFree(&(*ceed)->obj_delegates));
}
if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed));
for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) {
CeedCall(CeedFree(&(*ceed)->jit_source_roots[i]));
}
CeedCall(CeedFree(&(*ceed)->jit_source_roots));
CeedCall(CeedFree(&(*ceed)->f_offsets));
CeedCall(CeedFree(&(*ceed)->resource));
CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed));
CeedCall(CeedFree(&(*ceed)->op_fallback_resource));
CeedCall(CeedFree(ceed));
return CEED_ERROR_SUCCESS;
}
const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) {
if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args);
if (ceed->op_fallback_parent) return CeedErrorFormat(ceed->op_fallback_parent, format, args);
vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args); return ceed->err_msg;
}
int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) {
va_list args;
int ret_val;
va_start(args, format);
if (ceed) {
ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args);
} else {
const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
if (!ceed_error_handler) ceed_error_handler = "abort";
if (!strcmp(ceed_error_handler, "return")) ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args);
else
ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args);
}
va_end(args);
return ret_val;
}
int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
return err_code;
}
int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args);
if (ceed->op_fallback_parent) return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, err_code, format, args);
int len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func);
vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); return err_code;
}
int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
vfprintf(stderr, format, *args);
fprintf(stderr, "\n");
abort();
return err_code;
}
int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
vfprintf(stderr, format, *args); fprintf(stderr, "\n");
exit(err_code);
return err_code;
}
int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) {
ceed->Error = handler;
if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler);
for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler);
return CEED_ERROR_SUCCESS;
}
int CeedGetErrorMessage(Ceed ceed, const char **err_msg) {
if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg);
if (ceed->op_fallback_parent) return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg);
*err_msg = ceed->err_msg;
return CEED_ERROR_SUCCESS;
}
int CeedResetErrorMessage(Ceed ceed, const char **err_msg) {
if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg);
if (ceed->op_fallback_parent) return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg);
*err_msg = NULL;
memcpy(ceed->err_msg, "No error message stored", 24);
return CEED_ERROR_SUCCESS;
}
int CeedGetVersion(int *major, int *minor, int *patch, bool *release) {
if (major) *major = CEED_VERSION_MAJOR;
if (minor) *minor = CEED_VERSION_MINOR;
if (patch) *patch = CEED_VERSION_PATCH;
if (release) *release = CEED_VERSION_RELEASE;
return 0;
}
int CeedGetScalarType(CeedScalarType *scalar_type) {
*scalar_type = CEED_SCALAR_TYPE;
return 0;
}