Como evitar a duplicação de código em relação aos tipos primitivos?

9

fundo

Um fluxo de entrada de bits é apoiado por uma matriz de bytes. Existem vários métodos que lêem essa matriz de bytes em várias matrizes primitivas coagidas.

Problema

Existe um código duplicado. Java não possui genéricos em tipos primitivos, portanto, talvez a repetição seja inevitável.

Código

O código repetitivo é aparente nos seguintes métodos:

@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;
}

Observe como final byte[] outse relaciona readByte(bits)exatamente como final short[] outse relaciona readShort(bits). Essas relações são o cerne do problema.

Questão

Como a duplicação pode ser eliminada, se é que existe, sem incorrer em um impacto significativo no desempenho (por exemplo, por autoboxing)?

Relacionado

Dave Jarvis
fonte
6
Não, nada que você possa fazer lá. Duplicação é a única opção.
Andy Turner
Use uma coleção primitiva de terceiros
Vince Emigh 27/02
11
Java lacks generics on primitive types, so perhaps the repetition is unavoidable.Sim. (Geralmente, não é um problema, pois é raro um programa precisar de mais do que algumas primitivas diferentes. Você também pode "consertar" isso colocando as primitivas em uma classe e usando a serialização de objetos, embora isso possa ser relativamente lento. )
markspace
3
Além disso, (lembre-se disso), se você estiver lendo primitivos em massa, como o seu código parece indicar, usando ByteBuffermétodos como asDoubleBuffer()ou asShortBuffer()descarregará parte do trabalho de nível mais baixo. docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/…
markspace
11
Observe que existem alguns esforços para trazer suporte genérico primitivo ao Java, ou seja, List<int>etc. Liberte em talvez 2-5 anos ou mais. É chamado Projeto Valhalla.
Zabuzard 4/03

Respostas:

2

Se você estiver lendo primitivos em massa como o seu código parece indicar, o uso de métodos ByteBuffer como asDoubleBuffer () ou asShortBuffer () descarregará parte do trabalho de nível mais baixo.

Exemplo:

   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`
   }

(O código é compilado, mas não testado!)

markspace
fonte
0

Uma possibilidade, que incorrerá em uma penalidade de desempenho, é usar java.lang.reflect.Arraypara tratar a matriz como um Objeto que permite reutilizar o mesmo código em todos os métodos de leitura.

@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);
}

A duplicação foi abordada à custa de algum desempenho, uma pequena falta de segurança do tipo em tempo de compilação e uso de reflexão.

Dave Jarvis
fonte