-
Notifications
You must be signed in to change notification settings - Fork 111
Expand file tree
/
Copy pathvec_ext.rs
More file actions
174 lines (149 loc) · 4.64 KB
/
vec_ext.rs
File metadata and controls
174 lines (149 loc) · 4.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
use std::cmp::Ordering;
use std::fmt::Debug;
/// Extension methods for [`Vec`]
pub(crate) trait VecExt<T> {
/// Returns the unused capacity of the current [`Vec`],
/// equivalent to `vec.capacity() - vec.len()`
fn spare_capacity(&self) -> usize;
/// Returns `true` if the current [`Vec`] has any unused capacity
/// available
#[inline]
fn has_spare_capacity(&self) -> bool {
self.spare_capacity() != 0
}
/// Pushes to a [`Vec`] without reallocating, equivalent
/// to [`Vec::push()`] but without any checks
///
/// # Safety
///
/// - `vec` must have a capacity greater than zero
/// - `vec`'s length must be less than it's capacity
///
/// # Examples
///
/// ```rust,ignore
/// let mut vec = Vec::with_capacity(1);
/// unsafe { vec.push_unchecked("something") };
///
/// assert_eq!(vec.len(), 1);
/// assert_eq!(vec.capacity(), 1);
/// assert_eq!(&vec, &["something"]);
/// ```
unsafe fn push_unchecked(&mut self, elem: T);
// FIXME: Replace with `slice::is_sorted_by()` via rust/#53485
fn is_sorted_by<F>(&self, compare: F) -> bool
where
F: FnMut(&T, &T) -> Option<Ordering>;
fn is_sorted_by_key<F, U>(&self, mut key: F) -> bool
where
F: FnMut(&T) -> U,
U: PartialOrd,
{
self.is_sorted_by(|a, b| key(a).partial_cmp(&key(b)))
}
}
impl<T> VecExt<T> for Vec<T>
where
T: Debug,
{
#[inline]
fn spare_capacity(&self) -> usize {
self.capacity() - self.len()
}
#[inline(always)]
unsafe fn push_unchecked(&mut self, elem: T) {
debug_assert_ne!(self.capacity(), 0, "cannot push to a vec of length zero");
debug_assert!(
self.len() < self.capacity(),
"cannot push to a vec without spare capacity",
);
let len = self.len();
self.spare_capacity_mut().get_unchecked_mut(0).write(elem);
self.set_len(len + 1);
}
fn is_sorted_by<F>(&self, mut compare: F) -> bool
where
F: FnMut(&T, &T) -> Option<Ordering>,
{
let mut iter = self.iter();
let mut last = match iter.next() {
Some(item) => item,
None => return true,
};
iter.all(move |current| {
if let Some(Ordering::Greater) | None = compare(last, current) {
return false;
}
last = current;
true
})
}
}
#[cfg(test)]
mod tests {
use crate::utils::VecExt;
#[test]
fn is_sorted_by() {
let x = vec![1, 2, 3, 4, 5, 6];
assert!(x.is_sorted_by(|a, b| a.partial_cmp(b)));
let x = vec![1, 2, 6, 3, 4, 5];
assert!(!x.is_sorted_by(|a, b| a.partial_cmp(b)));
}
#[test]
fn spare_capacity() {
let mut vec = Vec::with_capacity(0);
assert_eq!(vec.spare_capacity(), 0);
assert!(!vec.has_spare_capacity());
vec.reserve_exact(10);
assert_eq!(vec.spare_capacity(), 10);
assert!(vec.has_spare_capacity());
for i in 0..9 {
vec.push(i);
}
assert_eq!(vec.spare_capacity(), 1);
assert!(vec.has_spare_capacity());
vec.push(0);
assert_eq!(vec.spare_capacity(), 0);
assert!(!vec.has_spare_capacity());
}
#[test]
fn push_unchecked_1() {
let mut vec = Vec::with_capacity(1);
unsafe { vec.push_unchecked("something") };
assert_eq!(vec.len(), 1);
assert_eq!(vec.capacity(), 1);
assert_eq!(&vec, &["something"]);
}
#[test]
fn push_unchecked_100() {
let mut vec = Vec::with_capacity(100);
assert!(vec.is_empty());
for i in 0..100 {
unsafe { vec.push_unchecked(i) };
}
assert_eq!(vec.len(), 100);
assert_eq!(vec.capacity(), 100);
assert_eq!(vec, (0..100).collect::<Vec<_>>());
}
// This test is gated under `debug_assertions` since we use `debug_assert!()`
// for checking `push_unchecked()`'s invariants
#[test]
#[cfg(debug_assertions)]
#[should_panic = "cannot push to a vec of length zero"]
fn push_unchecked_zero_capacity() {
let mut empty = Vec::with_capacity(0);
unsafe { empty.push_unchecked(false) };
}
// This test is gated under `debug_assertions` since we use `debug_assert!()`
// for checking `push_unchecked()`'s invariants
#[test]
#[cfg(debug_assertions)]
#[should_panic = "cannot push to a vec without spare capacity"]
fn push_unchecked_full() {
let mut full = Vec::with_capacity(10);
for i in 0..10 {
full.push(i);
}
unsafe { full.push_unchecked(0) };
}
}