xref: /libCEED/interface/ceed.c (revision 547d9b97859fb07c9c2b832a30615e0bf91eaab3)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17d7b241e6Sjeremylt #define _POSIX_C_SOURCE 200112
18d7b241e6Sjeremylt #include <ceed-impl.h>
19d863ab9bSjeremylt #include <ceed-backend.h>
20aedaa0e5Sjeremylt #include <limits.h>
21d7b241e6Sjeremylt #include <stdarg.h>
226e79d475Sjeremylt #include <stddef.h>
23d7b241e6Sjeremylt #include <stdio.h>
24d7b241e6Sjeremylt #include <stdlib.h>
25d7b241e6Sjeremylt #include <string.h>
26d7b241e6Sjeremylt 
27d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP
28d7b241e6Sjeremylt static CeedRequest ceed_request_immediate;
29d7b241e6Sjeremylt static CeedRequest ceed_request_ordered;
30d7b241e6Sjeremylt 
31d7b241e6Sjeremylt static struct {
32d7b241e6Sjeremylt   char prefix[CEED_MAX_RESOURCE_LEN];
33d7b241e6Sjeremylt   int (*init)(const char *resource, Ceed f);
34d7b241e6Sjeremylt   unsigned int priority;
35d7b241e6Sjeremylt } backends[32];
36d7b241e6Sjeremylt static size_t num_backends;
37fe2413ffSjeremylt 
386e79d475Sjeremylt #define CEED_FTABLE_ENTRY(class, method) \
396e79d475Sjeremylt   {#class #method, offsetof(struct class ##_private, method)}
40d7b241e6Sjeremylt /// @endcond
41d7b241e6Sjeremylt 
42d7b241e6Sjeremylt /// @file
43d7b241e6Sjeremylt /// Implementation of core components of Ceed library
44d7b241e6Sjeremylt ///
45dfdf5a53Sjeremylt /// @addtogroup Ceed
46d7b241e6Sjeremylt /// @{
47d7b241e6Sjeremylt 
48dfdf5a53Sjeremylt /**
49dfdf5a53Sjeremylt   @brief Request immediate completion
50dfdf5a53Sjeremylt 
51dfdf5a53Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
52dfdf5a53Sjeremylt   interfaces when the caller wishes for the operation to be performed
53dfdf5a53Sjeremylt   immediately.  The code
54dfdf5a53Sjeremylt 
55dfdf5a53Sjeremylt   @code
56dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE);
57dfdf5a53Sjeremylt   @endcode
58dfdf5a53Sjeremylt 
59dfdf5a53Sjeremylt   is semantically equivalent to
60dfdf5a53Sjeremylt 
61dfdf5a53Sjeremylt   @code
62dfdf5a53Sjeremylt     CeedRequest request;
63dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., &request);
64dfdf5a53Sjeremylt     CeedRequestWait(&request);
65dfdf5a53Sjeremylt   @endcode
66dfdf5a53Sjeremylt 
67dfdf5a53Sjeremylt   @sa CEED_REQUEST_ORDERED
68dfdf5a53Sjeremylt **/
69d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
70d7b241e6Sjeremylt 
71d7b241e6Sjeremylt /**
72b11c1e72Sjeremylt   @brief Request ordered completion
73d7b241e6Sjeremylt 
74d7b241e6Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
75d7b241e6Sjeremylt   interfaces when the caller wishes for the operation to be completed in the
76d7b241e6Sjeremylt   order that it is submitted to the device.  It is typically used in a construct
77d7b241e6Sjeremylt   such as
78d7b241e6Sjeremylt 
79d7b241e6Sjeremylt   @code
80d7b241e6Sjeremylt     CeedRequest request;
81d7b241e6Sjeremylt     CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED);
82d7b241e6Sjeremylt     CeedOperatorApply(op2, ..., &request);
83d7b241e6Sjeremylt     // other optional work
84d7b241e6Sjeremylt     CeedWait(&request);
85d7b241e6Sjeremylt   @endcode
86d7b241e6Sjeremylt 
87d7b241e6Sjeremylt   which allows the sequence to complete asynchronously but does not start
88d7b241e6Sjeremylt   `op2` until `op1` has completed.
89d7b241e6Sjeremylt 
90288c0443SJeremy L Thompson   @todo The current implementation is overly strict, offering equivalent
91d7b241e6Sjeremylt   semantics to CEED_REQUEST_IMMEDIATE.
92d7b241e6Sjeremylt 
93d7b241e6Sjeremylt   @sa CEED_REQUEST_IMMEDIATE
94d7b241e6Sjeremylt  */
95d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
96d7b241e6Sjeremylt 
97b11c1e72Sjeremylt /**
98b11c1e72Sjeremylt   @brief Error handling implementation; use \ref CeedError instead.
99dfdf5a53Sjeremylt 
100dfdf5a53Sjeremylt   @ref Developer
101b11c1e72Sjeremylt **/
102d7b241e6Sjeremylt int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func,
103d7b241e6Sjeremylt                   int ecode, const char *format, ...) {
104d7b241e6Sjeremylt   va_list args;
105683faae0SJed Brown   int retval;
106d7b241e6Sjeremylt   va_start(args, format);
107683faae0SJed Brown   if (ceed) {
108683faae0SJed Brown     retval = ceed->Error(ceed, filename, lineno, func, ecode, format, args);
109683faae0SJed Brown   } else {
110683faae0SJed Brown     // This function doesn't actually return
111683faae0SJed Brown     retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args);
112683faae0SJed Brown   }
113683faae0SJed Brown   va_end(args);
114683faae0SJed Brown   return retval;
115d7b241e6Sjeremylt }
116d7b241e6Sjeremylt 
117b11c1e72Sjeremylt /**
118b11c1e72Sjeremylt   @brief Error handler that returns without printing anything.
119b11c1e72Sjeremylt 
120b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
121dfdf5a53Sjeremylt 
122dfdf5a53Sjeremylt   @ref Developer
123b11c1e72Sjeremylt **/
12413873f79Sjeremylt // LCOV_EXCL_START
125d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno,
126d7b241e6Sjeremylt                     const char *func, int ecode, const char *format,
127d7b241e6Sjeremylt                     va_list args) {
128d7b241e6Sjeremylt   return ecode;
129d7b241e6Sjeremylt }
13013873f79Sjeremylt // LCOV_EXCL_STOP
131d7b241e6Sjeremylt 
132b11c1e72Sjeremylt /**
133b11c1e72Sjeremylt   @brief Error handler that prints to stderr and aborts
134b11c1e72Sjeremylt 
135b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
136dfdf5a53Sjeremylt 
137dfdf5a53Sjeremylt   @ref Developer
138b11c1e72Sjeremylt **/
13913873f79Sjeremylt // LCOV_EXCL_START
140d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno,
1411d102b48SJeremy L Thompson                    const char *func, int ecode, const char *format,
1421d102b48SJeremy L Thompson                    va_list args) {
143d7b241e6Sjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
144d7b241e6Sjeremylt   vfprintf(stderr, format, args);
145d7b241e6Sjeremylt   fprintf(stderr, "\n");
146d7b241e6Sjeremylt   abort();
147d7b241e6Sjeremylt   return ecode;
148d7b241e6Sjeremylt }
14913873f79Sjeremylt // LCOV_EXCL_STOP
150d7b241e6Sjeremylt 
151b11c1e72Sjeremylt /**
15256e866f4SJed Brown   @brief Error handler that prints to stderr and exits
15356e866f4SJed Brown 
15456e866f4SJed Brown   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
15556e866f4SJed Brown 
15656e866f4SJed Brown   In contrast to CeedErrorAbort(), this exits without a signal, so atexit()
15756e866f4SJed Brown   handlers (e.g., as used by gcov) are run.
15856e866f4SJed Brown 
15956e866f4SJed Brown   @ref Developer
16056e866f4SJed Brown **/
161692c2638Sjeremylt int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func,
162692c2638Sjeremylt                   int ecode, const char *format, va_list args) {
16356e866f4SJed Brown   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
16456e866f4SJed Brown   vfprintf(stderr, format, args);
16556e866f4SJed Brown   fprintf(stderr, "\n");
16656e866f4SJed Brown   exit(ecode);
16756e866f4SJed Brown   return ecode;
16856e866f4SJed Brown }
16956e866f4SJed Brown 
17056e866f4SJed Brown /**
171dfdf5a53Sjeremylt   @brief Set error handler
172b11c1e72Sjeremylt 
173b11c1e72Sjeremylt   A default error handler is set in CeedInit().  Use this function to change
174b11c1e72Sjeremylt   the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined
175b11c1e72Sjeremylt   error handler.
176dfdf5a53Sjeremylt 
177dfdf5a53Sjeremylt   @ref Developer
178b11c1e72Sjeremylt **/
179d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed,
180d7b241e6Sjeremylt                         int (eh)(Ceed, const char *, int, const char *,
181d7b241e6Sjeremylt                                  int, const char *, va_list)) {
182d7b241e6Sjeremylt   ceed->Error = eh;
183d7b241e6Sjeremylt   return 0;
184d7b241e6Sjeremylt }
185d7b241e6Sjeremylt 
186d7b241e6Sjeremylt /**
187b11c1e72Sjeremylt   @brief Register a Ceed backend
188d7b241e6Sjeremylt 
189d7b241e6Sjeremylt   @param prefix   Prefix of resources for this backend to respond to.  For
190d7b241e6Sjeremylt                     example, the reference backend responds to "/cpu/self".
191d7b241e6Sjeremylt   @param init     Initialization function called by CeedInit() when the backend
192d7b241e6Sjeremylt                     is selected to drive the requested resource.
193d7b241e6Sjeremylt   @param priority Integer priority.  Lower values are preferred in case the
194d7b241e6Sjeremylt                     resource requested by CeedInit() has non-unique best prefix
195d7b241e6Sjeremylt                     match.
196b11c1e72Sjeremylt 
197b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
198dfdf5a53Sjeremylt 
199dfdf5a53Sjeremylt   @ref Advanced
200b11c1e72Sjeremylt **/
201692c2638Sjeremylt int CeedRegister(const char *prefix, int (*init)(const char *, Ceed),
202692c2638Sjeremylt                  unsigned int priority) {
203c042f62fSJeremy L Thompson   if (num_backends >= sizeof(backends) / sizeof(backends[0]))
204c042f62fSJeremy L Thompson     // LCOV_EXCL_START
205d7b241e6Sjeremylt     return CeedError(NULL, 1, "Too many backends");
206c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
207c042f62fSJeremy L Thompson 
208d7b241e6Sjeremylt   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
209288c0443SJeremy L Thompson   backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0;
210d7b241e6Sjeremylt   backends[num_backends].init = init;
211d7b241e6Sjeremylt   backends[num_backends].priority = priority;
212d7b241e6Sjeremylt   num_backends++;
213d7b241e6Sjeremylt   return 0;
214d7b241e6Sjeremylt }
215d7b241e6Sjeremylt 
216b11c1e72Sjeremylt /**
217b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
218b11c1e72Sjeremylt 
219b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
220b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
221b11c1e72Sjeremylt 
222b11c1e72Sjeremylt   @param n Number of units to allocate
223b11c1e72Sjeremylt   @param unit Size of each unit
224b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
225b11c1e72Sjeremylt 
226b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
227b11c1e72Sjeremylt 
228b11c1e72Sjeremylt   @sa CeedFree()
229dfdf5a53Sjeremylt 
230dfdf5a53Sjeremylt   @ref Advanced
231b11c1e72Sjeremylt **/
232d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
233d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
234d7b241e6Sjeremylt   if (ierr)
235c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2361d102b48SJeremy L Thompson     return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd "
2371d102b48SJeremy L Thompson                      "members of size %zd\n", n, unit);
238c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
239c042f62fSJeremy L Thompson 
240d7b241e6Sjeremylt   return 0;
241d7b241e6Sjeremylt }
242d7b241e6Sjeremylt 
243b11c1e72Sjeremylt /**
244b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
245b11c1e72Sjeremylt 
246b11c1e72Sjeremylt   Memory usage can be tracked by the library.
247b11c1e72Sjeremylt 
248b11c1e72Sjeremylt   @param n    Number of units to allocate
249b11c1e72Sjeremylt   @param unit Size of each unit
250b11c1e72Sjeremylt   @param p    Address of pointer to hold the result.
251b11c1e72Sjeremylt 
252b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
253b11c1e72Sjeremylt 
254b11c1e72Sjeremylt   @sa CeedFree()
255dfdf5a53Sjeremylt 
256dfdf5a53Sjeremylt   @ref Advanced
257b11c1e72Sjeremylt **/
258d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
259d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
260d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
261c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2621d102b48SJeremy L Thompson     return CeedError(NULL, 1, "calloc failed to allocate %zd members of size "
2631d102b48SJeremy L Thompson                      "%zd\n", n, unit);
264c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
265c042f62fSJeremy L Thompson 
266d7b241e6Sjeremylt   return 0;
267d7b241e6Sjeremylt }
268d7b241e6Sjeremylt 
269b11c1e72Sjeremylt /**
270b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
271b11c1e72Sjeremylt 
272b11c1e72Sjeremylt   Memory usage can be tracked by the library.
273b11c1e72Sjeremylt 
274b11c1e72Sjeremylt   @param n    Number of units to allocate
275b11c1e72Sjeremylt   @param unit Size of each unit
276b11c1e72Sjeremylt   @param p    Address of pointer to hold the result.
277b11c1e72Sjeremylt 
278b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
279b11c1e72Sjeremylt 
280b11c1e72Sjeremylt   @sa CeedFree()
281dfdf5a53Sjeremylt 
282dfdf5a53Sjeremylt   @ref Advanced
283b11c1e72Sjeremylt **/
284d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
285d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
286d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
287c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2881d102b48SJeremy L Thompson     return CeedError(NULL, 1, "realloc failed to allocate %zd members of size "
2891d102b48SJeremy L Thompson                      "%zd\n", n, unit);
290c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
291c042f62fSJeremy L Thompson 
292d7b241e6Sjeremylt   return 0;
293d7b241e6Sjeremylt }
294d7b241e6Sjeremylt 
29534138859Sjeremylt /** Free memory allocated using CeedMalloc() or CeedCalloc()
29634138859Sjeremylt 
29734138859Sjeremylt   @param p address of pointer to memory.  This argument is of type void* to
29834138859Sjeremylt              avoid needing a cast, but is the address of the pointer (which is
29934138859Sjeremylt              zeroed) rather than the pointer.
30034138859Sjeremylt **/
301d7b241e6Sjeremylt int CeedFree(void *p) {
302d7b241e6Sjeremylt   free(*(void **)p);
303d7b241e6Sjeremylt   *(void **)p = NULL;
304d7b241e6Sjeremylt   return 0;
305d7b241e6Sjeremylt }
306d7b241e6Sjeremylt 
307d7b241e6Sjeremylt /**
308b11c1e72Sjeremylt   @brief Wait for a CeedRequest to complete.
309d7b241e6Sjeremylt 
310d7b241e6Sjeremylt   Calling CeedRequestWait on a NULL request is a no-op.
311d7b241e6Sjeremylt 
312d7b241e6Sjeremylt   @param req Address of CeedRequest to wait for; zeroed on completion.
313b11c1e72Sjeremylt 
314b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
315dfdf5a53Sjeremylt 
316dfdf5a53Sjeremylt   @ref Advanced
317b11c1e72Sjeremylt **/
318d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) {
3191d102b48SJeremy L Thompson   if (!*req)
3201d102b48SJeremy L Thompson     return 0;
321d7b241e6Sjeremylt   return CeedError(NULL, 2, "CeedRequestWait not implemented");
322d7b241e6Sjeremylt }
323d7b241e6Sjeremylt 
324b11c1e72Sjeremylt /**
325d79b80ecSjeremylt   @brief Initialize a \ref Ceed context to use the specified resource.
326b11c1e72Sjeremylt 
327b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
328b11c1e72Sjeremylt   @param ceed      The library context
329b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
330b11c1e72Sjeremylt 
331b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
332dfdf5a53Sjeremylt 
333dfdf5a53Sjeremylt   @ref Basic
334b11c1e72Sjeremylt **/
335d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
336d7b241e6Sjeremylt   int ierr;
337aedaa0e5Sjeremylt   size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority;
338d7b241e6Sjeremylt 
339fe2413ffSjeremylt   // Find matching backend
3401d102b48SJeremy L Thompson   if (!resource)
34113873f79Sjeremylt     // LCOV_EXCL_START
3421d102b48SJeremy L Thompson     return CeedError(NULL, 1, "No resource provided");
34313873f79Sjeremylt   // LCOV_EXCL_STOP
34413873f79Sjeremylt 
345d7b241e6Sjeremylt   for (size_t i=0; i<num_backends; i++) {
346d7b241e6Sjeremylt     size_t n;
347d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
348d7b241e6Sjeremylt     for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {}
349d7b241e6Sjeremylt     priority = backends[i].priority;
350d7b241e6Sjeremylt     if (n > matchlen || (n == matchlen && matchpriority > priority)) {
351d7b241e6Sjeremylt       matchlen = n;
352d7b241e6Sjeremylt       matchpriority = priority;
353d7b241e6Sjeremylt       matchidx = i;
354d7b241e6Sjeremylt     }
355d7b241e6Sjeremylt   }
3561d102b48SJeremy L Thompson   if (!matchlen)
35713873f79Sjeremylt     // LCOV_EXCL_START
3581d102b48SJeremy L Thompson     return CeedError(NULL, 1, "No suitable backend");
35913873f79Sjeremylt   // LCOV_EXCL_STOP
360fe2413ffSjeremylt 
361fe2413ffSjeremylt   // Setup Ceed
362d7b241e6Sjeremylt   ierr = CeedCalloc(1, ceed); CeedChk(ierr);
363bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
3641d102b48SJeremy L Thompson   if (!ceed_error_handler)
3651d102b48SJeremy L Thompson     ceed_error_handler = "abort";
366bc81ce41Sjeremylt   if (!strcmp(ceed_error_handler, "exit"))
36756e866f4SJed Brown     (*ceed)->Error = CeedErrorExit;
36856e866f4SJed Brown   else
369d7b241e6Sjeremylt     (*ceed)->Error = CeedErrorAbort;
370d7b241e6Sjeremylt   (*ceed)->refcount = 1;
371d7b241e6Sjeremylt   (*ceed)->data = NULL;
372fe2413ffSjeremylt 
373fe2413ffSjeremylt   // Set lookup table
3746e79d475Sjeremylt   foffset foffsets[] = {
3756e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Error),
3766e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
3776e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Destroy),
378f8902d9eSjeremylt     CEED_FTABLE_ENTRY(Ceed, VectorCreate),
3796e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
3806e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
3816e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
3826e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
3836e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
3846e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
3856e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
3866e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
3876e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetArray),
3886e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetValue),
3896e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArray),
3906e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
3916e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
3926e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
393*547d9b97Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Norm),
3946e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Destroy),
3956e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
3966e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
3976e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
3986e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Apply),
3996e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Destroy),
4006e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
4016e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
4026e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Apply),
4036e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
4041d102b48SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction),
405b7ec98d8SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal),
406713f43c3Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse),
4076e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Apply),
408250756a7Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite),
409cae8b89aSjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd),
410250756a7Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite),
4116e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
4126e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Destroy),
4136e79d475Sjeremylt     {NULL, 0} // End of lookup table - used in SetBackendFunction loop
4141dfeef1dSjeremylt   };
415fe2413ffSjeremylt 
4166e79d475Sjeremylt   ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr);
4176e79d475Sjeremylt   memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets));
418fe2413ffSjeremylt 
4195107b09fSJeremy L Thompson   // Set fallback for advanced CeedOperator functions
4205107b09fSJeremy L Thompson   const char fallbackresource[] = "/cpu/self/ref/serial";
4215107b09fSJeremy L Thompson   ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource);
4225107b09fSJeremy L Thompson   CeedChk(ierr);
4235107b09fSJeremy L Thompson 
424fe2413ffSjeremylt   // Backend specific setup
425d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
426fe2413ffSjeremylt 
427e07206deSjeremylt   // Copy resource prefix, if backend setup sucessful
428e07206deSjeremylt   size_t len = strlen(backends[matchidx].prefix);
429e07206deSjeremylt   char *tmp;
430e07206deSjeremylt   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
431e07206deSjeremylt   memcpy(tmp, backends[matchidx].prefix, len+1);
432e07206deSjeremylt   (*ceed)->resource = tmp;
433e07206deSjeremylt 
434d7b241e6Sjeremylt   return 0;
435d7b241e6Sjeremylt }
436d7b241e6Sjeremylt 
437d7b241e6Sjeremylt /**
438d79b80ecSjeremylt   @brief Retrieve a parent Ceed context
4392f86a920SJeremy L Thompson 
440d79b80ecSjeremylt   @param ceed        Ceed context to retrieve parent of
4412f86a920SJeremy L Thompson   @param[out] parent Address to save the parent to
4422f86a920SJeremy L Thompson 
4432f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4442f86a920SJeremy L Thompson 
4452f86a920SJeremy L Thompson   @ref Developer
4462f86a920SJeremy L Thompson **/
4472f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
4482f86a920SJeremy L Thompson   int ierr;
4492f86a920SJeremy L Thompson   if (ceed->parent) {
4502f86a920SJeremy L Thompson     ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr);
4512f86a920SJeremy L Thompson     return 0;
4522f86a920SJeremy L Thompson   }
4532f86a920SJeremy L Thompson   *parent = ceed;
4542f86a920SJeremy L Thompson   return 0;
4552f86a920SJeremy L Thompson }
4562f86a920SJeremy L Thompson 
4572f86a920SJeremy L Thompson /**
458d79b80ecSjeremylt   @brief Retrieve a delegate Ceed context
4595fe0d4faSjeremylt 
460d79b80ecSjeremylt   @param ceed          Ceed context to retrieve delegate of
4615fe0d4faSjeremylt   @param[out] delegate Address to save the delegate to
4625fe0d4faSjeremylt 
4635fe0d4faSjeremylt   @return An error code: 0 - success, otherwise - failure
4645fe0d4faSjeremylt 
46523617272Sjeremylt   @ref Developer
4665fe0d4faSjeremylt **/
4675fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
4684ce2993fSjeremylt   *delegate = ceed->delegate;
4694ce2993fSjeremylt   return 0;
4704ce2993fSjeremylt }
4714ce2993fSjeremylt 
4724ce2993fSjeremylt /**
473d79b80ecSjeremylt   @brief Set a delegate Ceed context
4744ce2993fSjeremylt 
475d79b80ecSjeremylt   This function allows a Ceed context to set a delegate Ceed context. All
476d79b80ecSjeremylt     backend implementations default to the delegate Ceed context, unless
477d79b80ecSjeremylt     overridden.
478f29ffe77Sjeremylt 
479d79b80ecSjeremylt   @param ceed           Ceed context to set delegate of
4804ce2993fSjeremylt   @param[out] delegate  Address to set the delegate to
4814ce2993fSjeremylt 
4824ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4834ce2993fSjeremylt 
48423617272Sjeremylt   @ref Advanced
4854ce2993fSjeremylt **/
486a4999eddSjeremylt int CeedSetDelegate(Ceed ceed, Ceed delegate) {
487a4999eddSjeremylt   ceed->delegate = delegate;
488a4999eddSjeremylt   delegate->parent = ceed;
4894ce2993fSjeremylt   return 0;
4904ce2993fSjeremylt }
4914ce2993fSjeremylt 
4924ce2993fSjeremylt /**
493d79b80ecSjeremylt   @brief Retrieve a delegate Ceed context for a specific object type
494aefd8378Sjeremylt 
495d79b80ecSjeremylt   @param ceed           Ceed context to retrieve delegate of
496aefd8378Sjeremylt   @param[out] delegate  Address to save the delegate to
497288c0443SJeremy L Thompson   @param[in] objname    Name of the object type to retrieve delegate for
498aefd8378Sjeremylt 
499aefd8378Sjeremylt   @return An error code: 0 - success, otherwise - failure
500aefd8378Sjeremylt 
501aefd8378Sjeremylt   @ref Developer
502aefd8378Sjeremylt **/
503aefd8378Sjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) {
504aefd8378Sjeremylt   CeedInt ierr;
505aefd8378Sjeremylt 
506aefd8378Sjeremylt   // Check for object delegate
5071d102b48SJeremy L Thompson   for (CeedInt i=0; i<ceed->objdelegatecount; i++)
508aefd8378Sjeremylt     if (!strcmp(objname, ceed->objdelegates->objname)) {
509aefd8378Sjeremylt       *delegate = ceed->objdelegates->delegate;
510aefd8378Sjeremylt       return 0;
511aefd8378Sjeremylt     }
512aefd8378Sjeremylt 
513aefd8378Sjeremylt   // Use default delegate if no object delegate
514aefd8378Sjeremylt   ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr);
515aefd8378Sjeremylt 
516aefd8378Sjeremylt   return 0;
517aefd8378Sjeremylt }
518aefd8378Sjeremylt 
519aefd8378Sjeremylt /**
520d79b80ecSjeremylt   @brief Set a delegate Ceed context for a specific object type
521aefd8378Sjeremylt 
522d79b80ecSjeremylt   This function allows a Ceed context to set a delegate Ceed context for a
523d79b80ecSjeremylt     given type of Ceed object. All backend implementations default to the
524d79b80ecSjeremylt     delegate Ceed context for this object. For example,
525f29ffe77Sjeremylt     CeedSetObjectDelegate(ceed, refceed, "Basis")
526f29ffe77Sjeremylt   uses refceed implementations for all CeedBasis backend functions.
527f29ffe77Sjeremylt 
528d79b80ecSjeremylt   @param ceed          Ceed context to set delegate of
529aefd8378Sjeremylt   @param[out] delegate Address to set the delegate to
530288c0443SJeremy L Thompson   @param[in] objname   Name of the object type to set delegate for
531aefd8378Sjeremylt 
532aefd8378Sjeremylt   @return An error code: 0 - success, otherwise - failure
533aefd8378Sjeremylt 
534aefd8378Sjeremylt   @ref Advanced
535aefd8378Sjeremylt **/
536a4999eddSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) {
537aefd8378Sjeremylt   CeedInt ierr;
538aefd8378Sjeremylt   CeedInt count = ceed->objdelegatecount;
539aefd8378Sjeremylt 
540aefd8378Sjeremylt   // Malloc or Realloc
541aefd8378Sjeremylt   if (count) {
5421d102b48SJeremy L Thompson     ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr);
543aefd8378Sjeremylt   } else {
544aefd8378Sjeremylt     ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr);
545aefd8378Sjeremylt   }
546aefd8378Sjeremylt   ceed->objdelegatecount++;
547aefd8378Sjeremylt 
548aefd8378Sjeremylt   // Set object delegate
549a4999eddSjeremylt   ceed->objdelegates[count].delegate = delegate;
55007a02837SJed Brown   size_t slen = strlen(objname) + 1;
55107a02837SJed Brown   ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr);
55207a02837SJed Brown   memcpy(ceed->objdelegates[count].objname, objname, slen);
553aefd8378Sjeremylt 
554aefd8378Sjeremylt   // Set delegate parent
555a4999eddSjeremylt   delegate->parent = ceed;
556aefd8378Sjeremylt 
557aefd8378Sjeremylt   return 0;
558aefd8378Sjeremylt }
559aefd8378Sjeremylt 
560aefd8378Sjeremylt /**
5615107b09fSJeremy L Thompson   @brief Set the fallback resource for CeedOperators. The current resource, if
5625107b09fSJeremy L Thompson            any, is freed by calling this function. This string is freed upon the
563d79b80ecSjeremylt            destruction of the Ceed context.
5645107b09fSJeremy L Thompson 
5655107b09fSJeremy L Thompson   @param[out] ceed Ceed context
5665107b09fSJeremy L Thompson   @param resource  Fallback resource to set
5675107b09fSJeremy L Thompson 
5685107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5695107b09fSJeremy L Thompson 
5705107b09fSJeremy L Thompson   @ref Advanced
5715107b09fSJeremy L Thompson **/
5725107b09fSJeremy L Thompson 
5735107b09fSJeremy L Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) {
5745107b09fSJeremy L Thompson   int ierr;
5755107b09fSJeremy L Thompson 
5765107b09fSJeremy L Thompson   // Free old
5775107b09fSJeremy L Thompson   ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr);
5785107b09fSJeremy L Thompson 
5795107b09fSJeremy L Thompson   // Set new
5805107b09fSJeremy L Thompson   size_t len = strlen(resource);
5815107b09fSJeremy L Thompson   char *tmp;
5825107b09fSJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
5835107b09fSJeremy L Thompson   memcpy(tmp, resource, len+1);
5845107b09fSJeremy L Thompson   ceed->opfallbackresource = tmp;
5855107b09fSJeremy L Thompson 
5865107b09fSJeremy L Thompson   return 0;
5875107b09fSJeremy L Thompson }
5885107b09fSJeremy L Thompson 
5895107b09fSJeremy L Thompson /**
5905107b09fSJeremy L Thompson   @brief Get the fallback resource for CeedOperators
5915107b09fSJeremy L Thompson 
5925107b09fSJeremy L Thompson   @param ceed          Ceed context
5935107b09fSJeremy L Thompson   @param[out] resource Variable to store fallback resource
5945107b09fSJeremy L Thompson 
5955107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5965107b09fSJeremy L Thompson 
5975107b09fSJeremy L Thompson   @ref Advanced
5985107b09fSJeremy L Thompson **/
5995107b09fSJeremy L Thompson 
6005107b09fSJeremy L Thompson int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) {
6015107b09fSJeremy L Thompson   *resource = (const char *)ceed->opfallbackresource;
6025107b09fSJeremy L Thompson   return 0;
6035107b09fSJeremy L Thompson }
6045107b09fSJeremy L Thompson 
6055107b09fSJeremy L Thompson /**
606d79b80ecSjeremylt   @brief Get the parent Ceed context associated with a fallback Ceed context
607d79b80ecSjeremylt            for a CeedOperator
6085107b09fSJeremy L Thompson 
6095107b09fSJeremy L Thompson   @param ceed         Ceed context
61077645d7bSjeremylt   @param[out] parent  Variable to store parent Ceed context
6115107b09fSJeremy L Thompson 
6125107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6135107b09fSJeremy L Thompson 
6145107b09fSJeremy L Thompson   @ref Advanced
6155107b09fSJeremy L Thompson **/
6165107b09fSJeremy L Thompson 
6175107b09fSJeremy L Thompson int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) {
6185107b09fSJeremy L Thompson   *parent = ceed->opfallbackparent;
6195107b09fSJeremy L Thompson   return 0;
6205107b09fSJeremy L Thompson }
6215107b09fSJeremy L Thompson 
6225107b09fSJeremy L Thompson /**
623d79b80ecSjeremylt   @brief Return Ceed context preferred memory type
624c907536fSjeremylt 
625d79b80ecSjeremylt   @param ceed      Ceed context to get preferred memory type of
626288c0443SJeremy L Thompson   @param[out] type Address to save preferred memory type to
627c907536fSjeremylt 
628c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
629c907536fSjeremylt 
630c907536fSjeremylt   @ref Basic
631c907536fSjeremylt **/
632c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) {
633c907536fSjeremylt   int ierr;
634c263cd57Sjeremylt 
635c907536fSjeremylt   if (ceed->GetPreferredMemType) {
636c907536fSjeremylt     ierr = ceed->GetPreferredMemType(type); CeedChk(ierr);
637c907536fSjeremylt   } else {
638c263cd57Sjeremylt     Ceed delegate;
639c263cd57Sjeremylt     ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr);
640c263cd57Sjeremylt 
641c263cd57Sjeremylt     if (delegate) {
642c263cd57Sjeremylt       ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr);
643c263cd57Sjeremylt     } else {
644c907536fSjeremylt       *type = CEED_MEM_HOST;
645c907536fSjeremylt     }
646c263cd57Sjeremylt   }
647c907536fSjeremylt 
648c907536fSjeremylt   return 0;
649c907536fSjeremylt }
650c907536fSjeremylt 
651c907536fSjeremylt /**
652fe2413ffSjeremylt   @brief Set a backend function
653fe2413ffSjeremylt 
654cb37edd8Sjeremylt   This function is used for a backend to set the function associated with
655d79b80ecSjeremylt   the Ceed objects. For example,
656f8902d9eSjeremylt     CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate)
657cb37edd8Sjeremylt   sets the backend implementation of 'CeedVectorCreate' and
658cb37edd8Sjeremylt     CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply)
659cb37edd8Sjeremylt   sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed'
660cb37edd8Sjeremylt   is not required for the object type ("Basis" vs "CeedBasis").
661cb37edd8Sjeremylt 
662d79b80ecSjeremylt   @param ceed           Ceed context for error handling
663fe2413ffSjeremylt   @param type           Type of Ceed object to set function for
664fe2413ffSjeremylt   @param[out] object    Ceed object to set function for
665fe2413ffSjeremylt   @param fname          Name of function to set
666fe2413ffSjeremylt   @param f              Function to set
667fe2413ffSjeremylt 
668fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
669fe2413ffSjeremylt 
670fe2413ffSjeremylt   @ref Advanced
671fe2413ffSjeremylt **/
672692c2638Sjeremylt int CeedSetBackendFunction(Ceed ceed, const char *type, void *object,
673fe2413ffSjeremylt                            const char *fname, int (*f)()) {
674409ab9adSjeremylt   char lookupname[CEED_MAX_RESOURCE_LEN+1] = "";
675fe2413ffSjeremylt 
676fe2413ffSjeremylt   // Build lookup name
6776e79d475Sjeremylt   if (strcmp(type, "Ceed"))
6786e79d475Sjeremylt     strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN);
679409ab9adSjeremylt   strncat(lookupname, type, CEED_MAX_RESOURCE_LEN);
680409ab9adSjeremylt   strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN);
681fe2413ffSjeremylt 
682fe2413ffSjeremylt   // Find and use offset
6831d102b48SJeremy L Thompson   for (CeedInt i = 0; ceed->foffsets[i].fname; i++)
684fe2413ffSjeremylt     if (!strcmp(ceed->foffsets[i].fname, lookupname)) {
685fe2413ffSjeremylt       size_t offset = ceed->foffsets[i].offset;
686cb0b5415Sjeremylt       int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD*
687a7a2e802Sjeremylt       *fpointer = f;
688fe2413ffSjeremylt       return 0;
689fe2413ffSjeremylt     }
690fe2413ffSjeremylt 
691c042f62fSJeremy L Thompson   // LCOV_EXCL_START
6921d102b48SJeremy L Thompson   return CeedError(ceed, 1, "Requested function '%s' was not found for CEED "
6931d102b48SJeremy L Thompson                    "object '%s'", fname, type);
694c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
695fe2413ffSjeremylt }
696fe2413ffSjeremylt 
697fe2413ffSjeremylt /**
698d79b80ecSjeremylt   @brief Retrieve backend data for a Ceed context
6994ce2993fSjeremylt 
700d79b80ecSjeremylt   @param ceed      Ceed context to retrieve data of
7014ce2993fSjeremylt   @param[out] data Address to save data to
7024ce2993fSjeremylt 
7034ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7044ce2993fSjeremylt 
70523617272Sjeremylt   @ref Advanced
7064ce2993fSjeremylt **/
7074ce2993fSjeremylt int CeedGetData(Ceed ceed, void **data) {
7084ce2993fSjeremylt   *data = ceed->data;
7095fe0d4faSjeremylt   return 0;
7105fe0d4faSjeremylt }
7115fe0d4faSjeremylt 
7125fe0d4faSjeremylt /**
713d79b80ecSjeremylt   @brief Set backend data for a Ceed context
714fe2413ffSjeremylt 
715d79b80ecSjeremylt   @param ceed           Ceed context to set data of
716fe2413ffSjeremylt   @param data           Address of data to set
717fe2413ffSjeremylt 
718fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
719fe2413ffSjeremylt 
720fe2413ffSjeremylt   @ref Advanced
721fe2413ffSjeremylt **/
722fe2413ffSjeremylt int CeedSetData(Ceed ceed, void **data) {
723fe2413ffSjeremylt   ceed->data = *data;
724fe2413ffSjeremylt   return 0;
725fe2413ffSjeremylt }
726fe2413ffSjeremylt 
727fe2413ffSjeremylt /**
728d79b80ecSjeremylt   @brief Get the full resource name for a Ceed context
729e07206deSjeremylt 
730d79b80ecSjeremylt   @param ceed            Ceed context to get resource name of
731e07206deSjeremylt   @param[out] resource   Variable to store resource name
732e07206deSjeremylt 
733e07206deSjeremylt   @return An error code: 0 - success, otherwise - failure
734e07206deSjeremylt 
735e07206deSjeremylt   @ref Basic
736e07206deSjeremylt **/
737e07206deSjeremylt 
738e07206deSjeremylt int CeedGetResource(Ceed ceed, const char **resource) {
739e07206deSjeremylt   *resource = (const char *)ceed->resource;
740e07206deSjeremylt   return 0;
741e07206deSjeremylt }
742e07206deSjeremylt 
743e07206deSjeremylt /**
744b11c1e72Sjeremylt   @brief Destroy a Ceed context
745d7b241e6Sjeremylt 
746d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
747b11c1e72Sjeremylt 
748b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
749dfdf5a53Sjeremylt 
750dfdf5a53Sjeremylt   @ref Basic
751b11c1e72Sjeremylt **/
752d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
753d7b241e6Sjeremylt   int ierr;
7541d102b48SJeremy L Thompson   if (!*ceed || --(*ceed)->refcount > 0)
7551d102b48SJeremy L Thompson     return 0;
7560ace9bf2Sjeremylt 
7575fe0d4faSjeremylt   if ((*ceed)->delegate) {
7585fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
7595fe0d4faSjeremylt   }
7600ace9bf2Sjeremylt 
761aefd8378Sjeremylt   if ((*ceed)->objdelegatecount > 0) {
762aefd8378Sjeremylt     for (int i=0; i<(*ceed)->objdelegatecount; i++) {
763aefd8378Sjeremylt       ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr);
764aefd8378Sjeremylt       ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr);
765aefd8378Sjeremylt     }
766aefd8378Sjeremylt     ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr);
767aefd8378Sjeremylt   }
7680ace9bf2Sjeremylt 
769d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
770d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
771d7b241e6Sjeremylt   }
7720ace9bf2Sjeremylt 
7736e79d475Sjeremylt   ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr);
774e07206deSjeremylt   ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr);
7755107b09fSJeremy L Thompson   ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr);
7765107b09fSJeremy L Thompson   ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr);
777d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
778d7b241e6Sjeremylt   return 0;
779d7b241e6Sjeremylt }
780d7b241e6Sjeremylt 
781d7b241e6Sjeremylt /// @}
782