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};
8use core::{marker::PhantomData, mem::MaybeUninit};
9use cxx::{type_id, ExternType};
10
11/// The QSet class is a template class that provides a hash-table-based set.
12///
13/// Note that this means that T needs to have a global `qHash()` function.
14///
15/// To use QSet with a custom type, implement the [`QSetElement`] trait for T.
16#[repr(C)]
17pub struct QSet<T>
18where
19    T: QSetElement,
20{
21    _space: MaybeUninit<usize>,
22    _value: PhantomData<T>,
23}
24
25impl<T> Clone for QSet<T>
26where
27    T: QSetElement,
28{
29    /// Constructs a copy of the QSet.
30    fn clone(&self) -> Self {
31        T::clone(self)
32    }
33}
34
35impl<T> Default for QSet<T>
36where
37    T: QSetElement,
38{
39    /// Constructs an empty set.
40    fn default() -> Self {
41        T::default()
42    }
43}
44
45impl<T> Drop for QSet<T>
46where
47    T: QSetElement,
48{
49    /// Destroys the QSet.
50    fn drop(&mut self) {
51        T::drop(self);
52    }
53}
54
55impl<T> PartialEq for QSet<T>
56where
57    T: QSetElement + PartialEq,
58{
59    /// Returns true if both sets contain the same elements
60    fn eq(&self, other: &Self) -> bool {
61        self.len() == other.len() && self.iter().all(|x| other.contains(x))
62    }
63}
64
65impl<T> Eq for QSet<T> where T: QSetElement + PartialEq {}
66
67impl<T> QSet<T>
68where
69    T: QSetElement,
70{
71    /// Removes all elements from the set.
72    pub fn clear(&mut self) {
73        T::clear(self);
74    }
75
76    /// Returns true if the set contains item value; otherwise returns false.
77    pub fn contains(&self, value: &T) -> bool {
78        T::contains(self, value)
79    }
80
81    /// Inserts item value into the set, if value isn't already in the set,
82    /// and returns an iterator pointing at the inserted item.
83    ///
84    /// The value is a reference here so it can be opaque or trivial but
85    /// note that the value is copied when being inserted into the set.
86    pub fn insert_clone(&mut self, value: &T) {
87        T::insert_clone(self, value);
88    }
89
90    /// Returns true if the set contains no elements; otherwise returns false.
91    pub fn is_empty(&self) -> bool {
92        T::len(self) == 0
93    }
94
95    /// An iterator visiting all elements in arbitrary order.
96    /// The iterator element type is &'a T.
97    pub fn iter(&self) -> Iter<'_, T> {
98        Iter {
99            set: self,
100            index: 0,
101        }
102    }
103
104    /// Returns the number of items in the set.
105    pub fn len(&self) -> isize {
106        T::len(self)
107    }
108
109    /// Removes any occurrence of item value from the set.
110    /// Returns true if an item was actually removed; otherwise returns false.
111    pub fn remove(&mut self, value: &T) -> bool {
112        T::remove(self, value)
113    }
114}
115
116impl<T> QSet<T>
117where
118    T: QSetElement + ExternType<Kind = cxx::kind::Trivial>,
119{
120    /// Inserts item value into the set, if value isn't already in the set,
121    /// and returns an iterator pointing at the inserted item.
122    pub fn insert(&mut self, value: T) {
123        T::insert(self, value);
124    }
125}
126
127unsafe impl<T> ExternType for QSet<T>
128where
129    T: ExternType + QSetElement,
130{
131    type Id = T::TypeId;
132    type Kind = cxx::kind::Trivial;
133}
134
135pub struct Iter<'a, T>
136where
137    T: QSetElement,
138{
139    set: &'a QSet<T>,
140    index: isize,
141}
142
143impl<'a, T> Iterator for Iter<'a, T>
144where
145    T: QSetElement,
146{
147    type Item = &'a T;
148
149    fn next(&mut self) -> Option<Self::Item> {
150        if self.index < self.set.len() {
151            let next = unsafe { T::get_unchecked(self.set, self.index) };
152            self.index += 1;
153            Some(next)
154        } else {
155            None
156        }
157    }
158
159    fn size_hint(&self) -> (usize, Option<usize>) {
160        let len = self.len();
161        (len, Some(len))
162    }
163}
164
165impl<T> ExactSizeIterator for Iter<'_, T>
166where
167    T: QSetElement,
168{
169    fn len(&self) -> usize {
170        (self.set.len() - self.index) as usize
171    }
172}
173
174/// Trait implementation for an element in a [`QSet`].
175pub trait QSetElement: Sized {
176    type TypeId;
177
178    fn clear(set: &mut QSet<Self>);
179    fn clone(set: &QSet<Self>) -> QSet<Self>;
180    fn contains(set: &QSet<Self>, value: &Self) -> bool;
181    fn default() -> QSet<Self>;
182    fn drop(set: &mut QSet<Self>);
183    /// # Safety
184    ///
185    /// Calling this method with an out-of-bounds index is undefined behavior
186    /// even if the resulting reference is not used.
187    unsafe fn get_unchecked(set: &QSet<Self>, pos: isize) -> &Self;
188    fn insert(set: &mut QSet<Self>, value: Self)
189    where
190        Self: ExternType<Kind = cxx::kind::Trivial>;
191    fn insert_clone(set: &mut QSet<Self>, value: &Self);
192    fn len(set: &QSet<Self>) -> isize;
193    fn remove(set: &mut QSet<Self>, value: &Self) -> bool;
194}
195
196macro_rules! impl_qset_element {
197    ( $typeName:ty, $module:ident, $typeId:literal ) => {
198        mod $module;
199
200        impl QSetElement for $typeName {
201            type TypeId = type_id!($typeId);
202
203            fn clear(set: &mut QSet<Self>) {
204                set.cxx_clear()
205            }
206
207            fn clone(set: &QSet<Self>) -> QSet<Self> {
208                $module::clone(set)
209            }
210
211            fn contains(set: &QSet<Self>, value: &Self) -> bool {
212                set.cxx_contains(value)
213            }
214
215            fn default() -> QSet<Self> {
216                $module::default()
217            }
218
219            fn drop(set: &mut QSet<Self>) {
220                $module::drop(set);
221            }
222
223            unsafe fn get_unchecked(set: &QSet<Self>, pos: isize) -> &Self {
224                $module::get_unchecked(set, pos)
225            }
226
227            fn insert(set: &mut QSet<Self>, value: Self) {
228                $module::insert(set, &value);
229            }
230
231            fn insert_clone(set: &mut QSet<Self>, value: &Self) {
232                $module::insert(set, value);
233            }
234
235            fn len(set: &QSet<Self>) -> isize {
236                $module::len(set)
237            }
238
239            fn remove(set: &mut QSet<Self>, value: &Self) -> bool {
240                set.cxx_remove(value)
241            }
242        }
243    };
244}
245
246impl_qset_element!(bool, qset_bool, "QSet_bool");
247impl_qset_element!(f32, qset_f32, "QSet_f32");
248impl_qset_element!(f64, qset_f64, "QSet_f64");
249impl_qset_element!(i8, qset_i8, "QSet_i8");
250impl_qset_element!(i16, qset_i16, "QSet_i16");
251impl_qset_element!(i32, qset_i32, "QSet_i32");
252impl_qset_element!(i64, qset_i64, "QSet_i64");
253impl_qset_element!(QByteArray, qset_qbytearray, "QSet_QByteArray");
254impl_qset_element!(QDate, qset_qdate, "QSet_QDate");
255#[cfg(not(target_os = "emscripten"))]
256impl_qset_element!(QDateTime, qset_qdatetime, "QSet_QDateTime");
257impl_qset_element!(
258    QPersistentModelIndex,
259    qset_qpersistentmodelindex,
260    "QSet_QPersistentModelIndex"
261);
262impl_qset_element!(QString, qset_qstring, "QSet_QString");
263impl_qset_element!(QTime, qset_qtime, "QSet_QTime");
264impl_qset_element!(QUrl, qset_qurl, "QSet_QUrl");
265impl_qset_element!(u8, qset_u8, "QSet_u8");
266impl_qset_element!(u16, qset_u16, "QSet_u16");
267impl_qset_element!(u32, qset_u32, "QSet_u32");
268impl_qset_element!(u64, qset_u64, "QSet_u64");