Класс Java для получения/установки определенных битов в массиве байтов

Я ищу вспомогательный класс, который может изменять определенные биты в массиве байтов с помощью API, подобного приведенному ниже:

void Set(int startPos, int lengthInBits, int value) {
  // Set the bits starting at startPos to the binary representation of value
  // Error if the binary representation of value is too long (ie. exceeds lengthInBits)
}

Цель состоит в том, чтобы иметь возможность помещать определенные значения произвольной длины в массив байтов - некоторые значения будут иметь длину меньше байта, другие больше, а некоторые будут «растягивать» байты.

Я просмотрел ByteBuffer, но это кажется слишком высокоуровневым, работает только с помещением целых байтов и преобразованием целых и коротких чисел в несколько байтов, а не позволяет вам выбрать их максимальное количество бит.

Я также просмотрел BitSet, но на этот раз он кажется слишком низкоуровневым, так как работает только на уровне одного бита (хотя я потенциально мог бы использовать его в качестве отправной точки для создания чего-либо с помощью API, описанного выше).

Также есть старый несколько похожий вопрос о переполнении стека, в основном относящийся к использованию битов со знаком/без знака, но изображенная структура данных — это то, что я пытаюсь построить (сообщение для отправки внешнему клиенту), и я Я хотел бы скрыть как можно больше сложности со сдвигом битов.


person asibs    schedule 28.10.2013    source источник


Ответы (2)


Это не так сложно. Возможно, это может помочь вам в качестве отправной точки:

ByteBuffer data;

int getBits(int bitOff, int bitSize)
{
  if(bitSize>32) throw new UnsupportedOperationException();
  final int mask= bitSize==32? -1: (1<<bitSize)-1;
  return (int)((data.getLong(bitOff>>>3) >>> (64-bitSize-(bitOff&7))) & mask);
}
void putBits(int bitOff, int bitSize, int intValue)
{
  final int byteOff=bitOff>>>3;
  bitOff -= byteOff<<3;
  final int shift = 64-bitSize-bitOff;
  long mask=Long.rotateLeft((-1L)<<bitSize, shift), lValue=intValue&0xffffffffL;
  data.putLong(byteOff, (lValue << shift) | (data.getLong(byteOff)&mask));
}
person Holger    schedule 28.10.2013
comment
Спасибо, в идеале я ищу существующий класс/библиотеку, которая обеспечивает такую ​​​​функциональность, поэтому мне не нужно создавать собственный класс и тесты для чего-то, что, как мне кажется, является довольно распространенной проблемой. Хотя, может, там ничего и нет... - person asibs; 28.10.2013

Вы можете расширить java.util.BitSet, он уже поддерживает хранение произвольного количества битов. Все, что вам нужно добавить, это массовые операции получения/установки:

public class BulkBitSet extends BitSet {

    public void bulkSet(int offset, int count, int data) {
        int ptr = offset + count;
        for (int i=0; i<count; ++i) {
            set(--ptr, (data & (1 << i)) == 0 ? false : true);
        }
    }

    public int bulkGet(int offset, int count) {
        int result = 0;
        for (int i=0; i<count; ++i) {
            result <<= 1;
            if (get(offset + i))
                result |= 1;
        }
        return result;
    }

}
person Durandal    schedule 28.10.2013