Skip to content

Commit 41babae

Browse files
Added signed int support to bitstream
1 parent e7a7649 commit 41babae

2 files changed

Lines changed: 68 additions & 26 deletions

File tree

middleware/include/bitstream.h

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
#include <stdlib.h>
66
#include <string.h>
77
#include <stdbool.h>
8+
#include <stddef.h>
89
#include <math.h>
910

11+
#define STATIC_ASSERT _Static_assert // Compile-time assertion (C11 thing)
12+
1013
typedef struct {
1114
uint8_t *data; // The bitstream data, stored as bytes
1215
size_t bytes; // The number of bytes in the bitstream
@@ -24,21 +27,33 @@ void bitstream_init(bitstream_t *bitstream, uint8_t *data, size_t bytes);
2427

2528
/**
2629
* @brief Adds data to a bitstream. The data is added to the end of the bitstream.
27-
* @param *bitstream The bitstream to add data to.
28-
* @param value The data to add to the bitstream.
30+
* @param *bitstream The bitstream to add data to. Must be of type: bitstream_t.
31+
* @param value The data to add to the bitstream. Must be of type: uint8_t, uint16_t, uint32_t, int8_t, int16_t, or int32_t.
2932
* @param num_bits The length of the data in bits.
3033
* @return Returns 0 if successful, -1 if there is insufficient space in the bitstream, and 1 if overflow occurs.
3134
*/
32-
int bitstream_add(bitstream_t *bitstream, uint32_t value, size_t num_bits);
35+
#define bitstream_add(bitstream, value, num_bits) \
36+
/* Check bitstream parameter type */ \
37+
STATIC_ASSERT( \
38+
__builtin_types_compatible_p(typeof(bitstream), \
39+
bitstream_t *), \
40+
"First argument of bitstream_add() must be a pointer to bitstream_t."), /* Check num_bits parameter type */ \
41+
STATIC_ASSERT( \
42+
__builtin_types_compatible_p(typeof(num_bits), \
43+
size_t), \
44+
"Third argument of bitstream_add() must be size_t."), /* Check value type and call the necessary function. */ \
45+
_Generic((value), \
46+
uint8_t: bitstream_add_uint, \
47+
uint16_t: bitstream_add_uint, \
48+
uint32_t: bitstream_add_uint, \
49+
int8_t: bitstream_add_int, \
50+
int16_t: bitstream_add_int, \
51+
int32_t: bitstream_add_int default: (void (*)( \
52+
void))_invalid_type_error)(bitstream, value, num_bits)
3353

34-
/**
35-
* @brief Reads info from the bitstream.
36-
* @param *bitstream The bitstream to read from.
37-
* @param start_bit The bit to start reading from.
38-
* @param num_bits The amount of bits to read. The maximum is 32 bits, and (start_bit + num_bits) must be less than the total number of bits in the bitstream.
39-
* @return Returns 1 if failed, and 0 if successful.
40-
*/
41-
uint32_t bitstream_read(bitstream_t *bitstream, uint32_t start_bit,
42-
size_t num_bits);
54+
/* Internal functions (not meant to be called directly). */
55+
/* Used by the bitstream_add() macro depending on the input data type. */
56+
int bitstream_add_uint(bitstream_t *bitstream, uint32_t value, size_t num_bits);
57+
int bitstream_add_int(bitstream_t *bitstream, int32_t value, size_t num_bits);
4358

4459
#endif // BITSTREAM_H

middleware/src/bitstream.c

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ void bitstream_init(bitstream_t *bitstream, uint8_t *data, size_t bytes)
99
memset(bitstream->data, 0, bytes); // Zero out the buffer
1010
}
1111

12-
int bitstream_add(bitstream_t *bitstream, uint32_t value, size_t num_bits)
12+
/* Adds an unsigned int to a bitstream. */
13+
static int bitstream_add_uint(bitstream_t *bitstream, uint32_t value,
14+
size_t num_bits)
1315
{
1416
if (bitstream->total_bits + num_bits > (bitstream->bytes * 8)) {
1517
return -1; // Error: not enough space in the bitstream
@@ -18,9 +20,8 @@ int bitstream_add(bitstream_t *bitstream, uint32_t value, size_t num_bits)
1820
bool overflow = false;
1921
if (value >= pow(2, num_bits)) {
2022
overflow =
21-
true; // Error: value is too large for the number of bits, so set overflow to true.
22-
value = pow(2, num_bits) -
23-
1; // Cap value to the maximum value that can be stored in the number of bits.
23+
true; // Error: value is too large for the number of bits
24+
value = pow(2, num_bits) - 1; // Cap value to maximum
2425
}
2526

2627
for (int i = 0; i < num_bits; ++i) {
@@ -34,27 +35,53 @@ int bitstream_add(bitstream_t *bitstream, uint32_t value, size_t num_bits)
3435

3536
if (overflow) {
3637
bitstream->overflow = true;
37-
return 1; // Overflow occurred
38+
return 1; // Error: Overflow occurred
3839
}
3940

4041
return 0; // Success
4142
}
4243

43-
uint32_t bitstream_read(bitstream_t *bitstream, uint32_t start_bit,
44-
size_t num_bits)
44+
/* Adds a signed int to a bitstream. */
45+
static int bitstream_add_int(bitstream_t *bitstream, int32_t value,
46+
size_t num_bits)
4547
{
46-
uint32_t result = 0;
48+
if (bitstream->total_bits + num_bits > (bitstream->bytes * 8)) {
49+
return -1; // Error: not enough space in the bitstream
50+
}
51+
52+
bool overflow = false;
53+
/* For a signed int, 'value' must be in between -2^(num_bits - 1) and 2^(num_bits-1) - 1. */
54+
/* For example, an 6-bit input value must be in-between -32 and 31. */
55+
int32_t max_value = (1LL << (num_bits - 1)) - 1;
56+
int32_t min_value = -(1LL << (num_bits - 1));
4757

48-
if (start_bit + num_bits > bitstream->total_bits) {
49-
return -1; // Error: trying to read beyond bit length
58+
if (value > max_value || value < min_value) {
59+
overflow = true; // Error: value is too large or too small
60+
61+
/* Cap value to maximum or minimum */
62+
if (value > max_value) {
63+
value = max_value;
64+
} else {
65+
value = min_value;
66+
}
5067
}
5168

69+
/* Convert to unsigned representation for bit manipulation */
70+
uint32_t unsigned_value = (uint32_t)value;
71+
5272
for (int i = 0; i < num_bits; ++i) {
53-
if (bitstream->data[(start_bit + i) / 8] &
54-
(1 << (7 - ((start_bit + i) % 8)))) {
55-
result |= (1 << (num_bits - 1 - i));
73+
if (unsigned_value & (1u << (num_bits - 1 - i))) {
74+
bitstream->data[(bitstream->total_bits + i) / 8] |=
75+
(1 << (7 - ((bitstream->total_bits + i) % 8)));
5676
}
5777
}
5878

59-
return result;
79+
bitstream->total_bits += num_bits;
80+
81+
if (overflow) {
82+
bitstream->overflow = true;
83+
return 1; // Error: Overflow occurred
84+
}
85+
86+
return 0; // Success
6087
}

0 commit comments

Comments
 (0)