1/*===- c_api.h - C API for the ORC runtime ------------------------*- C -*-===*\
2|* *|
3|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
4|* Exceptions. *|
5|* See https://llvm.org/LICENSE.txt for license information. *|
6|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
7|* *|
8|*===----------------------------------------------------------------------===*|
9|* *|
10|* This file defines the C API for the ORC runtime *|
11|* *|
12\*===----------------------------------------------------------------------===*/
13
14#ifndef ORC_RT_C_API_H
15#define ORC_RT_C_API_H
16
17#include <assert.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22/* Helper to suppress strict prototype warnings. */
23#ifdef __clang__
24#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN \
25 _Pragma("clang diagnostic push") \
26 _Pragma("clang diagnostic error \"-Wstrict-prototypes\"")
27#define ORC_RT_C_STRICT_PROTOTYPES_END _Pragma("clang diagnostic pop")
28#else
29#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN
30#define ORC_RT_C_STRICT_PROTOTYPES_END
31#endif
32
33/* Helper to wrap C code for C++ */
34#ifdef __cplusplus
35#define ORC_RT_C_EXTERN_C_BEGIN \
36 extern "C" { \
37 ORC_RT_C_STRICT_PROTOTYPES_BEGIN
38#define ORC_RT_C_EXTERN_C_END \
39 ORC_RT_C_STRICT_PROTOTYPES_END \
40 }
41#else
42#define ORC_RT_C_EXTERN_C_BEGIN ORC_RT_C_STRICT_PROTOTYPES_BEGIN
43#define ORC_RT_C_EXTERN_C_END ORC_RT_C_STRICT_PROTOTYPES_END
44#endif
45
46ORC_RT_C_EXTERN_C_BEGIN
47
48typedef union {
49 char *ValuePtr;
50 char Value[sizeof(char *)];
51} orc_rt_CWrapperFunctionResultDataUnion;
52
53/**
54 * orc_rt_CWrapperFunctionResult is a kind of C-SmallVector with an
55 * out-of-band error state.
56 *
57 * If Size == 0 and Data.ValuePtr is non-zero then the value is in the
58 * 'out-of-band error' state, and Data.ValuePtr points at a malloc-allocated,
59 * null-terminated string error message.
60 *
61 * If Size <= sizeof(orc_rt_CWrapperFunctionResultData) then the value is in
62 * the 'small' state and the content is held in the first Size bytes of
63 * Data.Value.
64 *
65 * If Size > sizeof(OrtRTCWrapperFunctionResultData) then the value is in the
66 * 'large' state and the content is held in the first Size bytes of the
67 * memory pointed to by Data.ValuePtr. This memory must have been allocated by
68 * malloc, and will be freed with free when this value is destroyed.
69 */
70typedef struct {
71 orc_rt_CWrapperFunctionResultDataUnion Data;
72 size_t Size;
73} orc_rt_CWrapperFunctionResult;
74
75/**
76 * Zero-initialize an orc_rt_CWrapperFunctionResult.
77 */
78static inline void
79orc_rt_CWrapperFunctionResultInit(orc_rt_CWrapperFunctionResult *R) {
80 R->Size = 0;
81 R->Data.ValuePtr = 0;
82}
83
84/**
85 * Create an orc_rt_CWrapperFunctionResult with an uninitialized buffer of
86 * size Size. The buffer is returned via the DataPtr argument.
87 */
88static inline orc_rt_CWrapperFunctionResult
89orc_rt_CWrapperFunctionResultAllocate(size_t Size) {
90 orc_rt_CWrapperFunctionResult R;
91 R.Size = Size;
92 // If Size is 0 ValuePtr must be 0 or it is considered an out-of-band error.
93 R.Data.ValuePtr = 0;
94 if (Size > sizeof(R.Data.Value))
95 R.Data.ValuePtr = (char *)malloc(size: Size);
96 return R;
97}
98
99/**
100 * Create an orc_rt_WrapperFunctionResult from the given data range.
101 */
102static inline orc_rt_CWrapperFunctionResult
103orc_rt_CreateCWrapperFunctionResultFromRange(const char *Data, size_t Size) {
104 orc_rt_CWrapperFunctionResult R;
105 R.Size = Size;
106 if (R.Size > sizeof(R.Data.Value)) {
107 char *Tmp = (char *)malloc(size: Size);
108 memcpy(dest: Tmp, src: Data, n: Size);
109 R.Data.ValuePtr = Tmp;
110 } else
111 memcpy(dest: R.Data.Value, src: Data, n: Size);
112 return R;
113}
114
115/**
116 * Create an orc_rt_CWrapperFunctionResult by copying the given string,
117 * including the null-terminator.
118 *
119 * This function copies the input string. The client is responsible for freeing
120 * the ErrMsg arg.
121 */
122static inline orc_rt_CWrapperFunctionResult
123orc_rt_CreateCWrapperFunctionResultFromString(const char *Source) {
124 return orc_rt_CreateCWrapperFunctionResultFromRange(Data: Source,
125 Size: strlen(s: Source) + 1);
126}
127
128/**
129 * Create an orc_rt_CWrapperFunctionResult representing an out-of-band
130 * error.
131 *
132 * This function copies the input string. The client is responsible for freeing
133 * the ErrMsg arg.
134 */
135static inline orc_rt_CWrapperFunctionResult
136orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(const char *ErrMsg) {
137 orc_rt_CWrapperFunctionResult R;
138 R.Size = 0;
139 char *Tmp = (char *)malloc(size: strlen(s: ErrMsg) + 1);
140 strcpy(dest: Tmp, src: ErrMsg);
141 R.Data.ValuePtr = Tmp;
142 return R;
143}
144
145/**
146 * This should be called to destroy orc_rt_CWrapperFunctionResult values
147 * regardless of their state.
148 */
149static inline void
150orc_rt_DisposeCWrapperFunctionResult(orc_rt_CWrapperFunctionResult *R) {
151 if (R->Size > sizeof(R->Data.Value) ||
152 (R->Size == 0 && R->Data.ValuePtr))
153 free(ptr: R->Data.ValuePtr);
154}
155
156/**
157 * Get a pointer to the data contained in the given
158 * orc_rt_CWrapperFunctionResult.
159 */
160static inline char *
161orc_rt_CWrapperFunctionResultData(orc_rt_CWrapperFunctionResult *R) {
162 assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
163 "Cannot get data for out-of-band error value");
164 return R->Size > sizeof(R->Data.Value) ? R->Data.ValuePtr : R->Data.Value;
165}
166
167/**
168 * Safely get the size of the given orc_rt_CWrapperFunctionResult.
169 *
170 * Asserts that we're not trying to access the size of an error value.
171 */
172static inline size_t
173orc_rt_CWrapperFunctionResultSize(const orc_rt_CWrapperFunctionResult *R) {
174 assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
175 "Cannot get size for out-of-band error value");
176 return R->Size;
177}
178
179/**
180 * Returns 1 if this value is equivalent to a value just initialized by
181 * orc_rt_CWrapperFunctionResultInit, 0 otherwise.
182 */
183static inline size_t
184orc_rt_CWrapperFunctionResultEmpty(const orc_rt_CWrapperFunctionResult *R) {
185 return R->Size == 0 && R->Data.ValuePtr == 0;
186}
187
188/**
189 * Returns a pointer to the out-of-band error string for this
190 * orc_rt_CWrapperFunctionResult, or null if there is no error.
191 *
192 * The orc_rt_CWrapperFunctionResult retains ownership of the error
193 * string, so it should be copied if the caller wishes to preserve it.
194 */
195static inline const char *orc_rt_CWrapperFunctionResultGetOutOfBandError(
196 const orc_rt_CWrapperFunctionResult *R) {
197 return R->Size == 0 ? R->Data.ValuePtr : 0;
198}
199
200ORC_RT_C_EXTERN_C_END
201
202#endif /* ORC_RT_C_API_H */
203