Skip to main content

cxx_qt_lib/core/qset/
mod.rs

1// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
3//
4// SPDX-License-Identifier: MIT OR Apache-2.0
5#[cfg(not(target_os = "emscripten"))]
6use crate::QDateTime;
7use crate::{QByteArray, QDate, QPersistentModelIndex, QString, QTime, QUrl, QUuid};
8use core::{marker::PhantomData, mem::MaybeUninit};
9use cxx::{type_id, ExternType};
10use std::fmt;
11
12/// The `QSet` class is a template class that provides a hash-table-based set.
13///
14/// Note that this means that `T` needs to have a global [`qHash()`](https://doc.qt.io/qt/qhash.html#qHash) function.
15///
16/// To use `QSet` with a custom type, implement the [`QSetElement`] trait for `T`.
17///
18/// Qt Documentation: [QSet]("https://doc.qt.io/qt/qset.html#details")
19#[repr(C)]
20pub struct QSet<T>
21where
22    T: QSetElement,
23{
24    _space: MaybeUninit<usize>,
25    _value: PhantomData<T>,
26}
27
28impl<T> Clone for QSet<T>
29where
30    T: QSetElement,
31{
32    /// Constructs a copy of the `QSet`.
33    fn clone(&self) -> Self {
34        T::clone(self)
35    }
36}
37
38impl<T> Default for QSet<T>
39where
40    T: QSetElement,
41{
42    /// Constructs an empty set.
43    fn default() -> Self {
44        T::default()
45    }
46}
47
48impl<T> Drop for QSet<T>
49where
50    T: QSetElement,
51{
52    /// Destroys the `QSet`.
53    fn drop(&mut self) {
54        T::drop(self);
55    }
56}
57
58impl<T> PartialEq for QSet<T>
59where
60    T: QSetElement + PartialEq,
61{
62    /// Returns `true` if the sets contain the same (key, value) pairs, otherwise `false`.
63    fn eq(&self, other: &Self) -> bool {
64        self.len() == other.len() && self.iter().all(|x| other.contains(x))
65    }
66}
67
68impl<T> Eq for QSet<T> where T: QSetElement + PartialEq {}
69
70impl<T> fmt::Debug for QSet<T>
71where
72    T: QSetElement + fmt::Debug,
73{
74    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75        f.debug_set().entries(self.iter()).finish()
76    }
77}
78
79impl<T> QSet<T>
80where
81    T: QSetElement,
82{
83    /// Removes all elements from the set.
84    pub fn clear(&mut self) {
85        T::clear(self);
86    }
87
88    /// Returns `true` if the set contains item `value`; otherwise returns `false`.
89    pub fn contains(&self, value: &T) -> bool {
90        T::contains(self, value)
91    }
92
93    /// Inserts item `value` into the set, if `value` isn't already in the set.
94    ///
95    /// The value is a reference here so it can be opaque or trivial but
96    /// note that the value is copied when being inserted into the set.
97    pub fn insert_clone(&mut self, value: &T) {
98        T::insert_clone(self, value);
99    }
100
101    /// Returns `true` if the set contains no elements; otherwise returns `false`.
102    pub fn is_empty(&self) -> bool {
103        T::len(self) == 0
104    }
105
106    /// An iterator visiting all elements in arbitrary order.
107    /// The iterator element type is `&'a T`.
108    pub fn iter(&self) -> Iter<'_, T> {
109        Iter {
110            set: self,
111            index: 0,
112        }
113    }
114
115    /// Returns the number of items in the set.
116    pub fn len(&self) -> isize {
117        T::len(self)
118    }
119
120    /// Removes any occurrence of item `value` from the set.
121    /// Returns `true` if an item was actually removed; otherwise returns `false`.
122    pub fn remove(&mut self, value: &T) -> bool {
123        T::remove(self, value)
124    }
125
126    /// Ensures that the set's internal hash table consists of at least `size` buckets.
127    ///
128    /// This function is useful for code that needs to build a huge set and wants to avoid repeated reallocation.
129    ///
130    /// Ideally, `size` should be slightly more than the maximum number of elements expected in the set. `size` doesn't have to be prime, because `QSet` will use a prime number internally anyway. If `size` is an underestimate, the worst that will happen is that the `QSet` will be a bit slower.
131    ///
132    /// In general, you will rarely ever need to call this function. `QSet`'s internal hash table automatically shrinks or grows to provide good performance without wasting too much memory.
133    pub fn reserve(&mut self, size: isize) {
134        T::reserve(self, size);
135    }
136
137    /// Helper function for handling Rust values.
138    pub(crate) fn reserve_usize(&mut self, size: usize) {
139        if size != 0 {
140            T::reserve(self, isize::try_from(size).unwrap_or(isize::MAX));
141        }
142    }
143}
144
145impl<T> QSet<T>
146where
147    T: QSetElement + ExternType<Kind = cxx::kind::Trivial>,
148{
149    /// Inserts item `value` into the set, if `value` isn't already in the set.
150    pub fn insert(&mut self, value: T) {
151        T::insert(self, value);
152    }
153}
154
155impl<'a, T> Extend<&'a T> for QSet<T>
156where
157    T: QSetElement,
158{
159    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
160        let iter = iter.into_iter();
161        self.reserve_usize(iter.size_hint().0);
162        for element in iter {
163            self.insert_clone(element);
164        }
165    }
166}
167
168impl<T> Extend<T> for QSet<T>
169where
170    T: QSetElement + ExternType<Kind = cxx::kind::Trivial>,
171{
172    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
173        let iter = iter.into_iter();
174        self.reserve_usize(iter.size_hint().0);
175        for element in iter {
176            self.insert(element);
177        }
178    }
179}
180
181impl<'a, T> FromIterator<&'a T> for QSet<T>
182where
183    T: QSetElement,
184{
185    fn from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Self {
186        let mut qset = Self::default();
187        qset.extend(iter);
188        qset
189    }
190}
191
192impl<T> FromIterator<T> for QSet<T>
193where
194    T: QSetElement + ExternType<Kind = cxx::kind::Trivial>,
195{
196    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
197        let mut qset = Self::default();
198        qset.extend(iter);
199        qset
200    }
201}
202
203unsafe impl<T> ExternType for QSet<T>
204where
205    T: ExternType + QSetElement,
206{
207    type Id = T::TypeId;
208    type Kind = cxx::kind::Trivial;
209}
210
211pub struct Iter<'a, T>
212where
213    T: QSetElement,
214{
215    set: &'a QSet<T>,
216    index: isize,
217}
218
219impl<'a, T> Iterator for Iter<'a, T>
220where
221    T: QSetElement,
222{
223    type Item = &'a T;
224
225    fn next(&mut self) -> Option<Self::Item> {
226        if self.index < self.set.len() {
227            let next = unsafe { T::get_unchecked(self.set, self.index) };
228            self.index += 1;
229            Some(next)
230        } else {
231            None
232        }
233    }
234
235    fn size_hint(&self) -> (usize, Option<usize>) {
236        let len = self.len();
237        (len, Some(len))
238    }
239}
240
241impl<T> ExactSizeIterator for Iter<'_, T>
242where
243    T: QSetElement,
244{
245    fn len(&self) -> usize {
246        (self.set.len() - self.index) as usize
247    }
248}
249
250impl<'a, T> IntoIterator for &'a QSet<T>
251where
252    T: QSetElement,
253{
254    type Item = &'a T;
255
256    type IntoIter = Iter<'a, T>;
257
258    fn into_iter(self) -> Self::IntoIter {
259        self.iter()
260    }
261}
262
263/// Trait implementation for an element in a [`QSet`].
264pub trait QSetElement: Sized {
265    type TypeId;
266
267    fn clear(set: &mut QSet<Self>);
268    fn clone(set: &QSet<Self>) -> QSet<Self>;
269    fn contains(set: &QSet<Self>, value: &Self) -> bool;
270    fn default() -> QSet<Self>;
271    fn drop(set: &mut QSet<Self>);
272    /// # Safety
273    ///
274    /// Calling this method with an out-of-bounds index is undefined behavior
275    /// even if the resulting reference is not used.
276    unsafe fn get_unchecked(set: &QSet<Self>, pos: isize) -> &Self;
277    fn insert(set: &mut QSet<Self>, value: Self)
278    where
279        Self: ExternType<Kind = cxx::kind::Trivial>;
280    fn insert_clone(set: &mut QSet<Self>, value: &Self);
281    fn len(set: &QSet<Self>) -> isize;
282    fn remove(set: &mut QSet<Self>, value: &Self) -> bool;
283    fn reserve(set: &mut QSet<Self>, size: isize);
284}
285
286macro_rules! impl_qset_element {
287    ( $typeName:ty, $module:ident, $typeId:literal ) => {
288        mod $module;
289
290        impl QSetElement for $typeName {
291            type TypeId = type_id!($typeId);
292
293            fn clear(set: &mut QSet<Self>) {
294                set.cxx_clear()
295            }
296
297            fn clone(set: &QSet<Self>) -> QSet<Self> {
298                $module::clone(set)
299            }
300
301            fn contains(set: &QSet<Self>, value: &Self) -> bool {
302                set.cxx_contains(value)
303            }
304
305            fn default() -> QSet<Self> {
306                $module::default()
307            }
308
309            fn drop(set: &mut QSet<Self>) {
310                $module::drop(set);
311            }
312
313            unsafe fn get_unchecked(set: &QSet<Self>, pos: isize) -> &Self {
314                $module::get_unchecked(set, pos)
315            }
316
317            fn insert(set: &mut QSet<Self>, value: Self) {
318                $module::insert(set, &value);
319            }
320
321            fn insert_clone(set: &mut QSet<Self>, value: &Self) {
322                $module::insert(set, value);
323            }
324
325            fn len(set: &QSet<Self>) -> isize {
326                $module::len(set)
327            }
328
329            fn remove(set: &mut QSet<Self>, value: &Self) -> bool {
330                set.cxx_remove(value)
331            }
332
333            fn reserve(set: &mut QSet<Self>, size: isize) {
334                $module::reserve(set, size);
335            }
336        }
337    };
338}
339
340impl_qset_element!(bool, qset_bool, "QSet_bool");
341impl_qset_element!(f32, qset_f32, "QSet_f32");
342impl_qset_element!(f64, qset_f64, "QSet_f64");
343impl_qset_element!(i8, qset_i8, "QSet_i8");
344impl_qset_element!(i16, qset_i16, "QSet_i16");
345impl_qset_element!(i32, qset_i32, "QSet_i32");
346impl_qset_element!(i64, qset_i64, "QSet_i64");
347impl_qset_element!(QByteArray, qset_qbytearray, "QSet_QByteArray");
348impl_qset_element!(QDate, qset_qdate, "QSet_QDate");
349#[cfg(not(target_os = "emscripten"))]
350impl_qset_element!(QDateTime, qset_qdatetime, "QSet_QDateTime");
351impl_qset_element!(
352    QPersistentModelIndex,
353    qset_qpersistentmodelindex,
354    "QSet_QPersistentModelIndex"
355);
356impl_qset_element!(QString, qset_qstring, "QSet_QString");
357impl_qset_element!(QTime, qset_qtime, "QSet_QTime");
358impl_qset_element!(QUrl, qset_qurl, "QSet_QUrl");
359impl_qset_element!(QUuid, qset_quuid, "QSet_QUuid");
360impl_qset_element!(u8, qset_u8, "QSet_u8");
361impl_qset_element!(u16, qset_u16, "QSet_u16");
362impl_qset_element!(u32, qset_u32, "QSet_u32");
363impl_qset_element!(u64, qset_u64, "QSet_u64");
364
365#[cfg(test)]
366mod test {
367    use super::*;
368
369    #[cfg(feature = "serde")]
370    #[test]
371    fn qset_serde() {
372        let mut set = QSet::default();
373        set.insert(0);
374        set.insert(1);
375        set.insert(2);
376        assert_eq!(crate::serde_impl::roundtrip(&set), set)
377    }
378}