From 4b7dfc02549bc714c71eb7b63e77c79699fe8186 Mon Sep 17 00:00:00 2001 From: Thad House Date: Wed, 19 Aug 2015 21:14:09 -0700 Subject: [PATCH] Implements individual getters and setters for the C interface. Starting to add Getters, Setters, and Allocators to the C interface Because of the union in the NT_Value structure, some languages would have a difficult time with the interop. This commit adds individual getters and setters to the C interface to make interop easier. In addition, some languages cannot allocate native memory in the same heap that the C code would use. This adds allocation functions to make sure that all our memory is allocated and can be freed properly from the same heap. The reason the getters are not individual get functions are because that would require the calling code to first get the type, and then call the specific getter for that type. Doing combined get functions causes interop code to only have to cross interop boundaries once to get the value instead of twice, for a light performance increase. However, this could be changed without much work. NT getters and setters round 2 Fixed some of the code based on the comments in the pull request. Creates individual getters. Should work better then 1 single getter. Fixes end of file new line, and fixes function nameing SetNTValue... made less sense then SetEntry... Matches the getter naming. Fixed methods to be less leaky. Fixed Formatting, Fixed return values on Bool and Double. Added Contains Key Changed ContainsKey to GetType. Also renamed Arr to Array In public functions, I think I like Array better then Arr. Also, make the getters that use value check for a null value, which should prevent segfaults. Fixes C++ Type functions to work properly NTString Set functions still do not work properly though. I need some help on there. Error message is in the pull request. Changes Get functions to return status and have pointer to data passed in to be set. Fixes NT_Strings Added new functions to ntcore.def Fixes NT_PostRpcResponse in the def file Was NT_PostRpcRepsonse, which was failing the build. Removed unused parameter from setters Since we were forcing exports in the cmake build, they were seen in windows, but since the header didnt match the implementation they wouldn't export on linux. So fixed that. Linux builds now work properly, tested on a physical RIO. Added a DisposeEntryInfoArray method. There was no way to free the array returned from GetEntryInfo Adds NT_DisposeEntryInfoArray to the def file. Implement automatic persistent saves. Also loads persistent file on server start. Update TODO. raw_istream and kin: a few cleanups. anchor() doesn't seem to change compiler output in current compilers, so remove it. Use default where appropriate rather than empty bodies. Clean up trailing whitespace. Dispatcher: Move several fixed initial values to header. Uninline constructors to reduce GetInstance() inlined code size. Logger: Move m_min_level init to header. Replaced time.h with std::chrono This implementation returns the same values as the previous one on both a Linux machine and the roboRIO. Value: Use variant of enable_if to fix MakeString/MakeRaw in GCC. Tested on GCC 4.8, GCC 4.9, and clang 3.6. Don't dispose in ConvertToC for NT_String and NT_Value. Fixes #16. Fixed Gradle build to actually export proper functions Finishes fixes in pull request Changes array setters to be const To build RPC, needed a way to allocate a Char Array Since after the callback, the C code explicitly frees, a way to make sure to allocate the callback return string from the same heap was needed. Adds const to NTString setters. Removes Const from NTString setters --- include/ntcore_c.h | 62 +++++++++ ntcore.def | 32 +++++ src/ntcore_c.cpp | 340 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 434 insertions(+) diff --git a/include/ntcore_c.h b/include/ntcore_c.h index d2113138f8..e63e84e0ad 100644 --- a/include/ntcore_c.h +++ b/include/ntcore_c.h @@ -339,8 +339,13 @@ void NT_DisposeString(struct NT_String *str); /* sets length to zero and pointer to null */ void NT_InitString(struct NT_String *str); +/* Gets the type for the specified key, or unassigned if non existent. */ +enum NT_Type NT_GetType(const char *name, size_t name_len); + void NT_DisposeConnectionInfoArray(struct NT_ConnectionInfo *arr, size_t count); +void NT_DisposeEntryInfoArray(struct NT_EntryInfo *arr, size_t count); + void NT_DisposeRpcDefinition(struct NT_RpcDefinition *def); void NT_DisposeRpcCallInfo(struct NT_RpcCallInfo *call_info); @@ -353,6 +358,63 @@ typedef void (*NT_LogFunc)(unsigned int level, const char *file, unsigned int line, const char *msg); void NT_SetLogger(NT_LogFunc func, unsigned int min_level); +/* +Interop Utility Functions +*/ + +/* Memory Allocators */ +char *NT_AllocateCharArray(size_t size); + +double *NT_AllocateDoubleArray(size_t size); + +int *NT_AllocateBooleanArray(size_t size); + +struct NT_String *NT_AllocateNTStringArray(size_t size); + +struct NT_String NT_AllocateNTString(size_t size); + +void NT_FreeDoubleArray(double *v_double); +void NT_FreeBooleanArray(int *v_boolean); +void NT_FreeStringArray(struct NT_String *v_string, size_t arr_size); + +enum NT_Type NT_GetTypeFromValue(struct NT_Value *value); + +int NT_GetEntryBooleanFromValue(struct NT_Value *value, unsigned long long *last_change, int *v_boolean); +int NT_GetEntryDoubleFromValue(struct NT_Value *value, unsigned long long *last_change, double *v_double); +int NT_GetEntryStringFromValue(struct NT_Value *value, unsigned long long *last_change, struct NT_String *v_string); +int NT_GetEntryRawFromValue(struct NT_Value *value, unsigned long long *last_change, struct NT_String *v_raw); + +int *NT_GetEntryBooleanArrayFromValue(struct NT_Value *value, unsigned long long *last_change, size_t *arr_size); +double *NT_GetEntryDoubleArrayFromValue(struct NT_Value *value, unsigned long long *last_change, size_t *arr_size); +NT_String *NT_GetEntryStringArrayFromValue(struct NT_Value *value, unsigned long long *last_change, size_t *arr_size); + + +int NT_GetEntryBoolean(const char* name, size_t name_len, unsigned long long *last_change, int *v_boolean); +int NT_GetEntryDouble(const char* name, size_t name_len, unsigned long long *last_change, double *v_double); +int NT_GetEntryString(const char *name, size_t name_len, unsigned long long *last_change, struct NT_String *v_string); +int NT_GetEntryRaw(const char *name, size_t name_len, unsigned long long *last_change, struct NT_String *v_raw); + +int *NT_GetEntryBooleanArray(const char* name, size_t name_len, unsigned long long *last_change, size_t *arr_size); +double *NT_GetEntryDoubleArray(const char* name, size_t name_len, unsigned long long *last_change, size_t *arr_size); +NT_String *NT_GetEntryStringArray(const char* name, size_t name_len, unsigned long long *last_change, size_t *arr_size); + +/* Entry Value Setters */ +int NT_SetEntryDouble(const char *name, size_t name_len, + double v_double, int force); +int NT_SetEntryBoolean(const char *name, size_t name_len, + int v_boolean, int force); +int NT_SetEntryString(const char *name, size_t name_len, + struct NT_String v_string, int force); +int NT_SetEntryRaw(const char *name, size_t name_len, + struct NT_String v_raw, int force); + +int NT_SetEntryBooleanArray(const char *name, size_t name_len, + const int *arr, size_t size, int force); +int NT_SetEntryDoubleArray(const char *name, size_t name_len, + const double *arr, size_t size, int force); +int NT_SetEntryNTStringArray(const char *name, size_t name_len, + const struct NT_String *arr, size_t size, int force); + #ifdef __cplusplus } #endif diff --git a/ntcore.def b/ntcore.def index 97bbbd1a92..232bb4b6a3 100644 --- a/ntcore.def +++ b/ntcore.def @@ -41,6 +41,38 @@ NT_PackRpcValues @42 NT_UnpackRpcValues @43 NT_DisposeRpcDefinition @44 NT_DisposeRpcCallInfo @45 +NT_GetType @46 +NT_AllocateDoubleArray @47 +NT_AllocateBooleanArray @48 +NT_AllocateNTStringArray @49 +NT_AllocateNTString @50 +NT_FreeDoubleArray @51 +NT_FreeBooleanArray @52 +NT_FreeStringArray @53 +NT_GetTypeFromValue @54 +NT_GetEntryBooleanFromValue @55 +NT_GetEntryDoubleFromValue @56 +NT_GetEntryStringFromValue @57 +NT_GetEntryRawFromValue @58 +NT_GetEntryBooleanArrayFromValue @59 +NT_GetEntryDoubleArrayFromValue @60 +NT_GetEntryStringArrayFromValue @61 +NT_GetEntryBoolean @62 +NT_GetEntryDouble @63 +NT_GetEntryString @64 +NT_GetEntryRaw @65 +NT_GetEntryBooleanArray @66 +NT_GetEntryDoubleArray @67 +NT_GetEntryStringArray @68 +NT_SetEntryDouble @69 +NT_SetEntryBoolean @70 +NT_SetEntryString @71 +NT_SetEntryRaw @72 +NT_SetEntryBooleanArray @73 +NT_SetEntryDoubleArray @74 +NT_SetEntryNTStringArray @75 +NT_DisposeEntryInfoArray @76 +NT_AllocateCharArray @77 ; JNI functions JNI_OnLoad diff --git a/src/ntcore_c.cpp b/src/ntcore_c.cpp index 334513dc2a..38db6c2659 100644 --- a/src/ntcore_c.cpp +++ b/src/ntcore_c.cpp @@ -76,6 +76,10 @@ static void DisposeConnectionInfo(NT_ConnectionInfo *info) { 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); @@ -409,11 +413,22 @@ void NT_InitString(NT_String *str) { 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); @@ -436,3 +451,328 @@ 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( + 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( + 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( + std::malloc(size * sizeof(double))); + return retVal; +} + +/* Allocates an NT_String array of the specified size. */ +struct NT_String *NT_AllocateNTStringArray(size_t size) +{ + NT_String *retVal = static_cast( + std::malloc(size * sizeof(NT_String))); + return retVal; +} + +/* Allocates */ +struct NT_String NT_AllocateNTString(size_t size) +{ + NT_String retVal; + retVal.len = size; + retVal.str = static_cast( + std::malloc(size * sizeof(char))); + return retVal; +} + +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)); + return 1; + } + else + { + return nt::SetEntryValue(StringRef(name, name_len), Value::MakeBoolean(v_boolean)); + } +} + +int NT_SetEntryString(const char *name, size_t name_len, struct NT_String v_string, int force) +{ + if (force != 0) + { + nt::SetEntryTypeValue(StringRef(name, name_len), Value::MakeString(StringRef(v_string.str, v_string.len))); + return 1; + } + else + { + return nt::SetEntryValue(StringRef(name, name_len), Value::MakeString(StringRef(v_string.str, v_string.len))); + } + +} + +int NT_SetEntryRaw(const char *name, size_t name_len, struct NT_String v_raw, int force) +{ + if (force != 0) + { + nt::SetEntryTypeValue(StringRef(name, name_len), Value::MakeString(StringRef(v_raw.str, v_raw.len))); + return 1; + } + else + { + return nt::SetEntryValue(StringRef(name, name_len), Value::MakeString(StringRef(v_raw.str, v_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_SetEntryNTStringArray(const char *name, size_t name_len, const struct NT_String *arr, size_t size, int force) +{ + std::vector 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_GetTypeFromValue(struct NT_Value *value) +{ + if (!value) return NT_Type::NT_UNASSIGNED; + return value->type; +} + +int NT_GetEntryBooleanFromValue(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_GetEntryDoubleFromValue(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; +} + +int NT_GetEntryStringFromValue(struct NT_Value *value, unsigned long long *last_change, struct NT_String *v_string) +{ + if (!value || value->type != NT_Type::NT_STRING) + { + return 0; + } + *last_change = value->last_change; + NT_DisposeString(v_string); + *v_string = value->data.v_string; + return 1; +} + +int NT_GetEntryRawFromValue(struct NT_Value *value, unsigned long long *last_change, struct NT_String *v_raw) +{ + if (!value || value->type != NT_Type::NT_RAW) + { + return 0; + } + *last_change = value->last_change; + NT_DisposeString(v_raw); + *v_raw = value->data.v_raw; + return 1; +} + +int *NT_GetEntryBooleanArrayFromValue(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; + return value->data.arr_boolean.arr; +} + +double *NT_GetEntryDoubleArrayFromValue(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; + return value->data.arr_double.arr; +} + +NT_String *NT_GetEntryStringArrayFromValue(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; + return value->data.arr_string.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; +} + +int NT_GetEntryString(const char *name, size_t name_len, unsigned long long *last_change, struct NT_String *v_string) +{ + auto v = nt::GetEntryValue(StringRef(name, name_len)); + if (!v || !v->IsString()) { + return 0; + } + *last_change = v->last_change(); + nt::ConvertToC(v->GetString(), v_string); + return 1; +} + +int NT_GetEntryRaw(const char *name, size_t name_len, unsigned long long *last_change, struct NT_String *v_raw) +{ + auto v = nt::GetEntryValue(StringRef(name, name_len)); + if (!v || !v->IsRaw()) + { + return 0; + } + *last_change = v->last_change(); + nt::ConvertToC(v->GetRaw(), v_raw); + return 1; +} + +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(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(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(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; +} +