Skip to content

Commit f9f90ed

Browse files
Add TinyList data structure.
1 parent 63cd4a3 commit f9f90ed

File tree

2 files changed

+252
-0
lines changed

2 files changed

+252
-0
lines changed

src/librustc_data_structures/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ pub mod control_flow_graph;
7474
pub mod flock;
7575
pub mod sync;
7676
pub mod owning_ref;
77+
pub mod tiny_list;
7778
pub mod sorted_map;
7879

7980
pub struct OnDrop<F: Fn()>(pub F);
+251
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
//! A singly-linked list.
13+
//!
14+
//! Using this data structure only makes sense under very specific
15+
//! circumstances:
16+
//!
17+
//! - If you have a list that rarely stores more than one element, then this
18+
//! data-structure can store the element without allocating and only uses as
19+
//! much space as a `Option<(T, usize)>`. If T can double as the `Option`
20+
//! discriminant, it will even only be as large as `T, usize`.
21+
//!
22+
//! If you expect to store more than 1 element in the common case, steer clear
23+
//! and use a `Vec<T>`, `Box<[T]>`, or a `SmallVec<T>`.
24+
25+
use std::mem;
26+
27+
#[derive(Clone, Hash, Debug, PartialEq)]
28+
pub struct TinyList<T: PartialEq> {
29+
head: Option<Element<T>>
30+
}
31+
32+
impl<T: PartialEq> TinyList<T> {
33+
34+
#[inline]
35+
pub fn new() -> TinyList<T> {
36+
TinyList {
37+
head: None
38+
}
39+
}
40+
41+
#[inline]
42+
pub fn new_single(data: T) -> TinyList<T> {
43+
TinyList {
44+
head: Some(Element {
45+
data,
46+
next: None,
47+
})
48+
}
49+
}
50+
51+
#[inline]
52+
pub fn insert(&mut self, data: T) {
53+
let current_head = mem::replace(&mut self.head, None);
54+
55+
if let Some(current_head) = current_head {
56+
let current_head = Box::new(current_head);
57+
self.head = Some(Element {
58+
data,
59+
next: Some(current_head)
60+
});
61+
} else {
62+
self.head = Some(Element {
63+
data,
64+
next: None,
65+
})
66+
}
67+
}
68+
69+
#[inline]
70+
pub fn remove(&mut self, data: &T) -> bool {
71+
let remove_head = if let Some(ref mut head) = self.head {
72+
if head.data == *data {
73+
Some(mem::replace(&mut head.next, None))
74+
} else {
75+
None
76+
}
77+
} else {
78+
return false
79+
};
80+
81+
if let Some(remove_head) = remove_head {
82+
if let Some(next) = remove_head {
83+
self.head = Some(*next);
84+
} else {
85+
self.head = None;
86+
}
87+
return true
88+
}
89+
90+
self.head.as_mut().unwrap().remove_next(data)
91+
}
92+
93+
#[inline]
94+
pub fn contains(&self, data: &T) -> bool {
95+
if let Some(ref head) = self.head {
96+
head.contains(data)
97+
} else {
98+
false
99+
}
100+
}
101+
102+
#[inline]
103+
pub fn len(&self) -> usize {
104+
if let Some(ref head) = self.head {
105+
head.len()
106+
} else {
107+
0
108+
}
109+
}
110+
}
111+
112+
#[derive(Clone, Hash, Debug, PartialEq)]
113+
struct Element<T: PartialEq> {
114+
data: T,
115+
next: Option<Box<Element<T>>>,
116+
}
117+
118+
impl<T: PartialEq> Element<T> {
119+
120+
fn remove_next(&mut self, data: &T) -> bool {
121+
let new_next = if let Some(ref mut next) = self.next {
122+
if next.data != *data {
123+
return next.remove_next(data)
124+
} else {
125+
mem::replace(&mut next.next, None)
126+
}
127+
} else {
128+
return false
129+
};
130+
131+
self.next = new_next;
132+
return true
133+
}
134+
135+
fn len(&self) -> usize {
136+
if let Some(ref next) = self.next {
137+
1 + next.len()
138+
} else {
139+
1
140+
}
141+
}
142+
143+
fn contains(&self, data: &T) -> bool {
144+
if self.data == *data {
145+
return true
146+
}
147+
148+
if let Some(ref next) = self.next {
149+
next.contains(data)
150+
} else {
151+
false
152+
}
153+
}
154+
}
155+
156+
#[cfg(test)]
157+
mod test {
158+
use super::*;
159+
160+
#[test]
161+
fn test_contains_and_insert() {
162+
fn do_insert(i : u32) -> bool {
163+
i % 2 == 0
164+
}
165+
166+
let mut list = TinyList::new();
167+
168+
for i in 0 .. 10 {
169+
for j in 0 .. i {
170+
if do_insert(j) {
171+
assert!(list.contains(&j));
172+
} else {
173+
assert!(!list.contains(&j));
174+
}
175+
}
176+
177+
assert!(!list.contains(i));
178+
179+
if do_insert(i) {
180+
list.insert(i);
181+
assert!(list.contains(&i));
182+
}
183+
}
184+
}
185+
186+
#[test]
187+
fn test_remove_first() {
188+
let mut list = TinyList::new();
189+
list.insert(1);
190+
list.insert(2);
191+
list.insert(3);
192+
list.insert(4);
193+
assert_eq!(list.len(), 4);
194+
195+
assert!(list.remove(&4));
196+
assert!(!list.contains(&4));
197+
198+
assert_eq!(list.len(), 3);
199+
assert!(list.contains(&1));
200+
assert!(list.contains(&2));
201+
assert!(list.contains(&3));
202+
}
203+
204+
#[test]
205+
fn test_remove_last() {
206+
let mut list = TinyList::new();
207+
list.insert(1);
208+
list.insert(2);
209+
list.insert(3);
210+
list.insert(4);
211+
assert_eq!(list.len(), 4);
212+
213+
assert!(list.remove(&1));
214+
assert!(!list.contains(&1));
215+
216+
assert_eq!(list.len(), 3);
217+
assert!(list.contains(&2));
218+
assert!(list.contains(&3));
219+
assert!(list.contains(&4));
220+
}
221+
222+
#[test]
223+
fn test_remove_middle() {
224+
let mut list = TinyList::new();
225+
list.insert(1);
226+
list.insert(2);
227+
list.insert(3);
228+
list.insert(4);
229+
assert_eq!(list.len(), 4);
230+
231+
assert!(list.remove(&2));
232+
assert!(!list.contains(&2));
233+
234+
assert_eq!(list.len(), 3);
235+
assert!(list.contains(&1));
236+
assert!(list.contains(&3));
237+
assert!(list.contains(&4));
238+
}
239+
240+
#[test]
241+
fn test_remove_single() {
242+
let mut list = TinyList::new();
243+
list.insert(1);
244+
assert_eq!(list.len(), 1);
245+
246+
assert!(list.remove(&1));
247+
assert!(!list.contains(&1));
248+
249+
assert_eq!(list.len(), 0);
250+
}
251+
}

0 commit comments

Comments
 (0)