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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
//! An alternative to the standard libraries' [`Vec`] which is indexed with a custom type instead of [`usize`].
//!
//! This is useful to catch errors like using the wrong variable to index the vector.
#![warn(missing_docs)]
use std::{
marker::PhantomData,
ops::{Bound, RangeBounds},
};
use mapped_range_bounds::MappedRangeBounds;
pub use crate::index_iterator::IndexIterator;
#[cfg(feature = "binary-io")]
mod binary_io;
mod index_iterator;
mod mapped_range_bounds;
#[cfg(test)]
mod tests;
mod trait_impls;
/// A [`Vec`] wrapper that allows indexing only via the given `Index` type.
///
/// For actual operation, `Index` must implement [`From<usize>`] and [`Into<usize>`].
pub struct TaggedVec<Index, Value> {
index_type: PhantomData<Index>,
vec: Vec<Value>,
}
impl<Index, Value> TaggedVec<Index, Value> {
/// Creates a new empty `TaggedVec`.
pub fn new() -> Self {
Self::default()
}
/// Creates a new empty `TaggedVec` with at least the specified capacity.
pub fn with_capacity(capacity: usize) -> Self {
Self {
index_type: PhantomData,
vec: Vec::with_capacity(capacity),
}
}
/// Returns the number of elements in the `TaggedVec`.
pub fn len(&self) -> usize {
self.vec.len()
}
/// Returns `true` if the `TaggedVec` contains no elements.
pub fn is_empty(&self) -> bool {
self.vec.is_empty()
}
/// Returns the total number of elements the `TaggedVec` can hold without reallocating.
pub fn capacity(&self) -> usize {
self.vec.capacity()
}
/// Returns the untagged slice of the `Vec` underlying this `TaggedVec`.
pub fn as_untagged_slice(&self) -> &[Value] {
&self.vec
}
/// Returns the untagged mutable slice of the `Vec` underlying this `TaggedVec`.
pub fn as_untagged_mut_slice(&mut self) -> &mut [Value] {
&mut self.vec
}
/// Inserts the given value at the back of the `TaggedVec`, returning its index.
pub fn push(&mut self, value: Value) -> Index
where
Index: From<usize>,
{
let index = self.vec.len().into();
self.vec.push(value);
index
}
/// Insert a single value into the `TaggedVec` by constructing it in place.
///
/// This method allows to create the value while already knowing its index.
/// Returns the index.
pub fn push_in_place(&mut self, value: impl FnOnce(Index) -> Value) -> Index
where
Index: From<usize>,
{
let index = self.vec.len();
self.vec.push(value(index.into()));
index.into()
}
/// Removes the value at the back of the `TaggedVec` and returns it with its index.
pub fn pop(&mut self) -> Option<(Index, Value)>
where
Index: From<usize>,
{
if let Some(value) = self.vec.pop() {
Some((self.vec.len().into(), value))
} else {
None
}
}
/// Inserts the given `value` at position `index`, shifting all existing values in range `index..` one position to the right.
pub fn insert(&mut self, index: Index, value: Value)
where
Index: Into<usize>,
{
self.vec.insert(index.into(), value);
}
/// See [`Vec::splice`].
pub fn splice<I: IntoIterator<Item = Value>>(
&mut self,
range: impl RangeBounds<Index>,
replace_with: I,
) -> std::vec::Splice<'_, I::IntoIter>
where
usize: From<Index>,
Index: Copy,
{
self.vec.splice(MappedRangeBounds::new(range), replace_with)
}
/// Retains only the values specified by the predicate.
///
/// In other words, remove all values `v` for which `f(&v)` returns `false`.
/// This method operates in place, visiting each value exactly once in the original order, and preserves the order of the retained values.
pub fn retain(&mut self, f: impl FnMut(&Value) -> bool) {
self.vec.retain(f);
}
/// Removes the elements at the specified indices, shifting other elements to the left to fill gaps as required.
///
/// The provided indices must be sorted.
pub fn remove_multi(&mut self, indices: impl IntoIterator<Item = Index>)
where
Index: Into<usize> + Clone,
{
let mut indices = indices.into_iter().peekable();
let mut current_index = 0;
self.vec.retain(|_| {
if let Some(next_delete_index) = indices.peek() {
let next_delete_index = next_delete_index.clone().into();
let result = if next_delete_index == current_index {
indices.next();
if let Some(next_next_delete_index) = indices.peek() {
let next_next_delete_index: usize = next_next_delete_index.clone().into();
assert!(next_next_delete_index > next_delete_index);
}
false
} else {
true
};
current_index += 1;
result
} else {
true
}
});
assert!(indices.next().is_none());
}
/// Returns a reference to the value at the given index, or `None` if the index is out of bounds.
pub fn get(&self, index: Index) -> Option<&Value>
where
Index: Into<usize>,
{
self.vec.get(index.into())
}
/// Returns an iterator over references to the entries of the `TaggedVec`.
///
/// The `range` specifies which subset of the entries to iterate over.
/// Iterating over a partial range with this argument is more efficient than iterating over the whole vector and skipping the unwanted entries, because the returned iterator does not support the skip optimisation.
pub fn iter(
&self,
range: impl RangeBounds<Index>,
) -> impl DoubleEndedIterator<Item = (Index, &Value)> + ExactSizeIterator
where
Index: From<usize> + Copy,
usize: From<Index>,
{
let range = MappedRangeBounds::new(range);
let start_index_inclusive = match range.start_bound() {
Bound::Included(index) => *index,
Bound::Excluded(index) => (*index).checked_add(1).expect("start index overflow"),
Bound::Unbounded => 0,
};
let end_index_exclusive = match range.end_bound() {
Bound::Included(index) => (*index).checked_add(1).expect("end index overflow"),
Bound::Excluded(index) => *index,
Bound::Unbounded => self.vec.len(),
};
self.vec
.iter()
.enumerate()
.skip(start_index_inclusive)
.take(end_index_exclusive - start_index_inclusive)
.map(|(index, value)| (index.into(), value))
}
/// Returns an iterator over mutable references to the entries of the `TaggedVec`.
///
/// The `range` specifies which subset of the entries to iterate over.
/// Iterating over a partial range with this argument is more efficient than iterating over the whole vector and skipping the unwanted entries, because the returned iterator does not support the skip optimisation.
pub fn iter_mut(
&mut self,
range: impl RangeBounds<Index>,
) -> impl DoubleEndedIterator<Item = (Index, &mut Value)> + ExactSizeIterator
where
Index: From<usize> + Copy,
usize: From<Index>,
{
let range = MappedRangeBounds::new(range);
let start_index_inclusive = match range.start_bound() {
Bound::Included(index) => *index,
Bound::Excluded(index) => (*index).checked_add(1).expect("start index overflow"),
Bound::Unbounded => 0,
};
let end_index_exclusive = match range.end_bound() {
Bound::Included(index) => (*index).checked_add(1).expect("end index overflow"),
Bound::Excluded(index) => *index,
Bound::Unbounded => self.vec.len(),
};
self.vec
.iter_mut()
.enumerate()
.skip(start_index_inclusive)
.take(end_index_exclusive - start_index_inclusive)
.map(|(index, value)| (index.into(), value))
}
/// Returns an iterator over references to the values of the `TaggedVec`.
pub fn iter_values(&self) -> std::slice::Iter<'_, Value> {
self.vec.iter()
}
/// Returns an iterator over mutable references to the values of the `TaggedVec`.
pub fn iter_values_mut(&mut self) -> std::slice::IterMut<'_, Value> {
self.vec.iter_mut()
}
/// Returns an iterator over the indices of the `TaggedVec`.
///
/// The `range` specifies which subset of the entries to iterate over.
/// Iterating over a partial range with this argument is more efficient than iterating over the whole vector and skipping the unwanted entries, because the returned iterator does not support the skip optimisation.
pub fn iter_indices(&self, range: impl RangeBounds<Index>) -> IndexIterator<Index>
where
Index: From<usize> + Copy,
usize: From<Index>,
{
let range = MappedRangeBounds::new(range);
let start_index_inclusive = match range.start_bound() {
Bound::Included(index) => *index,
Bound::Excluded(index) => (*index).checked_add(1).expect("start index overflow"),
Bound::Unbounded => 0,
};
let end_index_exclusive = match range.end_bound() {
Bound::Included(index) => (*index).checked_add(1).expect("end index overflow"),
Bound::Excluded(index) => *index,
Bound::Unbounded => self.vec.len(),
};
IndexIterator::new(start_index_inclusive, end_index_exclusive)
}
/// Consumes the `TaggedVec`, returning an iterator over the entries.
///
/// The `range` specifies which subset of the entries to iterate over.
/// Iterating over a partial range with this argument is more efficient than iterating over the whole vector and skipping the unwanted entries, because the returned iterator does not support the skip optimisation.
pub fn into_iter(
self,
range: impl RangeBounds<Index>,
) -> impl DoubleEndedIterator<Item = (Index, Value)> + ExactSizeIterator
where
Index: From<usize> + Copy,
usize: From<Index>,
{
let range = MappedRangeBounds::new(range);
let start_index_inclusive = match range.start_bound() {
Bound::Included(index) => *index,
Bound::Excluded(index) => (*index).checked_add(1).expect("start index overflow"),
Bound::Unbounded => 0,
};
let end_index_exclusive = match range.end_bound() {
Bound::Included(index) => (*index).checked_add(1).expect("end index overflow"),
Bound::Excluded(index) => *index,
Bound::Unbounded => self.vec.len(),
};
self.vec
.into_iter()
.enumerate()
.skip(start_index_inclusive)
.take(end_index_exclusive - start_index_inclusive)
.map(|(index, value)| (index.into(), value))
}
/// Consumes the `TaggedVec`, returning an iterator over the values.
pub fn into_values_iter(self) -> std::vec::IntoIter<Value> {
self.vec.into_iter()
}
/// Removes all values from the `TaggedVec`.
pub fn clear(&mut self) {
self.vec.clear()
}
}