Как избежать дублирования кода относительно примитивных типов? - PullRequest
9 голосов
/ 27 февраля 2020

Фон

Входной поток битов поддерживается массивом байтов. Есть несколько методов, которые читают из этого байтового массива в различные принудительные примитивные массивы.

Проблема

Существует дублированный код. Java не хватает обобщений для примитивных типов, поэтому, возможно, повторение неизбежно.

Код

Повторяющийся код проявляется в следующих методах:

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

Обратите внимание, как final byte[] out относится к readByte(bits) так же, как final short[] out относится к readShort(bits). Эти отношения составляют суть проблемы.

Вопрос

Как можно устранить дублирование, если оно вообще не происходит, без значительного снижения производительности (например, с помощью автобоксирования)?

Связанные

Ответы [ 2 ]

2 голосов
/ 28 февраля 2020

Если вы читаете массовые примитивы, как, по-видимому, указывает ваш код, использование ByteBuffer методов, таких как asDoubleBuffer () или asShortBuffer () приведет к разгрузке некоторых из работа самого низкого уровня.

Пример:

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

(код компилируется, но не тестируется!)

0 голосов
/ 04 марта 2020

Одна возможность, которая повлечет за собой снижение производительности, заключается в использовании java.lang.reflect.Array для обработки массива как объекта, который затем позволяет повторно использовать один и тот же код во всех методах чтения.

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

Дублирование было решено за счет некоторой производительности, незначительного отсутствия безопасности типа во время компиляции и использования отражения.

...