Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switch on enum in JNI?

Given:

enum Foo
{
  FIRST,
  SECOND
}

What is the JNI equivalent for the following code?

Foo foo = ...;
int value;
switch (foo)
{
  case FIRST:
    value = 1;
    break;
  case SECOND:
    value = 2;
    break;
}

I know I can use foo.equals(Foo.FIRST) from JNI, but I'd like to get the same performance as switch(enum). Any ideas?

like image 446
Gili Avatar asked Oct 24 '10 06:10

Gili


2 Answers

You can use a switch statement in your JNI code as well, if you:

  • Provide an integral value field in your Java enum class.
  • Define a parallel set of integral constants in C or C++ (e.g., by another enum).

The redundant definition introduces a risk of divergence. You can mitigate this by:

  • Heavily documenting the parallelism on both sides. This works best if the enumeration is small and changes infrequently.
  • Generating the code from a single source.

For example, in Java, you could have:

    public enum Foo {
            FIRST(0),
            SECOND(1);

            public int getValue() { return m_value; }

            private int m_value;
            private Foo( int value ) { m_value = value; }
    }

And in C++, you could have:

    enum Foo {
          FIRST = 0,
          SECOND = 1
    };

For a parallel enumeration, I personally always make the enum values explicit on the C/C++ side. Otherwise, a deletion of an enumerator on both sides can cause the values to diverge.

like image 29
Andy Thomas Avatar answered Sep 29 '22 06:09

Andy Thomas


You could have a process step that runs after the enum is compiled but before the JNI code is compiled. It would load the enum and output the values to a .h file. Your JNI code then includes this .h file.

Edit:

Here's some code that does this. It needs to be modified to accept arguments and to write to a file instead of System.out, but that's easy enough to do.

    URL u = new File("/home/adam/tmp").toURL();
    URLClassLoader loader = new URLClassLoader(new URL[] {u}, Test.class.getClassLoader());
    Class<? extends Enum> c = (Class<? extends Enum>) loader.loadClass("Color");
    PrintStream out = System.out;
    out.println("#ifndef COLOR_H");
    out.println("#define COLOR_H");
    for(Enum constant : c.getEnumConstants()) {
        out.println("#define " + c.getCanonicalName().replaceAll("\\.", "_") + "_" + constant.name() + " " + constant.ordinal());
    }
    out.println("#endif");
like image 53
Adam Crume Avatar answered Sep 29 '22 06:09

Adam Crume