Java – some absolute methods on ByteBuffer are missing

Maybe I will solve this problem in the wrong way, but I lack some absolute put methods on ByteBuffer

If you look at ByteBuffer, you will find that most put methods have absolute and relative variables

Except:

>Write part of byte array to ByteBuffer. > Write ByteBuffer to ByteBuffer

.. And I need those

To specify the ByteBuffer method:

put(byte[] src,int offset,int length)
 put(ByteBuffer src)

However, it lacks:

put(int index,byte[] src,int length)
 put(int index,ByteBuffer src)

I have reason why I don't want to move the position pointer of the buffer, so I just want to use the absolute put method

Do you know why these methods are missing?

I can certainly emulate the missing method without moving the buffer position pointer, but this will involve looping over the source byte Javadoc makes it clear that these methods are more effective than moving, rather than looping and moving bytes one by one I believe in Javadoc because my tests show the same I need to squeeze as much speed out of the implementation as possible, so I certainly prefer to use any batch methods I can get... If they exist

Even ByteBuffer lacks an absolute get method for moving some byte arrays But I don't really need such a method at present But the strange thing is that it doesn't exist

Solution

One way to get the required method is to have the second ByteBuffer share the same memory so that you can change its location without changing its original location

Unfortunately, the slice method also does not take position parameters; Instead, it uses the current location of the original buffer So you can't:

dstBuffer.slice(100).put(srcBuffer);

Here are some ideas, there is no special order, except that it is the order I think of:

>If it fits the way you use the buffer, you can use slice() to prepare a copy of the buffer and keep it when you need to put the data in a location independent of the original location. > If the position you want to place absolutely is always greater than or equal to the position pointer of the original buffer, you can do the following:

dstBuffer.slice().position(desiredPosition - dstBuffer.position()).put(srcBuffer);

Unfortunately, because the position on the slice is not allowed to be negative, it cannot be placed in an earlier position Editor: it doesn't matter. I forgot the duplicate method See @ Boris Brodski's good answer

>If you do not use a direct byte buffer, system Arraycopy is simple and fast:

System.arraycopy(
    srcBuffer.array(),srcBuffer.arrayOffset() + srcBuffer.position(),dstBuffer.array(),dstBuffer.arrayOffset() + desiredPosition,srcBuffer.remaining()
);

>If concurrent access is not required, you can temporarily change the location of the buffer when absolute placement is required, and then put it back If you need concurrent access but thread contention is low, you can synchronize all access to the buffer (which may be obvious, but included for integrity):

synchronize (lock) {
    int originalPosition = dstBuffer.position();
    dstBuffer.position(desiredPosition);
    dstBuffer.put(srcBuffer);
    dstBuffer.position(originalPosition);
}

>If nothing else suits you, you can crack the buffer This is troublesome, but this is an example:

private static final sun.misc.Unsafe UNSAFE;
static {
    Object result = null;
    try {
        Class<?> klass = Class.forName("sun.misc.Unsafe");
        for (Field field : klass.getDeclaredFields()) {
            if (field.getType() == klass &&
                (field.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) ==
                    (Modifier.FINAL | Modifier.STATIC)) {
                field.setAccessible(true);
                result = field.get(null);
                break;
            }
        }
    } catch (Throwable t) {}
    UNSAFE = result == null ? null : (sun.misc.Unsafe)result;
}

private static final Field ADDRESS_FIELD;
static {
    Field f;
    try {
        f = Buffer.class.getDeclaredField("address");
        f.setAccessible(true);
    } catch (NoSuchFieldException | SecurityException e) {
        f = null;
    }
    ADDRESS_FIELD = f;
}


public static void absolutePut(ByteBuffer dstBuffer,int dstPosition,ByteBuffer srcBuffer) {
    if (!srcBuffer.isDirect()) {
        absolutePut(dstBuffer,dstPosition,srcBuffer.array(),srcBuffer.remaining());
        return;
    }

    if (UNSAFE != null && ADDRESS_FIELD != null && dstBuffer.isDirect()) {
        try {
            long dstAddress = (long)ADDRESS_FIELD.get(dstBuffer) + dstPosition;
            long srcAddress = (long)ADDRESS_FIELD.get(srcBuffer) + srcBuffer.position();
            UNSAFE.copyMemory(srcAddress,dstAddress,srcBuffer.remaining());
        } catch (illegalaccessexception e) {
            throw new RuntimeException(e);
        }
    } else {
        // fallback to basic loop
        for (int i = srcBuffer.position(); i < srcBuffer.limit(); i++) {
            dstBuffer.put(dstPosition + i,srcBuffer.get(i));
        }
    }
}

public static void absolutePut(ByteBuffer dstBuffer,int srcOffset,int length) {
    if (UNSAFE != null && ADDRESS_FIELD != null && dstBuffer.isDirect()) {
        try {
            long dstAddress = (long)ADDRESS_FIELD.get(dstBuffer) + dstPosition;
            UNSAFE.copyMemory(
                src,UNSAFE.arrayBaSEOffset(byte[].class) + srcOffset,null,length);
        } catch (illegalaccessexception e) {
            throw new RuntimeException(e);
        }
    } else {
        // fallback to System.arraycopy
        System.arraycopy(
            src,srcOffset,dstBuffer.arrayOffset() + dstPosition,length);
    }
}

I gave this code some minimal tests, mixed direct and indirect buffers, and it looks ok If reflection technology fails (for example, because you are in the applet security sandbox or the Java implementation is incompatible), it can fall back to a more concise method

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>