1#![cfg_attr(not(feature = "std"), no_std)]
15
16use core::cmp::Ordering;
17use core::hash::{Hash, Hasher};
18use core::slice::{from_raw_parts, from_raw_parts_mut};
19
20pub trait TotallyOrderable {
24 fn total_eq(&self, other: &Self) -> bool;
27 fn total_cmp(&self, other: &Self) -> Ordering;
30 fn total_hash<H: Hasher>(&self, state: &mut H);
33
34 type TotalOrdKey: Ord + Hash + Sized;
35 fn total_ord_key(&self) -> Self::TotalOrdKey;
36}
37
38pub trait InPlaceTotallyOrderable: TotallyOrderable + Sized {
42 type Transformed: Ord + Hash + Sized;
45 unsafe fn total_order_transform(&mut self);
53 unsafe fn total_order_inverse_transform(&mut self);
59}
60
61#[cfg(feature = "std")]
62pub fn total_sort<E: InPlaceTotallyOrderable, T: AsMut<[E]>>(container: &mut T) {
74 fn total_sort_impl<E: InPlaceTotallyOrderable>(s: &mut [E]) {
75 for e in s.iter_mut() {
76 unsafe {
77 e.total_order_transform();
78 }
79 }
80 {
81 let st = unsafe { from_raw_parts_mut(s.as_ptr() as *mut E::Transformed, s.len()) };
82 st.sort_unstable();
84 }
85 for e in s.iter_mut() {
86 unsafe {
87 e.total_order_inverse_transform();
88 }
89 }
90 }
91 total_sort_impl(container.as_mut());
92}
93
94macro_rules! implement_float_order {
95 ($F:ident, $U:ident, $I:ident, $N:literal) => {
96 impl TotallyOrderable for $F {
98 fn total_eq(&self, other: &Self) -> bool {
99 self.to_bits() == other.to_bits()
100 }
101
102 fn total_cmp(&self, other: &Self) -> Ordering {
103 let mut a = self.to_bits() as $I;
104 let mut b = other.to_bits() as $I;
105 a ^= (((a >> ($N - 1)) as $U) >> 1) as $I;
106 b ^= (((b >> ($N - 1)) as $U) >> 1) as $I;
107 a.cmp(&b)
108 }
109
110 fn total_hash<H: Hasher>(&self, state: &mut H) {
111 self.to_bits().hash(state);
112 }
113
114 type TotalOrdKey = $I;
115 fn total_ord_key(&self) -> Self::TotalOrdKey {
116 let a = self.to_bits() as $I;
117 a ^ (((a >> ($N - 1)) as $U) >> 1) as $I
118 }
119 }
120
121 impl InPlaceTotallyOrderable for $F {
122 type Transformed = $I;
123
124 unsafe fn total_order_transform(&mut self) {
125 let mut bits = self.to_bits();
126 bits ^= ((((bits as $I) >> ($N - 1)) as $U) >> 1);
127 *self = $F::from_bits(bits);
128 }
129
130 unsafe fn total_order_inverse_transform(&mut self) {
131 self.total_order_transform();
133 }
134 }
135 };
136}
137
138implement_float_order!(f32, u32, i32, 32);
139implement_float_order!(f64, u64, i64, 64);
140
141#[derive(Copy, Clone, Debug, Default)]
144#[repr(transparent)]
145pub struct TotallyOrdered<F: TotallyOrderable>(pub F);
146
147impl<F: TotallyOrderable> TotallyOrdered<F> {
148 pub fn new(v: F) -> Self {
150 Self(v)
151 }
152
153 pub fn new_slice(s: &[F]) -> &[Self] {
166 unsafe { from_raw_parts(s.as_ptr() as *const _, s.len()) }
168 }
169
170 pub fn new_slice_mut(s: &mut [F]) -> &mut [Self] {
183 unsafe { from_raw_parts_mut(s.as_ptr() as *mut _, s.len()) }
185 }
186}
187
188impl<F: TotallyOrderable> PartialEq for TotallyOrdered<F> {
189 fn eq(&self, other: &Self) -> bool {
190 self.0.total_eq(&other.0)
191 }
192}
193
194impl<F: TotallyOrderable> Eq for TotallyOrdered<F> {}
195
196impl<F: TotallyOrderable> PartialOrd for TotallyOrdered<F> {
197 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
198 Some(self.0.total_cmp(&other.0))
199 }
200}
201
202impl<F: TotallyOrderable> Ord for TotallyOrdered<F> {
203 fn cmp(&self, other: &Self) -> Ordering {
204 self.0.total_cmp(&other.0)
205 }
206}
207
208impl<F: TotallyOrderable> Hash for TotallyOrdered<F> {
209 fn hash<H: Hasher>(&self, state: &mut H) {
210 self.0.total_hash(state);
211 }
212}
213
214impl<F: TotallyOrderable> From<F> for TotallyOrdered<F> {
215 fn from(v: F) -> Self {
216 Self(v)
217 }
218}
219
220impl<'a, F: TotallyOrderable> From<&'a F> for &'a TotallyOrdered<F> {
221 fn from(v: &F) -> Self {
239 unsafe { &*(v as *const _ as *const _) }
241 }
242}
243
244impl<'a, F: TotallyOrderable> From<&'a mut F> for &'a mut TotallyOrdered<F> {
245 fn from(v: &mut F) -> Self {
263 unsafe { &mut *(v as *mut _ as *mut _) }
265 }
266}
267
268#[cfg(test)]
269mod test {
270 use crate::TotallyOrdered;
271 use core::{f32, f64};
272
273 #[test]
274 fn test_total_order_f32() {
275 let mut values = [
276 -0.0,
277 0.0,
278 -1.0,
279 1.0,
280 f32::NEG_INFINITY,
281 f32::INFINITY,
282 -f32::NAN,
283 f32::NAN,
284 -f32::MIN_POSITIVE,
285 f32::MIN_POSITIVE,
286 f32::MIN,
287 f32::MAX,
288 ];
289
290 TotallyOrdered::new_slice_mut(&mut values).sort();
291 let values_total = TotallyOrdered::new_slice(&values);
292
293 assert_eq!(values_total[0], (-f32::NAN).into());
294 assert_eq!(values_total[1], f32::NEG_INFINITY.into());
295 assert_eq!(values_total[2], f32::MIN.into());
296 assert_eq!(values_total[3], (-1.0).into());
297 assert_eq!(values_total[4], (-f32::MIN_POSITIVE).into());
298 assert_eq!(values_total[5], (-0.0).into());
299 assert_eq!(values_total[6], 0.0.into());
300 assert_eq!(values_total[7], f32::MIN_POSITIVE.into());
301 assert_eq!(values_total[8], 1.0.into());
302 assert_eq!(values_total[9], f32::MAX.into());
303 assert_eq!(values_total[10], f32::INFINITY.into());
304 assert_eq!(values_total[11], f32::NAN.into());
305
306 assert_ne!(
307 TotallyOrdered::new(-f32::NAN),
308 TotallyOrdered::new(f32::NAN)
309 );
310 assert_ne!(TotallyOrdered::new(-0.0f32), TotallyOrdered::new(0.0f32));
311 }
312
313 #[test]
314 fn test_total_order_f64() {
315 let mut values = [
316 -0.0,
317 0.0,
318 -1.0,
319 1.0,
320 f64::NEG_INFINITY,
321 f64::INFINITY,
322 -f64::NAN,
323 f64::NAN,
324 -f64::MIN_POSITIVE,
325 f64::MIN_POSITIVE,
326 f64::MIN,
327 f64::MAX,
328 ];
329
330 TotallyOrdered::new_slice_mut(&mut values).sort();
331 let values_total = TotallyOrdered::new_slice(&values);
332
333 assert_eq!(values_total[0], (-f64::NAN).into());
334 assert_eq!(values_total[1], f64::NEG_INFINITY.into());
335 assert_eq!(values_total[2], f64::MIN.into());
336 assert_eq!(values_total[3], (-1.0).into());
337 assert_eq!(values_total[4], (-f64::MIN_POSITIVE).into());
338 assert_eq!(values_total[5], (-0.0).into());
339 assert_eq!(values_total[6], 0.0.into());
340 assert_eq!(values_total[7], f64::MIN_POSITIVE.into());
341 assert_eq!(values_total[8], 1.0.into());
342 assert_eq!(values_total[9], f64::MAX.into());
343 assert_eq!(values_total[10], f64::INFINITY.into());
344 assert_eq!(values_total[11], f64::NAN.into());
345
346 assert_ne!(
347 TotallyOrdered::new(-f64::NAN),
348 TotallyOrdered::new(f64::NAN)
349 );
350 assert_ne!(TotallyOrdered::new(-0.0f64), TotallyOrdered::new(0.0f64));
351 }
352}