Files
@ 97b87404ffa5
Branch filter:
Location: CSY/reowolf/src/collections/scoped_buffer.rs
97b87404ffa5
4.9 KiB
application/rls-services+xml
WIP on performance fixes
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 | /// scoped_buffer.rs
///
/// Solves the common pattern where we are performing some kind of recursive
/// pattern while using a temporary buffer. At the start, or during the
/// procedure, we push stuff into the buffer. At the end we take out what we
/// have put in.
///
/// It is unsafe because we're using pointers to circumvent borrowing rules in
/// the name of code cleanliness. The correctness of use is checked in debug
/// mode.
use std::iter::FromIterator;
pub(crate) struct ScopedBuffer<T: Sized> {
pub inner: Vec<T>,
}
/// A section of the buffer. Keeps track of where we started the section. When
/// done with the section one must call `into_vec` or `forget` to remove the
/// section from the underlying buffer. This will also be done upon dropping the
/// ScopedSection in case errors are being handled.
pub(crate) struct ScopedSection<T: Sized> {
inner: *mut Vec<T>,
start_size: u32,
#[cfg(debug_assertions)] cur_size: u32,
}
impl<T: Sized> ScopedBuffer<T> {
pub(crate) fn with_capacity(capacity: usize) -> Self {
Self { inner: Vec::with_capacity(capacity) }
}
pub(crate) fn start_section(&mut self) -> ScopedSection<T> {
let start_size = self.inner.len() as u32;
ScopedSection {
inner: &mut self.inner,
start_size,
#[cfg(debug_assertions)] cur_size: start_size
}
}
}
impl<T: Clone> ScopedBuffer<T> {
pub(crate) fn start_section_initialized(&mut self, initialize_with: &[T]) -> ScopedSection<T> {
let start_size = self.inner.len() as u32;
let _data_size = initialize_with.len() as u32;
self.inner.extend_from_slice(initialize_with);
ScopedSection{
inner: &mut self.inner,
start_size,
#[cfg(debug_assertions)] cur_size: start_size + _data_size,
}
}
}
#[cfg(debug_assertions)]
impl<T: Sized> Drop for ScopedBuffer<T> {
fn drop(&mut self) {
// Make sure that everyone cleaned up the buffer neatly
debug_assert!(self.inner.is_empty(), "dropped non-empty scoped buffer");
}
}
impl<T: Sized> ScopedSection<T> {
#[inline]
pub(crate) fn push(&mut self, value: T) {
let vec = unsafe{&mut *self.inner};
#[cfg(debug_assertions)] debug_assert_eq!(vec.len(), self.cur_size as usize, "trying to push onto section, but size is larger than expected");
vec.push(value);
#[cfg(debug_assertions)] { self.cur_size += 1; }
}
pub(crate) fn len(&self) -> usize {
let vec = unsafe{&mut *self.inner};
#[cfg(debug_assertions)] debug_assert_eq!(vec.len(), self.cur_size as usize, "trying to get section length, but size is larger than expected");
return vec.len() - self.start_size as usize;
}
#[inline]
#[allow(unused_mut)] // used in debug mode
pub(crate) fn forget(mut self) {
let vec = unsafe{&mut *self.inner};
#[cfg(debug_assertions)] {
debug_assert_eq!(
vec.len(), self.cur_size as usize,
"trying to forget section, but size is larger than expected"
);
self.cur_size = self.start_size;
}
vec.truncate(self.start_size as usize);
}
#[inline]
#[allow(unused_mut)] // used in debug mode
pub(crate) fn into_vec(mut self) -> Vec<T> {
let vec = unsafe{&mut *self.inner};
#[cfg(debug_assertions)] {
debug_assert_eq!(
vec.len(), self.cur_size as usize,
"trying to turn section into vec, but size is larger than expected"
);
self.cur_size = self.start_size;
}
let section = Vec::from_iter(vec.drain(self.start_size as usize..));
section
}
}
impl<T: Copy> ScopedSection<T> {
pub(crate) fn iter_copied(&self) -> ScopedIter<T> {
return ScopedIter{
inner: self.inner,
cur_index: self.start_size,
last_index: unsafe{ (*self.inner).len() as u32 },
}
}
}
impl<T: Sized> std::ops::Index<usize> for ScopedSection<T> {
type Output = T;
fn index(&self, idx: usize) -> &Self::Output {
let vec = unsafe{&*self.inner};
return &vec[self.start_size as usize + idx]
}
}
#[cfg(debug_assertions)]
impl<T: Sized> Drop for ScopedSection<T> {
fn drop(&mut self) {
let vec = unsafe{&mut *self.inner};
#[cfg(debug_assertions)] debug_assert_eq!(vec.len(), self.cur_size as usize);
vec.truncate(self.start_size as usize);
}
}
pub(crate) struct ScopedIter<T: Copy> {
inner: *mut Vec<T>,
cur_index: u32,
last_index: u32,
}
impl<T: Copy> Iterator for ScopedIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.cur_index >= self.last_index {
return None;
}
let vec = unsafe{ &*self.inner };
let index = self.cur_index as usize;
self.cur_index += 1;
return Some(vec[index]);
}
}
|