]> git.lizzy.rs Git - rust.git/blob - src/librustc_middle/ty/list.rs
Rollup merge of #73543 - GuillaumeGomez:cleanup-e0695, r=Dylan-DPC
[rust.git] / src / librustc_middle / ty / list.rs
1 use crate::arena::Arena;
2
3 use rustc_serialize::{Encodable, Encoder};
4
5 use std::alloc::Layout;
6 use std::cmp::Ordering;
7 use std::fmt;
8 use std::hash::{Hash, Hasher};
9 use std::iter;
10 use std::mem;
11 use std::ops::Deref;
12 use std::ptr;
13 use std::slice;
14
15 extern "C" {
16     /// A dummy type used to force `List` to be unsized while not requiring references to it be wide
17     /// pointers.
18     type OpaqueListContents;
19 }
20
21 /// A wrapper for slices with the additional invariant
22 /// that the slice is interned and no other slice with
23 /// the same contents can exist in the same context.
24 /// This means we can use pointer for both
25 /// equality comparisons and hashing.
26 ///
27 /// Unlike slices, The types contained in `List` are expected to be `Copy`
28 /// and iterating over a `List` returns `T` instead of a reference.
29 ///
30 /// Note: `Slice` was already taken by the `Ty`.
31 #[repr(C)]
32 pub struct List<T> {
33     len: usize,
34     data: [T; 0],
35     opaque: OpaqueListContents,
36 }
37
38 unsafe impl<T: Sync> Sync for List<T> {}
39
40 impl<T: Copy> List<T> {
41     #[inline]
42     pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> {
43         assert!(!mem::needs_drop::<T>());
44         assert!(mem::size_of::<T>() != 0);
45         assert!(!slice.is_empty());
46
47         let (layout, _offset) =
48             Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap();
49         let mem = arena.dropless.alloc_raw(layout);
50         unsafe {
51             let result = &mut *(mem as *mut List<T>);
52             // Write the length
53             result.len = slice.len();
54
55             // Write the elements
56             let arena_slice = slice::from_raw_parts_mut(result.data.as_mut_ptr(), result.len);
57             arena_slice.copy_from_slice(slice);
58
59             result
60         }
61     }
62
63     // If this method didn't exist, we would use `slice.iter` due to
64     // deref coercion.
65     //
66     // This would be weird, as `self.into_iter` iterates over `T` directly.
67     #[inline(always)]
68     pub fn iter(&self) -> <&'_ List<T> as IntoIterator>::IntoIter {
69         self.into_iter()
70     }
71 }
72
73 impl<T: fmt::Debug> fmt::Debug for List<T> {
74     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75         (**self).fmt(f)
76     }
77 }
78
79 impl<T: Encodable> Encodable for List<T> {
80     #[inline]
81     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
82         (**self).encode(s)
83     }
84 }
85
86 impl<T> Ord for List<T>
87 where
88     T: Ord,
89 {
90     fn cmp(&self, other: &List<T>) -> Ordering {
91         if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) }
92     }
93 }
94
95 impl<T> PartialOrd for List<T>
96 where
97     T: PartialOrd,
98 {
99     fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> {
100         if self == other {
101             Some(Ordering::Equal)
102         } else {
103             <[T] as PartialOrd>::partial_cmp(&**self, &**other)
104         }
105     }
106 }
107
108 impl<T: PartialEq> PartialEq for List<T> {
109     #[inline]
110     fn eq(&self, other: &List<T>) -> bool {
111         ptr::eq(self, other)
112     }
113 }
114 impl<T: Eq> Eq for List<T> {}
115
116 impl<T> Hash for List<T> {
117     #[inline]
118     fn hash<H: Hasher>(&self, s: &mut H) {
119         (self as *const List<T>).hash(s)
120     }
121 }
122
123 impl<T> Deref for List<T> {
124     type Target = [T];
125     #[inline(always)]
126     fn deref(&self) -> &[T] {
127         self.as_ref()
128     }
129 }
130
131 impl<T> AsRef<[T]> for List<T> {
132     #[inline(always)]
133     fn as_ref(&self) -> &[T] {
134         unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
135     }
136 }
137
138 impl<'a, T: Copy> IntoIterator for &'a List<T> {
139     type Item = T;
140     type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>;
141     #[inline(always)]
142     fn into_iter(self) -> Self::IntoIter {
143         self[..].iter().copied()
144     }
145 }
146
147 impl<T> List<T> {
148     #[inline(always)]
149     pub fn empty<'a>() -> &'a List<T> {
150         #[repr(align(64), C)]
151         struct EmptySlice([u8; 64]);
152         static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]);
153         assert!(mem::align_of::<T>() <= 64);
154         unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
155     }
156 }