A
A
Alexander Buliterov2021-10-04 23:30:48
C++ / C#
Alexander Buliterov, 2021-10-04 23:30:48

How to implement the function of copying bits with offsets in src and/or dst and not a multiple of 8 bits?

All the best!

It is necessary (optimally) to copy count bits from the uint8_t buffer with the start bit offset to another buffer, also with the start buffer offset.
What is the best way to use?

**
 * @param dst Pointer to destination buffer
 * @param src Pointer to sources buffer
 * @param dst_start Beginning bit number. Value of range 0..7
 * @param src_start Read start bit number. Value of range 0..7 - Смещение с которого начинать писать.
 * @param count Number of bits to copy. Value of range 1..255
 * @return Number of bits to copied
 */
int memcpy_bit(uint8_t *dst, uint8_t dst_start, uint8_t *src, uint8_t src_start, uint8_t count)


UPD4
Необходимо начиная с "src_start" бита первого элемента буфера "src", скопировать (заменить содержимое!)
"count" бит в буфер "dst" начиная с "dst_start" бита.
Байты:          3-ий       2-ой       1-ый       0-ой
src[4] = { 0101_1111, 0101_1111, 0101_1111, 0101_1111 }
dst[4] = { 1100_1111, 0010_0000, 0010_0000, 1010_1010 }
src_start = 3
dst_start = 5
count = 25 // Для примера: 4*8 - dst_start - 2(оставляем значение старших бит dst)
memcpy_bit(uint8_t *dst, uint8_t dst_start, uint8_t *src, uint8_t src_start, uint8_t count);
После выполнения функции:
1. младшие 5 бит 0-вого байта dst остались прежними
2. 2 старших бита 3-его байта dst остались прежними
                                              ! 5-ый бит
src     xx xx11 1101  0111 1101  0111 1101  011x xx     // сдвинул src так, чтобы src_start был над dst_start. x - игнорируемые биты
dst[4] = { 1100_1111, 0010_0000, 0010_0000, 0110_1010 } // исходное значение
dst[4] = { 1111_1101, 0111 1101  0111 1101, 0110_1010 } // результат

Так как порядок инициализация слева направо, а выше указал в порядке справа налево, вот исходники для тестов:
uint8_t src[4]     = { 0b01011111, 0b01011111, 0b01011111, 0b01011111 };
uint8_t dst[4]     = { 0b10101010, 0b00100000, 0b00100000, 0b11001111 };
uint8_t dst_res[4] = { 0b01101010, 0b01111101, 0b01111101, 0b11111101 };

Answer the question

In order to leave comments, you need to log in

1 answer(s)
W
Wataru, 2021-10-05
@wataru

The most efficient way is to use some kind of SSE (google shift bits sse. I think _mm_slli_epi64 is the best). But there will be a lot of code and cases. We will have to separately analyze the cases of shifting left and right, separately isolate the bits that the SSE operation would lose during the shift and write where necessary.
The next most efficient option is to read into int64_t and shift bits there. You will first have to get the upper/lower 1-7 bits from the variable and write them separately, then shift the bits and write them where necessary. Use memcopy to read/write 64 bits. You can also speed up if you process the first few bytes separately before 64-bit alignment, and then you have to process the extra 0-7 bytes at the end separately if their number is not divisible by 8.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question