Come evitare la duplicazione del codice per quanto riguarda i tipi primitivi?


9

sfondo

Un flusso di input bit è supportato da una matrice di byte. Esistono una manciata di metodi che leggono da quell'array di byte in vari array primitivi forzati.

Problema

C'è un codice duplicato. Java non ha generici sui tipi primitivi, quindi forse la ripetizione è inevitabile.

Codice

Il codice ripetitivo è evidente nei seguenti metodi:

@Override
public long readBytes(final byte[] out, final int offset, final int count, final int bits) {
    final int total = offset + count;

    assert out != null;
    assert total <= out.length;

    final long startPosition = position();

    for (int i = offset; i < total; i++) {
        out[i] = readByte(bits);
    }

    return position() - startPosition;
}

@Override
public long readShorts(final short[] out, final int offset, final int count, final int bits) {
    final int total = offset + count;

    assert out != null;
    assert total <= out.length;

    final long startPosition = position();

    for (int i = offset; i < total; i++) {
        out[i] = readShort(bits);
    }

    return position() - startPosition;
}

Nota come si final byte[] outriferisce a readByte(bits)come si final short[] outriferisce a readShort(bits). Queste relazioni sono il nocciolo del problema.

Domanda

Come è possibile eliminare la duplicazione, se non del tutto, senza incorrere in un significativo calo delle prestazioni (ad esempio, con l'autoboxing)?

Relazionato


6
No, niente che tu possa fare lì. La duplicazione è l'unica opzione.
Andy Turner,

Utilizzare una raccolta di primitive di terze parti
Vince Emigh,

1
Java lacks generics on primitive types, so perhaps the repetition is unavoidable.Sì. (Di solito non è un problema, dato che è raro che un programma abbia bisogno di più di alcune primitive diverse. Si potrebbe anche "risolvere" inserendo le primitive all'interno di una classe e usando la serializzazione degli oggetti, sebbene ciò possa essere relativamente lento. )
Mark Space

3
Inoltre, (appena ricordato questo) se stai leggendo primitive di massa come il tuo codice sembra indicare, usando ByteBuffermetodi come asDoubleBuffer()o asShortBuffer()scaricherà alcuni dei lavori di livello più basso. docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/…
Markspace

1
Si noti che ci sono alcuni sforzi per portare supporto generico primitivo a Java, ad esempio List<int>ecc. Rilascio in circa 2-5 anni circa. Si chiama Project Valhalla.
Zabuzard,

Risposte:


2

Se stai leggendo primitive di massa come il tuo codice sembra indicare, utilizzando ByteBuffer metodi come asDoubleBuffer () o asShortBuffer () sarà scaricare una parte del lavoro più basso livello.

Esempio:

   public void readBytes( final byte[] out, final int offset, final int count, final ByteBuffer buffer ) {
      buffer.get( out, offset, count );  // udates ByteBuffer `position` automatically
   }

   public void readShorts( final short[] out, final int offset, final int count, final ByteBuffer buffer ) {
      ShortBuffer sb = buffer.asShortBuffer();
      sb.get( out, offset, count );  // note that `count` reads two bytes for each `short`
   }

(Il codice viene compilato ma non testato!)


0

Una possibilità, che comporterà una penalizzazione delle prestazioni, è quella di utilizzare java.lang.reflect.Arrayl'array come un oggetto che consente quindi di riutilizzare lo stesso codice in tutti i metodi di lettura.

@FunctionalInterface
public interface BitArrayReader {
    Object read(int bits);
}

private long readPrimitive(
        final Object out, final int offset, final int count, final int bits,
        final BitArrayReader reader) {
    final int total = offset + count;

    assert out != null;
    assert total <= Array.getLength(out);

    final long startPosition = position();

    for (int i = offset; i < total; i++) {
        Array.set(out, i, reader.read(bits));
    }

    return position() - startPosition;
}

@Override
public long readBooleans(boolean[] out, int offset, int count, int bits) {
    return readPrimitive(out, offset, count, bits, this::readBoolean);
}

La duplicazione è stata affrontata a scapito di alcune prestazioni, una minore mancanza di sicurezza del tipo di compilazione in tempo reale e l'uso della riflessione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.