From: Philippe Proulx Date: Fri, 31 May 2024 19:43:23 +0000 (-0400) Subject: Add bt2c::reverseFixedLenIntBits() X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=e3dc1a7a45954244fdd6096757bfd23c87c9f516;p=babeltrace.git Add bt2c::reverseFixedLenIntBits() This new function reverses the first N least significant bits of a 64-bit integer value, sign-extending if needed, and returns the result. I basically read [1], which shows the version of Knuth, and adapted that code to our coding style and requirements. [1]: https://matthewarcus.wordpress.com/2012/11/18/reversing-a-64-bit-word/ Signed-off-by: Philippe Proulx Change-Id: Ib67fd5e8b94e0a82f46527534d47617c87013418 Reviewed-on: https://review.lttng.org/c/babeltrace/+/12706 --- diff --git a/src/Makefile.am b/src/Makefile.am index e9c65562..24efd77e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -185,6 +185,7 @@ cpp_common_libcpp_common_la_SOURCES = \ cpp-common/bt2c/prio-heap.hpp \ cpp-common/bt2c/read-fixed-len-int.hpp \ cpp-common/bt2c/regex.hpp \ + cpp-common/bt2c/reverse-fixed-len-int-bits.hpp \ cpp-common/bt2c/safe-ops.hpp \ cpp-common/bt2c/std-int.hpp \ cpp-common/bt2c/str-scanner.cpp \ diff --git a/src/cpp-common/bt2c/reverse-fixed-len-int-bits.hpp b/src/cpp-common/bt2c/reverse-fixed-len-int-bits.hpp new file mode 100644 index 00000000..b4068c86 --- /dev/null +++ b/src/cpp-common/bt2c/reverse-fixed-len-int-bits.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#ifndef BABELTRACE_CPP_COMMON_BT2C_REVERSE_FIXED_LEN_INT_BITS_HPP +#define BABELTRACE_CPP_COMMON_BT2C_REVERSE_FIXED_LEN_INT_BITS_HPP + +#include +#include + +#include "common/assert.h" + +#include "data-len.hpp" + +namespace bt2c { +namespace internal { + +/* + * Swaps the bits. + * + * And then returns the result. + * + * See . + */ +template +T swapBits(const T p) noexcept +{ + const auto q = ((p >> ShiftV) ^ p) & MaskV; + + return p ^ q ^ (q << ShiftV); +} + +} /* namespace internal */ + +/* + * Based on Knuth's. + * + * For example, given an unsigned `val` with the value 0b111011010 and + * `*len` set to 9, the returned value is 0b010110111. + * + * Given a _signed_ `val` with the value 0b01011 and `*len` set to 5, + * the returned value is + * 0b1111111111111111111111111111111111111111111111111111111111111010 + * (sign extended). + * + * `*len` must be less than or equal to 64. + */ +template +ValT reverseFixedLenIntBits(const ValT val, const DataLen len) +{ + static_assert(sizeof(val) == sizeof(std::uint64_t), "`val` is a 64-bit integer"); + + BT_ASSERT_DBG(*len <= 64); + + static constexpr std::uint64_t m0 = 0x5555555555555555ULL; + + /* Work with the unsigned version to perform the reversal */ + auto uVal = static_cast(val); + + uVal = ((uVal >> 1) & m0) | (uVal & m0) << 1; + uVal = internal::swapBits(uVal); + uVal = internal::swapBits(uVal); + uVal = internal::swapBits(uVal); + uVal = (uVal >> 34) | (uVal << 30); + + /* + * Sign-extends when `ValT` is signed because in that case the sign + * bit (LSB of `val`) is at position 63 before this shift. + */ + return static_cast(uVal) >> (64 - *len); +} + +} /* namespace bt2c */ + +#endif /* BABELTRACE_CPP_COMMON_BT2C_REVERSE_FIXED_LEN_INT_BITS_HPP */