Coverage Report

Created: 2025-08-26 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/Users/andrewlamb/Software/arrow-rs/arrow-buffer/src/buffer/ops.rs
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
use super::{Buffer, MutableBuffer};
19
use crate::util::bit_util::ceil;
20
21
/// Apply a bitwise operation `op` to four inputs and return the result as a Buffer.
22
/// The inputs are treated as bitmaps, meaning that offsets and length are specified in number of bits.
23
0
pub fn bitwise_quaternary_op_helper<F>(
24
0
    buffers: [&Buffer; 4],
25
0
    offsets: [usize; 4],
26
0
    len_in_bits: usize,
27
0
    op: F,
28
0
) -> Buffer
29
0
where
30
0
    F: Fn(u64, u64, u64, u64) -> u64,
31
{
32
0
    let first_chunks = buffers[0].bit_chunks(offsets[0], len_in_bits);
33
0
    let second_chunks = buffers[1].bit_chunks(offsets[1], len_in_bits);
34
0
    let third_chunks = buffers[2].bit_chunks(offsets[2], len_in_bits);
35
0
    let fourth_chunks = buffers[3].bit_chunks(offsets[3], len_in_bits);
36
37
0
    let chunks = first_chunks
38
0
        .iter()
39
0
        .zip(second_chunks.iter())
40
0
        .zip(third_chunks.iter())
41
0
        .zip(fourth_chunks.iter())
42
0
        .map(|(((first, second), third), fourth)| op(first, second, third, fourth));
43
    // Soundness: `BitChunks` is a `BitChunks` iterator which
44
    // correctly reports its upper bound
45
0
    let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
46
47
0
    let remainder_bytes = ceil(first_chunks.remainder_len(), 8);
48
0
    let rem = op(
49
0
        first_chunks.remainder_bits(),
50
0
        second_chunks.remainder_bits(),
51
0
        third_chunks.remainder_bits(),
52
0
        fourth_chunks.remainder_bits(),
53
0
    );
54
    // we are counting its starting from the least significant bit, to to_le_bytes should be correct
55
0
    let rem = &rem.to_le_bytes()[0..remainder_bytes];
56
0
    buffer.extend_from_slice(rem);
57
58
0
    buffer.into()
59
0
}
60
61
/// Apply a bitwise operation `op` to two inputs and return the result as a Buffer.
62
/// The inputs are treated as bitmaps, meaning that offsets and length are specified in number of bits.
63
0
pub fn bitwise_bin_op_helper<F>(
64
0
    left: &Buffer,
65
0
    left_offset_in_bits: usize,
66
0
    right: &Buffer,
67
0
    right_offset_in_bits: usize,
68
0
    len_in_bits: usize,
69
0
    mut op: F,
70
0
) -> Buffer
71
0
where
72
0
    F: FnMut(u64, u64) -> u64,
73
{
74
0
    let left_chunks = left.bit_chunks(left_offset_in_bits, len_in_bits);
75
0
    let right_chunks = right.bit_chunks(right_offset_in_bits, len_in_bits);
76
77
0
    let chunks = left_chunks
78
0
        .iter()
79
0
        .zip(right_chunks.iter())
80
0
        .map(|(left, right)| op(left, right));
81
    // Soundness: `BitChunks` is a `BitChunks` iterator which
82
    // correctly reports its upper bound
83
0
    let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
84
85
0
    let remainder_bytes = ceil(left_chunks.remainder_len(), 8);
86
0
    let rem = op(left_chunks.remainder_bits(), right_chunks.remainder_bits());
87
    // we are counting its starting from the least significant bit, to to_le_bytes should be correct
88
0
    let rem = &rem.to_le_bytes()[0..remainder_bytes];
89
0
    buffer.extend_from_slice(rem);
90
91
0
    buffer.into()
92
0
}
93
94
/// Apply a bitwise operation `op` to one input and return the result as a Buffer.
95
/// The input is treated as a bitmap, meaning that offset and length are specified in number of bits.
96
0
pub fn bitwise_unary_op_helper<F>(
97
0
    left: &Buffer,
98
0
    offset_in_bits: usize,
99
0
    len_in_bits: usize,
100
0
    mut op: F,
101
0
) -> Buffer
102
0
where
103
0
    F: FnMut(u64) -> u64,
104
{
105
    // reserve capacity and set length so we can get a typed view of u64 chunks
106
0
    let mut result =
107
0
        MutableBuffer::new(ceil(len_in_bits, 8)).with_bitset(len_in_bits / 64 * 8, false);
108
109
0
    let left_chunks = left.bit_chunks(offset_in_bits, len_in_bits);
110
111
0
    let result_chunks = result.typed_data_mut::<u64>().iter_mut();
112
113
0
    result_chunks
114
0
        .zip(left_chunks.iter())
115
0
        .for_each(|(res, left)| {
116
0
            *res = op(left);
117
0
        });
118
119
0
    let remainder_bytes = ceil(left_chunks.remainder_len(), 8);
120
0
    let rem = op(left_chunks.remainder_bits());
121
    // we are counting its starting from the least significant bit, to to_le_bytes should be correct
122
0
    let rem = &rem.to_le_bytes()[0..remainder_bytes];
123
0
    result.extend_from_slice(rem);
124
125
0
    result.into()
126
0
}
127
128
/// Apply a bitwise and to two inputs and return the result as a Buffer.
129
/// The inputs are treated as bitmaps, meaning that offsets and length are specified in number of bits.
130
0
pub fn buffer_bin_and(
131
0
    left: &Buffer,
132
0
    left_offset_in_bits: usize,
133
0
    right: &Buffer,
134
0
    right_offset_in_bits: usize,
135
0
    len_in_bits: usize,
136
0
) -> Buffer {
137
0
    bitwise_bin_op_helper(
138
0
        left,
139
0
        left_offset_in_bits,
140
0
        right,
141
0
        right_offset_in_bits,
142
0
        len_in_bits,
143
0
        |a, b| a & b,
144
    )
145
0
}
146
147
/// Apply a bitwise or to two inputs and return the result as a Buffer.
148
/// The inputs are treated as bitmaps, meaning that offsets and length are specified in number of bits.
149
0
pub fn buffer_bin_or(
150
0
    left: &Buffer,
151
0
    left_offset_in_bits: usize,
152
0
    right: &Buffer,
153
0
    right_offset_in_bits: usize,
154
0
    len_in_bits: usize,
155
0
) -> Buffer {
156
0
    bitwise_bin_op_helper(
157
0
        left,
158
0
        left_offset_in_bits,
159
0
        right,
160
0
        right_offset_in_bits,
161
0
        len_in_bits,
162
0
        |a, b| a | b,
163
    )
164
0
}
165
166
/// Apply a bitwise xor to two inputs and return the result as a Buffer.
167
/// The inputs are treated as bitmaps, meaning that offsets and length are specified in number of bits.
168
0
pub fn buffer_bin_xor(
169
0
    left: &Buffer,
170
0
    left_offset_in_bits: usize,
171
0
    right: &Buffer,
172
0
    right_offset_in_bits: usize,
173
0
    len_in_bits: usize,
174
0
) -> Buffer {
175
0
    bitwise_bin_op_helper(
176
0
        left,
177
0
        left_offset_in_bits,
178
0
        right,
179
0
        right_offset_in_bits,
180
0
        len_in_bits,
181
0
        |a, b| a ^ b,
182
    )
183
0
}
184
185
/// Apply a bitwise and_not to two inputs and return the result as a Buffer.
186
/// The inputs are treated as bitmaps, meaning that offsets and length are specified in number of bits.
187
0
pub fn buffer_bin_and_not(
188
0
    left: &Buffer,
189
0
    left_offset_in_bits: usize,
190
0
    right: &Buffer,
191
0
    right_offset_in_bits: usize,
192
0
    len_in_bits: usize,
193
0
) -> Buffer {
194
0
    bitwise_bin_op_helper(
195
0
        left,
196
0
        left_offset_in_bits,
197
0
        right,
198
0
        right_offset_in_bits,
199
0
        len_in_bits,
200
0
        |a, b| a & !b,
201
    )
202
0
}
203
204
/// Apply a bitwise not to one input and return the result as a Buffer.
205
/// The input is treated as a bitmap, meaning that offset and length are specified in number of bits.
206
0
pub fn buffer_unary_not(left: &Buffer, offset_in_bits: usize, len_in_bits: usize) -> Buffer {
207
0
    bitwise_unary_op_helper(left, offset_in_bits, len_in_bits, |a| !a)
208
0
}