[wpiutil] jni_util: Add JSpan and CriticalJSpan (#5554)

These replace JArrayRef et al and support statically sized arrays similar to std::span.
This commit is contained in:
Joseph Eng
2023-08-24 00:02:56 -07:00
committed by GitHub
parent 8f3d6a1d4b
commit 2e4ad35e36
19 changed files with 333 additions and 317 deletions

View File

@@ -504,15 +504,14 @@ Java_edu_wpi_first_apriltag_jni_AprilTagJNI_estimatePoseHomography
nullPointerEx.Throw(env, "homography cannot be null");
return nullptr;
}
JDoubleArrayRef harr{env, homography};
JSpan<const jdouble, 9> harr{env, homography};
if (harr.size() != 9) {
illegalArgEx.Throw(env, "homography array must be size 9");
return nullptr;
}
AprilTagPoseEstimator estimator({units::meter_t{tagSize}, fx, fy, cx, cy});
return MakeJObject(env, estimator.EstimateHomography(
std::span<const double, 9>{harr.array()}));
return MakeJObject(env, estimator.EstimateHomography(harr));
}
/*
@@ -530,7 +529,7 @@ Java_edu_wpi_first_apriltag_jni_AprilTagJNI_estimatePoseOrthogonalIteration
nullPointerEx.Throw(env, "homography cannot be null");
return nullptr;
}
JDoubleArrayRef harr{env, homography};
JSpan<const jdouble, 9> harr{env, homography};
if (harr.size() != 9) {
illegalArgEx.Throw(env, "homography array must be size 9");
return nullptr;
@@ -541,7 +540,7 @@ Java_edu_wpi_first_apriltag_jni_AprilTagJNI_estimatePoseOrthogonalIteration
nullPointerEx.Throw(env, "corners cannot be null");
return nullptr;
}
JDoubleArrayRef carr{env, corners};
JSpan<const jdouble, 8> carr{env, corners};
if (carr.size() != 8) {
illegalArgEx.Throw(env, "corners array must be size 8");
return nullptr;
@@ -549,9 +548,7 @@ Java_edu_wpi_first_apriltag_jni_AprilTagJNI_estimatePoseOrthogonalIteration
AprilTagPoseEstimator estimator({units::meter_t{tagSize}, fx, fy, cx, cy});
return MakeJObject(env,
estimator.EstimateOrthogonalIteration(
std::span<const double, 9>{harr.array()},
std::span<const double, 8>{carr.array()}, nIters));
estimator.EstimateOrthogonalIteration(harr, carr, nIters));
}
/*
@@ -569,7 +566,7 @@ Java_edu_wpi_first_apriltag_jni_AprilTagJNI_estimatePose
nullPointerEx.Throw(env, "homography cannot be null");
return nullptr;
}
JDoubleArrayRef harr{env, homography};
JSpan<const jdouble, 9> harr{env, homography};
if (harr.size() != 9) {
illegalArgEx.Throw(env, "homography array must be size 9");
return nullptr;
@@ -580,16 +577,14 @@ Java_edu_wpi_first_apriltag_jni_AprilTagJNI_estimatePose
nullPointerEx.Throw(env, "corners cannot be null");
return nullptr;
}
JDoubleArrayRef carr{env, corners};
JSpan<const jdouble, 8> carr{env, corners};
if (carr.size() != 8) {
illegalArgEx.Throw(env, "corners array must be size 8");
return nullptr;
}
AprilTagPoseEstimator estimator({units::meter_t{tagSize}, fx, fy, cx, cy});
return MakeJObject(
env, estimator.Estimate(std::span<const double, 9>{harr.array()},
std::span<const double, 8>{carr.array()}));
return MakeJObject(env, estimator.Estimate(harr, carr));
}
} // extern "C"

View File

@@ -69,12 +69,11 @@ Java_edu_wpi_first_hal_AddressableLEDJNI_setData
(JNIEnv* env, jclass, jint handle, jbyteArray arr)
{
int32_t status = 0;
JByteArrayRef jArrRef{env, arr};
auto arrRef = jArrRef.array();
JSpan<const jbyte> jArrRef{env, arr};
HAL_WriteAddressableLEDData(
static_cast<HAL_AddressableLEDHandle>(handle),
reinterpret_cast<const HAL_AddressableLEDData*>(arrRef.data()),
arrRef.size() / 4, &status);
reinterpret_cast<const HAL_AddressableLEDData*>(jArrRef.data()),
jArrRef.size() / 4, &status);
CheckStatus(env, status);
}

View File

@@ -71,11 +71,10 @@ Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacket
(JNIEnv* env, jclass, jint handle, jbyteArray data, jint apiId)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
JByteArrayRef arr{env, data};
auto arrRef = arr.array();
JSpan<const jbyte> arr{env, data};
int32_t status = 0;
HAL_WriteCANPacket(halHandle, reinterpret_cast<const uint8_t*>(arrRef.data()),
arrRef.size(), apiId, &status);
HAL_WriteCANPacket(halHandle, reinterpret_cast<const uint8_t*>(arr.data()),
arr.size(), apiId, &status);
CheckStatus(env, status);
}
@@ -90,12 +89,11 @@ Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacketRepeating
jint timeoutMs)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
JByteArrayRef arr{env, data};
auto arrRef = arr.array();
JSpan<const jbyte> arr{env, data};
int32_t status = 0;
HAL_WriteCANPacketRepeating(halHandle,
reinterpret_cast<const uint8_t*>(arrRef.data()),
arrRef.size(), apiId, timeoutMs, &status);
reinterpret_cast<const uint8_t*>(arr.data()),
arr.size(), apiId, timeoutMs, &status);
CheckStatus(env, status);
}
@@ -124,11 +122,10 @@ Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacketNoThrow
(JNIEnv* env, jclass, jint handle, jbyteArray data, jint apiId)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
JByteArrayRef arr{env, data};
auto arrRef = arr.array();
JSpan<const jbyte> arr{env, data};
int32_t status = 0;
HAL_WriteCANPacket(halHandle, reinterpret_cast<const uint8_t*>(arrRef.data()),
arrRef.size(), apiId, &status);
HAL_WriteCANPacket(halHandle, reinterpret_cast<const uint8_t*>(arr.data()),
arr.size(), apiId, &status);
return status;
}
@@ -143,12 +140,11 @@ Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacketRepeatingNoThrow
jint timeoutMs)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
JByteArrayRef arr{env, data};
auto arrRef = arr.array();
JSpan<const jbyte> arr{env, data};
int32_t status = 0;
HAL_WriteCANPacketRepeating(halHandle,
reinterpret_cast<const uint8_t*>(arrRef.data()),
arrRef.size(), apiId, timeoutMs, &status);
reinterpret_cast<const uint8_t*>(arr.data()),
arr.size(), apiId, timeoutMs, &status);
return status;
}

View File

@@ -26,11 +26,11 @@ JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_can_CANJNI_FRCNetCommCANSessionMuxSendMessage
(JNIEnv* env, jclass, jint messageID, jbyteArray data, jint periodMs)
{
JByteArrayRef dataArray{env, data};
JSpan<const jbyte> dataArray{env, data};
const uint8_t* dataBuffer =
reinterpret_cast<const uint8_t*>(dataArray.array().data());
uint8_t dataSize = dataArray.array().size();
reinterpret_cast<const uint8_t*>(dataArray.data());
uint8_t dataSize = dataArray.size();
int32_t status = 0;
HAL_CAN_SendMessage(messageID, dataBuffer, dataSize, periodMs, &status);

View File

@@ -5,12 +5,15 @@
#include <algorithm>
#include <cstring>
#include <wpi/jni_util.h>
#include "HALUtil.h"
#include "edu_wpi_first_hal_DMAJNI.h"
#include "hal/DMA.h"
#include "hal/handles/HandlesInternal.h"
using namespace hal;
using namespace wpi::java;
namespace hal {
bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
@@ -312,20 +315,17 @@ Java_edu_wpi_first_hal_DMAJNI_readDMA
env->SetIntArrayRegion(buf, 0, dmaSample.captureSize,
reinterpret_cast<jint*>(dmaSample.readBuffer));
int32_t* nativeArr =
static_cast<int32_t*>(env->GetPrimitiveArrayCritical(store, nullptr));
CriticalJSpan<jint> nativeArr{env, store};
std::copy_n(
dmaSample.channelOffsets,
sizeof(dmaSample.channelOffsets) / sizeof(dmaSample.channelOffsets[0]),
nativeArr);
nativeArr.data());
nativeArr[22] = static_cast<int32_t>(dmaSample.captureSize);
nativeArr[23] = static_cast<int32_t>(dmaSample.triggerChannels);
nativeArr[24] = remaining;
nativeArr[25] = readStatus;
env->ReleasePrimitiveArrayCritical(store, nativeArr, JNI_ABORT);
return dmaSample.timeStamp;
}

View File

@@ -251,10 +251,10 @@ Java_edu_wpi_first_hal_DriverStationJNI_getAllJoystickData
HAL_GetAllJoystickData(axes, povs, buttons);
CriticalJFloatArrayRef jAxes(env, axesArray);
CriticalJByteArrayRef jRawAxes(env, rawAxesArray);
CriticalJShortArrayRef jPovs(env, povsArray);
CriticalJLongArrayRef jButtons(env, buttonsAndMetadataArray);
CriticalJSpan<jfloat> jAxes(env, axesArray);
CriticalJSpan<jbyte> jRawAxes(env, rawAxesArray);
CriticalJSpan<jshort> jPovs(env, povsArray);
CriticalJSpan<jlong> jButtons(env, buttonsAndMetadataArray);
static_assert(sizeof(jAxes[0]) == sizeof(axes[0].axes[0]));
static_assert(sizeof(jRawAxes[0]) == sizeof(axes[0].raw[0]));

View File

@@ -79,7 +79,7 @@ Java_edu_wpi_first_hal_I2CJNI_i2CTransactionB
jint returnValue =
HAL_TransactionI2C(static_cast<HAL_I2CPort>(port), address,
reinterpret_cast<const uint8_t*>(
JByteArrayRef(env, dataToSend).array().data()),
JSpan<const jbyte>(env, dataToSend).data()),
sendSize, recvBuf.data(), receiveSize);
env->SetByteArrayRegion(dataReceived, 0, receiveSize,
reinterpret_cast<const jbyte*>(recvBuf.data()));
@@ -120,7 +120,7 @@ Java_edu_wpi_first_hal_I2CJNI_i2CWriteB
jint returnValue =
HAL_WriteI2C(static_cast<HAL_I2CPort>(port), address,
reinterpret_cast<const uint8_t*>(
JByteArrayRef(env, dataToSend).array().data()),
JSpan<const jbyte>(env, dataToSend).data()),
sendSize);
return returnValue;
}

View File

@@ -94,7 +94,7 @@ Java_edu_wpi_first_hal_SPIJNI_spiTransactionB
jint retVal =
HAL_TransactionSPI(static_cast<HAL_SPIPort>(port),
reinterpret_cast<const uint8_t*>(
JByteArrayRef(env, dataToSend).array().data()),
JSpan<const jbyte>(env, dataToSend).data()),
recvBuf.data(), size);
env->SetByteArrayRegion(dataReceived, 0, size,
reinterpret_cast<const jbyte*>(recvBuf.data()));
@@ -131,7 +131,7 @@ Java_edu_wpi_first_hal_SPIJNI_spiWriteB
{
jint retVal = HAL_WriteSPI(static_cast<HAL_SPIPort>(port),
reinterpret_cast<const uint8_t*>(
JByteArrayRef(env, dataToSend).array().data()),
JSpan<const jbyte>(env, dataToSend).data()),
size);
return retVal;
}
@@ -356,12 +356,11 @@ JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_SPIJNI_spiSetAutoTransmitData
(JNIEnv* env, jclass, jint port, jbyteArray dataToSend, jint zeroSize)
{
JByteArrayRef jarr(env, dataToSend);
JSpan<const jbyte> jarr(env, dataToSend);
int32_t status = 0;
HAL_SetSPIAutoTransmitData(
static_cast<HAL_SPIPort>(port),
reinterpret_cast<const uint8_t*>(jarr.array().data()),
jarr.array().size(), zeroSize, &status);
HAL_SetSPIAutoTransmitData(static_cast<HAL_SPIPort>(port),
reinterpret_cast<const uint8_t*>(jarr.data()),
jarr.size(), zeroSize, &status);
CheckStatus(env, status);
}

View File

@@ -261,11 +261,10 @@ Java_edu_wpi_first_hal_SerialPortJNI_serialWrite
(JNIEnv* env, jclass, jint handle, jbyteArray dataToSend, jint size)
{
int32_t status = 0;
jint retVal =
HAL_WriteSerial(static_cast<HAL_SerialPortHandle>(handle),
reinterpret_cast<const char*>(
JByteArrayRef(env, dataToSend).array().data()),
size, &status);
jint retVal = HAL_WriteSerial(
static_cast<HAL_SerialPortHandle>(handle),
reinterpret_cast<const char*>(JSpan<const jbyte>(env, dataToSend).data()),
size, &status);
CheckStatus(env, status);
return retVal;
}

View File

@@ -150,7 +150,7 @@ Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueEnumDouble
}
return HAL_CreateSimValueEnumDouble(
device, JStringRef{env, name}.c_str(), direction, len, carr.data(),
JDoubleArrayRef{env, optionValues}.array().data(), initialValue);
JSpan<const jdouble>{env, optionValues}.data(), initialValue);
}
/*

View File

@@ -269,7 +269,7 @@ JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_setData
(JNIEnv* env, jclass, jint index, jbyteArray arr)
{
JByteArrayRef jArrRef{env, arr};
JSpan<const jbyte> jArrRef{env, arr};
auto arrRef = jArrRef.array();
HALSIM_SetAddressableLEDData(
index, reinterpret_cast<const HAL_AddressableLEDData*>(arrRef.data()),

View File

@@ -436,7 +436,7 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickAxes
{
HAL_JoystickAxes axes;
{
wpi::java::JFloatArrayRef jArrayRef(env, axesArray);
JSpan<const jfloat> jArrayRef(env, axesArray);
auto arrayRef = jArrayRef.array();
auto arraySize = arrayRef.size();
int maxCount =
@@ -461,7 +461,7 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickPOVs
{
HAL_JoystickPOVs povs;
{
wpi::java::JShortArrayRef jArrayRef(env, povsArray);
JSpan<const jshort> jArrayRef(env, povsArray);
auto arrayRef = jArrayRef.array();
auto arraySize = arrayRef.size();
int maxCount =

View File

@@ -77,7 +77,7 @@ void JNI_UnloadTypes(JNIEnv* env) {
} // namespace nt
static std::vector<int> FromJavaBooleanArray(JNIEnv* env, jbooleanArray jarr) {
CriticalJBooleanArrayRef ref{env, jarr};
CriticalJSpan<const jboolean> ref{env, jarr};
if (!ref) {
return {};
}
@@ -214,7 +214,7 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_setRaw
indexOobEx.Throw(env, "len must be >= 0");
return false;
}
CriticalJByteArrayRef cvalue{env, value};
CriticalJSpan<const jbyte> cvalue{env, value};
if (static_cast<unsigned int>(start + len) > cvalue.size()) {
indexOobEx.Throw(env, "start + len must be smaller than array length");
return false;
@@ -243,7 +243,7 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_setRawBuffer
indexOobEx.Throw(env, "len must be >= 0");
return false;
}
JByteArrayRef cvalue{env, value, start + len};
JSpan<const jbyte> cvalue{env, value, static_cast<size_t>(start + len)};
if (!cvalue) {
illegalArgEx.Throw(env, "value must be a native ByteBuffer");
return false;
@@ -310,7 +310,7 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_setDefaultRaw
indexOobEx.Throw(env, "len must be >= 0");
return false;
}
CriticalJByteArrayRef cvalue{env, defaultValue};
CriticalJSpan<const jbyte> cvalue{env, defaultValue};
if (static_cast<unsigned int>(start + len) > cvalue.size()) {
indexOobEx.Throw(env, "start + len must be smaller than array length");
return false;
@@ -339,7 +339,7 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_setDefaultRawBuffer
indexOobEx.Throw(env, "len must be >= 0");
return false;
}
JByteArrayRef cvalue{env, defaultValue, start + len};
JSpan<const jbyte> cvalue{env, defaultValue, static_cast<size_t>(start + len)};
if (!cvalue) {
illegalArgEx.Throw(env, "value must be a native ByteBuffer");
return false;

View File

@@ -190,7 +190,7 @@
"jtype": "jbyteArray",
"jtypestr": "[B",
"JavaObject": true,
"FromJavaBegin": "CriticalJByteArrayRef{env, ",
"FromJavaBegin": "CriticalJSpan<const jbyte>{env, ",
"FromJavaEnd": "}.uarray()",
"ToJavaBegin": "MakeJByteArray(env, ",
"ToJavaEnd": ")",
@@ -262,7 +262,7 @@
"jtype": "jlongArray",
"jtypestr": "[J",
"JavaObject": true,
"FromJavaBegin": "CriticalJLongArrayRef{env, ",
"FromJavaBegin": "CriticalJSpan<const jlong>{env, ",
"FromJavaEnd": "}",
"ToJavaBegin": "MakeJLongArray(env, ",
"ToJavaEnd": ")",
@@ -298,7 +298,7 @@
"jtype": "jfloatArray",
"jtypestr": "[F",
"JavaObject": true,
"FromJavaBegin": "CriticalJFloatArrayRef{env, ",
"FromJavaBegin": "CriticalJSpan<const jfloat>{env, ",
"FromJavaEnd": "}",
"ToJavaBegin": "MakeJFloatArray(env, ",
"ToJavaEnd": ")",
@@ -334,7 +334,7 @@
"jtype": "jdoubleArray",
"jtypestr": "[D",
"JavaObject": true,
"FromJavaBegin": "CriticalJDoubleArrayRef{env, ",
"FromJavaBegin": "CriticalJSpan<const jdouble>{env, ",
"FromJavaEnd": "}",
"ToJavaBegin": "MakeJDoubleArray(env, ",
"ToJavaEnd": ")",

View File

@@ -1262,7 +1262,7 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_setServer__I_3Ljava_lang_Strin
"serverNames and ports arrays must be the same size");
return;
}
jint* portInts = env->GetIntArrayElements(ports, nullptr);
JSpan<const jint> portInts{env, ports};
if (!portInts) {
return;
}
@@ -1282,7 +1282,6 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_setServer__I_3Ljava_lang_Strin
servers.emplace_back(
std::make_pair(std::string_view{names.back()}, portInts[i]));
}
env->ReleaseIntArrayElements(ports, portInts, JNI_ABORT);
nt::SetServer(inst, servers);
}

View File

@@ -72,23 +72,23 @@ Java_edu_wpi_first_math_WPIMathJNI_dareDetailABQR
(JNIEnv* env, jclass, jdoubleArray A, jdoubleArray B, jdoubleArray Q,
jdoubleArray R, jint states, jint inputs, jdoubleArray S)
{
JDoubleArrayRef nativeA{env, A};
JDoubleArrayRef nativeB{env, B};
JDoubleArrayRef nativeQ{env, Q};
JDoubleArrayRef nativeR{env, R};
JSpan<const jdouble> nativeA{env, A};
JSpan<const jdouble> nativeB{env, B};
JSpan<const jdouble> nativeQ{env, Q};
JSpan<const jdouble> nativeR{env, R};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Amat{nativeA.array().data(), states, states};
Amat{nativeA.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Bmat{nativeB.array().data(), states, inputs};
Bmat{nativeB.data(), states, inputs};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Qmat{nativeQ.array().data(), states, states};
Qmat{nativeQ.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Rmat{nativeR.array().data(), inputs, inputs};
Rmat{nativeR.data(), inputs, inputs};
Eigen::MatrixXd RmatCopy{Rmat};
auto R_llt = RmatCopy.llt();
@@ -109,27 +109,27 @@ Java_edu_wpi_first_math_WPIMathJNI_dareDetailABQRN
(JNIEnv* env, jclass, jdoubleArray A, jdoubleArray B, jdoubleArray Q,
jdoubleArray R, jdoubleArray N, jint states, jint inputs, jdoubleArray S)
{
JDoubleArrayRef nativeA{env, A};
JDoubleArrayRef nativeB{env, B};
JDoubleArrayRef nativeQ{env, Q};
JDoubleArrayRef nativeR{env, R};
JDoubleArrayRef nativeN{env, N};
JSpan<const jdouble> nativeA{env, A};
JSpan<const jdouble> nativeB{env, B};
JSpan<const jdouble> nativeQ{env, Q};
JSpan<const jdouble> nativeR{env, R};
JSpan<const jdouble> nativeN{env, N};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Amat{nativeA.array().data(), states, states};
Amat{nativeA.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Bmat{nativeB.array().data(), states, inputs};
Bmat{nativeB.data(), states, inputs};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Qmat{nativeQ.array().data(), states, states};
Qmat{nativeQ.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Rmat{nativeR.array().data(), inputs, inputs};
Rmat{nativeR.data(), inputs, inputs};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Nmat{nativeN.array().data(), states, inputs};
Nmat{nativeN.data(), states, inputs};
Eigen::MatrixXd Rcopy{Rmat};
auto R_llt = Rcopy.llt();
@@ -150,23 +150,23 @@ Java_edu_wpi_first_math_WPIMathJNI_dareABQR
(JNIEnv* env, jclass, jdoubleArray A, jdoubleArray B, jdoubleArray Q,
jdoubleArray R, jint states, jint inputs, jdoubleArray S)
{
JDoubleArrayRef nativeA{env, A};
JDoubleArrayRef nativeB{env, B};
JDoubleArrayRef nativeQ{env, Q};
JDoubleArrayRef nativeR{env, R};
JSpan<const jdouble> nativeA{env, A};
JSpan<const jdouble> nativeB{env, B};
JSpan<const jdouble> nativeQ{env, Q};
JSpan<const jdouble> nativeR{env, R};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Amat{nativeA.array().data(), states, states};
Amat{nativeA.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Bmat{nativeB.array().data(), states, inputs};
Bmat{nativeB.data(), states, inputs};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Qmat{nativeQ.array().data(), states, states};
Qmat{nativeQ.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Rmat{nativeR.array().data(), inputs, inputs};
Rmat{nativeR.data(), inputs, inputs};
try {
Eigen::MatrixXd result =
@@ -191,27 +191,27 @@ Java_edu_wpi_first_math_WPIMathJNI_dareABQRN
(JNIEnv* env, jclass, jdoubleArray A, jdoubleArray B, jdoubleArray Q,
jdoubleArray R, jdoubleArray N, jint states, jint inputs, jdoubleArray S)
{
JDoubleArrayRef nativeA{env, A};
JDoubleArrayRef nativeB{env, B};
JDoubleArrayRef nativeQ{env, Q};
JDoubleArrayRef nativeR{env, R};
JDoubleArrayRef nativeN{env, N};
JSpan<const jdouble> nativeA{env, A};
JSpan<const jdouble> nativeB{env, B};
JSpan<const jdouble> nativeQ{env, Q};
JSpan<const jdouble> nativeR{env, R};
JSpan<const jdouble> nativeN{env, N};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Amat{nativeA.array().data(), states, states};
Amat{nativeA.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Bmat{nativeB.array().data(), states, inputs};
Bmat{nativeB.data(), states, inputs};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Qmat{nativeQ.array().data(), states, states};
Qmat{nativeQ.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Rmat{nativeR.array().data(), inputs, inputs};
Rmat{nativeR.data(), inputs, inputs};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Nmat{nativeN.array().data(), states, inputs};
Nmat{nativeN.data(), states, inputs};
try {
Eigen::MatrixXd result =
@@ -235,11 +235,11 @@ JNIEXPORT void JNICALL
Java_edu_wpi_first_math_WPIMathJNI_exp
(JNIEnv* env, jclass, jdoubleArray src, jint rows, jdoubleArray dst)
{
JDoubleArrayRef arrayBody{env, src};
JSpan<const jdouble> arrayBody{env, src};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Amat{arrayBody.array().data(), rows, rows};
Amat{arrayBody.data(), rows, rows};
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Aexp =
Amat.exp();
@@ -256,11 +256,11 @@ Java_edu_wpi_first_math_WPIMathJNI_pow
(JNIEnv* env, jclass, jdoubleArray src, jint rows, jdouble exponent,
jdoubleArray dst)
{
JDoubleArrayRef arrayBody{env, src};
JSpan<const jdouble> arrayBody{env, src};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Amat{arrayBody.array().data(), rows, rows}; // NOLINT
Amat{arrayBody.data(), rows, rows}; // NOLINT
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Apow =
Amat.pow(exponent);
@@ -331,16 +331,16 @@ Java_edu_wpi_first_math_WPIMathJNI_isStabilizable
(JNIEnv* env, jclass, jint states, jint inputs, jdoubleArray aSrc,
jdoubleArray bSrc)
{
JDoubleArrayRef nativeA{env, aSrc};
JDoubleArrayRef nativeB{env, bSrc};
JSpan<const jdouble> nativeA{env, aSrc};
JSpan<const jdouble> nativeB{env, bSrc};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
A{nativeA.array().data(), states, states};
A{nativeA.data(), states, states};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
B{nativeB.array().data(), states, inputs};
B{nativeB.data(), states, inputs};
bool isStabilizable =
frc::IsStabilizable<Eigen::Dynamic, Eigen::Dynamic>(A, B);
@@ -382,7 +382,7 @@ Java_edu_wpi_first_math_WPIMathJNI_toPathweaverJson
{
try {
auto trajectory =
CreateTrajectoryFromElements(JDoubleArrayRef{env, elements});
CreateTrajectoryFromElements(JSpan<const jdouble>{env, elements});
frc::TrajectoryUtil::ToPathweaverJson(trajectory,
JStringRef{env, path}.c_str());
} catch (std::exception& e) {
@@ -429,7 +429,7 @@ Java_edu_wpi_first_math_WPIMathJNI_serializeTrajectory
{
try {
auto trajectory =
CreateTrajectoryFromElements(JDoubleArrayRef{env, elements});
CreateTrajectoryFromElements(JSpan<const jdouble>{env, elements});
return MakeJString(env,
frc::TrajectoryUtil::SerializeTrajectory(trajectory));
} catch (std::exception& e) {
@@ -453,24 +453,20 @@ Java_edu_wpi_first_math_WPIMathJNI_rankUpdate
(JNIEnv* env, jclass, jdoubleArray mat, jint rows, jdoubleArray vec,
jdouble sigma, jboolean lowerTriangular)
{
// TODO: Replace with JSpan<jdouble> matBody{env, mat} when that exists
jdouble* matBody = env->GetDoubleArrayElements(mat, nullptr);
JDoubleArrayRef vecBody{env, vec};
JSpan<jdouble> matBody{env, mat};
JSpan<const jdouble> vecBody{env, vec};
Eigen::Map<
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>
L{matBody, rows, rows};
Eigen::Map<const Eigen::Vector<double, Eigen::Dynamic>> v{
vecBody.array().data(), rows};
L{matBody.data(), rows, rows};
Eigen::Map<const Eigen::Vector<double, Eigen::Dynamic>> v{vecBody.data(),
rows};
if (lowerTriangular == JNI_TRUE) {
Eigen::internal::llt_inplace<double, Eigen::Lower>::rankUpdate(L, v, sigma);
} else {
Eigen::internal::llt_inplace<double, Eigen::Upper>::rankUpdate(L, v, sigma);
}
// TODO: Remove this after JSpan transition
env->ReleaseDoubleArrayElements(mat, matBody, 0);
}
/*
@@ -483,15 +479,15 @@ Java_edu_wpi_first_math_WPIMathJNI_solveFullPivHouseholderQr
(JNIEnv* env, jclass, jdoubleArray A, jint Arows, jint Acols, jdoubleArray B,
jint Brows, jint Bcols, jdoubleArray dst)
{
JDoubleArrayRef nativeA{env, A};
JDoubleArrayRef nativeB{env, B};
JSpan<const jdouble> nativeA{env, A};
JSpan<const jdouble> nativeB{env, B};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Amat{nativeA.array().data(), Arows, Acols};
Amat{nativeA.data(), Arows, Acols};
Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
Bmat{nativeB.array().data(), Brows, Bcols};
Bmat{nativeB.data(), Brows, Bcols};
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Xmat =
Amat.fullPivHouseholderQr().solve(Bmat);

View File

@@ -201,7 +201,7 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_appendRaw
wpi::ThrowIndexOobException(env, "length must be >= 0");
return;
}
CriticalJByteArrayRef cvalue{env, value};
CriticalJSpan<const jbyte> cvalue{env, value};
if (static_cast<unsigned int>(start + length) > cvalue.size()) {
wpi::ThrowIndexOobException(
env, "start + len must be smaller than array length");
@@ -237,7 +237,7 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_appendRawBuffer
wpi::ThrowIndexOobException(env, "length must be >= 0");
return;
}
JByteArrayRef cvalue{env, value, start + length};
JSpan<const jbyte> cvalue{env, value, static_cast<size_t>(start + length)};
if (!cvalue) {
wpi::ThrowIllegalArgumentException(env,
"value must be a native ByteBuffer");
@@ -347,7 +347,7 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_appendBooleanArray
return;
}
reinterpret_cast<DataLog*>(impl)->AppendBooleanArray(
entry, JBooleanArrayRef{env, value}, timestamp);
entry, JSpan<const jboolean>{env, value}, timestamp);
}
/*
@@ -368,17 +368,15 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_appendIntegerArray
wpi::ThrowNullPointerException(env, "value is null");
return;
}
JLongArrayRef jarr{env, value};
JSpan<const jlong> jarr{env, value};
if constexpr (sizeof(jlong) == sizeof(int64_t)) {
reinterpret_cast<DataLog*>(impl)->AppendIntegerArray(
entry,
{reinterpret_cast<const int64_t*>(jarr.array().data()),
jarr.array().size()},
entry, {reinterpret_cast<const int64_t*>(jarr.data()), jarr.size()},
timestamp);
} else {
wpi::SmallVector<int64_t, 16> arr;
arr.reserve(jarr.size());
for (auto v : jarr.array()) {
for (auto v : jarr) {
arr.push_back(v);
}
reinterpret_cast<DataLog*>(impl)->AppendIntegerArray(entry, arr, timestamp);
@@ -404,7 +402,7 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_appendFloatArray
return;
}
reinterpret_cast<DataLog*>(impl)->AppendFloatArray(
entry, JFloatArrayRef{env, value}, timestamp);
entry, JSpan<const jfloat>{env, value}, timestamp);
}
/*
@@ -426,7 +424,7 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_appendDoubleArray
return;
}
reinterpret_cast<DataLog*>(impl)->AppendDoubleArray(
entry, JDoubleArrayRef{env, value}, timestamp);
entry, JSpan<const jdouble>{env, value}, timestamp);
}
/*

View File

@@ -275,11 +275,11 @@ JNIEXPORT jintArray JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_waitForObjects
(JNIEnv* env, jclass, jintArray handles)
{
JIntArrayRef handlesArr{env, handles};
JSpan<const jint> handlesArr{env, handles};
wpi::SmallVector<WPI_Handle, 8> signaledBuf;
signaledBuf.resize(handlesArr.size());
std::span<const WPI_Handle> handlesArr2{
reinterpret_cast<const WPI_Handle*>(handlesArr.array().data()),
reinterpret_cast<const WPI_Handle*>(handlesArr.data()),
handlesArr.size()};
auto signaled = wpi::WaitForObjects(handlesArr2, signaledBuf);
@@ -299,11 +299,11 @@ JNIEXPORT jintArray JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_waitForObjectsTimeout
(JNIEnv* env, jclass, jintArray handles, jdouble timeout)
{
JIntArrayRef handlesArr{env, handles};
JSpan<const jint> handlesArr{env, handles};
wpi::SmallVector<WPI_Handle, 8> signaledBuf;
signaledBuf.resize(handlesArr.size());
std::span<const WPI_Handle> handlesArr2{
reinterpret_cast<const WPI_Handle*>(handlesArr.array().data()),
reinterpret_cast<const WPI_Handle*>(handlesArr.data()),
handlesArr.size()};
bool timedOut;

View File

@@ -175,207 +175,242 @@ class JStringRef {
SmallString<128> m_str;
};
// Details for J*ArrayRef and CriticalJ*ArrayRef
namespace detail {
template <typename C, typename T>
class JArrayRefInner {
template <typename T>
struct ArrayHelper {};
#define WPI_JNI_ARRAYHELPER(T, F) \
template <> \
struct ArrayHelper<T> { \
using jarray_type = T##Array; \
static T* GetArrayElements(JNIEnv* env, jarray_type jarr) { \
return env->Get##F##ArrayElements(jarr, nullptr); \
} \
static void ReleaseArrayElements(JNIEnv* env, jarray_type jarr, T* elems, \
jint mode) { \
env->Release##F##ArrayElements(jarr, elems, mode); \
} \
};
WPI_JNI_ARRAYHELPER(jboolean, Boolean)
WPI_JNI_ARRAYHELPER(jbyte, Byte)
WPI_JNI_ARRAYHELPER(jshort, Short)
WPI_JNI_ARRAYHELPER(jint, Int)
WPI_JNI_ARRAYHELPER(jlong, Long)
WPI_JNI_ARRAYHELPER(jfloat, Float)
WPI_JNI_ARRAYHELPER(jdouble, Double)
#undef WPI_JNI_ARRAYHELPER
template <typename T>
concept JArrayType =
requires { typename ArrayHelper<std::remove_cv_t<T>>::jarray_type; };
template <typename CvSrc, typename Dest>
struct copy_cv {
private:
using U0 = std::remove_cv_t<Dest>;
using U1 = std::conditional_t<std::is_const_v<CvSrc>, const U0, U0>;
using U2 = std::conditional_t<std::is_volatile_v<CvSrc>, volatile U1, U1>;
public:
operator std::span<const T>() const { // NOLINT
return static_cast<const C*>(this)->array();
}
using type = U2;
};
/**
* Specialization of JArrayRefBase to provide std::string_view conversion
* and span<const uint8_t> conversion.
*/
template <typename C>
class JArrayRefInner<C, jbyte> {
public:
operator std::string_view() const { return str(); }
template <typename CvSrc, typename Dest>
using copy_cv_t = typename copy_cv<CvSrc, Dest>::type;
std::string_view str() const {
auto arr = static_cast<const C*>(this)->array();
template <typename From, typename To>
constexpr bool is_qualification_convertible_v =
!(std::is_const_v<From> && !std::is_const_v<To>)&&!(
std::is_volatile_v<From> && !std::is_volatile_v<To>);
/**
* Helper class for working with JNI arrays.
*
* This class exposes an is_valid() member and an explicit conversion to bool
* which indicate if the span is valid. Operations on invalid spans are
* undefined.
*
* Note that Set<PrimitiveType>ArrayRegion may be faster for pure writes since
* it avoids copying the elements from Java to C++.
*
* @tparam T The element type of the array (e.g., jdouble).
* @tparam IsCritical If true, Get/ReleasePrimitiveArrayCritical will be used
* instead of Get/Release\<PrimitiveType\>ArrayElements.
* @tparam Size The number of elements in the span.
*/
template <JArrayType T, bool IsCritical, size_t Size = std::dynamic_extent>
class JSpanBase {
using ArrHelper = ArrayHelper<std::remove_cv_t<T>>;
using jarray_type = typename ArrHelper::jarray_type;
public:
JSpanBase(const JSpanBase&) = delete;
JSpanBase& operator=(const JSpanBase&) = delete;
JSpanBase(JSpanBase&& other)
: m_valid{other.m_valid},
m_env{other.m_env},
m_jarr{other.m_jarr},
m_size{other.m_size},
m_elements{other.m_elements} {
other.m_jarr = nullptr;
other.m_elements = nullptr;
}
JSpanBase& operator=(JSpanBase&& other) {
m_valid = other.m_valid;
m_env = other.m_env;
m_jarr = other.m_jarr;
m_size = other.m_size;
m_elements = other.m_elements;
other.m_valid = false;
other.m_jarr = nullptr;
other.m_elements = nullptr;
return *this;
}
JSpanBase(JNIEnv* env, jobject bb, size_t size)
requires(!IsCritical)
: m_valid{Size == std::dynamic_extent || size == Size},
m_env{env},
m_jarr{nullptr},
m_size{size},
m_elements{static_cast<std::remove_cv_t<T>*>(
bb ? env->GetDirectBufferAddress(bb) : nullptr)} {
if (!bb) {
errs() << "JSpan was passed a null pointer at \n"
<< GetJavaStackTrace(env);
}
}
JSpanBase(JNIEnv* env, jarray_type jarr, size_t size)
: m_valid{Size == std::dynamic_extent || size == Size},
m_env{env},
m_jarr{jarr},
m_size{size},
m_elements{nullptr} {
if (jarr) {
if constexpr (IsCritical) {
m_elements = static_cast<std::remove_cv_t<T>*>(
env->GetPrimitiveArrayCritical(jarr, nullptr));
} else {
m_elements = ArrHelper::GetArrayElements(env, jarr);
}
} else {
errs() << "JSpan was passed a null pointer at \n"
<< GetJavaStackTrace(env);
}
}
JSpanBase(JNIEnv* env, jarray_type jarr)
: JSpanBase(env, jarr, jarr ? env->GetArrayLength(jarr) : 0) {}
~JSpanBase() {
if (m_jarr && m_elements) {
constexpr jint mode = std::is_const_v<T> ? JNI_ABORT : 0;
if constexpr (IsCritical) {
m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, mode);
} else {
ArrHelper::ReleaseArrayElements(m_env, m_jarr, m_elements, mode);
}
}
}
operator std::span<T, Size>() const { return array(); }
std::span<T, Size> array() const {
// If Size is dynamic_extent, can return empty span
// Unfortunately, sized spans will return a span over nullptr if m_elements
// is nullptr
if constexpr (Size == std::dynamic_extent) {
if (!m_elements) {
return {};
}
}
return std::span<T, Size>{m_elements, m_size};
}
T* begin() const { return m_elements; }
T* end() const { return m_elements + m_size; }
bool is_valid() const { return m_valid && m_elements != nullptr; }
explicit operator bool() const { return is_valid(); }
T* data() const { return m_elements; }
size_t size() const { return m_size; }
const T& operator[](size_t i) const { return m_elements[i]; }
T& operator[](size_t i)
requires(!std::is_const_v<T>)
{
return m_elements[i];
}
// Provide std::string_view and span<const uint8_t> conversions for jbyte
operator std::string_view() const
requires std::is_same_v<std::remove_cv_t<T>, jbyte>
{
return str();
}
std::string_view str() const
requires std::is_same_v<std::remove_cv_t<T>, jbyte>
{
auto arr = array();
if (arr.empty()) {
return {};
}
return {reinterpret_cast<const char*>(arr.data()), arr.size()};
}
std::span<const uint8_t> uarray() const {
auto arr = static_cast<const C*>(this)->array();
std::span<copy_cv_t<T, uint8_t>, Size> uarray() const
requires std::is_same_v<std::remove_cv_t<T>, jbyte>
{
auto arr = array();
if (arr.empty()) {
return {};
}
return {reinterpret_cast<const uint8_t*>(arr.data()), arr.size()};
}
};
/**
* Specialization of JArrayRefBase to handle both "long long" and "long" on
* 64-bit systems.
*/
template <typename C>
class JArrayRefInner<C, jlong> {
public:
// Support both "long long" and "long" on 64-bit systems
template <typename U>
requires(sizeof(U) == sizeof(jlong) && std::integral<U>)
operator std::span<const U>() const { // NOLINT
auto arr = static_cast<const C*>(this)->array();
requires(sizeof(U) == sizeof(jlong) && std::integral<U> &&
is_qualification_convertible_v<T, U>)
operator std::span<U, Size>() const
requires std::is_same_v<std::remove_cv_t<T>, jlong>
{
auto arr = array();
if (arr.empty()) {
return {};
}
return {reinterpret_cast<const U*>(arr.data()), arr.size()};
}
};
/**
* Base class for J*ArrayRef and CriticalJ*ArrayRef
*/
template <typename T>
class JArrayRefBase : public JArrayRefInner<JArrayRefBase<T>, T> {
public:
explicit operator bool() const { return this->m_elements != nullptr; }
std::span<const T> array() const {
if (!this->m_elements) {
return {};
}
return {this->m_elements, this->m_size};
return {reinterpret_cast<U*>(arr.data()), arr.size()};
}
size_t size() const { return this->m_size; }
T& operator[](size_t i) { return this->m_elements[i]; }
const T& operator[](size_t i) const { return this->m_elements[i]; }
JArrayRefBase(const JArrayRefBase&) = delete;
JArrayRefBase& operator=(const JArrayRefBase&) = delete;
JArrayRefBase(JArrayRefBase&& oth)
: m_env(oth.m_env),
m_jarr(oth.m_jarr),
m_size(oth.m_size),
m_elements(oth.m_elements) {
oth.m_jarr = nullptr;
oth.m_elements = nullptr;
}
JArrayRefBase& operator=(JArrayRefBase&& oth) {
this->m_env = oth.m_env;
this->m_jarr = oth.m_jarr;
this->m_size = oth.m_size;
this->m_elements = oth.m_elements;
oth.m_jarr = nullptr;
oth.m_elements = nullptr;
return *this;
}
protected:
JArrayRefBase(JNIEnv* env, T* elements, size_t size) {
this->m_env = env;
this->m_jarr = nullptr;
this->m_size = size;
this->m_elements = elements;
}
JArrayRefBase(JNIEnv* env, jarray jarr, size_t size) {
this->m_env = env;
this->m_jarr = jarr;
this->m_size = size;
this->m_elements = nullptr;
}
JArrayRefBase(JNIEnv* env, jarray jarr)
: JArrayRefBase(env, jarr, jarr ? env->GetArrayLength(jarr) : 0) {}
private:
bool m_valid;
JNIEnv* m_env;
jarray m_jarr = nullptr;
jarray_type m_jarr = nullptr;
size_t m_size;
T* m_elements;
std::remove_cv_t<T>* m_elements;
};
} // namespace detail
// Java array / DirectBuffer reference.
template <typename T, size_t Extent = std::dynamic_extent>
using JSpan = detail::JSpanBase<T, false, Extent>;
#define WPI_JNI_JARRAYREF(T, F) \
class J##F##ArrayRef : public detail::JArrayRefBase<T> { \
public: \
J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \
: detail::JArrayRefBase<T>( \
env, \
static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \
len) { \
if (!bb) { \
errs() << "JArrayRef was passed a null pointer at \n" \
<< GetJavaStackTrace(env); \
} \
} \
J##F##ArrayRef(JNIEnv* env, T##Array jarr, int len) \
: detail::JArrayRefBase<T>(env, jarr, len) { \
if (jarr) { \
m_elements = env->Get##F##ArrayElements(jarr, nullptr); \
} else { \
errs() << "JArrayRef was passed a null pointer at \n" \
<< GetJavaStackTrace(env); \
} \
} \
J##F##ArrayRef(JNIEnv* env, T##Array jarr) \
: detail::JArrayRefBase<T>(env, jarr) { \
if (jarr) { \
m_elements = env->Get##F##ArrayElements(jarr, nullptr); \
} else { \
errs() << "JArrayRef was passed a null pointer at \n" \
<< GetJavaStackTrace(env); \
} \
} \
~J##F##ArrayRef() { \
if (m_jarr && m_elements) { \
m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr), \
m_elements, JNI_ABORT); \
} \
} \
}; \
\
class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> { \
public: \
CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr, int len) \
: detail::JArrayRefBase<T>(env, jarr, len) { \
if (jarr) { \
m_elements = \
static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \
} else { \
errs() << "JArrayRef was passed a null pointer at \n" \
<< GetJavaStackTrace(env); \
} \
} \
CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \
: detail::JArrayRefBase<T>(env, jarr) { \
if (jarr) { \
m_elements = \
static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \
} else { \
errs() << "JArrayRef was passed a null pointer at \n" \
<< GetJavaStackTrace(env); \
} \
} \
~CriticalJ##F##ArrayRef() { \
if (m_jarr && m_elements) { \
m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \
} \
} \
};
WPI_JNI_JARRAYREF(jboolean, Boolean)
WPI_JNI_JARRAYREF(jbyte, Byte)
WPI_JNI_JARRAYREF(jshort, Short)
WPI_JNI_JARRAYREF(jint, Int)
WPI_JNI_JARRAYREF(jlong, Long)
WPI_JNI_JARRAYREF(jfloat, Float)
WPI_JNI_JARRAYREF(jdouble, Double)
#undef WPI_JNI_JARRAYREF
template <typename T, size_t Extent = std::dynamic_extent>
using CriticalJSpan = detail::JSpanBase<T, true, Extent>;
//
// Conversions from C++ to Java objects