pinned_deque/
impl.rs

1use crate::{chunk::Chunk, *};
2use std::{alloc::Layout, collections::VecDeque};
3
4pub struct PinnedDeque<T: Sized> {
5    size: usize,
6    cap_per_chunk: u32,
7    layout: Layout,
8    pub(crate) used: VecDeque<*mut Chunk<T>>,
9    freed: Vec<*mut Chunk<T>>,
10}
11
12impl<T> PinnedDeque<T>
13where
14    T: Sized,
15{
16    /// Creates an empty deque with the adaptive capacity per chunk.
17    ///
18    /// Caveat:
19    /// The default capacity per chunk intends to fit a chunk into a memory page.
20    /// So, if the size of a single element plus the chunk overhead (8B) exceeds
21    /// the size of a memory page, do not use this constructor.
22    pub fn new() -> Self {
23        let cap_per_chunk = Chunk::<T>::capacity_per_chunk();
24        let layout = Chunk::<T>::layout(cap_per_chunk);
25        Self {
26            size: 0,
27            cap_per_chunk,
28            layout,
29            used: VecDeque::new(),
30            freed: Vec::new(),
31        }
32    }
33
34    /// Creates an empty deque with the given capacity per chunk.
35    pub fn with_capacity_per_chunk(cap_per_chunk: u32) -> Self {
36        let layout = Chunk::<T>::layout(cap_per_chunk);
37        Self {
38            size: 0,
39            cap_per_chunk,
40            layout,
41            used: VecDeque::new(),
42            freed: Vec::new(),
43        }
44    }
45
46    /// Reserves additional capacity in order to avoid memory allocations then.
47    pub fn reserve(&mut self, additional: usize) {
48        let cap_per_chunk = self.cap_per_chunk as usize;
49        let n = additional.div_ceil(cap_per_chunk);
50        if n > self.freed.len() {
51            for _ in self.freed.len()..n {
52                self.freed.push(Chunk::<T>::new(self.layout));
53            }
54        }
55        debug_assert!(n <= self.freed.len());
56    }
57
58    pub fn len(&self) -> usize {
59        self.size
60    }
61
62    pub fn is_empty(&self) -> bool {
63        self.len() == 0
64    }
65
66    /// Returns the total capacity of the deque.
67    ///
68    /// This deque do not guarantee that pushing elements will not cause memory allocations
69    /// even if there is enough free capacity (i.e., `capacity() - len()`).
70    pub fn capacity(&self) -> usize {
71        (self.used.len() + self.freed.len()) * (self.cap_per_chunk as usize)
72    }
73
74    pub fn push_back(&mut self, elem: T) {
75        self.size += 1;
76        if let Some(back_chunk) = self.used.back() {
77            let back_chunk = unsafe { &mut **back_chunk };
78            if let Some(slot) = back_chunk.reserve_back(self.cap_per_chunk) {
79                slot.write(elem);
80                return;
81            }
82        }
83        let new_chunk = self.fetch_a_freed_chunk();
84        unsafe {
85            let new_chunk = &mut *new_chunk;
86            new_chunk.reset_for_back_insertion();
87            new_chunk
88                .reserve_back(self.cap_per_chunk)
89                .unwrap_unchecked()
90                .write(elem);
91        }
92        self.used.push_back(new_chunk);
93    }
94
95    pub fn push_front(&mut self, elem: T) {
96        self.size += 1;
97        if let Some(front_chunk) = self.used.front() {
98            let front_chunk = unsafe { &mut **front_chunk };
99            if let Some(slot) = front_chunk.reserve_front() {
100                slot.write(elem);
101                return;
102            }
103        }
104        let new_chunk = self.fetch_a_freed_chunk();
105        unsafe {
106            let new_chunk = &mut *new_chunk;
107            new_chunk.reset_for_front_insertion(self.cap_per_chunk);
108            new_chunk.reserve_front().unwrap_unchecked().write(elem);
109        }
110        self.used.push_front(new_chunk);
111    }
112
113    pub fn pop_back(&mut self) -> Option<T> {
114        if let Some(back_chunk) = self.used.back() {
115            let back_chunk = unsafe { &mut **back_chunk };
116            let res = back_chunk.pop_back();
117            if back_chunk.len() == 0 {
118                let last_chunk = unsafe { self.used.pop_back().unwrap_unchecked() };
119                self.recycle(last_chunk);
120            }
121            self.size -= 1;
122            Some(res)
123        } else {
124            None
125        }
126    }
127
128    pub fn pop_front(&mut self) -> Option<T> {
129        if let Some(front_chunk) = self.used.front() {
130            let front_chunk = unsafe { &mut **front_chunk };
131            let res = front_chunk.pop_front();
132            if front_chunk.len() == 0 {
133                let first_chunk = unsafe { self.used.pop_front().unwrap_unchecked() };
134                self.recycle(first_chunk);
135            }
136            self.size -= 1;
137            Some(res)
138        } else {
139            None
140        }
141    }
142
143    pub fn back(&self) -> Option<&T> {
144        self.used.back().map(|back_chunk| {
145            let back_chunk = unsafe { &*(*back_chunk as *const Chunk<T>) };
146            back_chunk.back()
147        })
148    }
149
150    pub fn front(&self) -> Option<&T> {
151        self.used.front().map(|front_chunk| {
152            let front_chunk = unsafe { &*(*front_chunk as *const Chunk<T>) };
153            front_chunk.front()
154        })
155    }
156
157    pub fn back_mut(&mut self) -> Option<&mut T> {
158        self.used.back().map(|back_chunk| {
159            let back_chunk = unsafe { &mut **back_chunk };
160            back_chunk.back_mut()
161        })
162    }
163
164    pub fn front_mut(&mut self) -> Option<&mut T> {
165        self.used.front().map(|front_chunk| {
166            let front_chunk = unsafe { &mut **front_chunk };
167            front_chunk.front_mut()
168        })
169    }
170
171    pub fn clear(&mut self) {
172        while let Some(chunk_ptr) = self.used.pop_front() {
173            let chunk = unsafe { &mut *chunk_ptr };
174            chunk.drop_all();
175            self.recycle(chunk_ptr);
176        }
177    }
178
179    pub fn get(&self, mut idx: usize) -> Option<&T> {
180        if idx >= self.len() {
181            return None;
182        }
183        let first_chunk = unsafe { &*(*self.used.front().unwrap_unchecked() as *const Chunk<T>) };
184        if idx < first_chunk.len() {
185            return Some(first_chunk.get(idx));
186        } else {
187            idx -= first_chunk.len();
188        }
189        let n = idx / (self.cap_per_chunk as usize);
190        let offset = idx % (self.cap_per_chunk as usize);
191        let target_chunk = unsafe { &*(self.used[n + 1] as *const Chunk<T>) };
192        Some(target_chunk.get(offset))
193    }
194
195    pub fn get_mut(&mut self, mut idx: usize) -> Option<&mut T> {
196        if idx >= self.len() {
197            return None;
198        }
199        let front_chunk = unsafe { &mut **self.used.front().unwrap_unchecked() };
200        if idx < front_chunk.len() {
201            return Some(front_chunk.get_mut(idx));
202        } else {
203            idx -= front_chunk.len();
204        }
205        let n = idx / (self.cap_per_chunk as usize);
206        let offset = idx % (self.cap_per_chunk as usize);
207        let target_chunk = unsafe { &mut *self.used[n + 1] };
208        Some(target_chunk.get_mut(offset))
209    }
210
211    pub fn iter(&self) -> Iter<'_, T> {
212        Iter::new(self)
213    }
214
215    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
216        IterMut::new(self)
217    }
218
219    fn fetch_a_freed_chunk(&mut self) -> *mut Chunk<T> {
220        if let Some(chunk) = self.freed.pop() {
221            chunk
222        } else {
223            Chunk::<T>::new(self.layout)
224        }
225    }
226
227    fn recycle(&mut self, chunk: *mut Chunk<T>) {
228        self.freed.push(chunk);
229    }
230}
231
232impl<T> Drop for PinnedDeque<T>
233where
234    T: Sized,
235{
236    fn drop(&mut self) {
237        self.clear();
238        while let Some(chunk) = self.freed.pop() {
239            Chunk::<T>::free(chunk, self.layout);
240        }
241    }
242}