【问题标题】:SWIG typemap uint8_t* from C/C++ to java.nio.ByteBuffer从 C/C++ 到 java.nio.ByteBuffer 的 SWIG 类型映射 uint8_t*
【发布时间】:2017-05-09 04:07:18
【问题描述】:

我正在尝试将输入和输出缓冲区从 C++ 传递给 java 类。 出于效率原因,我需要使用 ByteBuffer。

两个缓冲区都在 C++ 部分中分配,我需要将它们传递给 java 函数,该函数将使用输入缓冲区进行一些计算并将结果写入输出缓冲区。

以下是 C++ 外观的简化示例:

// SWIG mapped with %feature("director") JavaDelegate;
class JavaDelegate {
public:
    JavaDelegate() {}
    virtual ~JavaDelegate() {}
    virtual int compute(const uint8_t* input, size_t inSize,
                        uint8_t* output, size_t maxOutSize,
                        int someFlag) = 0;
};

// assume inputBuf is filled with valid data
std::vector<uint8_t> inputBuf;
std::vector<uint8_t> outputBuf(10000);

// delegate also points to a valid SWIG mapped class
JavaDelegate* delegate;

void computeOutput() {
   int someFlag = 1;
   int numValuesComputed = delegate->compute(inputBuf.data(), inputBuf.size(), 
                                             outputBuf.data(), outputBuf.size(), 
                                             someFlag);
   std::cout << "Computed " << numValuesComputed << " value from input.\n";
}

在 Java 方面,我想实现这一点(JavaDelegate 类已由 SWIG 生成):

public class Delegate extends JavaDelegate {

    public long compute(java.nio.ByteBuffer input, 
                        java.nio.ByteBuffer output, 
                        long someFlag) 
    {
        // read input
        // compute something n values from m input values
        // write result to output
        return numOutputValues;
    }
}

问题是,我根本不知道如何使用类型映射将普通的 char* 包装到 ByteBuffer,尤其是结合为抽象基类打开的 SWIG 导演功能。 我知道如何将 ByteBuffer 从 Java 传递到 C++,但我不知道如何做相反的事情。

任何帮助表示赞赏!

【问题讨论】:

  • 我会将 DirectByteBuffer 从 Java 传递给 C++ 以供其填充,您可以通过更改地址和容量来避免复制数据。
  • 输出缓冲区实际上是一个硬件缓冲区,所以我不能真正从java中分配它。当然我可以在之后将它复制回硬件缓冲区,但如果可能的话,我更愿意直接将它映射到 java。
  • 感谢您的帮助,但这是为它创建一个 SWIG 类型图。例如。从Java到C++的路在github.com/swig/swig/blob/master/Lib/java/various.i已经搞定了,但是反过来就没了。

标签: java c++ swig


【解决方案1】:

前言:这不是 SWIG 式的解决方案,这是通用的,我发现 this 与您的问题有些相关


首先,据我所知,Java 中没有 ref 参数,因此直接从 C++ 传递它不是一种选择,除非您准备好更改签名并将其作为返回值。这可以通过从 Java 传递 typewrapper 并在其中使用 C++ 创建/设置缓冲区来规避,例如:

public class BufferWrapper {
    private ByteBuffer mBuffer;

    public void setBuffer(ByteBuffer buffer) {
        mBuffer = buffer;
    }
} 

只需将它传递给 C++ 并让它分配并将缓冲区设置为包装器。

NewDirectByteBuffer JNI 函数可以满足您的需求:

分配并返回一个直接的 java.nio.ByteBuffer 引用 从内存地址地址开始并扩展的内存块 容量字节。

调用此函数并返回结果的本机代码 字节缓冲区对象到 Java 级代码应确保缓冲区 指可读取的有效内存区域,并且, 如果合适,写作。试图访问无效内存 Java 代码中的位置将返回任意值,没有 可见效果,或引发未指定的异常。


PS 我们本可以采用其他方式 - ByteBuffer 具有 wrap 方法,可以让您包装现有的 byte[] 缓冲区,这不完全是 char*,但我们可以将它们结合起来(看看这个 answer)。

深入了解您的 Jni 方法实现:

 jsize n = sizeof(yourBuf);
 jbyteArray arr = (*env)->NewByteArray(env, n);
 (*env)->SetByteArrayRegion(env,arr,0,n, (jbyte*)yourBuf);

但是请注意,根据doc,此功能会导致复制而不仅仅是包装,所以我注定它在这里不是很有帮助

【讨论】:

  • 我认为你的答案是正确的。我发现了这个svn.apache.org/repos/asf/qpid/branches/address-refactor2/qpid/…,它的作用与你所描述的非常相似。我也可以更改我的签名。现在,我正在尝试传递一个跟踪数据指针的包装器。这似乎是去这里的方式。一旦我得到它的工作,我会发布完整的代码。谢谢奥列格!
  • 我需要做同样的事情 - 你还有那个代码吗?
【解决方案2】:

一种方法是扩展 C++ 类以返回一个 ByteBuffer。粗略地说,可以这样处理:

%extend some::namespace::Buffer {
    jobject byteBuffer() {
        if (cached_jvm != 0) {
            JNIEnv *env = JNU_GetEnv();
            return env->NewDirectByteBuffer($self->get(), $self->size());
        }
    }
}

此外,您需要在 swig.i 文件中的某处使用此代码来缓存启动时的 jenv。

%{
#include <stdexcept>
#include "jni.h"

static JavaVM *cached_jvm = 0;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
  cached_jvm = jvm;
  return JNI_VERSION_1_2;
}

static JNIEnv * JNU_GetEnv() {
  JNIEnv *env;
  jint rc = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_2);
  if (rc == JNI_EDETACHED)
    throw std::runtime_error("current thread not attached");
  if (rc == JNI_EVERSION)
    throw std::runtime_error("jni version not supported");
  return env;
}
%}

您也许可以在不启用导演功能支持的情况下逃脱。

现在您可以像这样在 Java 中调用扩展函数:

ByteBuffer bb = (ByteBuffer)nativeBufferReference.byteBuffer();

【讨论】:

    猜你喜欢
    • 2016-11-26
    • 1970-01-01
    • 1970-01-01
    • 2019-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多