arrow_buffer/buffer/
ops.rs

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
18use super::{Buffer, MutableBuffer};
19use 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.
23pub fn bitwise_quaternary_op_helper<F>(
24    buffers: [&Buffer; 4],
25    offsets: [usize; 4],
26    len_in_bits: usize,
27    op: F,
28) -> Buffer
29where
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.
63pub fn bitwise_bin_op_helper<F>(
64    left: &Buffer,
65    left_offset_in_bits: usize,
66    right: &Buffer,
67    right_offset_in_bits: usize,
68    len_in_bits: usize,
69    mut op: F,
70) -> Buffer
71where
72    F: FnMut(u64, u64) -> u64,
73{
74    let left_chunks = left.bit_chunks(left_offset_in_bits, len_in_bits);
75    let right_chunks = right.bit_chunks(right_offset_in_bits, len_in_bits);
76
77    let chunks = left_chunks
78        .iter()
79        .zip(right_chunks.iter())
80        .map(|(left, right)| op(left, right));
81    // Soundness: `BitChunks` is a `BitChunks` iterator which
82    // correctly reports its upper bound
83    let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
84
85    let remainder_bytes = ceil(left_chunks.remainder_len(), 8);
86    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    let rem = &rem.to_le_bytes()[0..remainder_bytes];
89    buffer.extend_from_slice(rem);
90
91    buffer.into()
92}
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.
96pub fn bitwise_unary_op_helper<F>(
97    left: &Buffer,
98    offset_in_bits: usize,
99    len_in_bits: usize,
100    mut op: F,
101) -> Buffer
102where
103    F: FnMut(u64) -> u64,
104{
105    // reserve capacity and set length so we can get a typed view of u64 chunks
106    let mut result =
107        MutableBuffer::new(ceil(len_in_bits, 8)).with_bitset(len_in_bits / 64 * 8, false);
108
109    let left_chunks = left.bit_chunks(offset_in_bits, len_in_bits);
110
111    let result_chunks = result.typed_data_mut::<u64>().iter_mut();
112
113    result_chunks
114        .zip(left_chunks.iter())
115        .for_each(|(res, left)| {
116            *res = op(left);
117        });
118
119    let remainder_bytes = ceil(left_chunks.remainder_len(), 8);
120    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    let rem = &rem.to_le_bytes()[0..remainder_bytes];
123    result.extend_from_slice(rem);
124
125    result.into()
126}
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.
130pub fn buffer_bin_and(
131    left: &Buffer,
132    left_offset_in_bits: usize,
133    right: &Buffer,
134    right_offset_in_bits: usize,
135    len_in_bits: usize,
136) -> Buffer {
137    bitwise_bin_op_helper(
138        left,
139        left_offset_in_bits,
140        right,
141        right_offset_in_bits,
142        len_in_bits,
143        |a, b| a & b,
144    )
145}
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.
149pub fn buffer_bin_or(
150    left: &Buffer,
151    left_offset_in_bits: usize,
152    right: &Buffer,
153    right_offset_in_bits: usize,
154    len_in_bits: usize,
155) -> Buffer {
156    bitwise_bin_op_helper(
157        left,
158        left_offset_in_bits,
159        right,
160        right_offset_in_bits,
161        len_in_bits,
162        |a, b| a | b,
163    )
164}
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.
168pub fn buffer_bin_xor(
169    left: &Buffer,
170    left_offset_in_bits: usize,
171    right: &Buffer,
172    right_offset_in_bits: usize,
173    len_in_bits: usize,
174) -> Buffer {
175    bitwise_bin_op_helper(
176        left,
177        left_offset_in_bits,
178        right,
179        right_offset_in_bits,
180        len_in_bits,
181        |a, b| a ^ b,
182    )
183}
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.
187pub fn buffer_bin_and_not(
188    left: &Buffer,
189    left_offset_in_bits: usize,
190    right: &Buffer,
191    right_offset_in_bits: usize,
192    len_in_bits: usize,
193) -> Buffer {
194    bitwise_bin_op_helper(
195        left,
196        left_offset_in_bits,
197        right,
198        right_offset_in_bits,
199        len_in_bits,
200        |a, b| a & !b,
201    )
202}
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.
206pub fn buffer_unary_not(left: &Buffer, offset_in_bits: usize, len_in_bits: usize) -> Buffer {
207    bitwise_unary_op_helper(left, offset_in_bits, len_in_bits, |a| !a)
208}