Skip to content

Commit f4ab4fe

Browse files
committed
Fix pad_to_size to work correctly with bytes less than 4
Fix bit_writer::flush to return 0 when the buffer is empty
1 parent 62b879b commit f4ab4fe

File tree

3 files changed

+63
-33
lines changed

3 files changed

+63
-33
lines changed

include/bitstream/stream/bit_reader.h

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,21 +139,24 @@ namespace bitstream
139139
*/
140140
bool serialize_checksum(uint32_t protocol_version) noexcept
141141
{
142+
BS_ASSERT(m_NumBitsRead == 0);
143+
144+
BS_ASSERT(can_serialize_bits(32U));
145+
142146
uint32_t num_bytes = (m_TotalBits - 1U) / 8U + 1U;
143147

144148
// Read the checksum
145-
uint32_t checksum;
146-
std::memcpy(&checksum, m_Buffer, sizeof(uint32_t));
149+
uint32_t checksum = *m_Buffer;
147150

148151
// Copy protocol version to buffer
149152
uint32_t* buffer = const_cast<uint32_t*>(m_Buffer); // Somewhat of a hack, but it's faster to change the checksum twice than allocate memory for it
150-
std::memcpy(buffer, &protocol_version, sizeof(uint32_t));
153+
*buffer = protocol_version;
151154

152155
// Generate checksum to compare against
153156
uint32_t generated_checksum = utility::crc_uint32(reinterpret_cast<uint8_t*>(buffer), num_bytes);
154157

155158
// Write the checksum back, just in case
156-
std::memcpy(buffer, &checksum, sizeof(uint32_t));
159+
*buffer = checksum;
157160

158161
// Advance the reader by the size of the checksum (32 bits / 1 word)
159162
m_WordIndex++;
@@ -174,30 +177,23 @@ namespace bitstream
174177

175178
BS_ASSERT(num_bytes * 8U >= m_NumBitsRead);
176179

177-
// Align with word size
178-
uint32_t remainder = m_NumBitsRead % 32;
179-
if (remainder != 0)
180-
{
181-
uint32_t zero;
182-
bool status = serialize_bits(zero, 32 - remainder);
183-
184-
BS_ASSERT(status && zero == 0);
185-
}
180+
uint32_t offset = m_NumBitsRead / 32;
181+
uint32_t zero;
186182

187183
// Test for zeros in padding
188-
for (uint32_t i = m_WordIndex; i < num_bytes / 4; i++)
184+
for (uint32_t i = offset; i < num_bytes / 4; i++)
189185
{
190-
uint32_t zero = 0;
191186
bool status = serialize_bits(zero, 32);
192187

193188
BS_ASSERT(status && zero == 0);
194189
}
195190

191+
uint32_t remainder = num_bytes * 8U - m_NumBitsRead;
192+
196193
// Test the last word more carefully, as it may have data
197-
if (num_bytes % 4 != 0)
194+
if (remainder % 32U != 0U)
198195
{
199-
uint32_t zero = 0;
200-
bool status = serialize_bits(zero, (num_bytes % 4) * 8);
196+
bool status = serialize_bits(zero, remainder);
201197

202198
BS_ASSERT(status && zero == 0);
203199
}

include/bitstream/stream/bit_writer.h

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ namespace bitstream
159159
m_WordIndex++;
160160
}
161161

162-
return (m_NumBitsWritten - 1U) / 8U + 1U;
162+
if (m_NumBitsWritten > 0U)
163+
return (m_NumBitsWritten - 1U) / 8U + 1U;
164+
else
165+
return 0U;
163166
}
164167

165168
/**
@@ -189,13 +192,13 @@ namespace bitstream
189192
uint32_t num_bytes = flush();
190193

191194
// Copy protocol version to buffer
192-
std::memcpy(m_Buffer, &protocol_version, sizeof(uint32_t));
195+
*m_Buffer = protocol_version;
193196

194197
// Generate checksum of version + data
195198
uint32_t checksum = utility::crc_uint32(reinterpret_cast<uint8_t*>(m_Buffer), num_bytes);
196199

197200
// Put checksum at beginning
198-
std::memcpy(m_Buffer, &checksum, sizeof(uint32_t));
201+
*m_Buffer = checksum;
199202

200203
return num_bytes;
201204
}
@@ -209,18 +212,20 @@ namespace bitstream
209212
{
210213
BS_ASSERT(num_bytes * 8U <= m_TotalBits);
211214

212-
flush();
213-
214215
BS_ASSERT(num_bytes * 8U >= m_NumBitsWritten);
215216

216-
// Set to the padding to 0
217-
std::memset(m_Buffer + m_WordIndex, 0, num_bytes - m_WordIndex * 4U);
217+
uint32_t offset = m_NumBitsWritten / 32;
218+
uint32_t zero = 0;
219+
220+
// Serialize words
221+
for (uint32_t i = offset; i < num_bytes / 4; i++)
222+
BS_ASSERT(serialize_bits(zero, 32));
218223

219-
m_NumBitsWritten = num_bytes * 8U;
224+
uint32_t remainder = num_bytes * 8U - m_NumBitsWritten;
220225

221-
m_Scratch = 0ULL;
222-
m_ScratchBits = (num_bytes % 4U) * 8U;
223-
m_WordIndex = num_bytes / 4U;
226+
// Align to byte
227+
if (remainder % 32U != 0U)
228+
BS_ASSERT(serialize_bits(zero, remainder));
224229

225230
return true;
226231
}

src/test/stream_test.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,27 +77,56 @@ namespace bitstream::test::stream
7777
{
7878
// Test checksum
7979
uint32_t protocol_version = 0xDEADBEEF;
80-
uint32_t value = 3;
80+
uint32_t value = 5;
8181

8282
// Write some initial values and finish with a checksum
8383
byte_buffer<16> buffer;
8484
bit_writer writer(buffer);
8585

8686
writer.prepend_checksum();
87-
BS_TEST_ASSERT(writer.serialize_bits(value, 2));
87+
BS_TEST_ASSERT(writer.serialize_bits(value, 3));
8888
uint16_t num_bytes = writer.serialize_checksum(protocol_version);
8989

9090
// Read the checksum and validate
9191
uint32_t out_value;
9292
bit_reader reader(buffer, num_bytes);
9393

9494
BS_TEST_ASSERT(reader.serialize_checksum(protocol_version));
95-
BS_TEST_ASSERT(reader.serialize_bits(out_value, 2));
95+
BS_TEST_ASSERT(reader.serialize_bits(out_value, 3));
9696

9797
BS_TEST_ASSERT(out_value == value);
9898
}
9999

100-
BS_ADD_TEST(test_serialize_padding)
100+
BS_ADD_TEST(test_serialize_padding_small)
101+
{
102+
// Test padding
103+
uint32_t in_value1 = 3;
104+
uint32_t in_value2 = 6;
105+
106+
// Write some initial value, pad it, and then write another value
107+
byte_buffer<32> buffer;
108+
bit_writer writer(buffer);
109+
BS_TEST_ASSERT(writer.serialize_bits(in_value1, 3));
110+
BS_TEST_ASSERT(writer.pad_to_size(2));
111+
BS_TEST_ASSERT(writer.serialize_bits(in_value2, 5));
112+
uint32_t num_bytes = writer.flush();
113+
114+
BS_TEST_ASSERT(num_bytes == 3);
115+
116+
// Read the values and validate padding
117+
uint32_t out_value1;
118+
uint32_t out_value2;
119+
bit_reader reader(buffer, num_bytes);
120+
121+
BS_TEST_ASSERT(reader.serialize_bits(out_value1, 3));
122+
BS_TEST_ASSERT(reader.pad_to_size(2));
123+
BS_TEST_ASSERT(reader.serialize_bits(out_value2, 5));
124+
125+
BS_TEST_ASSERT(out_value1 == in_value1);
126+
BS_TEST_ASSERT(out_value2 == in_value2);
127+
}
128+
129+
BS_ADD_TEST(test_serialize_padding_large)
101130
{
102131
// Test padding
103132
uint32_t in_value1 = 3;

0 commit comments

Comments
 (0)