Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/18: Рейтинг темы: голосов - 18, средняя оценка - 4.67
2 / 2 / 0
Регистрация: 24.05.2016
Сообщений: 88

Нарезка байтового массива на битовые части

07.01.2021, 04:15. Показов 3445. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброй ночи, уважаемые форумчане, всех с наступившим новым годом.

Немного информации, которая связана с вопросом:

1.Имеется сырой буфер изображения, который, предположительно, может иметь размер, который не вмещается в границу байта или, наоборот, до неё не дотягивает, цветовых компонет пикселей. Также важным является то, что место в данном буфере тоже экономится, поэтому данные лежат подряд, и, поэтому, важно учесть, что если первая компонента цвета будет иметь размер 5 бит, то следующие 3 бита, будут приходиться на другую компоненту цвета пикселя.

2.Вектор с информацией о количестве бит в каждой цветовой компоненте - тут всё достаточно просто, тут может быть одно значение(двуцветное изображение) или 3, или даже 6 (какая-нибудь экзотика). Сами значения представляют количество бит в каждой цветовой компоненте.

3. Порядок бит, идентификатор/флаг, который информирует о порядке бит (справа-налево/наоборот)

4. Дабы немного прояснить для чего это нужно, сделаю небольшую вставку из спецификации формата TIFF 6.0:

Кликните здесь для просмотра всего текста

FillOrder
The logical order of bits within a byte.
Tag = 266 (10A.H)
Type = SHORT
N = 1
1 = pixels are arranged within a byte such that pixels with lower column values are stored in the higher-order bits of the byte.
1-bit uncompressed data example: Pixel 0 of a row is stored in the high-order bit of byte 0, pixel 1 is stored in the next-highest bit, ..., pixel 7 is stored in the low-order bit of byte 0, pixel 8 is stored in the high-order bit of byte 1, and so on. CCITT 1-bit compressed data example: The high-order bit of the first compression code is stored in the high-order bit of byte 0, the next-highest bit of the first compression code is stored in the next-highest bit of byte 0, and so on.
2 = pixels are arranged within a byte such that pixels with lower column values are stored in the lower-order bits of the byte. We recommend that FillOrder=2 be used only in special-purpose applications. It is easy and inexpensive for writers to reverse bit order by using a 256-byte lookup table. FillOrder = 2 should be used only when BitsPerSample = 1 and the data is either uncompressed or compressed using CCITT 1D or 2D compression, to avoid potentially ambigous situations. Support for FillOrder=2 is not required in a Baseline TIFF compliant reader.
Default is FillOrder = 1.


Если опустить лишнее, то получается примерно так:

Кликните здесь для просмотра всего текста
пример для однобитных изображений
пиксели:
Fill Order = 1-
*0 1 2 3 4 5 6 7
Fill Order = 2-
*7 6 5 4 3 2 1 0
+---------------+
|1|0|1|0|1|0|1|0|
+---------------+
пример для произвольно битных изображений [5 6 5] bit (предположительно 2 варианта (Fill Order = 2), спецификация явно об этом не говорит)
вариант 1:
Fill Order = 1-
|----R----|------G-----|----B----|
Fill Order = 2-
|----R----|------G-----|----B----| - только биты наоборот
Fill Order = 2-
|--G--|----R----||----B----|--G--|
+---------------++---------------+
|1|0|1|0|1|0|1|0||1|0|1|0|1|0|1|0|
+---------------++---------------+
0 байт________1 байт



Есть потребность в алгоритме, который бы принимал: массив байт, размер массива, вектор с информацией о количестве и значении битовых компонент, а также порядок бит, и нарезал поступивший массив на битовые отрезки произвольной длины и компановал это в новый буфер (массив/вектор не важно) типа данных unsigned char, где внутри каждая отдельная переменная содержала бы в себе компоненту с определенным количеством бит.

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

Написал только это, да и то, одно расстройство:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
void TiffReader::SliceRawBuffer(unsigned char *RawBuffer, unsigned long long Size, 
std::vector<short> &BitsPerSimple, std::vector<unsigned char> &Buffer, unsigned char FillOrder)
{
    unsigned int NumberCuttingBits = 0;
    unsigned int StartBit = 0;
    unsigned char ColorComponent = 0;
    for (unsigned long long IndxRawBuffer = 0; IndxRawBuffer < Size;)
    {
        for (unsigned short IndxComponent = 0; IndxComponent < BitsPerSimple.size(); ++IndxComponent)
        {
            if (IndxRawBuffer > Size - 1)
                return;
 
            NumberCuttingBits = BitsPerSimple.at(IndxComponent);
 
            if (StartBit + BitsPerSimple.at(IndxComponent) > 8)
            {
                unsigned int TempNumberCuttingBits = StartBit + BitsPerSimple.at(IndxComponent) - NumberCuttingBits;
                ColorComponent =
                (
                 (RawBuffer[IndxRawBuffer] >> StartBit)
                 &
                 ((1 << (NumberCuttingBits - TempNumberCuttingBits)) - 1)
                );
 
                ColorComponent <<= TempNumberCuttingBits;
 
                ++IndxRawBuffer;
                if (IndxRawBuffer > Size - 1)
                {
                    Buffer.push_back(ColorComponent);
                    return;
                }
 
                ColorComponent |=
                (
                 ((RawBuffer[IndxRawBuffer] >> 0)
                 &
                 ((1 << (TempNumberCuttingBits)) - 1))
                 << NumberCuttingBits
                );
 
                StartBit = TempNumberCuttingBits + 1;
 
                Buffer.push_back(ColorComponent);
            }
            else
            {
                ColorComponent =
                (
                 (RawBuffer[IndxRawBuffer] >> StartBit)
                 &
                 ((1 << NumberCuttingBits) - 1)
                );
 
                //ColorComponent <<= (8 - NumberCuttingBits);
                Buffer.push_back(ColorComponent);
                ColorComponent = 0;
 
                if (NumberCuttingBits == 8)
                {
                    StartBit = 0;
                    IndxRawBuffer++;
 
                    if (IndxRawBuffer > Size - 1)
                        return;
                }
                else
                    StartBit++;
            }
        }
    }
}
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
07.01.2021, 04:15
Ответы с готовыми решениями:

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

Шифрование в DPAPI байтового массива
Есть код шифрования строки &quot;Мой Мир&quot; при помощи DPAPI string text = &quot;Мой Мир&quot;; string entropy =...

Создание файла из байтового массива
Вот открыл я файл при помощи Get в моде Binary, а как сохранить его как новый? Добавлено через 1 час 20 минут Чет туплю седня)))%-)...

5
Мозгоправ
 Аватар для L0M
1745 / 1039 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
08.01.2021, 04:38
Лучший ответ Сообщение было отмечено Aringot как решение

Решение

Aringot, у вас как-то всё сложно получилось... Да и контекст тяжеловат для понимания. Я вам накидал эскиз класса, который реализует битовый поток.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <climits>
#include <fstream>
 
using namespace std;
 
typedef unsigned char Byte;
 
class BitStream
{
    bool m_reverseOrder;
    Byte m_data;
    int m_bit;
    istream &m_is;
public:
    // is - поток, из которого читаются данные побайтно.
    // reverseOrder - если true, метод get() будет возвращать биты в обратном порядке.
    BitStream(istream &is, bool reverseOrder = false) : m_is(is), m_reverseOrder(reverseOrder), m_bit(0), m_data(0) {}
 
    // Метод записывает в параметр sink указанное количество (bits) битов из входного потока.
    // Прямой или обратный порядок битов определяется параметром конструктора reverseOrder.
    // При ошибке метод возвращает false.
    template <typename T>
    bool get(T &sink, size_t bits)
    {
        if (sizeof(T) * CHAR_BIT < bits || bits == 0)
            return false;
        sink = (T)0;
        Byte mask;
        while (bits--) {
            sink <<= 1;
            if (m_bit == 0) {
                if (!m_is.read((char *)&m_data, 1))     // <-- чтение байта из входного потока
                {
                    sink = 0;
                    return false;
                }
                m_bit = CHAR_BIT;
            }
            if (m_reverseOrder)
                mask = 1 << (CHAR_BIT - m_bit);
            else
                mask = 1 << (m_bit - 1);
            sink |= (m_data & mask) ? 1 : 0;
            --m_bit;
        }
        return true;
    }
};
 
 
template <typename T>
void bin(ostream &os, const T &data, size_t limit = 0) {
    size_t len;
    if (limit == 0)
        len = sizeof(T) * CHAR_BIT;
    else
        len = limit;
    while (len--)
        os << ((data & (1 << len)) ? '1' : '0');
    os << ' ';
}
 
int main()
{
    ifstream ifs("1.txt", ios_base::in | ios_base::binary);
    Byte data;
    ifs.read((char *)&data, 1);
    while (ifs) {
        bin(cout, data);
        ifs.read((char *)&data, 1);
    }
    cout << endl;
    ifs.close();
    
    const size_t getBits = 5;     // по сколько битов читаем в переменную
 
    ifs.open("1.txt", ios_base::in | ios_base::binary);
    BitStream bs(ifs, false);
    while (bs.get(data, getBits)) {
        bin(cout, data, getBits);
    }
    cout << endl;
    ifs.close();
 
}
С помощью метода get() вы можете читать и записывать в переменную любое (разумное) число битов из входного потока. Т.е. это штука достаточно низкоуровневая.

Вы можете изменить класс под ваши потребности относительно источника данных. У меня это istream. Чтение байта из потока производится в одном месте. Можете поставить туда свою функцию, которая извлекает очередной байт из вашего массива/вектора.

В main() небольшая проверка работы класса.

С пристрастием код не тестировал, но вроде работает.
1
2 / 2 / 0
Регистрация: 24.05.2016
Сообщений: 88
08.01.2021, 13:58  [ТС]
Доброе утро, выражаю большую благодарность за достаточно информативный пример класса.
Следуя Вашим советам накидал вот это:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <iostream>
#include <vector>
#include <fstream>
 
template <typename T>
class ByteSlice
{
private:
    enum WhatCame
    {
        VECTOR   = 1,
        PTRARRAY = 2
    };
 
    T     SequenceСomponent; /*часть потока, вектора, массива указателей*/
 
    unsigned long long      Now; /*текущий элемент(для вектора/массива уазателей)*/
    std::vector<T>      &Vector; /*вектор*/
    T                 *PtrArray; /*массив указателей*/
    unsigned long long     Size; /*размер массива указателей*/
    unsigned char      FlagCame; /*флаг источника*/
    unsigned long long SizeBits; /*размер типа данных*/
 
public:
    ByteSlice(void) = delete;
    ByteSlice(const ByteSlice<T> &) = delete;
 
    ByteSlice(std::vector<T> &VectorData)
    : SequenceСomponent(0),
      Now(0), Vector(VectorData),
      PtrArray(nullptr), Size(0),
      FlagCame(VECTOR), SizeBits(sizeof(T) * 8u) {this->Size = this->Vector.size();}
 
    ByteSlice(T *PtrArrayData, unsigned long long SizeArray)
    : SequenceСomponent(0),
      Now(0), Vector(reinterpret_cast<T>(0)),
      PtrArray(PtrArrayData), Size(SizeArray),
      FlagCame(PTRARRAY), SizeBits(sizeof(T) * 8u) {}
 
    bool GetBits(T &Buffer, unsigned long long NumberOfBits, bool ReverseOrder = false)
    {
        if (sizeof(Buffer) * 8u < NumberOfBits || NumberOfBits == 0)
            return false;
 
        Buffer = 0;
        T Mask = 0;
        unsigned long long SizeTypeInBit = 0;
 
        while (NumberOfBits--)
        {
            Buffer <<= 1;
            if (SizeTypeInBit == 0)
            {
                switch(FlagCame)
                {
                    case VECTOR:
                    {
                        if (this->Now == this->Size)
                        {
                            return false;
                        }
                        SequenceСomponent = this->Vector.at(this->Now);
                        this->Now++;
                        SizeTypeInBit = SizeBits;
                        break;
                    }
                    case PTRARRAY:
                    {
                        if (this->Now == this->Size - 1)
                        {
                            return false;
                        }
                        SequenceСomponent = this->PtrArray[this->Now];
                        this->Now++;
                        SizeTypeInBit = SizeBits;
                        break;
                    }
                    default:
                        return false;
                }
            }
            if (ReverseOrder)
                Mask = 1 << (SizeBits - (SizeTypeInBit - 1));
            else
                Mask = 1 << (SizeTypeInBit - 1);
            Buffer |= (SequenceСomponent & Mask) ? 1 : 0;
            --SizeTypeInBit;
        }
        return true;
    }
 
    void PrintBits(std::ostream &out, const T &Buffer, unsigned long long Limit, bool ReverseOrder = false)
    {
        unsigned long long Len;
        if (Limit == 0)
            Len = sizeof(T) * 8u;
        else
            Len = Limit;
 
        if (ReverseOrder)
        {
            unsigned long long Index = 0;
            while (Index != Len)
                out << ((Buffer & (1 << Index++)) ? '1' : '0');
        }
        else
            while (Len--)
                out << ((Buffer & (1 << Len)) ? '1' : '0');
        out << ' ' << std::flush;
    }
};
 
int main()
{
    std::vector<unsigned char> Stream = {170, 210, 255};
    ByteSlice<unsigned char> Slicer(Stream);
    unsigned char Buffer = 0;
    unsigned int Index = 0;
    while(Slicer.GetBits(Buffer, 5, true))
    {
        std::cout << "Original: " << (int)Stream[Index] << std::endl;
        Slicer.PrintBits(std::cout, Stream[Index], sizeof(Buffer) * 8u);
        std::cout << "\nSlicer: " << (int)Buffer << std::endl;
        Slicer.PrintBits(std::cout, Buffer, sizeof(Buffer) * 8u);
        std::cout << std::endl;
        ++Index;
    }
    return 0;
}
Также своим ненаметаным глазом заметил, что если использовать Вашу конструкцию:
C++
1
2
            if (m_reverseOrder)
                mask = 1 << (CHAR_BIT - m_bit);
у меня это:
C++
1
2
            if (ReverseOrder)
                Mask = 1 << (SizeBits - SizeTypeInBit);
то срез почему то идет некорректно при нуле(предположительно с моим примером)
и, предположительно необходимо сделать следующее:
C++
1
2
            if (ReverseOrder)
                Mask = 1 << (SizeBits - (SizeTypeInBit - 1));
тогда режет нормально.
Немогли бы Вы просмотреть своим наметаным глазом на эту проблему, возможно ошибаюсь я, а может и действительно, произошла опечатка.
Спасибо.
0
2 / 2 / 0
Регистрация: 24.05.2016
Сообщений: 88
08.01.2021, 14:05  [ТС]
Вот сделал наглядный скриншот с двумя вариантами, первый - там моей правки нет, второй - есть.
Миниатюры
Нарезка байтового массива на битовые части  
0
Мозгоправ
 Аватар для L0M
1745 / 1039 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
08.01.2021, 18:09
Aringot, во-первых, вы опять всё усложнили. Сложную задачу надо разбивать на последовательность простых решений. А вы взяли простое решение подзадачи и начали его "дорабатывать" до полного решения. И получили монстра. Почитайте про SOLID.

Во-вторых, или я неправильно понял постановку задачи, или ваш вариант работает неправильно в принципе. Если изменить в вашем варианте main() таким образом:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
    std::vector<unsigned char> Stream = { 170, 210, 255 };
    ByteSlice<unsigned char> Slicer(Stream);
    unsigned char Buffer = 0;
    unsigned int Index = 0;
 
    for (const auto v : Stream)
        Slicer.PrintBits(std::cout, v, CHAR_BIT);
    std::cout << std::endl;
 
    while (Slicer.GetBits(Buffer, 5, true))
    {
        Slicer.PrintBits(std::cout, Buffer, 5);
    }
    std::cout << std::endl;
 
    return 0;
}
то, на мой взгляд, вывод должен быть следующим:
Code
1
2
10101010 11010010 11111111
10101 01011 01001 01111
В первой строке { 170, 210, 255 } в двоичном представлении, во второй строке - та же последовательность битов, но разделённая на группы по 5 штук. Последние четыре бита 1111 отбрасываются, поскольку не образуют полную группу из 5 битов.

Ваша программа выдаёт:
Code
1
2
10101010 11010010 11111111
10101 10010 11111
Всего 3 числа (во второй строке). Каждое из чисел - это 5 младших битов исходных трёх чисел. Старшие 3 бита каждого числа просто отброшены. Если это именно то, чего вы хотели, то такое преобразование делается совсем просто, безо всяких классов и прочих бубнов.

Как всё-таки должно работать разбиение на группы битов? Как реализовал я или как вы?

Добавлено через 1 час 6 минут
Aringot, когда я написал
Цитата Сообщение от L0M Посмотреть сообщение
Вы можете изменить класс под ваши потребности относительно источника данных. У меня это istream. Чтение байта из потока производится в одном месте. Можете поставить туда свою функцию, которая извлекает очередной байт из вашего массива/вектора.
я имел ввиду примерно следующее:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <iostream>
#include <climits>
#include <fstream>
#include <vector>
 
using namespace std;
 
typedef unsigned char Byte;
 
class ByteStream {
    const vector<unsigned char> &m_container;
    vector<unsigned char>::const_iterator m_it;
    bool m_eof;
public:
    ByteStream(const vector<unsigned char> &v) : m_container(v), m_eof(false) { reset(); }
    void reset() { m_it = m_container.cbegin(); m_eof = false; }
    bool getByte(unsigned char &data)
    {
        if (m_it == m_container.cend()) {
            m_eof = true;
            return false;
        }
        data = *m_it++;
        return true;
    }
    operator bool() { return !m_eof; }
};
 
class BitStream
{
    bool m_reverseOrder;
    Byte m_data;
    int m_bit;
    ByteStream &m_is;
public:
    // is - поток, из которого читаются данные побайтно.
    // reverseOrder - если true, метод get() будет возвращать биты в обратном порядке.
    BitStream(ByteStream &is, bool reverseOrder = false) : m_is(is), m_reverseOrder(reverseOrder), m_bit(0), m_data(0) {}
 
    // Метод записывает в параметр sink указанное количество (bits) битов из входного потока.
    // Прямой или обратный порядок битов определяется параметром конструктора reverseOrder.
    // При ошибке метод возвращает false.
    template <typename T>
    bool get(T &sink, size_t bits)
    {
        if (sizeof(T) * CHAR_BIT < bits || bits == 0)
            return false;
        sink = (T)0;
        Byte mask;
        while (bits--) {
            sink <<= 1;
            if (m_bit == 0) {
                if (!m_is.getByte(m_data))     // <-- чтение байта из входного потока
                {
                    sink = 0;
                    return false;
                }
                m_bit = CHAR_BIT;
            }
            if (m_reverseOrder)
                mask = 1 << (CHAR_BIT - m_bit);
            else
                mask = 1 << (m_bit - 1);
            sink |= (m_data & mask) ? 1 : 0;
            --m_bit;
        }
        return true;
    }
};
 
 
template <typename T>
void bin(ostream &os, const T &data, size_t limit = 0) {
    size_t len;
    if (limit == 0)
        len = sizeof(T) * CHAR_BIT;
    else
        len = limit;
    while (len--)
        os << ((data & (1 << len)) ? '1' : '0');
    os << ' ';
}
 
int main()
{
    vector<unsigned char> Stream = { 170, 210, 255 };
    ByteStream src(Stream);
 
    Byte data;
    src.getByte(data);
    while (src) {
        bin(cout, data);
        src.getByte(data);
    }
    cout << endl;
 
    const size_t getBits = 5;     // по сколько битов читаем в переменную
 
    src.reset();
    BitStream bs(src, false);
    while (bs.get(data, getBits)) {
        bin(cout, data, getBits);
    }
    cout << endl;
}
Добавлено через 24 минуты
Если вам надо работать с несколькими источниками байтовых данных (я вижу у вас VECTOR, PTRARRAY), то сделайте абстрактный базовый класс, описывающий интерфейс, и унаследуйте от него классы, которые реализуют абстрактные методы для различных источников данных. В этом случае BitStream будет обращаться как бы к методам абстрактного класса, но при создании объекта вы будете указывать объект класса-наследника, имеющий нужную реализацию методов.
0
2 / 2 / 0
Регистрация: 24.05.2016
Сообщений: 88
08.01.2021, 23:54  [ТС]
Приношу извинения за дезенформацию, Ваше решение верное, это я некорректно сделал свой вариант, в данный момент сел и нашёл косяк, он был в этом:
C++
1
2
3
4
5
6
    bool GetBits(T &Buffer, unsigned long long NumberOfBits, bool ReverseOrder = false)
    {
     ...
        unsigned long long SizeTypeInBit = 0;
     ...
    }
Проблема в том, что я всегда счетчик обнулял при вызове, а у Вас с этим всё было порядок.

Таким образом, проблема решена.
Вот код, может пригодится кому-нибудь:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
template <typename T>
class ByteSlice
{
private:
    enum WhatCame
    {
        VECTOR   = 1,
        PTRARRAY = 2
    };
 
    T           SequenceComponent; /*часть потока, вектора, массива указателей*/
 
    unsigned long long        Now; /*текущий элемент(для вектора/массива уазателей)*/
    std::vector<T>        &Vector; /*вектор*/
    T                   *PtrArray; /*массив указателей*/
    unsigned long long       Size; /*размер массива указателей*/
    unsigned char        FlagCame; /*флаг источника*/
    unsigned long long   SizeBits; /*размер типа данных*/
    unsigned long long IndexInBit; /*битовый индекс*/
 
public:
    ByteSlice(void) = delete;
    ByteSlice(const ByteSlice<T> &) = delete;
 
    ByteSlice(std::vector<T> &VectorData)
    : SequenceComponent(0),
      Now(0), Vector(VectorData),
      PtrArray(nullptr), Size(0),
      FlagCame(VECTOR), SizeBits(sizeof(T) * 8u),
      IndexInBit(0) {this->Size = this->Vector.size();}
 
    ByteSlice(T *PtrArrayData, unsigned long long SizeArray)
    : SequenceComponent(0),
      Now(0), Vector(reinterpret_cast<T>(0)),
      PtrArray(PtrArrayData), Size(SizeArray),
      FlagCame(PTRARRAY), SizeBits(sizeof(T) * 8u),
      IndexInBit(0) {}
 
    bool GetBits(T &Buffer, unsigned long long NumberOfBits, bool ReverseOrder = false)
    {
        if (sizeof(Buffer) * 8u < NumberOfBits || NumberOfBits == 0)
            return false;
 
        Buffer = 0;
        T Mask = 0;
 
        while (NumberOfBits--)
        {
            Buffer <<= 1;
            if (IndexInBit == 0)
            {
                switch(FlagCame)
                {
                    case VECTOR:
                    {
                        if (this->Now == this->Size)
                        {
                            return false;
                        }
                        SequenceComponent = this->Vector.at(this->Now);
                        this->Now++;
                        IndexInBit = SizeBits;
                        break;
                    }
                    case PTRARRAY:
                    {
                        if (this->Now == this->Size - 1)
                        {
                            return false;
                        }
                        SequenceComponent = this->PtrArray[this->Now];
                        this->Now++;
                        IndexInBit = SizeBits;
                        break;
                    }
                    default:
                        return false;
                }
            }
            if (ReverseOrder)
                Mask = 1 << (SizeBits - IndexInBit);
            else
                Mask = 1 << (IndexInBit - 1);
            Buffer |= (SequenceComponent & Mask) ? 1 : 0;
            --IndexInBit;
        }
        return true;
    }
 
    void PrintBits(std::ostream &out, const T &Buffer, unsigned long long Limit, bool ReverseOrder = false)
    {
        unsigned long long Len;
        if (Limit == 0)
            Len = sizeof(T) * 8u;
        else
            Len = Limit;
 
        if (ReverseOrder)
        {
            unsigned long long Index = 0;
            while (Index != Len)
                out << ((Buffer & (1 << Index++)) ? '1' : '0');
        }
        else
            while (Len--)
                out << ((Buffer & (1 << Len)) ? '1' : '0');
        out << ' ' << std::flush;
    }
};
 
int main()
{
    std::vector<unsigned short> Stream = {170, 210, 255};
    ByteSlice<unsigned short> Slicer(Stream);
    unsigned short Buffer = 0;
    unsigned int Index = 0;
    for (unsigned int i = 0; i < 3; i++)
        Slicer.PrintBits(std::cout, Stream.at(i), sizeof(unsigned short) * 8u);
    std::cout << std::endl;
    while(Slicer.GetBits(Buffer, 5))
    {
        std::cout << "\nSlicer: " << (int)Buffer << std::endl;
        Slicer.PrintBits(std::cout, Buffer, sizeof(unsigned short)*8u);
        std::cout << std::endl;
        ++Index;
    }
    return 0;
}
С интерфейсом идея хорошая, спасибо. Есть с чем посидеть-покумекать.

Большое спасибо!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.01.2021, 23:54
Помогаю со студенческими работами здесь

Нарезка массива
Доброго времени суток! Есть массив (10,3,1,2,4,5,9,10,1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1). Нужно вырезать участки между 10-ми и...

Перевод байтового массива в другую кодировку
Добрый день, форумчане. Подскажите, какие есть варианты решить такую задачу: Из БД вычитывается Blob (который, по идее, содержит...

Преобразование динамического байтового массива в SafeArray
Здравствуйте товарищи! В общем такая проблема, есть рабочая функция, которая преобразовывает байтовые массивы в PSafeArray. Но она работает...

Создание байтового массива с помощью MemCopy, RtlMoveMemory
Замучался экспериментировать. Помогите, пжлста. Есть байтовый массив a, как с помощью MemCopy или RtlMoveMemory создать новый...

Быстрые алгоритмы сборки байтового массива в строку и наоборот
Всем привет! Народ не поделитесь быстрым алгоритмом сборки байтового массива из строки (только цифры) и разборки массива в строку? К...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru