diff --git a/include/bitstream/stream/bit_reader.h b/include/bitstream/stream/bit_reader.h index ad385a1..8c11412 100644 --- a/include/bitstream/stream/bit_reader.h +++ b/include/bitstream/stream/bit_reader.h @@ -1,16 +1,15 @@ #pragma once #include "../utility/assert.h" -#include "../utility/crc.h" #include "../utility/endian.h" #include "../utility/meta.h" #include "byte_buffer.h" +#include "multi.h" #include "serialize_traits.h" #include "stream_traits.h" #include #include -#include #include namespace bitstream @@ -272,6 +271,20 @@ namespace bitstream return true; } + /** + * @brief Reads from the buffer into mulitple variables. + * @note Pass multi(...) to this in place of multiple calls to the regular serialize functions. + * @tparam ...Args The types of the arguments to pass to the serialize function + * @param ...args The arguments to pass to the serialize function + * @return Whether successful or not + */ + template && ...)>> + [[nodiscard]] bool serialize(Args&&... args) + noexcept((noexcept(std::declval().serialize(std::declval())) && ...)) + { + return (std::forward(args).serialize(*this) && ...); + } + /** * @brief Reads from the buffer, using the given @p Trait. * @note The Trait type in this function must always be explicitly declared diff --git a/include/bitstream/stream/bit_writer.h b/include/bitstream/stream/bit_writer.h index 04585b8..72ae509 100644 --- a/include/bitstream/stream/bit_writer.h +++ b/include/bitstream/stream/bit_writer.h @@ -1,10 +1,10 @@ #pragma once #include "../utility/assert.h" -#include "../utility/crc.h" #include "../utility/endian.h" #include "../utility/meta.h" #include "byte_buffer.h" +#include "multi.h" #include "serialize_traits.h" #include "stream_traits.h" @@ -316,6 +316,20 @@ namespace bitstream return true; } + /** + * @brief Writes to the buffer from multiple variables. + * @note Pass multi(...) to this in place of multiple calls to the regular serialize functions. + * @tparam ...Args The types of the arguments to pass to the serialize function + * @param ...args The arguments to pass to the serialize function + * @return Whether successful or not + */ + template && ...)>> + [[nodiscard]] bool serialize(Args&&... args) + noexcept((noexcept(std::declval().serialize(std::declval())) && ...)) + { + return (std::forward(args).serialize(*this) && ...); + } + /** * @brief Writes to the buffer, using the given @p Trait. * @note The Trait type in this function must always be explicitly declared diff --git a/include/bitstream/stream/multi.h b/include/bitstream/stream/multi.h new file mode 100644 index 0000000..2987f7b --- /dev/null +++ b/include/bitstream/stream/multi.h @@ -0,0 +1,28 @@ +#pragma once +#include "../utility/meta.h" +#include "../utility/parameter.h" + +#include "serialize_traits.h" + +#include + +namespace bitstream +{ + template + struct multi_args + { + std::tuple Args; + + template> + bool serialize(Stream& stream) noexcept(utility::is_serialize_noexcept_v) + { + return std::apply([&](auto&&... args) { return serialize_traits::serialize(stream, args ...); }, std::move(Args)); + } + }; + + template + multi_args multi(Args&&... args) noexcept + { + return multi_args{ std::forward_as_tuple(std::forward(args) ...) }; + } +} \ No newline at end of file diff --git a/include/bitstream/utility/meta.h b/include/bitstream/utility/meta.h index 66c9ca4..dd1868f 100644 --- a/include/bitstream/utility/meta.h +++ b/include/bitstream/utility/meta.h @@ -6,6 +6,17 @@ namespace bitstream::utility { + // Check if instance has a serializable trait + template + struct has_instance_serialize : std::false_type {}; + + template + struct has_instance_serialize().serialize(std::declval()))>> : std::true_type {}; + + template + constexpr bool has_instance_serialize_v = has_instance_serialize::value; + + // Check if type has a serializable trait template struct has_serialize : std::false_type {}; diff --git a/src/test/serialize_multi_test.cpp b/src/test/serialize_multi_test.cpp new file mode 100644 index 0000000..00a0e0d --- /dev/null +++ b/src/test/serialize_multi_test.cpp @@ -0,0 +1,46 @@ +#include "../shared/assert.h" +#include "../shared/test.h" + +#include +#include + +#include +#include + +namespace bitstream::test::multi_serialize +{ + BS_ADD_TEST(test_serialize_multi) + { + // Test serializing multiple values at once + uint32_t in_value1 = 511; + float in_value2 = 99.12345f; + + bounded_range range(-1000.0f, 1000.0f, 0.001f); + + // Write some values + byte_buffer<16> buffer; + fixed_bit_writer writer(buffer); + + BS_TEST_ASSERT(writer.serialize( + multi(in_value1, 328, 611), + multi(range, in_value2) + )); + + uint32_t num_bits = writer.flush(); + + BS_TEST_ASSERT(num_bits == 30); + + // Read the values back and validate + uint32_t out_value1; + float out_value2; + fixed_bit_reader reader(buffer, num_bits); + + BS_TEST_ASSERT(reader.serialize( + multi(out_value1, 328U, 611U), + multi(range, out_value2) + )); + + BS_TEST_ASSERT(out_value1 == in_value1); + BS_TEST_ASSERT(std::abs(in_value2 - out_value2) <= range.get_precision()); + } +} \ No newline at end of file