taffy/util/
front_back_vec_builder.rs1use crate::util::sys::Vec;
3
4pub(crate) struct FrontBackVecBuilder<T> {
14 vec: Vec<T>,
17 capacity: usize,
19 front_len: usize,
21 back_len: usize,
23}
24
25impl<T> FrontBackVecBuilder<T> {
26 #[inline(always)]
28 pub(crate) fn with_capacity(capacity: usize) -> Self {
29 Self { vec: Vec::with_capacity(capacity), capacity, front_len: 0, back_len: 0 }
30 }
31
32 #[inline(always)]
37 pub(crate) fn push_front(&mut self, value: T) {
38 self.vec.spare_capacity_mut()[self.front_len].write(value);
39 self.front_len += 1;
40 }
41
42 #[inline(always)]
47 pub(crate) fn push_back(&mut self, value: T) {
48 self.vec.spare_capacity_mut()[self.capacity - self.back_len - 1].write(value);
49 self.back_len += 1;
50 }
51
52 #[inline(always)]
57 pub(crate) fn into_vec(self) -> (Vec<T>, usize) {
58 let Self { mut vec, capacity, front_len, back_len } = self;
59 assert_eq!(
60 front_len + back_len,
61 capacity,
62 "the number of items pushed to a FrontBackVecBuilder must equal its capacity"
63 );
64 #[allow(unsafe_code)]
73 unsafe {
74 vec.set_len(capacity);
75 }
76 (vec, front_len)
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::FrontBackVecBuilder;
83 use crate::util::sys::Vec;
84
85 #[test]
86 fn front_items_keep_their_order_and_back_items_are_reversed() {
87 let mut builder = FrontBackVecBuilder::with_capacity(6);
88 for value in 0..6 {
89 if value % 2 == 0 {
90 builder.push_front(value);
91 } else {
92 builder.push_back(value);
93 }
94 }
95 let (vec, front_len) = builder.into_vec();
96 assert_eq!(vec, [0, 2, 4, 5, 3, 1]);
97 assert_eq!(front_len, 3);
98 }
99
100 #[test]
101 fn all_items_pushed_to_one_end() {
102 let mut builder = FrontBackVecBuilder::with_capacity(3);
103 (0..3).for_each(|value| builder.push_front(value));
104 assert_eq!(builder.into_vec(), (Vec::from([0, 1, 2]), 3));
105
106 let mut builder = FrontBackVecBuilder::with_capacity(3);
107 (0..3).for_each(|value| builder.push_back(value));
108 assert_eq!(builder.into_vec(), (Vec::from([2, 1, 0]), 0));
109 }
110
111 #[test]
112 fn zero_capacity() {
113 let (vec, front_len) = FrontBackVecBuilder::<u8>::with_capacity(0).into_vec();
114 assert!(vec.is_empty());
115 assert_eq!(front_len, 0);
116 }
117
118 #[test]
119 fn owned_items_are_moved_into_the_vec() {
120 let mut builder = FrontBackVecBuilder::with_capacity(2);
121 builder.push_back(Vec::from([1, 2]));
122 builder.push_front(Vec::from([3]));
123 let (vec, front_len) = builder.into_vec();
124 assert_eq!(vec, [Vec::from([3]), Vec::from([1, 2])]);
125 assert_eq!(front_len, 1);
126 }
127
128 #[test]
129 #[should_panic(expected = "must equal its capacity")]
130 fn pushing_too_many_items_to_the_front_panics_in_into_vec() {
131 let mut builder = FrontBackVecBuilder::with_capacity(1);
132 builder.push_back(1);
133 builder.push_front(2);
134 let _ = builder.into_vec();
135 }
136
137 #[test]
138 #[should_panic(expected = "must equal its capacity")]
139 fn pushing_too_many_items_to_the_back_panics_in_into_vec() {
140 let mut builder = FrontBackVecBuilder::with_capacity(1);
141 builder.push_front(1);
142 builder.push_back(2);
143 let _ = builder.into_vec();
144 }
145
146 #[test]
147 #[should_panic]
148 fn push_front_out_of_bounds_panics() {
149 let mut builder = FrontBackVecBuilder::with_capacity(0);
150 builder.push_front(1);
151 }
152
153 #[test]
154 #[should_panic]
155 fn push_back_out_of_bounds_panics() {
156 let mut builder = FrontBackVecBuilder::with_capacity(1);
157 builder.push_back(1);
158 builder.push_back(2);
159 }
160
161 #[test]
162 #[should_panic(expected = "must equal its capacity")]
163 fn into_vec_before_full_panics() {
164 let mut builder = FrontBackVecBuilder::with_capacity(2);
165 builder.push_front(1);
166 let _ = builder.into_vec();
167 }
168}