vortex_array/operator/
hash.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::any::Any;
5use std::hash::{Hash, Hasher};
6use std::sync::Arc;
7
8use vortex_buffer::Buffer;
9use vortex_mask::Mask;
10
11use crate::ArrayRef;
12use crate::operator::{Operator, OperatorRef};
13use crate::validity::Validity;
14
15/// A hash trait for operators that loosens the semantics to permit pointer-based hashing for
16/// data objects such as buffers.
17///
18/// Note that since this trait can use pointer hashing, the hash is only valid for the lifetime of
19/// the object.
20pub trait OperatorHash {
21    fn operator_hash<H: Hasher>(&self, state: &mut H);
22}
23
24pub trait DynOperatorHash: private::SealedHash {
25    fn dyn_operator_hash(&self, state: &mut dyn Hasher);
26}
27
28impl<T: OperatorHash + ?Sized> DynOperatorHash for T {
29    fn dyn_operator_hash(&self, mut state: &mut dyn Hasher) {
30        OperatorHash::operator_hash(self, &mut state);
31    }
32}
33
34/// An equality trait for operators that loosens the semantics to permit pointer-based equality
35/// for data objects such as buffers.
36pub trait OperatorEq {
37    fn operator_eq(&self, other: &Self) -> bool;
38}
39
40pub trait DynOperatorEq: private::SealedEq {
41    fn dyn_operator_eq(&self, other: &dyn Any) -> bool;
42}
43
44impl<T: OperatorEq + 'static> DynOperatorEq for T {
45    fn dyn_operator_eq(&self, other: &dyn Any) -> bool {
46        other
47            .downcast_ref::<Self>()
48            .is_some_and(|other| OperatorEq::operator_eq(self, other))
49    }
50}
51
52mod private {
53    use crate::operator::{OperatorEq, OperatorHash};
54
55    pub trait SealedHash {}
56    impl<T: OperatorHash + ?Sized> SealedHash for T {}
57    pub trait SealedEq {}
58    impl<T: OperatorEq + ?Sized> SealedEq for T {}
59}
60
61impl OperatorHash for dyn Operator + '_ {
62    fn operator_hash<H: Hasher>(&self, state: &mut H) {
63        self.dyn_operator_hash(state);
64    }
65}
66
67impl OperatorEq for dyn Operator + '_ {
68    fn operator_eq(&self, other: &Self) -> bool {
69        self.dyn_operator_eq(other.as_any())
70    }
71}
72
73impl OperatorHash for OperatorRef {
74    fn operator_hash<H: Hasher>(&self, state: &mut H) {
75        self.as_ref().operator_hash(state);
76    }
77}
78
79impl OperatorEq for OperatorRef {
80    fn operator_eq(&self, other: &Self) -> bool {
81        self.as_ref().operator_eq(other.as_ref())
82    }
83}
84
85/// A wrapper type to implement [`Hash`], [`PartialEq`], and [`Eq`] using the semantics defined
86/// by [`OperatorHash`] and [`OperatorEq`].
87pub struct OperatorKey<T>(pub T);
88impl<T: OperatorHash> Hash for OperatorKey<T> {
89    fn hash<H: Hasher>(&self, state: &mut H) {
90        self.0.operator_hash(state);
91    }
92}
93impl<T: OperatorEq + Any> PartialEq for OperatorKey<T> {
94    fn eq(&self, other: &Self) -> bool {
95        self.0.operator_eq(&other.0)
96    }
97}
98impl<T: OperatorEq + Any> Eq for OperatorKey<T> {}
99
100impl<T> OperatorHash for Buffer<T> {
101    fn operator_hash<H: Hasher>(&self, state: &mut H) {
102        self.as_ptr().hash(state);
103        self.len().hash(state);
104    }
105}
106impl<T> OperatorEq for Buffer<T> {
107    fn operator_eq(&self, other: &Self) -> bool {
108        self.as_ptr() == other.as_ptr() && self.len() == other.len()
109    }
110}
111
112impl OperatorHash for Mask {
113    fn operator_hash<H: Hasher>(&self, state: &mut H) {
114        std::mem::discriminant(self).hash(state);
115        match self {
116            Mask::AllTrue(len) => {
117                len.hash(state);
118            }
119            Mask::AllFalse(len) => {
120                len.hash(state);
121            }
122            Mask::Values(values) => {
123                let buffer = values.boolean_buffer();
124                buffer.offset().hash(state);
125                buffer.len().hash(state);
126                buffer.inner().as_ptr().hash(state);
127            }
128        }
129    }
130}
131impl OperatorEq for Mask {
132    fn operator_eq(&self, other: &Self) -> bool {
133        match (self, other) {
134            (Mask::AllTrue(len1), Mask::AllTrue(len2)) => len1 == len2,
135            (Mask::AllFalse(len1), Mask::AllFalse(len2)) => len1 == len2,
136            (Mask::Values(buf1), Mask::Values(buf2)) => {
137                let b1 = buf1.boolean_buffer();
138                let b2 = buf2.boolean_buffer();
139                b1.offset() == b2.offset()
140                    && b1.len() == b2.len()
141                    && b1.inner().as_ptr() == b2.inner().as_ptr()
142            }
143            _ => false,
144        }
145    }
146}
147
148impl OperatorHash for Validity {
149    fn operator_hash<H: Hasher>(&self, state: &mut H) {
150        std::mem::discriminant(self).hash(state);
151        if let Validity::Array(array) = self {
152            Arc::as_ptr(array).hash(state);
153        }
154    }
155}
156impl OperatorEq for Validity {
157    fn operator_eq(&self, other: &Self) -> bool {
158        match (self, other) {
159            (Validity::AllValid, Validity::AllValid) => true,
160            (Validity::AllInvalid, Validity::AllInvalid) => true,
161            (Validity::NonNullable, Validity::NonNullable) => true,
162            (Validity::Array(arr1), Validity::Array(arr2)) => Arc::ptr_eq(arr1, arr2),
163            _ => false,
164        }
165    }
166}
167
168impl OperatorHash for ArrayRef {
169    fn operator_hash<H: Hasher>(&self, state: &mut H) {
170        Arc::as_ptr(self).hash(state);
171    }
172}
173impl OperatorEq for ArrayRef {
174    fn operator_eq(&self, other: &Self) -> bool {
175        Arc::ptr_eq(self, other)
176    }
177}