2011-10-03 18 views
17

Tengo una clase que toma un ByteBuffer como argumento de constructor. ¿Hay alguna manera de evitar hacer copias defensivas para garantizar que el buffer no se modifique más allá de ese punto?¿Cómo evitar hacer copias defensivas de ByteBuffer?

ByteBuffer.isReadOnly() no garantiza que el propietario original no modifique el búfer. Para empeorar las cosas, no parece haber una forma de subclasificar a ByteBuffer. ¿Algunas ideas?

+1

1. Buena pregunta sobre buenas prácticas. – helios

+0

Suena como lo que necesita el destinatario es un búfer de bytes de escritura en escritura. –

Respuesta

2

Esto es lo mejor que podía hacer por ahora:

/** 
* Helper functions for java.nio.Buffer. 
* <p/> 
* @author Gili Tzabari 
*/ 
public final class Buffers 
{ 
    /** 
    * Returns a ByteBuffer that is identical but distinct from the original buffer. 
    * <p/> 
    * @param original the buffer to copy 
    * @return an independent copy of original 
    * @throws NullPointerException if original is null 
    */ 
    public static ByteBuffer clone(ByteBuffer original) 
    { 
     Preconditions.checkNotNull(original, "original may not be null"); 

     ByteBuffer result = ByteBuffer.allocate(original.capacity()); 
     ByteBuffer source = original.duplicate(); 
     source.rewind(); 
     result.put(source); 

     try 
     { 
      source.reset(); 
      result.position(source.position()); 
      result.mark(); 
     } 
     catch (InvalidMarkException unused) 
     { 
      // Mark is unset, ignore. 
     } 
     result.position(original.position()); 
     result.limit(original.limit()); 
     return result; 
    } 

    /** 
    * Returns an array representation of a buffer. The returned buffer may, or may not, be tied to 
    * the underlying buffer's contents (so it should not be modified). 
    * <p/> 
    * @param buffer the buffer 
    * @return the remaining bytes 
    */ 
    public static byte[] toArray(ByteBuffer buffer) 
    { 
     if (buffer.hasArray() && !buffer.isReadOnly() && buffer.position() == 0 
      && buffer.remaining() == buffer.limit()) 
     { 
      return buffer.array(); 
     } 
     ByteBuffer copy = buffer.duplicate(); 
     byte[] result = new byte[copy.remaining()]; 
     copy.get(result); 
     return result; 
    } 

    /** 
    * Prevent construction. 
    */ 
    private Buffers() 
    { 
    } 
} 

También he presentado una solicitud de función con Oracle: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7130631

4

La única manera real es, como dices, buf.asReadOnlyBuffer(), luego pasa esto al constructor. No hay otra opción aparte de esto, aunque podría hacer una copia del contenido en un nuevo ByteBuffer, luego pasarlo.

+1

Incluso si el constructor recibe un búfer de solo lectura, no tiene forma de garantizar que el búfer no será modificado por el propietario original (que conservó el acceso de escritura). Entonces todavía estás obligado a hacer una copia defensiva. – Gili

1

no evita una copia, pero tal vez:

  1. uso de una piscina precargada de ByteBuffers preasignados
  2. Permitir la constructor de la clase de autor para permitir una 'copia' de entrada ByteBuffer, pero la clase usa un ByteBuffer del grupo para mover Costos de Alloc/Dealloc para el inicio/cierre de la aplicación. Solo pague un costo de memcopy de esta manera.
0

Esto no responde del todo la pregunta, pero, para algunos usos (por ejemplo, si está tratando principalmente de aplicar el "diseño por contrato") puede ser lo suficientemente bueno y más eficiente. Para otros usos, no funcionará y puede ser mucho menos eficiente.

Durante su constructor, guardar distancia el código hash de la ByteBuffer

última int originalBBHashCode = byteBuffer.hashCode();

Luego, en los pocos lugares críticos en su código donde desea verificar que el ByteBuffer no ha cambiado, verifique que el byteBuffer.hashCode() == originalBBHashCode. Si no, lanza una excepción. Francamente, estaría tentado de lanzar una ConcurrentModificationException, ya que ese es el comportamiento que estás imitando, pero YMMV.

Cuestiones relacionadas