Skip to content

Commit

Permalink
Progress on #235, adding unaligned copy. (#266)
Browse files Browse the repository at this point in the history
Adding a version of unaligned copy for little-endian platforms that
provides a single abstraction for vectorized unaligned copy. This
replaces the v0 BitStream + unalignedCopy abstractions making a v1
"bit stream" into simply an std::vector and a std::size_t bit_offset.

The abstraction allows the vector's word size to be parameterized which
could provide better optimizations where a given architecture can
perform single operations across multiple bytes instead of hard-coding
all 8-bit operations. The usefulness versus complexity of this
optimization will play out in subsequent pull-requests as we start
utilizing this copy operation in the generated dsdl types.

Progress on #235, adding unaligned copy

Version 2 of this utility. This one is endian agnostic (I think).
  • Loading branch information
thirtytwobits authored Aug 9, 2019
1 parent 989c947 commit 1e0d947
Show file tree
Hide file tree
Showing 6 changed files with 458 additions and 2 deletions.
27 changes: 26 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,32 @@
"functional": "cpp",
"iomanip": "cpp",
"ratio": "cpp",
"thread": "cpp"
"thread": "cpp",
"__bit_reference": "cpp",
"__config": "cpp",
"__debug": "cpp",
"__errc": "cpp",
"__functional_base": "cpp",
"__hash_table": "cpp",
"__locale": "cpp",
"__mutex_base": "cpp",
"__node_handle": "cpp",
"__nullptr": "cpp",
"__split_buffer": "cpp",
"__string": "cpp",
"__threading_support": "cpp",
"__tree": "cpp",
"__tuple": "cpp",
"atomic": "cpp",
"bitset": "cpp",
"cstdarg": "cpp",
"ios": "cpp",
"iterator": "cpp",
"locale": "cpp",
"map": "cpp",
"mutex": "cpp",
"set": "cpp",
"string": "cpp"
},
"C_Cpp.default.cppStandard": "c++11",
"C_Cpp.default.cStandard": "c99",
Expand Down
94 changes: 94 additions & 0 deletions libuavcan/include/libuavcan/platform/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,100 @@ class LIBUAVCAN_EXPORT PoolAllocator
}
};

/**
* Copy bits from a byte array using arbitrary alignment to an aligned byte array.
*
* @param src The byte array to copy from.
* @param src_offset_bits The offset, in bits, from the start of the src array to
* start copying from.
* @param dst The byte array to copy data into.
* @param length_bits The total length of bits to copy. The caller must ensure
* that the size of src and dst are >= this value.
*
* @return The number of bits copied.
*/
inline std::size_t copyBitsUnalignedToAligned(const std::uint8_t* const src,
const std::size_t src_offset_bits,
std::uint8_t* const dst,
const std::size_t length_bits)
{
if (nullptr == src || nullptr == dst || length_bits == 0)
{
return 0;
}
std::size_t bits_copied = 0;
std::size_t offset_bits = src_offset_bits;
const std::size_t local_offset = src_offset_bits % 8U;
do
{
std::size_t current_byte = offset_bits / 8U;
const std::size_t bits_from_src_byte = 8U - local_offset;
bits_copied += std::min(length_bits, bits_from_src_byte);
dst[current_byte] &= static_cast<std::uint8_t>(0xFF << bits_from_src_byte);
dst[current_byte] |= static_cast<std::uint8_t>(src[current_byte] >> local_offset);
offset_bits += 8U;
if (offset_bits < length_bits)
{
current_byte = offset_bits / 8U;
dst[current_byte] = static_cast<std::uint8_t>(src[current_byte] << bits_from_src_byte);
bits_copied += local_offset;
}
else
{
// we don't need to reevaluate the while condition.
break;
}
} while (true);
return bits_copied;
}

/**
* Copy aligned bits from a byte array to another byte array using arbitrary alignment.
*
* @param src The byte array to copy from.
* @param dst The byte array to copy data into.
* @param dst_offset_bits The offset, in bits, from the start of the dst array to
* start writing to.
* @param length_bits The total length of bits to copy. The caller must ensure
* that the size of src and dst are >= this value.
*
* @return The number of bits copied.
*/
inline std::size_t copyBitsAlignedToUnaligned(const std::uint8_t* const src,
std::uint8_t* const dst,
const std::size_t dst_offset_bits,
const std::size_t length_bits)
{
if (nullptr == src || nullptr == dst || length_bits == 0)
{
return 0;
}
std::size_t bits_copied = 0;
std::size_t offset_bits = dst_offset_bits;
const std::size_t local_offset = dst_offset_bits % 8U;
do
{
std::size_t current_byte = offset_bits / 8U;
const std::size_t bits_from_src_byte = 8U - local_offset;
dst[current_byte] &= static_cast<std::uint8_t>(0xFF >> bits_from_src_byte);
dst[current_byte] |= static_cast<std::uint8_t>(src[current_byte] << local_offset);
offset_bits += 8U;
bits_copied += std::min(length_bits, bits_from_src_byte);
if (offset_bits < length_bits)
{
dst[current_byte] |= static_cast<std::uint8_t>(src[offset_bits / 8U] >> bits_from_src_byte);
bits_copied += local_offset;
}
else
{
// we don't need to reevaluate the while condition.
break;
}
} while (true);

return bits_copied;
}

} // namespace memory
} // namespace platform
} // namespace libuavcan
Expand Down
1 change: 1 addition & 0 deletions libuavcan_validation_suite/include/lvs/lvs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define LIBUAVCAN_LVS_HPP_INCLUDED

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "libuavcan/libuavcan.hpp"

#include <ostream>
Expand Down
Loading

0 comments on commit 1e0d947

Please sign in to comment.