Coverage Report

Created: 2025-11-17 14:14

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
pub fn bitwise_quaternary_op_helper<F>(
24
    buffers: [&Buffer; 4],
25
    offsets: [usize; 4],
26
    len_in_bits: usize,
27
    op: F,
28
) -> Buffer
29
where
30
    F: Fn(u64, u64, u64, u64) -> u64,
31
{
32
    let first_chunks = buffers[0].bit_chunks(offsets[0], len_in_bits);
33
    let second_chunks = buffers[1].bit_chunks(offsets[1], len_in_bits);
34
    let third_chunks = buffers[2].bit_chunks(offsets[2], len_in_bits);
35
    let fourth_chunks = buffers[3].bit_chunks(offsets[3], len_in_bits);
36
37
    let chunks = first_chunks
38
        .iter()
39
        .zip(second_chunks.iter())
40
        .zip(third_chunks.iter())
41
        .zip(fourth_chunks.iter())
42
        .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
    let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
46
47
    let remainder_bytes = ceil(first_chunks.remainder_len(), 8);
48
    let rem = op(
49
        first_chunks.remainder_bits(),
50
        second_chunks.remainder_bits(),
51
        third_chunks.remainder_bits(),
52
        fourth_chunks.remainder_bits(),
53
    );
54
    // we are counting its starting from the least significant bit, to to_le_bytes should be correct
55
    let rem = &rem.to_le_bytes()[0..remainder_bytes];
56
    buffer.extend_from_slice(rem);
57
58
    buffer.into()
59
}
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
789
pub fn bitwise_bin_op_helper<F>(
64
789
    left: &Buffer,
65
789
    left_offset_in_bits: usize,
66
789
    right: &Buffer,
67
789
    right_offset_in_bits: usize,
68
789
    len_in_bits: usize,
69
789
    mut op: F,
70
789
) -> Buffer
71
789
where
72
789
    F: FnMut(u64, u64) -> u64,
73
{
74
789
    let left_chunks = left.bit_chunks(left_offset_in_bits, len_in_bits);
75
789
    let right_chunks = right.bit_chunks(right_offset_in_bits, len_in_bits);
76
77
789
    let chunks = left_chunks
78
789
        .iter()
79
789
        .zip(right_chunks.iter())
80
789
        .map(|(left, right)| 
op768
(
left768
,
right768
));
81
    // Soundness: `BitChunks` is a `BitChunks` iterator which
82
    // correctly reports its upper bound
83
789
    let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
84
85
789
    let remainder_bytes = ceil(left_chunks.remainder_len(), 8);
86
789
    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
789
    let rem = &rem.to_le_bytes()[0..remainder_bytes];
89
789
    buffer.extend_from_slice(rem);
90
91
789
    buffer.into()
92
789
}
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
271
pub fn bitwise_unary_op_helper<F>(
97
271
    left: &Buffer,
98
271
    offset_in_bits: usize,
99
271
    len_in_bits: usize,
100
271
    mut op: F,
101
271
) -> Buffer
102
271
where
103
271
    F: FnMut(u64) -> u64,
104
{
105
    // reserve capacity and set length so we can get a typed view of u64 chunks
106
271
    let mut result =
107
271
        MutableBuffer::new(ceil(len_in_bits, 8)).with_bitset(len_in_bits / 64 * 8, false);
108
109
271
    let left_chunks = left.bit_chunks(offset_in_bits, len_in_bits);
110
111
271
    let result_chunks = result.typed_data_mut::<u64>().iter_mut();
112
113
271
    result_chunks
114
271
        .zip(left_chunks.iter())
115
271
        .for_each(|(res, left)| 
{256
116
256
            *res = op(left);
117
256
        });
118
119
271
    let remainder_bytes = ceil(left_chunks.remainder_len(), 8);
120
271
    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
271
    let rem = &rem.to_le_bytes()[0..remainder_bytes];
123
271
    result.extend_from_slice(rem);
124
125
271
    result.into()
126
271
}
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
530
pub fn buffer_bin_and(
131
530
    left: &Buffer,
132
530
    left_offset_in_bits: usize,
133
530
    right: &Buffer,
134
530
    right_offset_in_bits: usize,
135
530
    len_in_bits: usize,
136
530
) -> Buffer {
137
530
    bitwise_bin_op_helper(
138
530
        left,
139
530
        left_offset_in_bits,
140
530
        right,
141
530
        right_offset_in_bits,
142
530
        len_in_bits,
143
1.04k
        |a, b| a & b,
144
    )
145
530
}
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
9
pub fn buffer_unary_not(left: &Buffer, offset_in_bits: usize, len_in_bits: usize) -> Buffer {
207
9
    bitwise_unary_op_helper(left, offset_in_bits, len_in_bits, |a| !a)
208
9
}