diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/README.md | 2 | ||||
-rw-r--r-- | lib/arena/Cargo.toml | 10 | ||||
-rw-r--r-- | lib/arena/src/lib.rs | 231 | ||||
-rw-r--r-- | lib/arena/src/map.rs | 69 |
4 files changed, 312 insertions, 0 deletions
diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 000000000..6b2eeac2c --- /dev/null +++ b/lib/README.md | |||
@@ -0,0 +1,2 @@ | |||
1 | Crates in this directory are published to crates.io and obey semver. | ||
2 | They *could* live in a separate repo, but we want to experiment with a monorepo setup. | ||
diff --git a/lib/arena/Cargo.toml b/lib/arena/Cargo.toml new file mode 100644 index 000000000..f4d2ecb6c --- /dev/null +++ b/lib/arena/Cargo.toml | |||
@@ -0,0 +1,10 @@ | |||
1 | [package] | ||
2 | name = "la-arena" | ||
3 | version = "0.2.0" | ||
4 | description = "Simple index-based arena without deletion." | ||
5 | license = "MIT OR Apache-2.0" | ||
6 | repository = "https://github.com/rust-analyzer/rust-analyzer" | ||
7 | documentation = "https://docs.rs/la-arena" | ||
8 | categories = ["data-structures", "memory-management", "rust-patterns"] | ||
9 | authors = ["rust-analyzer developers"] | ||
10 | edition = "2018" | ||
diff --git a/lib/arena/src/lib.rs b/lib/arena/src/lib.rs new file mode 100644 index 000000000..230a50291 --- /dev/null +++ b/lib/arena/src/lib.rs | |||
@@ -0,0 +1,231 @@ | |||
1 | //! Yet another index-based arena. | ||
2 | |||
3 | #![warn(missing_docs)] | ||
4 | |||
5 | use std::{ | ||
6 | fmt, | ||
7 | hash::{Hash, Hasher}, | ||
8 | iter::FromIterator, | ||
9 | marker::PhantomData, | ||
10 | ops::{Index, IndexMut}, | ||
11 | }; | ||
12 | |||
13 | mod map; | ||
14 | pub use map::ArenaMap; | ||
15 | |||
16 | /// The raw index of a value in an arena. | ||
17 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
18 | pub struct RawIdx(u32); | ||
19 | |||
20 | impl From<RawIdx> for u32 { | ||
21 | fn from(raw: RawIdx) -> u32 { | ||
22 | raw.0 | ||
23 | } | ||
24 | } | ||
25 | |||
26 | impl From<u32> for RawIdx { | ||
27 | fn from(idx: u32) -> RawIdx { | ||
28 | RawIdx(idx) | ||
29 | } | ||
30 | } | ||
31 | |||
32 | impl fmt::Debug for RawIdx { | ||
33 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
34 | self.0.fmt(f) | ||
35 | } | ||
36 | } | ||
37 | |||
38 | impl fmt::Display for RawIdx { | ||
39 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
40 | self.0.fmt(f) | ||
41 | } | ||
42 | } | ||
43 | |||
44 | /// The index of a value allocated in an arena that holds `T`s. | ||
45 | pub struct Idx<T> { | ||
46 | raw: RawIdx, | ||
47 | _ty: PhantomData<fn() -> T>, | ||
48 | } | ||
49 | |||
50 | impl<T> Clone for Idx<T> { | ||
51 | fn clone(&self) -> Self { | ||
52 | *self | ||
53 | } | ||
54 | } | ||
55 | impl<T> Copy for Idx<T> {} | ||
56 | |||
57 | impl<T> PartialEq for Idx<T> { | ||
58 | fn eq(&self, other: &Idx<T>) -> bool { | ||
59 | self.raw == other.raw | ||
60 | } | ||
61 | } | ||
62 | impl<T> Eq for Idx<T> {} | ||
63 | |||
64 | impl<T> Hash for Idx<T> { | ||
65 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
66 | self.raw.hash(state) | ||
67 | } | ||
68 | } | ||
69 | |||
70 | impl<T> fmt::Debug for Idx<T> { | ||
71 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
72 | let mut type_name = std::any::type_name::<T>(); | ||
73 | if let Some(idx) = type_name.rfind(':') { | ||
74 | type_name = &type_name[idx + 1..] | ||
75 | } | ||
76 | write!(f, "Idx::<{}>({})", type_name, self.raw) | ||
77 | } | ||
78 | } | ||
79 | |||
80 | impl<T> Idx<T> { | ||
81 | /// Creates a new index from a [`RawIdx`]. | ||
82 | pub fn from_raw(raw: RawIdx) -> Self { | ||
83 | Idx { raw, _ty: PhantomData } | ||
84 | } | ||
85 | |||
86 | /// Converts this index into the underlying [`RawIdx`]. | ||
87 | pub fn into_raw(self) -> RawIdx { | ||
88 | self.raw | ||
89 | } | ||
90 | } | ||
91 | |||
92 | /// Yet another index-based arena. | ||
93 | #[derive(Clone, PartialEq, Eq)] | ||
94 | pub struct Arena<T> { | ||
95 | data: Vec<T>, | ||
96 | } | ||
97 | |||
98 | impl<T: fmt::Debug> fmt::Debug for Arena<T> { | ||
99 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
100 | fmt.debug_struct("Arena").field("len", &self.len()).field("data", &self.data).finish() | ||
101 | } | ||
102 | } | ||
103 | |||
104 | impl<T> Arena<T> { | ||
105 | /// Creates a new empty arena. | ||
106 | /// | ||
107 | /// ``` | ||
108 | /// let arena: la_arena::Arena<i32> = la_arena::Arena::new(); | ||
109 | /// assert!(arena.is_empty()); | ||
110 | /// ``` | ||
111 | pub const fn new() -> Arena<T> { | ||
112 | Arena { data: Vec::new() } | ||
113 | } | ||
114 | |||
115 | /// Empties the arena, removing all contained values. | ||
116 | /// | ||
117 | /// ``` | ||
118 | /// let mut arena = la_arena::Arena::new(); | ||
119 | /// | ||
120 | /// arena.alloc(1); | ||
121 | /// arena.alloc(2); | ||
122 | /// arena.alloc(3); | ||
123 | /// assert_eq!(arena.len(), 3); | ||
124 | /// | ||
125 | /// arena.clear(); | ||
126 | /// assert!(arena.is_empty()); | ||
127 | /// ``` | ||
128 | pub fn clear(&mut self) { | ||
129 | self.data.clear(); | ||
130 | } | ||
131 | |||
132 | /// Returns the length of the arena. | ||
133 | /// | ||
134 | /// ``` | ||
135 | /// let mut arena = la_arena::Arena::new(); | ||
136 | /// assert_eq!(arena.len(), 0); | ||
137 | /// | ||
138 | /// arena.alloc("foo"); | ||
139 | /// assert_eq!(arena.len(), 1); | ||
140 | /// | ||
141 | /// arena.alloc("bar"); | ||
142 | /// assert_eq!(arena.len(), 2); | ||
143 | /// | ||
144 | /// arena.alloc("baz"); | ||
145 | /// assert_eq!(arena.len(), 3); | ||
146 | /// ``` | ||
147 | pub fn len(&self) -> usize { | ||
148 | self.data.len() | ||
149 | } | ||
150 | |||
151 | /// Returns whether the arena contains no elements. | ||
152 | /// | ||
153 | /// ``` | ||
154 | /// let mut arena = la_arena::Arena::new(); | ||
155 | /// assert!(arena.is_empty()); | ||
156 | /// | ||
157 | /// arena.alloc(0.5); | ||
158 | /// assert!(!arena.is_empty()); | ||
159 | /// ``` | ||
160 | pub fn is_empty(&self) -> bool { | ||
161 | self.data.is_empty() | ||
162 | } | ||
163 | |||
164 | /// Allocates a new value on the arena, returning the value’s index. | ||
165 | /// | ||
166 | /// ``` | ||
167 | /// let mut arena = la_arena::Arena::new(); | ||
168 | /// let idx = arena.alloc(50); | ||
169 | /// | ||
170 | /// assert_eq!(arena[idx], 50); | ||
171 | /// ``` | ||
172 | pub fn alloc(&mut self, value: T) -> Idx<T> { | ||
173 | let idx = RawIdx(self.data.len() as u32); | ||
174 | self.data.push(value); | ||
175 | Idx::from_raw(idx) | ||
176 | } | ||
177 | |||
178 | /// Returns an iterator over the arena’s elements. | ||
179 | /// | ||
180 | /// ``` | ||
181 | /// let mut arena = la_arena::Arena::new(); | ||
182 | /// let idx1 = arena.alloc(20); | ||
183 | /// let idx2 = arena.alloc(40); | ||
184 | /// let idx3 = arena.alloc(60); | ||
185 | /// | ||
186 | /// let mut iterator = arena.iter(); | ||
187 | /// assert_eq!(iterator.next(), Some((idx1, &20))); | ||
188 | /// assert_eq!(iterator.next(), Some((idx2, &40))); | ||
189 | /// assert_eq!(iterator.next(), Some((idx3, &60))); | ||
190 | /// ``` | ||
191 | pub fn iter( | ||
192 | &self, | ||
193 | ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator { | ||
194 | self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value)) | ||
195 | } | ||
196 | |||
197 | /// Reallocates the arena to make it take up as little space as possible. | ||
198 | pub fn shrink_to_fit(&mut self) { | ||
199 | self.data.shrink_to_fit(); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | impl<T> Default for Arena<T> { | ||
204 | fn default() -> Arena<T> { | ||
205 | Arena { data: Vec::new() } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | impl<T> Index<Idx<T>> for Arena<T> { | ||
210 | type Output = T; | ||
211 | fn index(&self, idx: Idx<T>) -> &T { | ||
212 | let idx = idx.into_raw().0 as usize; | ||
213 | &self.data[idx] | ||
214 | } | ||
215 | } | ||
216 | |||
217 | impl<T> IndexMut<Idx<T>> for Arena<T> { | ||
218 | fn index_mut(&mut self, idx: Idx<T>) -> &mut T { | ||
219 | let idx = idx.into_raw().0 as usize; | ||
220 | &mut self.data[idx] | ||
221 | } | ||
222 | } | ||
223 | |||
224 | impl<T> FromIterator<T> for Arena<T> { | ||
225 | fn from_iter<I>(iter: I) -> Self | ||
226 | where | ||
227 | I: IntoIterator<Item = T>, | ||
228 | { | ||
229 | Arena { data: Vec::from_iter(iter) } | ||
230 | } | ||
231 | } | ||
diff --git a/lib/arena/src/map.rs b/lib/arena/src/map.rs new file mode 100644 index 000000000..d8acfe051 --- /dev/null +++ b/lib/arena/src/map.rs | |||
@@ -0,0 +1,69 @@ | |||
1 | use std::marker::PhantomData; | ||
2 | |||
3 | use crate::Idx; | ||
4 | |||
5 | /// A map from arena indexes to some other type. | ||
6 | /// Space requirement is O(highest index). | ||
7 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
8 | pub struct ArenaMap<IDX, V> { | ||
9 | v: Vec<Option<V>>, | ||
10 | _ty: PhantomData<IDX>, | ||
11 | } | ||
12 | |||
13 | impl<T, V> ArenaMap<Idx<T>, V> { | ||
14 | /// Inserts a value associated with a given arena index into the map. | ||
15 | pub fn insert(&mut self, idx: Idx<T>, t: V) { | ||
16 | let idx = Self::to_idx(idx); | ||
17 | |||
18 | self.v.resize_with((idx + 1).max(self.v.len()), || None); | ||
19 | self.v[idx] = Some(t); | ||
20 | } | ||
21 | |||
22 | /// Returns a reference to the value associated with the provided index | ||
23 | /// if it is present. | ||
24 | pub fn get(&self, idx: Idx<T>) -> Option<&V> { | ||
25 | self.v.get(Self::to_idx(idx)).and_then(|it| it.as_ref()) | ||
26 | } | ||
27 | |||
28 | /// Returns a mutable reference to the value associated with the provided index | ||
29 | /// if it is present. | ||
30 | pub fn get_mut(&mut self, idx: Idx<T>) -> Option<&mut V> { | ||
31 | self.v.get_mut(Self::to_idx(idx)).and_then(|it| it.as_mut()) | ||
32 | } | ||
33 | |||
34 | /// Returns an iterator over the values in the map. | ||
35 | pub fn values(&self) -> impl Iterator<Item = &V> { | ||
36 | self.v.iter().filter_map(|o| o.as_ref()) | ||
37 | } | ||
38 | |||
39 | /// Returns an iterator over mutable references to the values in the map. | ||
40 | pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> { | ||
41 | self.v.iter_mut().filter_map(|o| o.as_mut()) | ||
42 | } | ||
43 | |||
44 | /// Returns an iterator over the arena indexes and values in the map. | ||
45 | pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> { | ||
46 | self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?))) | ||
47 | } | ||
48 | |||
49 | fn to_idx(idx: Idx<T>) -> usize { | ||
50 | u32::from(idx.into_raw()) as usize | ||
51 | } | ||
52 | |||
53 | fn from_idx(idx: usize) -> Idx<T> { | ||
54 | Idx::from_raw((idx as u32).into()) | ||
55 | } | ||
56 | } | ||
57 | |||
58 | impl<T, V> std::ops::Index<Idx<V>> for ArenaMap<Idx<V>, T> { | ||
59 | type Output = T; | ||
60 | fn index(&self, idx: Idx<V>) -> &T { | ||
61 | self.v[Self::to_idx(idx)].as_ref().unwrap() | ||
62 | } | ||
63 | } | ||
64 | |||
65 | impl<T, V> Default for ArenaMap<Idx<V>, T> { | ||
66 | fn default() -> Self { | ||
67 | ArenaMap { v: Vec::new(), _ty: PhantomData } | ||
68 | } | ||
69 | } | ||