bytedeco / javacpp

The missing bridge between Java and native C++
Other
4.43k stars 576 forks source link

Question related to std::function #759

Closed zaki699 closed 1 month ago

zaki699 commented 1 month ago

Hi Everyone,

I am facing some issues that I can't solve on my own. I tried to look at the code of Torch and TensorFlow but I could not find an answer to my issues.

Do you mind looking at it and tell me if you find a fix that will solve my problems?

namespace shaka {

 /// Encrypted stream information that is used to determine stream label.
  struct EncryptedStreamAttributes {
    enum StreamType {
      kUnknown,
      kVideo,
      kAudio,
    };

    StreamType stream_type = kUnknown;
    union OneOf {
      OneOf() {}

      struct {
        int width = 0;
        int height = 0;
        float frame_rate = 0;
        int bit_depth = 0;
      } video;

      struct {
        int number_of_channels = 0;
      } audio;
    } oneof;
  };
  /// Stream label function assigns a stream label to the stream to be
  /// encrypted. Stream label is used to associate KeyPair with streams. Streams
  /// with the same stream label always uses the same keyPair; Streams with
  /// different stream label could use the same or different KeyPairs.
  /// A default stream label function will be generated if not set.
  std::function<std::string(const EncryptedStreamAttributes& stream_attributes)>
      stream_label_func;
};
              .put(new Info("std::function<std::string(const shaka::EncryptionParams::EncryptedStreamAttributes&)>").pointerTypes("WriterBufferCallback"))    

@Properties(inherit = org.bytedeco.shakapackager.presets.packager.class)
public class WriterBufferCallback extends FunctionPointer {
    static {
        Loader.load();
    }

    /**
     * Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}.
     */
    public WriterBufferCallback(Pointer p) {
        super(p);
    }

    protected WriterBufferCallback() {
        allocate();
    }

    private native void allocate();

    public native @StdString @Cast({"", "char*"}) BytePointer call(@Const @ByRef EncryptionParams.EncryptedStreamAttributes tensor);
}

but then I've got the error

/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:2423:35: error: incompatible pointer types assigning to 'char ()(const shaka::EncryptionParams::EncryptedStreamAttributes &)' from 'std::function<std::string (const EncryptedStreamAttributes &)> ' (aka 'function<basic_string (const shaka::EncryptionParams::EncryptedStreamAttributes &)> ') if (rptr != NULL) rptr->ptr = &ptr->stream_label_func;

My second issue is related to std::map

/// Raw key encryption/decryption parameters, i.e. with key parameters provided.
struct RawKeyParams {
  /// An optional initialization vector. If not provided, a random `iv` will be
  /// generated. Note that this parameter should only be used during testing.
  /// Not needed for decryption.
  std::vector<uint8_t> iv;
  /// Inject a custom `pssh` or multiple concatenated `psshs`. If not provided,
  /// a common system pssh will be generated.
  /// Not needed for decryption.
  std::vector<uint8_t> pssh;

  using StreamLabel = std::string;
  struct KeyInfo {
    std::vector<uint8_t> key_id;
    std::vector<uint8_t> key;
    std::vector<uint8_t> iv;
  };
  /// Defines the KeyInfo for the streams. An empty `StreamLabel` indicates the
  /// default `KeyInfo`, which applies to all the `StreamLabels` not present in
  /// `key_map`.
  std::map<StreamLabel, KeyInfo> key_map;
};

Then In InfoMap

       .put( new Info("shaka::RawKeyParams::KeyInfo").valueTypes("RawKeyParams.KeyInfo"))
       .put(new Info("std::map<std::string,shaka::RawKeyParams::KeyInfo>").pointerTypes("StringKeyInfoMap").define())

And the JAVA generated

/** Raw key encryption/decryption parameters, i.e. with key parameters provided. */
@Namespace("shaka") @Properties(inherit = org.bytedeco.shakapackager.presets.packager.class)
public class RawKeyParams extends Pointer {
    static { Loader.load(); }
    /** Default native constructor. */
    public RawKeyParams() { super((Pointer)null); allocate(); }
    /** Native array allocator. Access with {@link Pointer#position(long)}. */
    public RawKeyParams(long size) { super((Pointer)null); allocateArray(size); }
    /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
    public RawKeyParams(Pointer p) { super(p); }
    private native void allocate();
    private native void allocateArray(long size);
    @Override public RawKeyParams position(long position) {
        return (RawKeyParams)super.position(position);
    }
    @Override public RawKeyParams getPointer(long i) {
        return new RawKeyParams((Pointer)this).offsetAddress(i);
    }

  /** An optional initialization vector. If not provided, a random {@code iv} will be
   *  generated. Note that this parameter should only be used during testing.
   *  Not needed for decryption. */
  public native @Cast("uint8_t*") @StdVector BytePointer iv(); public native RawKeyParams iv(BytePointer setter);
  /** Inject a custom {@code pssh} or multiple concatenated {@code psshs}. If not provided,
   *  a common system pssh will be generated.
   *  Not needed for decryption. */
  public native @Cast("uint8_t*") @StdVector BytePointer pssh(); public native RawKeyParams pssh(BytePointer setter);
  public static class KeyInfo extends Pointer {
      static { Loader.load(); }
      /** Default native constructor. */
      public KeyInfo() { super((Pointer)null); allocate(); }
      /** Native array allocator. Access with {@link Pointer#position(long)}. */
      public KeyInfo(long size) { super((Pointer)null); allocateArray(size); }
      /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
      public KeyInfo(Pointer p) { super(p); }
      private native void allocate();
      private native void allocateArray(long size);
      @Override public KeyInfo position(long position) {
          return (KeyInfo)super.position(position);
      }
      @Override public KeyInfo getPointer(long i) {
          return new KeyInfo((Pointer)this).offsetAddress(i);
      }

    public native @Cast("uint8_t*") @StdVector BytePointer key_id(); public native KeyInfo key_id(BytePointer setter);
    public native @Cast("uint8_t*") @StdVector BytePointer key(); public native KeyInfo key(BytePointer setter);
    public native @Cast("uint8_t*") @StdVector BytePointer iv(); public native KeyInfo iv(BytePointer setter);
  }

  /** Defines the KeyInfo for the streams. An empty {@code StreamLabel} indicates the
   *  default {@code KeyInfo}, which applies to all the {@code StreamLabels} not present in
   *  {@code key_map}. */
  public native @ByRef KeyInfoStringMap key_map(); public native RawKeyParams key_map(KeyInfoStringMap setter);
}
@Name("std::map<std::string,shaka::RawKeyParams::KeyInfo>") @Properties(inherit = org.bytedeco.shakapackager.presets.packager.class)
public class StringKeyInfoMap extends Pointer {
    static { Loader.load(); }
    /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
    public StringKeyInfoMap(Pointer p) { super(p); }
    public StringKeyInfoMap()       { allocate();  }
    private native void allocate();
    public native @Name("operator =") @ByRef StringKeyInfoMap put(@ByRef StringKeyInfoMap x);

    public boolean empty() { return size() == 0; }
    public native long size();

    @Index public native RawKeyParams.KeyInfo get(@StdString BytePointer i);
    public native StringKeyInfoMap put(@StdString BytePointer i, RawKeyParams.KeyInfo value);

    public native void erase(@ByVal Iterator pos);
    public native @ByVal Iterator begin();
    public native @ByVal Iterator end();
    @NoOffset @Name("iterator") public static class Iterator extends Pointer {
        public Iterator(Pointer p) { super(p); }
        public Iterator() { }

        public native @Name("operator ++") @ByRef Iterator increment();
        public native @Name("operator ==") boolean equals(@ByRef Iterator it);
        public native @Name("operator *().first") @MemberGetter @StdString BytePointer first();
        public native @Name("operator *().second") @MemberGetter RawKeyParams.KeyInfo second();
    }
}

But unfortunately I've got this compilation error


/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:8143:30: error: assigning to 'shaka::RawKeyParams::KeyInfo *' from incompatible type 'shaka::RawKeyParams::KeyInfo'; take the address with &
    rptr = ptr->operator *().second;
           ~~~~~~~~~~~~~~~~~~^~~~~~

/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:8200:12: error: assigning to 'shaka::RawKeyParams::KeyInfo *' from incompatible type 'mapped_type' (aka 'shaka::RawKeyParams::KeyInfo'); take the address with &
    rptr = (*ptr)[(std::basic_string< char >&)adapter0];
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:8273:50: error: no viable overloaded '='
    (*ptr)[(std::basic_string< char >&)adapter0] = ptr1;

And finally I've get some errors like this related to 'std::basic_string' to 'std::string :

/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:3080:76: error: no viable conversion from 'std::basic_string<char>' to 'std::string *' (aka 'basic_string<char> *')
        bool rval = (bool)shaka::File::ReadFileToString((const char*)ptr0, (std::basic_string< char >&)adapter1);

/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:3392:168: error: no viable conversion from 'std::basic_string<char>' to 'std::string *' (aka 'basic_string<char> *')
        bool rval = (bool)shaka::File::ParseCallbackFileName((std::basic_string< char >&)adapter0, (const shaka::BufferCallbackParams**)(arg1 == NULL ? NULL : &ptr1), (std::basic_string< char >&)adapter2);

Thanks for your help and your time.

saudet commented 1 month ago

/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:2423:35: error: incompatible pointer types assigning to 'char ()(const shaka::EncryptionParams::EncryptedStreamAttributes &)' from 'std::function<std::string (const EncryptedStreamAttributes &)> ' (aka 'function<basic_string (const shaka::EncryptionParams::EncryptedStreamAttributes &)> ') if (rptr != NULL) rptr->ptr = &ptr->stream_label_func;

You'll need to create an actual instance of std::function like this with Info.define: https://github.com/bytedeco/javacpp/wiki/Mapping-Recipes#defining-wrappers-for-basic-c-containers

       .put( new Info("shaka::RawKeyParams::KeyInfo").valueTypes("RawKeyParams.KeyInfo"))

You'll need to set Info.pointerTypes, not Info.valueTypes, like this: https://github.com/bytedeco/javacpp/wiki/Mapping-Recipes#specifying-names-to-use-in-java

zaki699 commented 1 month ago

Hi @saudet ,

I'm not sure to understand the created instance part. Did you mean like this ?:

       .put(new Info("std::function<std::string(const shaka::EncryptionParams::EncryptedStreamAttributes&)>").pointerTypes("StringEncryptedStreamAttributes").define())      

It seems to work fine. Annoyingly, it leads to another issue related to the class Packager.h

static std::string DefaultStreamLabelFunction(
      int max_sd_pixels,
      int max_hd_pixels,
      int max_uhd1_pixels,
      const EncryptionParams::EncryptedStreamAttributes& stream_attributes);

Generated Java:

public static native @StdString BytePointer DefaultStreamLabelFunction(
        int max_sd_pixels,
        int max_hd_pixels,
        int max_uhd1_pixels,
        EncryptionParams.EncryptedStreamAttributes stream_attributes);

Error

/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:5744:102: error: reference to type 'const EncryptionParams::EncryptedStreamAttributes' could not bind to an lvalue of type 'shaka::EncryptionParams::EncryptedStreamAttributes *'
        StringAdapter< char > radapter(shaka::Packager::DefaultStreamLabelFunction(arg0, arg1, arg2, ptr3));
                                                                                                     ^~~~
/Users/zak/Repo/javacpp-presets/shaka-packager/cppbuild/macosx-arm64/include/packager/packager.h:213:58: note: passing argument to parameter 'stream_attributes' here
      const EncryptionParams::EncryptedStreamAttributes& stream_attributes);

Thx

saudet commented 1 month ago

Looks like something is failing somewhere with EncryptionParams.EncryptedStreamAttributes...

zaki699 commented 1 month ago

I was currently updating this issue.

I manage to solve most of the errors (Thx to you). I have only 3 left :)

1) /Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:8104:16: error: assigning to 'signed char *' from incompatible type 'std::string'
        rptr = ptr->operator ()(*(const shaka::EncryptionParams::EncryptedStreamAttributes*)ptr0);

2) /Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:5333:24: error: no viable overloaded '='
        rptr = &((*ptr)=(*ptr0));

3) /Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:5013:24: error: no viable overloaded '='
        rptr = &((*ptr)=(*ptr0));

For Number 1:

JNIEXPORT jobject JNICALL Java_org_bytedeco_shakapackager_StringEncryptedStreamAttributes_call(JNIEnv* env, jobject obj, jobject arg0) {
    std::function<std::string(const shaka::EncryptionParams::EncryptedStreamAttributes&)>* ptr = (std::function<std::string(const shaka::EncryptionParams::EncryptedStreamAttributes&)>*)jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));
    if (ptr == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 9), "This pointer address is NULL.");
        return 0;
    }
    jlong position = env->GetLongField(obj, JavaCPP_positionFID);
    ptr += position;
    shaka::EncryptionParams::EncryptedStreamAttributes* ptr0 = arg0 == NULL ? NULL : (shaka::EncryptionParams::EncryptedStreamAttributes*)jlong_to_ptr(env->GetLongField(arg0, JavaCPP_addressFID));
    if (ptr0 == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 9), "Pointer address of argument 0 is NULL.");
        return 0;
    }
    jlong position0 = arg0 == NULL ? 0 : env->GetLongField(arg0, JavaCPP_positionFID);
    ptr0 += position0;
    jobject rarg = NULL;
    signed char* rptr;
    jthrowable exc = NULL;
    try {
        rptr = ptr->operator ()(*(const shaka::EncryptionParams::EncryptedStreamAttributes*)ptr0);
        if (rptr != NULL) {
            rarg = JavaCPP_createPointer(env, 27);
            if (rarg != NULL) {
                env->SetLongField(rarg, JavaCPP_addressFID, ptr_to_jlong(rptr));
            }
        }
    } catch (...) {
        exc = JavaCPP_handleException(env, 8);
    }

    if (exc != NULL) {
        env->Throw(exc);
    }
    return rarg;
}
@Properties(inherit = org.bytedeco.shakapackager.presets.packager.class)
public class StringEncryptedStreamAttributes_EncryptionParams_EncryptedStreamAttributes extends FunctionPointer {
    static { Loader.load(); }
    /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
    public    StringEncryptedStreamAttributes_EncryptionParams_EncryptedStreamAttributes(Pointer p) { super(p); }
    protected StringEncryptedStreamAttributes_EncryptionParams_EncryptedStreamAttributes() { allocate(); }
    private native void allocate();
    public native @StdString BytePointer call(@Const @ByRef EncryptionParams.EncryptedStreamAttributes arg0);
}

@NoOffset @Name("std::function<std::string(const shaka::EncryptionParams::EncryptedStreamAttributes&)>") @Properties(inherit = org.bytedeco.shakapackager.presets.packager.class)
public class StringEncryptedStreamAttributes extends Pointer {
    static { Loader.load(); }
    /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
    public StringEncryptedStreamAttributes(Pointer p) { super(p); }
    public StringEncryptedStreamAttributes(StringEncryptedStreamAttributes_EncryptionParams_EncryptedStreamAttributes value) { this(); put(value); }
    public StringEncryptedStreamAttributes()       { allocate();  }
    private native void allocate();
    public native @Name("operator =") @ByRef StringEncryptedStreamAttributes put(@ByRef StringEncryptedStreamAttributes x);

    public native @Name("operator =") @ByRef StringEncryptedStreamAttributes put(@ByRef StringEncryptedStreamAttributes_EncryptionParams_EncryptedStreamAttributes value);
    public native @Name("operator ()") BytePointer call(@Const @ByRef EncryptionParams.EncryptedStreamAttributes arg0);
}

It should return @StdString BytePointer instead of BytePointer only. I replaced it and the compiler does not produce an error. The problem is how to tell the parser to add it ? or I should just add it manually as a FunctionPointer.

public native @Name("operator ()") BytePointer call(@Const @ByRef EncryptionParams.EncryptedStreamAttributes arg0);

public native @Name("operator ()") @StdString BytePointer call(@Const @ByRef EncryptionParams.EncryptedStreamAttributes arg0);
saudet commented 1 month ago

There's probably something that needs to be fixed somewhere around here: https://github.com/bytedeco/javacpp/blob/1.5.10/src/main/java/org/bytedeco/javacpp/tools/Parser.java#L1778

zaki699 commented 1 month ago

I have one more issue that I am trying to fix but wow I'm lacking expertise on that one.

The compilation error:

/Users/zak/Repo/javacpp-presets/shaka-packager/target/native/org/bytedeco/shakapackager/macosx-arm64/jnipackager.cpp:5333:24: error: no viable overloaded '='
        rptr = &((*ptr)=(*ptr0));

InfoMap

       .put(new Info("std::function<int64_t(const std::string&,const void*,uint64_t)>").pointerTypes("Node2Fn").define())

JNI CPP

JNIEXPORT jobject JNICALL Java_org_bytedeco_shakapackager_NodeFn_put__Lorg_bytedeco_shakapackager_NodeFn_1BytePointer_1Pointer_1long_2(JNIEnv* env, jobject obj, jobject arg0) {
    std::function<int64_t(const std::string&,void*,uint64_t)>* ptr = (std::function<int64_t(const std::string&,void*,uint64_t)>*)jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));
    if (ptr == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 9), "This pointer address is NULL.");
        return 0;
    }
    jlong position = env->GetLongField(obj, JavaCPP_positionFID);
    ptr += position;
    JavaCPP_org_bytedeco_shakapackager_NodeFn_1BytePointer_1Pointer_1long* ptr0 = arg0 == NULL ? NULL : (JavaCPP_org_bytedeco_shakapackager_NodeFn_1BytePointer_1Pointer_1long*)jlong_to_ptr(env->GetLongField(arg0, JavaCPP_addressFID));
    if (ptr0 == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 9), "Pointer address of argument 0 is NULL.");
        return 0;
    }
    jlong position0 = arg0 == NULL ? 0 : env->GetLongField(arg0, JavaCPP_positionFID);
    ptr0 += position0;
    jobject rarg = NULL;
    std::function<int64_t(const std::string&,void*,uint64_t)>* rptr;
    jthrowable exc = NULL;
    try {
        rptr = &((*ptr)=(*ptr0));
        if (rptr == ptr) {
            rarg = obj;
        } else if (rptr != NULL) {
            rarg = JavaCPP_createPointer(env, 12);
            if (rarg != NULL) {
                env->SetLongField(rarg, JavaCPP_addressFID, ptr_to_jlong(rptr));
            }
        }
    } catch (...) {
        exc = JavaCPP_handleException(env, 8);
    }

    if (exc != NULL) {
        env->Throw(exc);
    }
    return rarg;
}
@Properties(inherit = org.bytedeco.shakapackager.presets.packager.class)
public class Node2Fn_BytePointer_Pointer_long extends FunctionPointer {
    static { Loader.load(); }
    /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
    public    Node2Fn_BytePointer_Pointer_long(Pointer p) { super(p); }
    protected Node2Fn_BytePointer_Pointer_long() { allocate(); }
    private native void allocate();
    public native  @Cast("int64_t") long call(@StdString BytePointer arg0,@Const Pointer arg1,@Cast("uint64_t") long arg2);
}

@NoOffset @Name("std::function<int64_t(const std::string&,const void*,uint64_t)>") @Properties(inherit = org.bytedeco.shakapackager.presets.packager.class)
public class Node2Fn extends Pointer {
    static { Loader.load(); }
    /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
    public Node2Fn(Pointer p) { super(p); }
    public Node2Fn(Node2Fn_BytePointer_Pointer_long value) { this(); put(value); }
    public Node2Fn()       { allocate();  }
    private native void allocate();
    public native @Name("operator =") @ByRef Node2Fn put(@ByRef Node2Fn x);

    public native @Name("operator =") @ByRef Node2Fn put(@ByRef Node2Fn_BytePointer_Pointer_long value);
    public native @Name("operator ()") long call(@StdString BytePointer arg0,@Const Pointer arg1,@Cast("uint64_t") long arg2);
}

I can't find where does the issue come from.

zaki699 commented 1 month ago

OK I found the issue. It was because of the missing @Const on the first function argument

The problem was here

    public native  @Cast("int64_t") long call(@StdString BytePointer arg0,@Const Pointer arg1,@Cast("uint64_t") long arg2);

and solved with

    public native  @Cast("int64_t") long call(@Const @StdString BytePointer arg0,@Const Pointer arg1,@Cast("uint64_t") long arg2);