mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
During JVM shutdown, some JNI calls may not return, so it's not possible to reliably perform a join() during static variable destruction (which occurs as the JVM unloads the JNI module). Also, due to static variable destruction, it's not safe to use any members of a static class instance from a separate thread of execution. SafeThread is a templated thread class and a related owner class that's designed for safe operation and shutdown of threads in the presence of callbacks that may not return. It also passes ownership of variables from the static instance to the thread, so the thread can safely operate until it exits (the last operation of the thread being to destroy its instance). Notifiers, RpcServer, and Logger now use SafeThread to ensure race-free destruction in both C++ and Java. All Java callback threads are now marked as Java daemon threads so they don't keep the JVM running after main() terminates. All Java callback threads are now named so their purpose is more easily identified in a debugger. Add SetRpcServerOnStart and SetRpcServerOnExit (similar to Listener).
779 lines
24 KiB
C++
779 lines
24 KiB
C++
/*----------------------------------------------------------------------------*/
|
|
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
/* the project. */
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
#include "ntcore.h"
|
|
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
|
|
#include "Value_internal.h"
|
|
|
|
using namespace nt;
|
|
|
|
// Conversion helpers
|
|
|
|
static void ConvertToC(llvm::StringRef in, char** out) {
|
|
*out = static_cast<char*>(std::malloc(in.size() + 1));
|
|
std::memmove(*out, in.data(), in.size());
|
|
(*out)[in.size()] = '\0';
|
|
}
|
|
|
|
static void ConvertToC(const EntryInfo& in, NT_EntryInfo* out) {
|
|
ConvertToC(in.name, &out->name);
|
|
out->type = in.type;
|
|
out->flags = in.flags;
|
|
out->last_change = in.last_change;
|
|
}
|
|
|
|
static void ConvertToC(const ConnectionInfo& in, NT_ConnectionInfo* out) {
|
|
ConvertToC(in.remote_id, &out->remote_id);
|
|
ConvertToC(in.remote_name, &out->remote_name);
|
|
out->remote_port = in.remote_port;
|
|
out->last_update = in.last_update;
|
|
out->protocol_version = in.protocol_version;
|
|
}
|
|
|
|
static void ConvertToC(const RpcParamDef& in, NT_RpcParamDef* out) {
|
|
ConvertToC(in.name, &out->name);
|
|
ConvertToC(*in.def_value, &out->def_value);
|
|
}
|
|
|
|
static void ConvertToC(const RpcResultDef& in, NT_RpcResultDef* out) {
|
|
ConvertToC(in.name, &out->name);
|
|
out->type = in.type;
|
|
}
|
|
|
|
static void ConvertToC(const RpcDefinition& in, NT_RpcDefinition* out) {
|
|
out->version = in.version;
|
|
ConvertToC(in.name, &out->name);
|
|
|
|
out->num_params = in.params.size();
|
|
out->params = static_cast<NT_RpcParamDef*>(
|
|
std::malloc(in.params.size() * sizeof(NT_RpcParamDef)));
|
|
for (size_t i = 0; i < in.params.size(); ++i)
|
|
ConvertToC(in.params[i], &out->params[i]);
|
|
|
|
out->num_results = in.results.size();
|
|
out->results = static_cast<NT_RpcResultDef*>(
|
|
std::malloc(in.results.size() * sizeof(NT_RpcResultDef)));
|
|
for (size_t i = 0; i < in.results.size(); ++i)
|
|
ConvertToC(in.results[i], &out->results[i]);
|
|
}
|
|
|
|
static void ConvertToC(const RpcCallInfo& in, NT_RpcCallInfo* out) {
|
|
out->rpc_id = in.rpc_id;
|
|
out->call_uid = in.call_uid;
|
|
ConvertToC(in.name, &out->name);
|
|
ConvertToC(in.params, &out->params);
|
|
}
|
|
|
|
static void DisposeConnectionInfo(NT_ConnectionInfo *info) {
|
|
std::free(info->remote_id.str);
|
|
std::free(info->remote_name);
|
|
}
|
|
|
|
static void DisposeEntryInfo(NT_EntryInfo *info) {
|
|
std::free(info->name.str);
|
|
}
|
|
|
|
static RpcParamDef ConvertFromC(const NT_RpcParamDef& in) {
|
|
RpcParamDef out;
|
|
out.name = ConvertFromC(in.name);
|
|
out.def_value = ConvertFromC(in.def_value);
|
|
return out;
|
|
}
|
|
|
|
static RpcResultDef ConvertFromC(const NT_RpcResultDef& in) {
|
|
RpcResultDef out;
|
|
out.name = ConvertFromC(in.name);
|
|
out.type = in.type;
|
|
return out;
|
|
}
|
|
|
|
static RpcDefinition ConvertFromC(const NT_RpcDefinition& in) {
|
|
RpcDefinition out;
|
|
out.version = in.version;
|
|
out.name = ConvertFromC(in.name);
|
|
|
|
out.params.reserve(in.num_params);
|
|
for (size_t i = 0; i < in.num_params; ++i)
|
|
out.params.push_back(ConvertFromC(in.params[i]));
|
|
|
|
out.results.reserve(in.num_results);
|
|
for (size_t i = 0; i < in.num_results; ++i)
|
|
out.results.push_back(ConvertFromC(in.results[i]));
|
|
|
|
return out;
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
/*
|
|
* Table Functions
|
|
*/
|
|
|
|
void NT_GetEntryValue(const char *name, size_t name_len,
|
|
struct NT_Value *value) {
|
|
NT_InitValue(value);
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v) return;
|
|
ConvertToC(*v, value);
|
|
}
|
|
|
|
int NT_SetEntryValue(const char *name, size_t name_len,
|
|
const struct NT_Value *value) {
|
|
return nt::SetEntryValue(StringRef(name, name_len), ConvertFromC(*value));
|
|
}
|
|
|
|
void NT_SetEntryTypeValue(const char *name, size_t name_len,
|
|
const struct NT_Value *value) {
|
|
nt::SetEntryTypeValue(StringRef(name, name_len), ConvertFromC(*value));
|
|
}
|
|
|
|
void NT_SetEntryFlags(const char *name, size_t name_len, unsigned int flags) {
|
|
nt::SetEntryFlags(StringRef(name, name_len), flags);
|
|
}
|
|
|
|
unsigned int NT_GetEntryFlags(const char *name, size_t name_len) {
|
|
return nt::GetEntryFlags(StringRef(name, name_len));
|
|
}
|
|
|
|
void NT_DeleteEntry(const char *name, size_t name_len) {
|
|
nt::DeleteEntry(StringRef(name, name_len));
|
|
}
|
|
|
|
void NT_DeleteAllEntries(void) { nt::DeleteAllEntries(); }
|
|
|
|
struct NT_EntryInfo *NT_GetEntryInfo(const char *prefix, size_t prefix_len,
|
|
unsigned int types, size_t *count) {
|
|
auto info_v = nt::GetEntryInfo(StringRef(prefix, prefix_len), types);
|
|
*count = info_v.size();
|
|
if (info_v.size() == 0) return nullptr;
|
|
|
|
// create array and copy into it
|
|
NT_EntryInfo* info = static_cast<NT_EntryInfo*>(
|
|
std::malloc(info_v.size() * sizeof(NT_EntryInfo)));
|
|
for (size_t i = 0; i < info_v.size(); ++i) ConvertToC(info_v[i], &info[i]);
|
|
return info;
|
|
}
|
|
|
|
void NT_Flush(void) { nt::Flush(); }
|
|
|
|
/*
|
|
* Callback Creation Functions
|
|
*/
|
|
|
|
void NT_SetListenerOnStart(void (*on_start)(void *data), void *data) {
|
|
nt::SetListenerOnStart([=]() { on_start(data); });
|
|
}
|
|
|
|
void NT_SetListenerOnExit(void (*on_exit)(void *data), void *data) {
|
|
nt::SetListenerOnExit([=]() { on_exit(data); });
|
|
}
|
|
|
|
unsigned int NT_AddEntryListener(const char *prefix, size_t prefix_len,
|
|
void *data,
|
|
NT_EntryListenerCallback callback,
|
|
unsigned int flags) {
|
|
return nt::AddEntryListener(
|
|
StringRef(prefix, prefix_len),
|
|
[=](unsigned int uid, StringRef name, std::shared_ptr<Value> value,
|
|
unsigned int flags_) {
|
|
callback(uid, data, name.data(), name.size(), &value->value(), flags_);
|
|
},
|
|
flags);
|
|
}
|
|
|
|
void NT_RemoveEntryListener(unsigned int entry_listener_uid) {
|
|
nt::RemoveEntryListener(entry_listener_uid);
|
|
}
|
|
|
|
unsigned int NT_AddConnectionListener(void *data,
|
|
NT_ConnectionListenerCallback callback,
|
|
int immediate_notify) {
|
|
return nt::AddConnectionListener(
|
|
[=](unsigned int uid, bool connected, const ConnectionInfo &conn) {
|
|
NT_ConnectionInfo conn_c;
|
|
ConvertToC(conn, &conn_c);
|
|
callback(uid, data, connected ? 1 : 0, &conn_c);
|
|
DisposeConnectionInfo(&conn_c);
|
|
},
|
|
immediate_notify != 0);
|
|
}
|
|
|
|
void NT_RemoveConnectionListener(unsigned int conn_listener_uid) {
|
|
nt::RemoveConnectionListener(conn_listener_uid);
|
|
}
|
|
|
|
int NT_NotifierDestroyed() { return nt::NotifierDestroyed(); }
|
|
|
|
/*
|
|
* Remote Procedure Call Functions
|
|
*/
|
|
|
|
void NT_SetRpcServerOnStart(void (*on_start)(void *data), void *data) {
|
|
nt::SetRpcServerOnStart([=]() { on_start(data); });
|
|
}
|
|
|
|
void NT_SetRpcServerOnExit(void (*on_exit)(void *data), void *data) {
|
|
nt::SetRpcServerOnExit([=]() { on_exit(data); });
|
|
}
|
|
|
|
void NT_CreateRpc(const char *name, size_t name_len, const char *def,
|
|
size_t def_len, void *data, NT_RpcCallback callback) {
|
|
nt::CreateRpc(
|
|
StringRef(name, name_len), StringRef(def, def_len),
|
|
[=](StringRef name, StringRef params) -> std::string {
|
|
size_t results_len;
|
|
char* results_c = callback(data, name.data(), name.size(),
|
|
params.data(), params.size(), &results_len);
|
|
std::string results(results_c, results_len);
|
|
std::free(results_c);
|
|
return results;
|
|
});
|
|
}
|
|
|
|
void NT_CreatePolledRpc(const char *name, size_t name_len, const char *def,
|
|
size_t def_len) {
|
|
nt::CreatePolledRpc(StringRef(name, name_len), StringRef(def, def_len));
|
|
}
|
|
|
|
int NT_PollRpc(int blocking, NT_RpcCallInfo* call_info) {
|
|
RpcCallInfo call_info_cpp;
|
|
if (!nt::PollRpc(blocking != 0, &call_info_cpp))
|
|
return 0;
|
|
ConvertToC(call_info_cpp, call_info);
|
|
return 1;
|
|
}
|
|
|
|
void NT_PostRpcResponse(unsigned int rpc_id, unsigned int call_uid,
|
|
const char *result, size_t result_len) {
|
|
nt::PostRpcResponse(rpc_id, call_uid, StringRef(result, result_len));
|
|
}
|
|
|
|
unsigned int NT_CallRpc(const char *name, size_t name_len,
|
|
const char *params, size_t params_len) {
|
|
return nt::CallRpc(StringRef(name, name_len), StringRef(params, params_len));
|
|
}
|
|
|
|
char *NT_GetRpcResult(int blocking, unsigned int call_uid, size_t *result_len) {
|
|
std::string result;
|
|
if (!nt::GetRpcResult(blocking != 0, call_uid, &result)) return nullptr;
|
|
|
|
// convert result
|
|
*result_len = result.size();
|
|
char *result_cstr;
|
|
ConvertToC(result, &result_cstr);
|
|
return result_cstr;
|
|
}
|
|
|
|
char *NT_PackRpcDefinition(const NT_RpcDefinition *def, size_t *packed_len) {
|
|
auto packed = nt::PackRpcDefinition(ConvertFromC(*def));
|
|
|
|
// convert result
|
|
*packed_len = packed.size();
|
|
char *packed_cstr;
|
|
ConvertToC(packed, &packed_cstr);
|
|
return packed_cstr;
|
|
}
|
|
|
|
int NT_UnpackRpcDefinition(const char *packed, size_t packed_len,
|
|
NT_RpcDefinition *def) {
|
|
nt::RpcDefinition def_v;
|
|
if (!nt::UnpackRpcDefinition(StringRef(packed, packed_len), &def_v))
|
|
return 0;
|
|
|
|
// convert result
|
|
ConvertToC(def_v, def);
|
|
return 1;
|
|
}
|
|
|
|
char *NT_PackRpcValues(const NT_Value **values, size_t values_len,
|
|
size_t *packed_len) {
|
|
// create input vector
|
|
std::vector<std::shared_ptr<Value>> values_v;
|
|
values_v.reserve(values_len);
|
|
for (size_t i = 0; i < values_len; ++i)
|
|
values_v.push_back(ConvertFromC(*values[i]));
|
|
|
|
// make the call
|
|
auto packed = nt::PackRpcValues(values_v);
|
|
|
|
// convert result
|
|
*packed_len = packed.size();
|
|
char *packed_cstr;
|
|
ConvertToC(packed, &packed_cstr);
|
|
return packed_cstr;
|
|
}
|
|
|
|
NT_Value **NT_UnpackRpcValues(const char *packed, size_t packed_len,
|
|
const NT_Type *types, size_t types_len) {
|
|
auto values_v = nt::UnpackRpcValues(StringRef(packed, packed_len),
|
|
ArrayRef<NT_Type>(types, types_len));
|
|
if (values_v.size() == 0) return nullptr;
|
|
|
|
// create array and copy into it
|
|
NT_Value** values = static_cast<NT_Value**>(
|
|
std::malloc(values_v.size() * sizeof(NT_Value*)));
|
|
for (size_t i = 0; i < values_v.size(); ++i) {
|
|
values[i] = static_cast<NT_Value*>(std::malloc(sizeof(NT_Value)));
|
|
ConvertToC(*values_v[i], values[i]);
|
|
}
|
|
return values;
|
|
}
|
|
|
|
/*
|
|
* Client/Server Functions
|
|
*/
|
|
|
|
void NT_SetNetworkIdentity(const char *name, size_t name_len) {
|
|
nt::SetNetworkIdentity(StringRef(name, name_len));
|
|
}
|
|
|
|
void NT_StartServer(const char *persist_filename, const char *listen_address,
|
|
unsigned int port) {
|
|
nt::StartServer(persist_filename, listen_address, port);
|
|
}
|
|
|
|
void NT_StopServer(void) { nt::StopServer(); }
|
|
|
|
void NT_StartClient(const char *server_name, unsigned int port) {
|
|
nt::StartClient(server_name, port);
|
|
}
|
|
|
|
void NT_StopClient(void) {
|
|
nt::StopClient();
|
|
}
|
|
|
|
void NT_StopRpcServer(void) {
|
|
nt::StopRpcServer();
|
|
}
|
|
|
|
void NT_StopNotifier(void) {
|
|
nt::StopNotifier();
|
|
}
|
|
|
|
void NT_SetUpdateRate(double interval) {
|
|
nt::SetUpdateRate(interval);
|
|
}
|
|
|
|
struct NT_ConnectionInfo *NT_GetConnections(size_t *count) {
|
|
auto conn_v = nt::GetConnections();
|
|
*count = conn_v.size();
|
|
if (conn_v.size() == 0) return nullptr;
|
|
|
|
// create array and copy into it
|
|
NT_ConnectionInfo *conn = static_cast<NT_ConnectionInfo *>(
|
|
std::malloc(conn_v.size() * sizeof(NT_ConnectionInfo)));
|
|
for (size_t i = 0; i < conn_v.size(); ++i) ConvertToC(conn_v[i], &conn[i]);
|
|
return conn;
|
|
}
|
|
|
|
/*
|
|
* Persistent Functions
|
|
*/
|
|
|
|
const char *NT_SavePersistent(const char *filename) {
|
|
return nt::SavePersistent(filename);
|
|
}
|
|
|
|
const char *NT_LoadPersistent(const char *filename,
|
|
void (*warn)(size_t line, const char *msg)) {
|
|
return nt::LoadPersistent(filename, warn);
|
|
}
|
|
|
|
/*
|
|
* Utility Functions
|
|
*/
|
|
|
|
void NT_SetLogger(NT_LogFunc func, unsigned int min_level) {
|
|
nt::SetLogger(func, min_level);
|
|
}
|
|
|
|
void NT_DisposeValue(NT_Value *value) {
|
|
switch (value->type) {
|
|
case NT_UNASSIGNED:
|
|
case NT_BOOLEAN:
|
|
case NT_DOUBLE:
|
|
break;
|
|
case NT_STRING:
|
|
case NT_RAW:
|
|
case NT_RPC:
|
|
std::free(value->data.v_string.str);
|
|
break;
|
|
case NT_BOOLEAN_ARRAY:
|
|
std::free(value->data.arr_boolean.arr);
|
|
break;
|
|
case NT_DOUBLE_ARRAY:
|
|
std::free(value->data.arr_double.arr);
|
|
break;
|
|
case NT_STRING_ARRAY: {
|
|
for (size_t i = 0; i < value->data.arr_string.size; i++)
|
|
std::free(value->data.arr_string.arr[i].str);
|
|
std::free(value->data.arr_string.arr);
|
|
break;
|
|
}
|
|
default:
|
|
assert(false && "unknown value type");
|
|
}
|
|
value->type = NT_UNASSIGNED;
|
|
value->last_change = 0;
|
|
}
|
|
|
|
void NT_InitValue(NT_Value *value) {
|
|
value->type = NT_UNASSIGNED;
|
|
value->last_change = 0;
|
|
}
|
|
|
|
void NT_DisposeString(NT_String *str) {
|
|
std::free(str->str);
|
|
str->str = nullptr;
|
|
str->len = 0;
|
|
}
|
|
|
|
void NT_InitString(NT_String *str) {
|
|
str->str = nullptr;
|
|
str->len = 0;
|
|
}
|
|
|
|
enum NT_Type NT_GetType(const char *name, size_t name_len) {
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v) return NT_Type::NT_UNASSIGNED;
|
|
return v->type();
|
|
}
|
|
|
|
void NT_DisposeConnectionInfoArray(NT_ConnectionInfo *arr, size_t count) {
|
|
for (size_t i = 0; i < count; i++) DisposeConnectionInfo(&arr[i]);
|
|
std::free(arr);
|
|
}
|
|
|
|
void NT_DisposeEntryInfoArray(NT_EntryInfo *arr, size_t count){
|
|
for (size_t i = 0; i < count; i++) DisposeEntryInfo(&arr[i]);
|
|
std::free(arr);
|
|
}
|
|
|
|
void NT_DisposeRpcDefinition(NT_RpcDefinition *def) {
|
|
NT_DisposeString(&def->name);
|
|
|
|
for (size_t i = 0; i < def->num_params; ++i) {
|
|
NT_DisposeString(&def->params[i].name);
|
|
NT_DisposeValue(&def->params[i].def_value);
|
|
}
|
|
std::free(def->params);
|
|
def->params = nullptr;
|
|
def->num_params = 0;
|
|
|
|
for (size_t i = 0; i < def->num_results; ++i)
|
|
NT_DisposeString(&def->results[i].name);
|
|
std::free(def->results);
|
|
def->results = nullptr;
|
|
def->num_results = 0;
|
|
}
|
|
|
|
void NT_DisposeRpcCallInfo(NT_RpcCallInfo *call_info) {
|
|
NT_DisposeString(&call_info->name);
|
|
NT_DisposeString(&call_info->params);
|
|
}
|
|
|
|
/* Interop Utility Functions */
|
|
|
|
/* Array and Struct Allocations */
|
|
|
|
/* Allocates a char array of the specified size.*/
|
|
char *NT_AllocateCharArray(size_t size) {
|
|
char *retVal = static_cast<char *>(std::malloc(size * sizeof(char)));
|
|
return retVal;
|
|
}
|
|
|
|
/* Allocates an integer or boolean array of the specified size. */
|
|
int *NT_AllocateBooleanArray(size_t size) {
|
|
int *retVal = static_cast<int *>(std::malloc(size * sizeof(int)));
|
|
return retVal;
|
|
}
|
|
|
|
/* Allocates a double array of the specified size. */
|
|
double *NT_AllocateDoubleArray(size_t size) {
|
|
double *retVal = static_cast<double *>(std::malloc(size * sizeof(double)));
|
|
return retVal;
|
|
}
|
|
|
|
/* Allocates an NT_String array of the specified size. */
|
|
struct NT_String *NT_AllocateStringArray(size_t size) {
|
|
NT_String *retVal =
|
|
static_cast<NT_String *>(std::malloc(size * sizeof(NT_String)));
|
|
return retVal;
|
|
}
|
|
|
|
void NT_FreeCharArray(char *v_char) { std::free(v_char); }
|
|
void NT_FreeDoubleArray(double *v_double) { std::free(v_double); }
|
|
void NT_FreeBooleanArray(int *v_boolean) { std::free(v_boolean); }
|
|
void NT_FreeStringArray(struct NT_String *v_string, size_t arr_size) {
|
|
for (size_t i = 0; i < arr_size; i++) std::free(v_string[i].str);
|
|
std::free(v_string);
|
|
}
|
|
|
|
int NT_SetEntryDouble(const char *name, size_t name_len, double v_double,
|
|
int force) {
|
|
if (force != 0) {
|
|
nt::SetEntryTypeValue(StringRef(name, name_len),
|
|
Value::MakeDouble(v_double));
|
|
return 1;
|
|
} else {
|
|
return nt::SetEntryValue(StringRef(name, name_len),
|
|
Value::MakeDouble(v_double));
|
|
}
|
|
}
|
|
|
|
int NT_SetEntryBoolean(const char *name, size_t name_len, int v_boolean,
|
|
int force) {
|
|
if (force != 0) {
|
|
nt::SetEntryTypeValue(StringRef(name, name_len),
|
|
Value::MakeBoolean(v_boolean != 0));
|
|
return 1;
|
|
} else {
|
|
return nt::SetEntryValue(StringRef(name, name_len),
|
|
Value::MakeBoolean(v_boolean != 0));
|
|
}
|
|
}
|
|
|
|
int NT_SetEntryString(const char *name, size_t name_len, const char *str,
|
|
size_t str_len, int force) {
|
|
if (force != 0) {
|
|
nt::SetEntryTypeValue(StringRef(name, name_len),
|
|
Value::MakeString(StringRef(str, str_len)));
|
|
return 1;
|
|
} else {
|
|
return nt::SetEntryValue(StringRef(name, name_len),
|
|
Value::MakeString(StringRef(str, str_len)));
|
|
}
|
|
}
|
|
|
|
int NT_SetEntryRaw(const char *name, size_t name_len, const char *raw,
|
|
size_t raw_len, int force) {
|
|
if (force != 0) {
|
|
nt::SetEntryTypeValue(StringRef(name, name_len),
|
|
Value::MakeRaw(StringRef(raw, raw_len)));
|
|
return 1;
|
|
} else {
|
|
return nt::SetEntryValue(StringRef(name, name_len),
|
|
Value::MakeRaw(StringRef(raw, raw_len)));
|
|
}
|
|
}
|
|
|
|
int NT_SetEntryBooleanArray(const char *name, size_t name_len, const int *arr,
|
|
size_t size, int force) {
|
|
if (force != 0) {
|
|
nt::SetEntryTypeValue(
|
|
StringRef(name, name_len),
|
|
Value::MakeBooleanArray(llvm::makeArrayRef(arr, size)));
|
|
return 1;
|
|
} else {
|
|
return nt::SetEntryValue(
|
|
StringRef(name, name_len),
|
|
Value::MakeBooleanArray(llvm::makeArrayRef(arr, size)));
|
|
}
|
|
}
|
|
|
|
int NT_SetEntryDoubleArray(const char *name, size_t name_len, const double *arr,
|
|
size_t size, int force) {
|
|
if (force != 0) {
|
|
nt::SetEntryTypeValue(
|
|
StringRef(name, name_len),
|
|
Value::MakeDoubleArray(llvm::makeArrayRef(arr, size)));
|
|
return 1;
|
|
} else {
|
|
return nt::SetEntryValue(
|
|
StringRef(name, name_len),
|
|
Value::MakeDoubleArray(llvm::makeArrayRef(arr, size)));
|
|
}
|
|
}
|
|
|
|
int NT_SetEntryStringArray(const char *name, size_t name_len,
|
|
const struct NT_String *arr, size_t size,
|
|
int force) {
|
|
std::vector<std::string> v;
|
|
v.reserve(size);
|
|
for (size_t i = 0; i < size; ++i) v.push_back(ConvertFromC(arr[i]));
|
|
|
|
if (force != 0) {
|
|
nt::SetEntryTypeValue(StringRef(name, name_len),
|
|
Value::MakeStringArray(std::move(v)));
|
|
return 1;
|
|
} else {
|
|
return nt::SetEntryValue(StringRef(name, name_len),
|
|
Value::MakeStringArray(std::move(v)));
|
|
}
|
|
}
|
|
|
|
enum NT_Type NT_GetValueType(const struct NT_Value *value) {
|
|
if (!value) return NT_Type::NT_UNASSIGNED;
|
|
return value->type;
|
|
}
|
|
|
|
int NT_GetValueBoolean(const struct NT_Value *value,
|
|
unsigned long long *last_change, int *v_boolean) {
|
|
if (!value || value->type != NT_Type::NT_BOOLEAN) return 0;
|
|
*v_boolean = value->data.v_boolean;
|
|
*last_change = value->last_change;
|
|
return 1;
|
|
}
|
|
|
|
int NT_GetValueDouble(const struct NT_Value *value,
|
|
unsigned long long *last_change, double *v_double) {
|
|
if (!value || value->type != NT_Type::NT_DOUBLE) return 0;
|
|
*last_change = value->last_change;
|
|
*v_double = value->data.v_double;
|
|
return 1;
|
|
}
|
|
|
|
char *NT_GetValueString(const struct NT_Value *value,
|
|
unsigned long long *last_change, size_t *str_len) {
|
|
if (!value || value->type != NT_Type::NT_STRING) return nullptr;
|
|
*last_change = value->last_change;
|
|
*str_len = value->data.v_string.len;
|
|
char *str = (char*)std::malloc(value->data.v_string.len + 1);
|
|
std::memcpy(str, value->data.v_string.str, value->data.v_string.len + 1);
|
|
return str;
|
|
}
|
|
|
|
char *NT_GetValueRaw(const struct NT_Value *value,
|
|
unsigned long long *last_change, size_t *raw_len) {
|
|
if (!value || value->type != NT_Type::NT_RAW) return nullptr;
|
|
*last_change = value->last_change;
|
|
*raw_len = value->data.v_string.len;
|
|
char *raw = (char*)std::malloc(value->data.v_string.len + 1);
|
|
std::memcpy(raw, value->data.v_string.str, value->data.v_string.len + 1);
|
|
return raw;
|
|
}
|
|
|
|
int *NT_GetValueBooleanArray(const struct NT_Value *value,
|
|
unsigned long long *last_change,
|
|
size_t *arr_size) {
|
|
if (!value || value->type != NT_Type::NT_BOOLEAN_ARRAY) return nullptr;
|
|
*last_change = value->last_change;
|
|
*arr_size = value->data.arr_boolean.size;
|
|
int *arr = (int*)std::malloc(value->data.arr_boolean.size * sizeof(int));
|
|
std::memcpy(arr, value->data.arr_boolean.arr,
|
|
value->data.arr_boolean.size * sizeof(int));
|
|
return arr;
|
|
}
|
|
|
|
double *NT_GetValueDoubleArray(const struct NT_Value *value,
|
|
unsigned long long *last_change,
|
|
size_t *arr_size) {
|
|
if (!value || value->type != NT_Type::NT_DOUBLE_ARRAY) return nullptr;
|
|
*last_change = value->last_change;
|
|
*arr_size = value->data.arr_double.size;
|
|
double *arr =
|
|
(double *)std::malloc(value->data.arr_double.size * sizeof(double));
|
|
std::memcpy(arr, value->data.arr_double.arr,
|
|
value->data.arr_double.size * sizeof(double));
|
|
return arr;
|
|
}
|
|
|
|
NT_String *NT_GetValueStringArray(const struct NT_Value *value,
|
|
unsigned long long *last_change,
|
|
size_t *arr_size) {
|
|
if (!value || value->type != NT_Type::NT_STRING_ARRAY) return nullptr;
|
|
*last_change = value->last_change;
|
|
*arr_size = value->data.arr_string.size;
|
|
NT_String *arr = static_cast<NT_String *>(
|
|
std::malloc(value->data.arr_string.size * sizeof(NT_String)));
|
|
for (size_t i = 0; i < value->data.arr_string.size; ++i) {
|
|
size_t len = value->data.arr_string.arr[i].len;
|
|
arr[i].len = len;
|
|
arr[i].str = (char*)std::malloc(len + 1);
|
|
std::memcpy(arr[i].str, value->data.arr_string.arr[i].str, len + 1);
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
int NT_GetEntryBoolean(const char *name, size_t name_len,
|
|
unsigned long long *last_change, int *v_boolean) {
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v || !v->IsBoolean()) return 0;
|
|
*v_boolean = v->GetBoolean();
|
|
*last_change = v->last_change();
|
|
return 1;
|
|
}
|
|
|
|
int NT_GetEntryDouble(const char *name, size_t name_len,
|
|
unsigned long long *last_change, double *v_double) {
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v || !v->IsDouble()) return 0;
|
|
*last_change = v->last_change();
|
|
*v_double = v->GetDouble();
|
|
return 1;
|
|
}
|
|
|
|
char *NT_GetEntryString(const char *name, size_t name_len,
|
|
unsigned long long *last_change, size_t *str_len) {
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v || !v->IsString()) return nullptr;
|
|
*last_change = v->last_change();
|
|
struct NT_String v_string;
|
|
nt::ConvertToC(v->GetString(), &v_string);
|
|
*str_len = v_string.len;
|
|
return v_string.str;
|
|
}
|
|
|
|
char *NT_GetEntryRaw(const char *name, size_t name_len,
|
|
unsigned long long *last_change, size_t *raw_len) {
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v || !v->IsRaw()) return nullptr;
|
|
*last_change = v->last_change();
|
|
struct NT_String v_raw;
|
|
nt::ConvertToC(v->GetRaw(), &v_raw);
|
|
*raw_len = v_raw.len;
|
|
return v_raw.str;
|
|
}
|
|
|
|
int *NT_GetEntryBooleanArray(const char *name, size_t name_len,
|
|
unsigned long long *last_change,
|
|
size_t *arr_size) {
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v || !v->IsBooleanArray()) return nullptr;
|
|
*last_change = v->last_change();
|
|
auto vArr = v->GetBooleanArray();
|
|
int *arr = static_cast<int *>(std::malloc(vArr.size() * sizeof(int)));
|
|
*arr_size = vArr.size();
|
|
std::copy(vArr.begin(), vArr.end(), arr);
|
|
return arr;
|
|
}
|
|
|
|
double *NT_GetEntryDoubleArray(const char *name, size_t name_len,
|
|
unsigned long long *last_change,
|
|
size_t *arr_size) {
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v || !v->IsDoubleArray()) return nullptr;
|
|
*last_change = v->last_change();
|
|
auto vArr = v->GetDoubleArray();
|
|
double *arr =
|
|
static_cast<double *>(std::malloc(vArr.size() * sizeof(double)));
|
|
*arr_size = vArr.size();
|
|
std::copy(vArr.begin(), vArr.end(), arr);
|
|
return arr;
|
|
}
|
|
|
|
NT_String *NT_GetEntryStringArray(const char *name, size_t name_len,
|
|
unsigned long long *last_change,
|
|
size_t *arr_size) {
|
|
auto v = nt::GetEntryValue(StringRef(name, name_len));
|
|
if (!v || !v->IsStringArray()) return nullptr;
|
|
*last_change = v->last_change();
|
|
auto vArr = v->GetStringArray();
|
|
NT_String *arr =
|
|
static_cast<NT_String *>(std::malloc(vArr.size() * sizeof(NT_String)));
|
|
for (size_t i = 0; i < vArr.size(); ++i) {
|
|
ConvertToC(vArr[i], &arr[i]);
|
|
}
|
|
*arr_size = vArr.size();
|
|
return arr;
|
|
}
|
|
|
|
} // extern "C"
|