Как использовать JNI для вызова MEMCMP из Java - PullRequest
0 голосов
/ 07 октября 2010

Мне нужно сравнить 2-байтовые массивы и узнать, какой из них больше или равны ли они (просто равно или мало). Массивы байтов представляют строковое значение из 15 символов или более. Это сравнение значительно повторяется в моем коде.

Я хотел бы улучшить сравнение массива пока, используя эквивалентный C ++ метод memcmp в Java (надеюсь, JNI) Я нашел пример использования DLLImport в C #, поэтому я надеюсь, что вызов JNI также может быть применен.

Вот сегмент кода C #:

[DllImport("msvcrt.dll")]
    unsafe static extern int memcmp(void* b1, void* b2, long count);

    unsafe static int ByteArrayCompare1(byte[] b1, int b1Index, int b1Length, byte[] b2, int b2Index, int b2Length)
    {
        CompareCount++;
        fixed (byte* p1 = b1)
        fixed (byte* p2 = b2)
        {
            int cmp = memcmp(p1 + b1Index, p2 + b2Index, Math.Min(b1Length, b2Length));
            if (cmp == 0)
            {
                cmp = b1Length.CompareTo(b2Length);
            }

            return cmp;
        }
    }

Кто-нибудь знает, как реализовать это в Java?

Заранее спасибо,

Diana

Ответы [ 3 ]

2 голосов
/ 07 октября 2010

Вы уверены, что ваш код тратит значительное время на эти сравнения?Я бы предложил вызвать функцию Java на данный момент, а затем синхронизировать ее;если вам все еще нужно, вы можете добавить JNI / JNA.

Помните, что, добавляя JNI, вы значительно увеличиваете вероятность ошибок и ограничивает свою программу только для архитектур, для которых вы компилируете библиотеку.

0 голосов
/ 17 октября 2010

Просто возьмите следующий код и посмотрите, достаточно ли он быстр.

package so3883485;

import java.util.concurrent.atomic.AtomicLong;

public class ByteArrayUtils {

  static final AtomicLong COMPARE_COUNT = new AtomicLong(0);

  public static int compare(byte[] b1, int b1Index, int b1Length, byte[] b2, int b2Index, int b2Length) {
    COMPARE_COUNT.incrementAndGet();

    final int commonLength = Math.min(b1Length, b2Length);
    for (int i = 0; i < commonLength; i++) {
      final byte byte1 = b1[b1Index + i];
      final byte byte2 = b2[b2Index + i];
      if (byte1 != byte2) {
        return (byte1 < byte2) ? -1 : 1;
      }
    }

    if (b1Length != b2Length) {
      return (b1Length < b2Length) ? -2 : 2;
    }

    return 0;
  }

}

И какой-нибудь модульный тест, чтобы убедиться, что базовые случаи работают как положено.

package so3883485;

import static org.junit.Assert.*;
import static so3883485.ByteArrayUtils.*;

import org.junit.Test;

public class ByteArrayUtilsTest {

  @Test
  public void test() {
    byte[] bytes = { 1, 2, 3, 4, 5 };
    assertEquals(0, compare(bytes, 0, bytes.length, bytes, 0, bytes.length));
    assertEquals(0, compare(bytes, 0, 0, bytes, 0, 0));
    assertEquals(-2, compare(bytes, 0, 0, bytes, 0, 1));
    assertEquals(2, compare(bytes, 0, 1, bytes, 0, 0));
    assertEquals(-1, compare(bytes, 1, 1, bytes, 2, 1));
    assertEquals(1, compare(bytes, 2, 1, bytes, 1, 1));
  }
}
0 голосов
/ 07 октября 2010

Вы можете использовать JNI, но у Java есть разновидность JNI, называемая JNA (Java Native Access) , которая позволяет получать доступ к общим библиотекам напрямую, без необходимости использования интерфейса JNI, обернутого вокруг них. так что вы можете использовать это для прямого доступа к memcmp:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

public class Test {
    public interface CStdLib extends Library {
        int memcmp(Pointer s1, Pointer s2, int n);
    }

    public static void main(String[] args) {
        CStdLib c = (CStdLib)Native.loadLibrary("msvcrt", CStdLib.class);
        c.memcmp(...);
    }
}

Я не проверял вышеизложенное, и я не уверен, в частности, в сигнатуре memcmp, поскольку она требует void* и size_t, которые оба не имеют очевидных эквивалентов Java, но имеют некоторые различия это должно работать правильно

(Атрибуция: я взял некоторую информацию о JNA из другого моего ответа )

...