Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/src/arrow/util/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ add_arrow_test(bit-utility-test
bit_util_test.cc
bitmap_test.cc
bpacking_test.cc
rle_bitmap_test.cc
rle_encoding_test.cc
Comment thread
AntoinePrv marked this conversation as resolved.
test_common.cc)

Expand Down
36 changes: 36 additions & 0 deletions cpp/src/arrow/util/bit_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
#pragma once

#include <bit>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <type_traits>

#include "arrow/util/endian.h"
#include "arrow/util/macros.h"
#include "arrow/util/visibility.h"

Expand Down Expand Up @@ -176,6 +179,39 @@ static constexpr bool GetBitFromByte(uint8_t byte, uint8_t i) {
return byte & kBitmask[i];
}

template <typename Uint>
struct CopyBitsParams {
Uint src = {};
Uint dst = {};
int start = {};
int end = {};
};

/// Copy a contiguous span of bits from src into dst.
///
/// Copy bits [start, end[ from src into the position [start, end[ in dst
/// and return the result (inputs are unmodified).
/// Setting ``kAllowFullCopy`` to false is an optimization when the caller can
/// guarantee that the range of bits to copy does not cover the whole range.
template <typename Uint, bool kAllowFullCopy = true>
[[nodiscard]] constexpr Uint CopyBitsInInteger(const CopyBitsParams<Uint>& params) {
constexpr auto kUintSizeBits = static_cast<int>(sizeof(Uint) * 8);
assert(params.start <= params.end);
assert(params.start < kUintSizeBits);
assert(params.end <= kUintSizeBits);

const int length = params.end - params.start;
if constexpr (kAllowFullCopy) {
if (length == kUintSizeBits) {
return params.src;
}
}
Comment thread
AntoinePrv marked this conversation as resolved.
assert(length < kUintSizeBits);
const Uint mask =
static_cast<Uint>(LeastSignificantBitMask<Uint, false>(length) << params.start);
return (~mask & params.dst) | (mask & params.src);
}

static inline void ClearBit(uint8_t* bits, int64_t i) {
bits[i / 8] &= kFlippedBitmask[i % 8];
}
Expand Down
43 changes: 43 additions & 0 deletions cpp/src/arrow/util/bit_util_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1065,4 +1065,47 @@ TEST(SpliceWord, SpliceWord) {
0xfedc456789abcdef);
}

TEST(BitUtil, CopyBits) {
// Copy bits [start, end[ from src into dst, keeping dst's other bits.
using bit_util::CopyBitsInInteger;

// Empty range: result equals dst.
ASSERT_EQ(CopyBitsInInteger<uint8_t>(
{.src = 0b11111111, .dst = 0b00010010, .start = 3, .end = 3}),
0b00010010);
// dst = 0101 0101, src = 1010 1010 -> 0101 1010
ASSERT_EQ(CopyBitsInInteger<uint8_t>(
{.src = 0b10101010, .dst = 0b01010101, .start = 0, .end = 4}),
0b01011010);
// Copy a middle span [2, 5[ of all-ones into an all-zeros dst.
ASSERT_EQ(CopyBitsInInteger<uint8_t>(
{.src = 0b11111111, .dst = 0b00000000, .start = 2, .end = 5}),
0b00011100);
// Copy a middle span [2, 5[ of all-zeros into an all-ones dst.
ASSERT_EQ(CopyBitsInInteger<uint8_t>(
{.src = 0b00000000, .dst = 0b11111111, .start = 2, .end = 5}),
0b11100011);
// Full-word copy returns src unchanged.
ASSERT_EQ(CopyBitsInInteger<uint8_t>(
{.src = 0b10101011, .dst = 0b00010010, .start = 0, .end = 8}),
0b10101011);
// uint16_t partial range [4, 12[: dst keeps its bits outside, src fills inside.
ASSERT_EQ(
CopyBitsInInteger<uint16_t>(
{.src = 0b1010101010101010, .dst = 0b0101010101010101, .start = 4, .end = 12}),
0b0101101010100101);
// uint64_t
ASSERT_EQ(CopyBitsInInteger<uint64_t>({
.src = 0x0123456789abcdef,
.dst = 0xfedcba9876543210,
.start = 0,
.end = 64,
}),
0x0123456789abcdef);
// constexpr-evaluable.
static_assert(CopyBitsInInteger<uint8_t>(
{.src = 0b10101010, .dst = 0b01010101, .start = 0, .end = 4}) ==
0b01011010);
}

} // namespace arrow
Loading
Loading