[ntcore] NetworkTables 4 (#3217)

This commit is contained in:
Peter Johnson
2022-10-08 10:01:31 -07:00
committed by GitHub
parent 90cfa00115
commit 77301b126c
380 changed files with 34573 additions and 22095 deletions

View File

@@ -0,0 +1,245 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <jni.h>
#include <wpi/jni_util.h>
#include "edu_wpi_first_networktables_NetworkTablesJNI.h"
#include "ntcore.h"
using namespace wpi::java;
//
// Globals and load/unload
//
{% for t in types %}
static JClass timestamped{{ t.TypeName }}Cls;
{%- endfor %}
{%- for t in types %}
{%- if t.jni.ToJavaArray == "MakeJObjectArray" %}
static JClass {{ t.jni.jtype }}Cls;
{%- endif %}
{%- endfor %}
static JException nullPointerEx;
static const JClassInit classes[] = {
{%- for t in types %}
{"edu/wpi/first/networktables/Timestamped{{ t.TypeName }}", &timestamped{{ t.TypeName }}Cls},
{%- endfor %}
{%- for t in types %}
{%- if t.jni.ToJavaArray == "MakeJObjectArray" %}
{"{{ t.jni.jtypestr }}", &{{ t.jni.jtype }}Cls},
{%- endif %}
{%- endfor %}
};
static const JExceptionInit exceptions[] = {
{"java/lang/NullPointerException", &nullPointerEx},
};
namespace nt {
bool JNI_LoadTypes(JNIEnv* env) {
// Cache references to classes
for (auto& c : classes) {
*c.cls = JClass(env, c.name);
if (!*c.cls) {
return false;
}
}
for (auto& c : exceptions) {
*c.cls = JException(env, c.name);
if (!*c.cls) {
return false;
}
}
return true;
}
void JNI_UnloadTypes(JNIEnv* env) {
// Delete global references
for (auto& c : classes) {
c.cls->free(env);
}
}
} // namespace nt
static std::vector<int> FromJavaBooleanArray(JNIEnv* env, jbooleanArray jarr) {
CriticalJBooleanArrayRef ref{env, jarr};
if (!ref) {
return {};
}
wpi::span<const jboolean> elements{ref};
size_t len = elements.size();
std::vector<int> arr;
arr.reserve(len);
for (size_t i = 0; i < len; ++i) {
arr.push_back(elements[i]);
}
return arr;
}
static std::vector<std::string> FromJavaStringArray(JNIEnv* env, jobjectArray jarr) {
size_t len = env->GetArrayLength(jarr);
std::vector<std::string> arr;
arr.reserve(len);
for (size_t i = 0; i < len; ++i) {
JLocal<jstring> elem{
env, static_cast<jstring>(env->GetObjectArrayElement(jarr, i))};
if (!elem) {
return {};
}
arr.emplace_back(JStringRef{env, elem}.str());
}
return arr;
}
{% for t in types %}
static jobject MakeJObject(JNIEnv* env, nt::Timestamped{{ t.TypeName }} value) {
static jmethodID constructor = env->GetMethodID(
timestamped{{ t.TypeName }}Cls, "<init>", "(JJ{{ t.jni.jtypestr }})V");
{%- if t.jni.JavaObject %}
JLocal<{{ t.jni.jtype }}> val{env, {{ t.jni.ToJavaBegin }}value.value{{ t.jni.ToJavaEnd }}};
return env->NewObject(timestamped{{ t.TypeName }}Cls, constructor,
static_cast<jlong>(value.time),
static_cast<jlong>(value.serverTime), val.obj());
{%- else %}
return env->NewObject(timestamped{{ t.TypeName }}Cls, constructor,
static_cast<jlong>(value.time),
static_cast<jlong>(value.serverTime),
{{ t.jni.ToJavaBegin }}value.value{{ t.jni.ToJavaEnd }});
{%- endif %}
}
{% endfor %}
{%- for t in types %}
static jobjectArray MakeJObject(JNIEnv* env,
wpi::span<const nt::Timestamped{{ t.TypeName }}> arr) {
jobjectArray jarr =
env->NewObjectArray(arr.size(), timestamped{{ t.TypeName }}Cls, nullptr);
if (!jarr) {
return nullptr;
}
for (size_t i = 0; i < arr.size(); ++i) {
JLocal<jobject> elem{env, MakeJObject(env, arr[i])};
env->SetObjectArrayElement(jarr, i, elem.obj());
}
return jarr;
}
{% endfor %}
{%- for t in types %}
{%- if t.jni.ToJavaArray == "MakeJObjectArray" %}
static jobjectArray MakeJObjectArray(JNIEnv* env, wpi::span<const {{ t.cpp.ValueType }}> arr) {
jobjectArray jarr =
env->NewObjectArray(arr.size(), {{ t.jni.jtype }}Cls, nullptr);
if (!jarr) {
return nullptr;
}
for (size_t i = 0; i < arr.size(); ++i) {
JLocal<jobject> elem{env, {{ t.jni.ToJavaBegin }}arr[i]{{ t.jni.ToJavaEnd }}};
env->SetObjectArrayElement(jarr, i, elem.obj());
}
return jarr;
}
{% endif %}
{%- endfor %}
extern "C" {
{% for t in types %}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: getAtomic{{ t.TypeName }}
* Signature: (I{{ t.jni.jtypestr }})Ledu/wpi/first/networktables/Timestamped{{ t.TypeName }};
*/
JNIEXPORT jobject JNICALL
Java_edu_wpi_first_networktables_NetworkTablesJNI_getAtomic{{ t.TypeName }}
(JNIEnv* env, jclass, jint subentry, {{ t.jni.jtype }} defaultValue)
{
return MakeJObject(env, nt::GetAtomic{{ t.TypeName }}(subentry, {{ t.jni.FromJavaBegin }}defaultValue{{ t.jni.FromJavaEnd }}));
}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: readQueue{{ t.TypeName }}
* Signature: (I)[Ledu/wpi/first/networktables/Timestamped{{ t.TypeName }};
*/
JNIEXPORT jobjectArray JNICALL
Java_edu_wpi_first_networktables_NetworkTablesJNI_readQueue{{ t.TypeName }}
(JNIEnv* env, jclass, jint subentry)
{
return MakeJObject(env, nt::ReadQueue{{ t.TypeName }}(subentry));
}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: readQueueValues{{ t.TypeName }}
* Signature: (I)[{{ t.jni.jtypestr }}
*/
JNIEXPORT {% if t.jni.JavaObject %}jobject{% else %}{{ t.jni.jtype }}{% endif %}Array JNICALL
Java_edu_wpi_first_networktables_NetworkTablesJNI_readQueueValues{{ t.TypeName }}
(JNIEnv* env, jclass, jint subentry)
{
return {{ t.jni.ToJavaArray }}(env, nt::ReadQueueValues{{ t.TypeName }}(subentry));
}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: set{{ t.TypeName }}
* Signature: (IJ{{ t.jni.jtypestr }})Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_networktables_NetworkTablesJNI_set{{ t.TypeName }}
(JNIEnv*{% if t.jni.JavaObject %} env{% endif %}, jclass, jint entry, jlong time, {{ t.jni.jtype }} value)
{
{%- if t.jni.JavaObject %}
if (!value) {
nullPointerEx.Throw(env, "value cannot be null");
return false;
}
{%- endif %}
return nt::Set{{ t.TypeName }}(entry, {{ t.jni.FromJavaBegin }}value{{ t.jni.FromJavaEnd }}, time);
}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: get{{ t.TypeName }}
* Signature: (I{{ t.jni.jtypestr }}){{ t.jni.jtypestr }}
*/
JNIEXPORT {{ t.jni.jtype }} JNICALL
Java_edu_wpi_first_networktables_NetworkTablesJNI_get{{ t.TypeName }}
(JNIEnv*{% if t.jni.JavaObject %} env{% endif %}, jclass, jint entry, {{ t.jni.jtype }} defaultValue)
{
{%- if t.jni.JavaObject %}
auto val = nt::GetEntryValue(entry);
if (!val || !val.Is{{ t.TypeName }}()) {
return defaultValue;
}
return {{ t.jni.ToJavaBegin }}val.Get{{ t.TypeName }}(){{ t.jni.ToJavaEnd }};
{%- else %}
return nt::Get{{ t.TypeName }}(entry, defaultValue);
{%- endif %}
}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: setDefault{{ t.TypeName }}
* Signature: (IJ{{ t.jni.jtypestr }})Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_networktables_NetworkTablesJNI_setDefault{{ t.TypeName }}
(JNIEnv*{% if t.jni.JavaObject %} env{% endif %}, jclass, jint entry, jlong, {{ t.jni.jtype }} defaultValue)
{
{%- if t.jni.JavaObject %}
if (!defaultValue) {
nullPointerEx.Throw(env, "defaultValue cannot be null");
return false;
}
{%- endif %}
return nt::SetDefault{{ t.TypeName }}(entry, {{ t.jni.FromJavaBegin }}defaultValue{{ t.jni.FromJavaEnd }});
}
{% endfor %}
} // extern "C"

View File

@@ -0,0 +1,106 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "ntcore_c_types.h"
#include "Value_internal.h"
#include "ntcore_cpp.h"
using namespace nt;
template <typename T>
static inline wpi::span<const T> ConvertFromC(const T* arr, size_t size) {
return {arr, size};
}
static inline std::string_view ConvertFromC(const char* arr, size_t size) {
return {arr, size};
}
static std::vector<std::string> ConvertFromC(const NT_String* arr, size_t size) {
std::vector<std::string> v;
v.reserve(size);
for (size_t i = 0; i < size; ++i) {
v.emplace_back(ConvertFromC(arr[i]));
}
return v;
}
{% for t in types %}
static void ConvertToC(const nt::Timestamped{{ t.TypeName }}& in, NT_Timestamped{{ t.TypeName }}* out) {
out->time = in.time;
out->serverTime = in.serverTime;
{%- if t.c.IsArray %}
out->value = ConvertToC<{{ t.c.ValueType[:-1] }}>(in.value, &out->len);
{% else %}
out->value = in.value;
{% endif -%}
}
{% endfor %}
extern "C" {
{% for t in types %}
NT_Bool NT_Set{{ t.TypeName }}(NT_Handle pubentry, int64_t time, {{ t.c.ParamType }} value{% if t.c.IsArray %}, size_t len{% endif %}) {
{%- if t.c.IsArray %}
return nt::Set{{ t.TypeName }}(pubentry, ConvertFromC(value, len), time);
{%- else %}
return nt::Set{{ t.TypeName }}(pubentry, value, time);
{%- endif %}
}
NT_Bool NT_SetDefault{{ t.TypeName }}(NT_Handle pubentry, {{ t.c.ParamType }} defaultValue{% if t.c.IsArray %}, size_t defaultValueLen{% endif %}) {
{%- if t.c.IsArray %}
return nt::SetDefault{{ t.TypeName }}(pubentry, ConvertFromC(defaultValue, defaultValueLen));
{%- else %}
return nt::SetDefault{{ t.TypeName }}(pubentry, defaultValue);
{%- endif %}
}
{{ t.c.ValueType }} NT_Get{{ t.TypeName }}(NT_Handle subentry, {{ t.c.ParamType }} defaultValue{% if t.c.IsArray %}, size_t defaultValueLen, size_t* len{% endif %}) {
{%- if t.c.IsArray %}
auto cppValue = nt::Get{{ t.TypeName }}(subentry, ConvertFromC(defaultValue, defaultValueLen));
return ConvertToC<{{ t.c.ValueType[:-1] }}>(cppValue, len);
{%- else %}
return nt::Get{{ t.TypeName }}(subentry, defaultValue);
{%- endif %}
}
void NT_GetAtomic{{ t.TypeName }}(NT_Handle subentry, {{ t.c.ParamType }} defaultValue{% if t.c.IsArray %}, size_t defaultValueLen{% endif %}, struct NT_Timestamped{{ t.TypeName }}* value) {
{%- if t.c.IsArray %}
auto cppValue = nt::GetAtomic{{ t.TypeName }}(subentry, ConvertFromC(defaultValue, defaultValueLen));
{%- else %}
auto cppValue = nt::GetAtomic{{ t.TypeName }}(subentry, defaultValue);
{%- endif %}
ConvertToC(cppValue, value);
}
void NT_DisposeTimestamped{{ t.TypeName }}(struct NT_Timestamped{{ t.TypeName }}* value) {
{%- if t.TypeName == "StringArray" %}
NT_FreeStringArray(value->value, value->len);
{%- elif t.c.IsArray %}
std::free(value->value);
{%- endif %}
}
struct NT_Timestamped{{ t.TypeName }}* NT_ReadQueue{{ t.TypeName }}(NT_Handle subentry, size_t* len) {
auto arr = nt::ReadQueue{{ t.TypeName }}(subentry);
return ConvertToC<NT_Timestamped{{ t.TypeName }}>(arr, len);
}
void NT_FreeQueue{{ t.TypeName }}(struct NT_Timestamped{{ t.TypeName }}* arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
NT_DisposeTimestamped{{ t.TypeName }}(&arr[i]);
}
std::free(arr);
}
{%- if not t.c.IsArray %}
{{ t.c.ValueType }}* NT_ReadQueueValues{{ t.TypeName }}(NT_Handle subentry, size_t* len) {
auto arr = nt::ReadQueueValues{{ t.TypeName }}(subentry);
return ConvertToC<{{ t.c.ValueType }}>(arr, len);
}
{%- endif %}
{% endfor %}
} // extern "C"

View File

@@ -0,0 +1,76 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "ntcore_cpp_types.h"
#include "Handle.h"
#include "InstanceImpl.h"
namespace nt {
{% for t in types %}
bool Set{{ t.TypeName }}(NT_Handle pubentry, {{ t.cpp.ParamType }} value, int64_t time) {
if (auto ii = InstanceImpl::Get(Handle{pubentry}.GetInst())) {
return ii->localStorage.SetEntryValue(pubentry,
Value::Make{{ t.TypeName }}(value, time == 0 ? Now() : time));
} else {
return {};
}
}
bool SetDefault{{ t.TypeName }}(NT_Handle pubentry, {{ t.cpp.ParamType }} defaultValue) {
if (auto ii = InstanceImpl::Get(Handle{pubentry}.GetInst())) {
return ii->localStorage.SetDefaultEntryValue(pubentry,
Value::Make{{ t.TypeName }}(defaultValue, 1));
} else {
return {};
}
}
{{ t.cpp.ValueType }} Get{{ t.TypeName }}(NT_Handle subentry, {{ t.cpp.ParamType }} defaultValue) {
return GetAtomic{{ t.TypeName }}(subentry, defaultValue).value;
}
Timestamped{{ t.TypeName }} GetAtomic{{ t.TypeName }}(NT_Handle subentry, {{ t.cpp.ParamType }} defaultValue) {
if (auto ii = InstanceImpl::Get(Handle{subentry}.GetInst())) {
return ii->localStorage.GetAtomic{{ t.TypeName }}(subentry, defaultValue);
} else {
return {};
}
}
std::vector<Timestamped{{ t.TypeName }}> ReadQueue{{ t.TypeName }}(NT_Handle subentry) {
if (auto ii = InstanceImpl::Get(Handle{subentry}.GetInst())) {
return ii->localStorage.ReadQueue{{ t.TypeName }}(subentry);
} else {
return {};
}
}
std::vector<{% if t.cpp.ValueType == "bool" %}int{% else %}{{ t.cpp.ValueType }}{% endif %}> ReadQueueValues{{ t.TypeName }}(NT_Handle subentry) {
std::vector<{% if t.cpp.ValueType == "bool" %}int{% else %}{{ t.cpp.ValueType }}{% endif %}> rv;
auto arr = ReadQueue{{ t.TypeName }}(subentry);
rv.reserve(arr.size());
for (auto&& elem : arr) {
rv.emplace_back(std::move(elem.value));
}
return rv;
}
{% if t.cpp.SmallRetType and t.cpp.SmallElemType %}
{{ t.cpp.SmallRetType }} Get{{ t.TypeName }}(NT_Handle subentry, wpi::SmallVectorImpl<{{ t.cpp.SmallElemType }}>& buf, {{ t.cpp.ParamType }} defaultValue) {
return GetAtomic{{ t.TypeName }}(subentry, buf, defaultValue).value;
}
Timestamped{{ t.TypeName }}View GetAtomic{{ t.TypeName }}(
NT_Handle subentry,
wpi::SmallVectorImpl<{{ t.cpp.SmallElemType }}>& buf,
{{ t.cpp.ParamType }} defaultValue) {
if (auto ii = InstanceImpl::Get(Handle{subentry}.GetInst())) {
return ii->localStorage.GetAtomic{{ t.TypeName }}(subentry, buf, defaultValue);
} else {
return {};
}
}
{% endif %}
{% endfor %}
} // namespace nt