2014-08-29 4 views
4

Есть ли способ получить прямое ByteBuffer нулевое положение относительно другого, учитывая только два объекта ByteBuffer, если известно, что это подпоследовательность другого буфера?Получить прямое положение среза ByteBuffer относительно исходного ByteBuffer

Я знаю, что это может быть сделано с помощью непрямого массива ценных ByteBuffer используя arrayOffset() метод следующим образом:

int getRelativeBufferOffset(ByteBuffer parentBuffer, ByteBuffer childBuffer) 
{ 
    return childBuffer.arrayOffset() - parentBuffer.arrayOffset(); 
} 

void example() 
{ 
    ByteBuffer buffer1 = ByteBuffer.allocate(10000); 
    buffer1 .position(22); 
    ByteBuffer buffer2 = buffer1.slice(); 
    buffer2.position(55); 
    ByteBuffer buffer3 = buffer2.slice(); 

    // returns 22 
    getRelativeBufferOffset(buffer1, buffer2); 

    // returns 55 
    getRelativeBufferOffset(buffer2, buffer3); 

    // returns 77 
    getRelativeBufferOffset(buffer1, buffer3); 
} 

Я думаю, что нет ничего, что существует свободный для прямых буферов , Чтобы получить что-то подобное, лучшим вариантом, о котором я могу думать, является расширение ByteBuffer, чтобы сохранить ссылку на буфер, из которого он был создан (родительский буфер), и нулевую позицию относительно нулевой позиции родителя, в которой он был создан.

EDIT: Раздражающе выглядит, что я не могу продлить ByteBuffer, потому что ни один из его конструкторов не виден. Наверное, мне придется написать какой-то класс оболочки.

ответ

1

Возможно, используя отражающий. Но в зависимости от того, чего вы хотите достичь, вы должны рассмотреть альтернативные решения. Не понятно, для какой цели вам нужно это смещение. «Прагматичная» рекомендация будет обернуть буфера в простой, собственный класс, как

class SlicedBuffer { 
    int getBuffer() { ... } 
    Buffer getParent() { ... } 
    int getOffsetToParent() { ... } 
} 

и работать с этим, но это не ясно, является ли это применимо в вашем случае.

Я отправлю код с помощью отражения здесь, но обратите внимание, что

// Many things... 
// ... can go ... 
// ... wrong when... 
// ... using reflection 

так это только демонстрация:

import java.lang.reflect.Field; 
import java.nio.Buffer; 
import java.nio.ByteBuffer; 

public class DirectByteBufferSliceOffsetsTest 
{ 
    public static void main(String[] args) 
    { 
     testArray(); 
     testDirect(); 
    } 

    private static void testArray() 
    { 
     System.out.println("Array: "); 

     ByteBuffer buffer1 = ByteBuffer.allocate(10000); 
     buffer1.position(22); 
     ByteBuffer buffer2 = buffer1.slice(); 
     buffer2.position(55); 
     ByteBuffer buffer3 = buffer2.slice(); 

     // prints 22 
     System.out.println(getRelativeBufferOffsetArray(buffer1, buffer2)); 

     // prints 55 
     System.out.println(getRelativeBufferOffsetArray(buffer2, buffer3)); 

     // prints 77 
     System.out.println(getRelativeBufferOffsetArray(buffer1, buffer3)); 
    } 

    private static int getRelativeBufferOffsetArray(
     ByteBuffer parentBuffer, ByteBuffer childBuffer) 
    { 
     return childBuffer.arrayOffset() - parentBuffer.arrayOffset(); 
    } 


    private static void testDirect() 
    { 
     System.out.println("Direct: "); 

     ByteBuffer buffer1 = ByteBuffer.allocateDirect(10000); 
     buffer1.position(22); 
     ByteBuffer buffer2 = buffer1.slice(); 
     buffer2.position(55); 
     ByteBuffer buffer3 = buffer2.slice(); 

     // prints 22 
     System.out.println(getRelativeBufferOffsetDirect(buffer1, buffer2)); 

     // prints 55 
     System.out.println(getRelativeBufferOffsetDirect(buffer2, buffer3)); 

     // prints 77 
     System.out.println(getRelativeBufferOffsetDirect(buffer1, buffer3)); 
    } 

    private static int getRelativeBufferOffsetDirect(
     ByteBuffer parentBuffer, ByteBuffer childBuffer) 
    { 
     long parentAddress = getAddress(parentBuffer); 
     long childAddress = getAddress(childBuffer); 
     int offset = (int)(childAddress - parentAddress); 
     return offset; 
    } 

    private static long getAddress(Buffer buffer) 
    { 
     Field f = null; 
     try 
     { 
      f = Buffer.class.getDeclaredField("address"); 
      f.setAccessible(true); 
      return f.getLong(buffer); 
     } 
     catch (NoSuchFieldException e) 
     { 
      // Many things... 
      e.printStackTrace(); 
     } 
     catch (SecurityException e) 
     { 
      // ... can go ... 
      e.printStackTrace(); 
     } 
     catch (IllegalArgumentException e) 
     { 
      // ... wrong when... 
      e.printStackTrace(); 
     } 
     catch (IllegalAccessException e) 
     { 
      // ... using reflection 
      e.printStackTrace(); 
     } 
     finally 
     { 
      if (f != null) 
      { 
       f.setAccessible(false); 
      } 
     } 
     return 0; 
    } 
} 
+0

Решение отражения аккуратное, но и для безопасности я думаю, что я чтобы спуститься по маршруту обертки и инкапсулировать 'ByteBuffer' в класс RelativeByteBuffer. К сожалению, 'Buffer' не предоставляет методы' duplicate() 'и' slice() ', поэтому я не могу сделать что-то опрятное, как' RelativeBuffer '. – PaddyD

+0

Смещение предназначено для ведения журнала диагностики при непредвиденных данных в буфере - мне нужно знать смещение данных относительно другого буфера, из которого был создан буфер. – PaddyD

+0

Я считаю, что для * исключительно * диагностических целей решение отражения должно быть прекрасным. Я не уверен, насколько далеко намерение выполнить такой анализ должно повлиять на то, как моделируются в первую очередь. Но в конце концов, решение зависит от вас. И, возможно, кто-то другой пишет и отвечает, что лучше соответствует вашим потребностям. – Marco13