[orc-rt] Add C and C++ APIs for WrapperFunctionResult. (#154927)
orc_rt_WrapperFunctionResult is a byte-buffer with inline storage and a builtin error state. It is intended as a general purpose return type for functions that return a serialized result (e.g. for communication across ABIs or via IPC/RPC). orc_rt_WrapperFunctionResult contains a small amount of inline storage, allowing it to avoid heap-allocation for small return types (e.g. bools, chars, pointers).
This commit is contained in:
parent
d2b810e24f
commit
3292edb7b4
@ -1,10 +1,13 @@
|
||||
set(ORC_RT_HEADERS
|
||||
orc-rt-c/ExternC.h
|
||||
orc-rt-c/WrapperFunctionResult.h
|
||||
orc-rt-c/orc-rt.h
|
||||
orc-rt/BitmaskEnum.h
|
||||
orc-rt/Compiler.h
|
||||
orc-rt/Error.h
|
||||
orc-rt/Math.h
|
||||
orc-rt/RTTI.h
|
||||
orc-rt/WrapperFunctionResult.h
|
||||
orc-rt/move_only_function.h
|
||||
orc-rt/span.h
|
||||
)
|
||||
|
41
orc-rt/include/orc-rt-c/ExternC.h
Normal file
41
orc-rt/include/orc-rt-c/ExternC.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*===- ExternC.h - C API for the ORC runtime ----------------------*- C -*-===*\
|
||||
|* *|
|
||||
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
|
||||
|* Exceptions. *|
|
||||
|* See https://llvm.org/LICENSE.txt for license information. *|
|
||||
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This file defines the C API for the ORC runtime *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef ORC_RT_C_EXTERNC_H
|
||||
#define ORC_RT_C_EXTERNC_H
|
||||
|
||||
/* Helper to suppress strict prototype warnings. */
|
||||
#ifdef __clang__
|
||||
#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic error \"-Wstrict-prototypes\"")
|
||||
#define ORC_RT_C_STRICT_PROTOTYPES_END _Pragma("clang diagnostic pop")
|
||||
#else
|
||||
#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN
|
||||
#define ORC_RT_C_STRICT_PROTOTYPES_END
|
||||
#endif
|
||||
|
||||
/* Helper to wrap C code for C++ */
|
||||
#ifdef __cplusplus
|
||||
#define ORC_RT_C_EXTERN_C_BEGIN \
|
||||
extern "C" { \
|
||||
ORC_RT_C_STRICT_PROTOTYPES_BEGIN
|
||||
#define ORC_RT_C_EXTERN_C_END \
|
||||
ORC_RT_C_STRICT_PROTOTYPES_END \
|
||||
}
|
||||
#else
|
||||
#define ORC_RT_C_EXTERN_C_BEGIN ORC_RT_C_STRICT_PROTOTYPES_BEGIN
|
||||
#define ORC_RT_C_EXTERN_C_END ORC_RT_C_STRICT_PROTOTYPES_END
|
||||
#endif
|
||||
|
||||
#endif /* ORC_RT_C_EXTERNC_H */
|
178
orc-rt/include/orc-rt-c/WrapperFunctionResult.h
Normal file
178
orc-rt/include/orc-rt-c/WrapperFunctionResult.h
Normal file
@ -0,0 +1,178 @@
|
||||
/*===----- WrapperFunctionResult.h - blob-of-bytes container -----*- C -*-===*\
|
||||
|* *|
|
||||
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
|
||||
|* Exceptions. *|
|
||||
|* See https://llvm.org/LICENSE.txt for license information. *|
|
||||
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* Defines orc_rt_WrapperFunctionResult and related APIs. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef ORC_RT_C_WRAPPERFUNCTIONRESULT_H
|
||||
#define ORC_RT_C_WRAPPERFUNCTIONRESULT_H
|
||||
|
||||
#include "orc-rt-c/ExternC.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
ORC_RT_C_EXTERN_C_BEGIN
|
||||
|
||||
typedef union {
|
||||
char *ValuePtr;
|
||||
char Value[sizeof(char *)];
|
||||
} orc_rt_WrapperFunctionResultDataUnion;
|
||||
|
||||
/**
|
||||
* orc_rt_WrapperFunctionResult is a kind of C-SmallVector with an
|
||||
* out-of-band error state.
|
||||
*
|
||||
* If Size == 0 and Data.ValuePtr is non-zero then the value is in the
|
||||
* 'out-of-band error' state, and Data.ValuePtr points at a malloc-allocated,
|
||||
* null-terminated string error message.
|
||||
*
|
||||
* If Size <= sizeof(orc_rt_WrapperFunctionResultData) then the value is in
|
||||
* the 'small' state and the content is held in the first Size bytes of
|
||||
* Data.Value.
|
||||
*
|
||||
* If Size > sizeof(orc_rt_WrapperFunctionResultData) then the value is in the
|
||||
* 'large' state and the content is held in the first Size bytes of the
|
||||
* memory pointed to by Data.ValuePtr. This memory must have been allocated by
|
||||
* malloc, and will be freed with free when this value is destroyed.
|
||||
*/
|
||||
typedef struct {
|
||||
orc_rt_WrapperFunctionResultDataUnion Data;
|
||||
size_t Size;
|
||||
} orc_rt_WrapperFunctionResult;
|
||||
|
||||
/**
|
||||
* Zero-initialize an orc_rt_WrapperFunctionResult.
|
||||
*/
|
||||
static inline void
|
||||
orc_rt_WrapperFunctionResultInit(orc_rt_WrapperFunctionResult *R) {
|
||||
R->Size = 0;
|
||||
R->Data.ValuePtr = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orc_rt_WrapperFunctionResult with an uninitialized buffer of
|
||||
* size Size. The buffer is returned via the DataPtr argument.
|
||||
*/
|
||||
static inline orc_rt_WrapperFunctionResult
|
||||
orc_rt_WrapperFunctionResultAllocate(size_t Size) {
|
||||
orc_rt_WrapperFunctionResult R;
|
||||
R.Size = Size;
|
||||
// If Size is 0 ValuePtr must be 0 or it is considered an out-of-band error.
|
||||
R.Data.ValuePtr = 0;
|
||||
if (Size > sizeof(R.Data.Value))
|
||||
R.Data.ValuePtr = (char *)malloc(Size);
|
||||
return R;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orc_rt_WrapperFunctionResult from the given data range.
|
||||
*/
|
||||
static inline orc_rt_WrapperFunctionResult
|
||||
orc_rt_CreateWrapperFunctionResultFromRange(const char *Data, size_t Size) {
|
||||
orc_rt_WrapperFunctionResult R;
|
||||
R.Size = Size;
|
||||
if (R.Size > sizeof(R.Data.Value)) {
|
||||
char *Tmp = (char *)malloc(Size);
|
||||
memcpy(Tmp, Data, Size);
|
||||
R.Data.ValuePtr = Tmp;
|
||||
} else
|
||||
memcpy(R.Data.Value, Data, Size);
|
||||
return R;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orc_rt_WrapperFunctionResult by copying the given string,
|
||||
* including the null-terminator.
|
||||
*
|
||||
* This function copies the input string. The client is responsible for freeing
|
||||
* the ErrMsg arg.
|
||||
*/
|
||||
static inline orc_rt_WrapperFunctionResult
|
||||
orc_rt_CreateWrapperFunctionResultFromString(const char *Source) {
|
||||
return orc_rt_CreateWrapperFunctionResultFromRange(Source,
|
||||
strlen(Source) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orc_rt_WrapperFunctionResult representing an out-of-band
|
||||
* error.
|
||||
*
|
||||
* This function copies the input string. The client is responsible for freeing
|
||||
* the ErrMsg arg.
|
||||
*/
|
||||
static inline orc_rt_WrapperFunctionResult
|
||||
orc_rt_CreateWrapperFunctionResultFromOutOfBandError(const char *ErrMsg) {
|
||||
orc_rt_WrapperFunctionResult R;
|
||||
R.Size = 0;
|
||||
char *Tmp = (char *)malloc(strlen(ErrMsg) + 1);
|
||||
strcpy(Tmp, ErrMsg);
|
||||
R.Data.ValuePtr = Tmp;
|
||||
return R;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be called to destroy orc_rt_WrapperFunctionResult values
|
||||
* regardless of their state.
|
||||
*/
|
||||
static inline void
|
||||
orc_rt_DisposeWrapperFunctionResult(orc_rt_WrapperFunctionResult *R) {
|
||||
if (R->Size > sizeof(R->Data.Value) || (R->Size == 0 && R->Data.ValuePtr))
|
||||
free(R->Data.ValuePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to the data contained in the given
|
||||
* orc_rt_WrapperFunctionResult.
|
||||
*/
|
||||
static inline char *
|
||||
orc_rt_WrapperFunctionResultData(orc_rt_WrapperFunctionResult *R) {
|
||||
assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
|
||||
"Cannot get data for out-of-band error value");
|
||||
return R->Size > sizeof(R->Data.Value) ? R->Data.ValuePtr : R->Data.Value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely get the size of the given orc_rt_WrapperFunctionResult.
|
||||
*
|
||||
* Asserts that we're not trying to access the size of an error value.
|
||||
*/
|
||||
static inline size_t
|
||||
orc_rt_WrapperFunctionResultSize(const orc_rt_WrapperFunctionResult *R) {
|
||||
assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
|
||||
"Cannot get size for out-of-band error value");
|
||||
return R->Size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if this value is equivalent to a value just initialized by
|
||||
* orc_rt_WrapperFunctionResultInit, 0 otherwise.
|
||||
*/
|
||||
static inline size_t
|
||||
orc_rt_WrapperFunctionResultEmpty(const orc_rt_WrapperFunctionResult *R) {
|
||||
return R->Size == 0 && R->Data.ValuePtr == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the out-of-band error string for this
|
||||
* orc_rt_WrapperFunctionResult, or null if there is no error.
|
||||
*
|
||||
* The orc_rt_WrapperFunctionResult retains ownership of the error
|
||||
* string, so it should be copied if the caller wishes to preserve it.
|
||||
*/
|
||||
static inline const char *orc_rt_WrapperFunctionResultGetOutOfBandError(
|
||||
const orc_rt_WrapperFunctionResult *R) {
|
||||
return R->Size == 0 ? R->Data.ValuePtr : 0;
|
||||
}
|
||||
|
||||
ORC_RT_C_EXTERN_C_END
|
||||
|
||||
#endif /* ORC_RT_WRAPPERFUNCTIONRESULT_H */
|
106
orc-rt/include/orc-rt/WrapperFunctionResult.h
Normal file
106
orc-rt/include/orc-rt/WrapperFunctionResult.h
Normal file
@ -0,0 +1,106 @@
|
||||
//===---- WrapperFunctionResult.h -- blob-of-bytes container ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines WrapperFunctionResult and related APIs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ORC_RT_WRAPPERFUNCTIONRESULT_H
|
||||
#define ORC_RT_WRAPPERFUNCTIONRESULT_H
|
||||
|
||||
#include "orc-rt-c/WrapperFunctionResult.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace orc_rt {
|
||||
|
||||
/// A C++ convenience wrapper for orc_rt_WrapperFunctionResult. Auto-disposes
|
||||
/// the contained result on destruction.
|
||||
class WrapperFunctionResult {
|
||||
public:
|
||||
/// Create a default WrapperFunctionResult.
|
||||
WrapperFunctionResult() { orc_rt_WrapperFunctionResultInit(&R); }
|
||||
|
||||
/// Create a WrapperFunctionResult from a WrapperFunctionResult. This
|
||||
/// instance takes ownership of the result object and will automatically
|
||||
/// call dispose on the result upon destruction.
|
||||
WrapperFunctionResult(orc_rt_WrapperFunctionResult R) : R(R) {}
|
||||
|
||||
WrapperFunctionResult(const WrapperFunctionResult &) = delete;
|
||||
WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
|
||||
|
||||
WrapperFunctionResult(WrapperFunctionResult &&Other) {
|
||||
orc_rt_WrapperFunctionResultInit(&R);
|
||||
std::swap(R, Other.R);
|
||||
}
|
||||
|
||||
WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
|
||||
orc_rt_WrapperFunctionResult Tmp;
|
||||
orc_rt_WrapperFunctionResultInit(&Tmp);
|
||||
std::swap(Tmp, Other.R);
|
||||
std::swap(R, Tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~WrapperFunctionResult() { orc_rt_DisposeWrapperFunctionResult(&R); }
|
||||
|
||||
/// Relinquish ownership of and return the
|
||||
/// orc_rt_WrapperFunctionResult.
|
||||
orc_rt_WrapperFunctionResult release() {
|
||||
orc_rt_WrapperFunctionResult Tmp;
|
||||
orc_rt_WrapperFunctionResultInit(&Tmp);
|
||||
std::swap(R, Tmp);
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
/// Get a pointer to the data contained in this instance.
|
||||
char *data() { return orc_rt_WrapperFunctionResultData(&R); }
|
||||
|
||||
/// Returns the size of the data contained in this instance.
|
||||
size_t size() const { return orc_rt_WrapperFunctionResultSize(&R); }
|
||||
|
||||
/// Returns true if this value is equivalent to a default-constructed
|
||||
/// WrapperFunctionResult.
|
||||
bool empty() const { return orc_rt_WrapperFunctionResultEmpty(&R); }
|
||||
|
||||
/// Create a WrapperFunctionResult with the given size and return a pointer
|
||||
/// to the underlying memory.
|
||||
static WrapperFunctionResult allocate(size_t Size) {
|
||||
WrapperFunctionResult R;
|
||||
R.R = orc_rt_WrapperFunctionResultAllocate(Size);
|
||||
return R;
|
||||
}
|
||||
|
||||
/// Copy from the given char range.
|
||||
static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
|
||||
return orc_rt_CreateWrapperFunctionResultFromRange(Source, Size);
|
||||
}
|
||||
|
||||
/// Copy from the given null-terminated string (includes the null-terminator).
|
||||
static WrapperFunctionResult copyFrom(const char *Source) {
|
||||
return orc_rt_CreateWrapperFunctionResultFromString(Source);
|
||||
}
|
||||
|
||||
/// Create an out-of-band error by copying the given string.
|
||||
static WrapperFunctionResult createOutOfBandError(const char *Msg) {
|
||||
return orc_rt_CreateWrapperFunctionResultFromOutOfBandError(Msg);
|
||||
}
|
||||
|
||||
/// If this value is an out-of-band error then this returns the error message,
|
||||
/// otherwise returns nullptr.
|
||||
const char *getOutOfBandError() const {
|
||||
return orc_rt_WrapperFunctionResultGetOutOfBandError(&R);
|
||||
}
|
||||
|
||||
private:
|
||||
orc_rt_WrapperFunctionResult R;
|
||||
};
|
||||
|
||||
} // namespace orc_rt
|
||||
|
||||
#endif // ORC_RT_WRAPPERFUNCTIONRESULT_H
|
@ -16,6 +16,7 @@ add_orc_rt_unittest(CoreTests
|
||||
ErrorTest.cpp
|
||||
MathTest.cpp
|
||||
RTTITest.cpp
|
||||
WrapperFunctionResultTest.cpp
|
||||
move_only_function-test.cpp
|
||||
span-test.cpp
|
||||
DISABLE_LLVM_LINK_LLVM_DYLIB
|
||||
|
60
orc-rt/unittests/WrapperFunctionResultTest.cpp
Normal file
60
orc-rt/unittests/WrapperFunctionResultTest.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
//===-- wrapper_function_utils_test.cpp -----------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of the ORC runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "orc-rt-c/WrapperFunctionResult.h"
|
||||
#include "orc-rt/WrapperFunctionResult.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace orc_rt;
|
||||
|
||||
namespace {
|
||||
constexpr const char *TestString = "test string";
|
||||
} // end anonymous namespace
|
||||
|
||||
TEST(WrapperFunctionUtilsTest, DefaultWrapperFunctionResult) {
|
||||
WrapperFunctionResult R;
|
||||
EXPECT_TRUE(R.empty());
|
||||
EXPECT_EQ(R.size(), 0U);
|
||||
EXPECT_EQ(R.getOutOfBandError(), nullptr);
|
||||
}
|
||||
|
||||
TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCStruct) {
|
||||
orc_rt_WrapperFunctionResult CR =
|
||||
orc_rt_CreateWrapperFunctionResultFromString(TestString);
|
||||
WrapperFunctionResult R(CR);
|
||||
EXPECT_EQ(R.size(), strlen(TestString) + 1);
|
||||
EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
|
||||
EXPECT_FALSE(R.empty());
|
||||
EXPECT_EQ(R.getOutOfBandError(), nullptr);
|
||||
}
|
||||
|
||||
TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromRange) {
|
||||
auto R = WrapperFunctionResult::copyFrom(TestString, strlen(TestString) + 1);
|
||||
EXPECT_EQ(R.size(), strlen(TestString) + 1);
|
||||
EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
|
||||
EXPECT_FALSE(R.empty());
|
||||
EXPECT_EQ(R.getOutOfBandError(), nullptr);
|
||||
}
|
||||
|
||||
TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCString) {
|
||||
auto R = WrapperFunctionResult::copyFrom(TestString);
|
||||
EXPECT_EQ(R.size(), strlen(TestString) + 1);
|
||||
EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
|
||||
EXPECT_FALSE(R.empty());
|
||||
EXPECT_EQ(R.getOutOfBandError(), nullptr);
|
||||
}
|
||||
|
||||
TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromOutOfBandError) {
|
||||
auto R = WrapperFunctionResult::createOutOfBandError(TestString);
|
||||
EXPECT_FALSE(R.empty());
|
||||
EXPECT_TRUE(strcmp(R.getOutOfBandError(), TestString) == 0);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user