Skip to content

Commit

Permalink
Remove exceptions from unsigned packing in to_bytes() (#5)
Browse files Browse the repository at this point in the history
remove exceptions from `to_bytes()` in favor of a status boolean
  • Loading branch information
polymerizedsage authored Oct 28, 2024
1 parent 4ebf558 commit d2097f5
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 32 deletions.
29 changes: 9 additions & 20 deletions include/science/libndtp/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ inline uint16_t crc16(const ByteArray& data, uint16_t poly = 0x8005, uint16_t in
* Handles both signed and unsigned integers.
*/
template <typename T>
std::pair<ByteArray, BitOffset> to_bytes(
std::tuple<ByteArray, BitOffset, bool> to_bytes(
const std::vector<T>& values,
uint8_t bit_width,
const ByteArray& existing = {},
Expand Down Expand Up @@ -61,29 +61,18 @@ std::pair<ByteArray, BitOffset> to_bytes(
uint8_t current_byte = (continue_last && !result.empty()) ? result.back() : 0;
int bits_in_current_byte = writing_bit_offset;

bool status_good = true;
for (const auto& value : values) {
int val = value;
T val = value;
if (is_signed) {
int min_value = -(1 << (bit_width - 1));
int max_value = (1 << (bit_width - 1)) - 1;
if (val < min_value || val > max_value) {
throw std::invalid_argument(
"signed value " + std::to_string(val) + " doesn't fit in " + std::to_string(bit_width) + " bits"
);
}
if (val < 0) {
val = (1 << bit_width) + val;
if ( val > (1 << (bit_width - 1)) - 1 || val < -(1 << (bit_width - 1))) {
status_good = false;
}
} else {
if (val < 0) {
throw std::invalid_argument("unsigned packing specified, but value is negative");
}
if (val >= (1 << bit_width)) {
throw std::invalid_argument(
"unsigned value " + std::to_string(val) + " doesn't fit in " + std::to_string(bit_width) + " bits"
);
if (val > (1 << bit_width) - 1) {
status_good = false;
}
}
}

int remaining_bits = bit_width;
while (remaining_bits > 0) {
Expand Down Expand Up @@ -119,7 +108,7 @@ std::pair<ByteArray, BitOffset> to_bytes(
result.push_back(current_byte);
}

return { result, bits_in_current_byte };
return { result, bits_in_current_byte, status_good };
}


Expand Down
2 changes: 1 addition & 1 deletion src/science/libndtp/ndtp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ ByteArray NDTPPayloadSpiketrain::pack() const {
result.push_back(bin_size_ms);

// pack clamped spike counts
auto [bytes, final_bit_offset] = to_bytes(clamped_counts, BIT_WIDTH_BINNED_SPIKES, {}, 0);
auto [bytes, final_bit_offset, _] = to_bytes(clamped_counts, BIT_WIDTH_BINNED_SPIKES, {}, 0);
result.insert(result.end(), bytes.begin(), bytes.end());

return result;
Expand Down
34 changes: 23 additions & 11 deletions test/test_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,66 @@
namespace science::libndtp {

TEST(UtilsTest, ToBytesBasicFunctionality) {
auto [result1, offset1] = to_bytes<uint64_t>({1, 2, 3, 0}, 2);
auto [result1, offset1, success1] = to_bytes<uint64_t>({1, 2, 3, 0}, 2);
EXPECT_EQ(result1, (std::vector<uint8_t>{0x6C}));
EXPECT_EQ(offset1, 0);
EXPECT_TRUE(success1);

auto [result2, offset2] = to_bytes<uint64_t>({1, 2, 3, 2, 1}, 2);
auto [result2, offset2, success2] = to_bytes<uint64_t>({1, 2, 3, 2, 1}, 2);
EXPECT_EQ(result2, (std::vector<uint8_t>{0x6E, 0x40}));
EXPECT_EQ(offset2, 2);
EXPECT_TRUE(success2);

auto [result3, offset3] = to_bytes<uint64_t>({7, 5, 3, 1}, 12);
auto [result3, offset3, success3] = to_bytes<uint64_t>({7, 5, 3, 1}, 12);
EXPECT_EQ(result3, (std::vector<uint8_t>{0x00, 0x70, 0x05, 0x00, 0x30, 0x01}));
EXPECT_EQ(offset3, 0);
EXPECT_TRUE(success3);

auto [result4, offset4] = to_bytes<int64_t>({-7, -5, -3, -1}, 12, {}, 0, true);
auto [result4, offset4, success4] = to_bytes<int64_t>({-7, -5, -3, -1}, 12, {}, 0, true);
EXPECT_EQ(result4, (std::vector<uint8_t>{0xFF, 0x9F, 0xFB, 0xFF, 0xDF, 0xFF}));
EXPECT_EQ(offset4, 0);
EXPECT_TRUE(success4);

auto [result5, offset5] = to_bytes<uint64_t>({7, 5, 3}, 12, {0x01, 0x00}, 4);
auto [result5, offset5, success5] = to_bytes<uint64_t>({7, 5, 3}, 12, {0x01, 0x00}, 4);
EXPECT_EQ(result5, (std::vector<uint8_t>{0x01, 0x00, 0x07, 0x00, 0x50, 0x03}));
EXPECT_EQ(offset5, 0);
EXPECT_TRUE(success5);

auto [result6, offset6] = to_bytes<int64_t>({-7, -5, -3}, 12, {0x01, 0x00}, 4, true);
auto [result6, offset6, success6] = to_bytes<int64_t>({-7, -5, -3}, 12, {0x01, 0x00}, 4, true);
EXPECT_EQ(result6, (std::vector<uint8_t>{0x01, 0x0F, 0xF9, 0xFF, 0xBF, 0xFD}));
EXPECT_EQ(offset6, 0);
EXPECT_TRUE(success6);

auto [result7, offset7] = to_bytes<uint64_t>({7, 5, 3}, 12);
auto [result7, offset7, success7] = to_bytes<uint64_t>({7, 5, 3}, 12);
EXPECT_EQ(result7, (std::vector<uint8_t>{0x00, 0x70, 0x05, 0x00, 0x30}));
EXPECT_EQ(offset7, 4);
EXPECT_TRUE(success7);

auto [result8, offset8] = to_bytes<uint64_t>({1, 2, 3, 4}, 8);
auto [result8, offset8, success8] = to_bytes<uint64_t>({1, 2, 3, 4}, 8);
EXPECT_EQ(result8, (std::vector<uint8_t>{0x01, 0x02, 0x03, 0x04}));
EXPECT_EQ(offset8, 0);
EXPECT_TRUE(success8);

std::vector<uint8_t> result9;
int offset9;
std::tie(result9, offset9) = to_bytes<uint64_t>({7, 5, 3}, 12);
bool success9;
std::tie(result9, offset9, success9) = to_bytes<uint64_t>({7, 5, 3}, 12);
EXPECT_EQ(result9, (std::vector<uint8_t>{0x00, 0x70, 0x05, 0x00, 0x30}));
EXPECT_EQ(result9.size(), 5);
EXPECT_EQ(offset9, 4);
EXPECT_TRUE(success9);

auto [result10, offset10] = to_bytes<uint64_t>({3, 5, 7}, 12, result9, offset9);
auto [result10, offset10, success10] = to_bytes<uint64_t>({3, 5, 7}, 12, result9, offset9);
EXPECT_EQ(result10, (std::vector<uint8_t>{0x00, 0x70, 0x05, 0x00, 0x30, 0x03, 0x00, 0x50, 0x07}));
EXPECT_EQ(result10.size(), 9);
EXPECT_EQ(offset10, 0);
EXPECT_TRUE(success10);
}

TEST(UtilsTest, ToBytesErrorCases) {
// Test case: 8 doesn't fit in 3 bits
EXPECT_THROW(to_bytes<uint64_t>({8}, 3), std::invalid_argument);
auto [_1, _2, success] = to_bytes<uint64_t>({8}, 3);
EXPECT_FALSE(success);

// Test case: Invalid bit width
EXPECT_THROW(to_bytes<uint64_t>({1, 2, 3, 0}, 0), std::invalid_argument);
Expand Down

0 comments on commit d2097f5

Please sign in to comment.