Skip to content

Commit 7385a8f

Browse files
fulmicotonPSeitz
andauthored
Supporting PartialCmp in VectorColumn. (#1735)
* Supporting PartialCmp in VectorColumn. * Apply suggestions from code review Co-authored-by: PSeitz <[email protected]>
1 parent 13b89cb commit 7385a8f

File tree

2 files changed

+93
-31
lines changed

2 files changed

+93
-31
lines changed

bitpacker/src/lib.rs

+92-30
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
mod bitpacker;
22
mod blocked_bitpacker;
33

4+
use std::cmp::Ordering;
5+
46
pub use crate::bitpacker::{BitPacker, BitUnpacker};
57
pub use crate::blocked_bitpacker::BlockedBitpacker;
68

@@ -37,44 +39,104 @@ pub fn compute_num_bits(n: u64) -> u8 {
3739
}
3840
}
3941

42+
/// Computes the (min, max) of an iterator of `PartialOrd` values.
43+
///
44+
/// For values implementing `Ord` (in a way consistent to their `PartialOrd` impl),
45+
/// this function behaves as expected.
46+
///
47+
/// For values with partial ordering, the behavior is non-trivial and may
48+
/// depends on the order of the values.
49+
/// For floats however, it simply returns the same results as if NaN were
50+
/// skipped.
4051
pub fn minmax<I, T>(mut vals: I) -> Option<(T, T)>
4152
where
4253
I: Iterator<Item = T>,
43-
T: Copy + Ord,
54+
T: Copy + PartialOrd,
4455
{
45-
if let Some(first_el) = vals.next() {
46-
return Some(vals.fold((first_el, first_el), |(min_val, max_val), el| {
47-
(min_val.min(el), max_val.max(el))
48-
}));
56+
let first_el = vals.find(|val| {
57+
// We use this to make sure we skip all NaN values when
58+
// working with a float type.
59+
val.partial_cmp(val) == Some(Ordering::Equal)
60+
})?;
61+
let mut min_so_far: T = first_el;
62+
let mut max_so_far: T = first_el;
63+
for val in vals {
64+
if val.partial_cmp(&min_so_far) == Some(Ordering::Less) {
65+
min_so_far = val;
66+
}
67+
if val.partial_cmp(&max_so_far) == Some(Ordering::Greater) {
68+
max_so_far = val;
69+
}
4970
}
50-
None
71+
Some((min_so_far, max_so_far))
5172
}
5273

53-
#[test]
54-
fn test_compute_num_bits() {
55-
assert_eq!(compute_num_bits(1), 1u8);
56-
assert_eq!(compute_num_bits(0), 0u8);
57-
assert_eq!(compute_num_bits(2), 2u8);
58-
assert_eq!(compute_num_bits(3), 2u8);
59-
assert_eq!(compute_num_bits(4), 3u8);
60-
assert_eq!(compute_num_bits(255), 8u8);
61-
assert_eq!(compute_num_bits(256), 9u8);
62-
assert_eq!(compute_num_bits(5_000_000_000), 33u8);
63-
}
74+
#[cfg(test)]
75+
mod tests {
76+
use super::*;
6477

65-
#[test]
66-
fn test_minmax_empty() {
67-
let vals: Vec<u32> = vec![];
68-
assert_eq!(minmax(vals.into_iter()), None);
69-
}
78+
#[test]
79+
fn test_compute_num_bits() {
80+
assert_eq!(compute_num_bits(1), 1u8);
81+
assert_eq!(compute_num_bits(0), 0u8);
82+
assert_eq!(compute_num_bits(2), 2u8);
83+
assert_eq!(compute_num_bits(3), 2u8);
84+
assert_eq!(compute_num_bits(4), 3u8);
85+
assert_eq!(compute_num_bits(255), 8u8);
86+
assert_eq!(compute_num_bits(256), 9u8);
87+
assert_eq!(compute_num_bits(5_000_000_000), 33u8);
88+
}
7089

71-
#[test]
72-
fn test_minmax_one() {
73-
assert_eq!(minmax(vec![1].into_iter()), Some((1, 1)));
74-
}
90+
#[test]
91+
fn test_minmax_empty() {
92+
let vals: Vec<u32> = vec![];
93+
assert_eq!(minmax(vals.into_iter()), None);
94+
}
7595

76-
#[test]
77-
fn test_minmax_two() {
78-
assert_eq!(minmax(vec![1, 2].into_iter()), Some((1, 2)));
79-
assert_eq!(minmax(vec![2, 1].into_iter()), Some((1, 2)));
96+
#[test]
97+
fn test_minmax_one() {
98+
assert_eq!(minmax(vec![1].into_iter()), Some((1, 1)));
99+
}
100+
101+
#[test]
102+
fn test_minmax_two() {
103+
assert_eq!(minmax(vec![1, 2].into_iter()), Some((1, 2)));
104+
assert_eq!(minmax(vec![2, 1].into_iter()), Some((1, 2)));
105+
}
106+
107+
#[test]
108+
fn test_minmax_nan() {
109+
assert_eq!(
110+
minmax(vec![f64::NAN, 1f64, 2f64].into_iter()),
111+
Some((1f64, 2f64))
112+
);
113+
assert_eq!(
114+
minmax(vec![2f64, f64::NAN, 1f64].into_iter()),
115+
Some((1f64, 2f64))
116+
);
117+
assert_eq!(
118+
minmax(vec![2f64, 1f64, f64::NAN].into_iter()),
119+
Some((1f64, 2f64))
120+
);
121+
}
122+
123+
#[test]
124+
fn test_minmax_inf() {
125+
assert_eq!(
126+
minmax(vec![f64::INFINITY, 1f64, 2f64].into_iter()),
127+
Some((1f64, f64::INFINITY))
128+
);
129+
assert_eq!(
130+
minmax(vec![-f64::INFINITY, 1f64, 2f64].into_iter()),
131+
Some((-f64::INFINITY, 2f64))
132+
);
133+
assert_eq!(
134+
minmax(vec![2f64, f64::INFINITY, 1f64].into_iter()),
135+
Some((1f64, f64::INFINITY))
136+
);
137+
assert_eq!(
138+
minmax(vec![2f64, 1f64, -f64::INFINITY].into_iter()),
139+
Some((-f64::INFINITY, 2f64))
140+
);
141+
}
80142
}

fastfield_codecs/src/column.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl<'a, T: Copy + PartialOrd + Send + Sync> Column<T> for VecColumn<'a, T> {
135135
}
136136
}
137137

138-
impl<'a, T: Copy + Ord + Default, V> From<&'a V> for VecColumn<'a, T>
138+
impl<'a, T: Copy + PartialOrd + Default, V> From<&'a V> for VecColumn<'a, T>
139139
where V: AsRef<[T]> + ?Sized
140140
{
141141
fn from(values: &'a V) -> Self {

0 commit comments

Comments
 (0)