My algorithm uses a Vec<RwLockReadGuard<..>>
for processing data. The algorithm is called repeatedly, and I don't want to allocate the Vec
each time it gets called, I'd be happy if I could just clear()
it at the end of processing, and reuse it the next time by storing it in the same struct that is tied to the data processing. However, RwLockReadGuard
takes a lifetime that is shorter than possible lifetime of the holding struct. Since I only use the Vec
inside the data processing function, and outside it it is always empty, can I still store it in the struct somehow? Is there a crate or an idiom that might help me with that?
The minimal reproducible example showing the problem is at the bottom of the question.
This is how it would look like if I was allocating the Vec
each time:
#[derive(Clone)]
pub struct T;
pub fn process_ts(ts: &[T]) {
unimplemented!();
}
struct Process {
locked_ts: Vec<RwLock<Vec<T>>>,
}
impl Process {
pub fn process(&self) {
let mut ts: Vec<T> = Vec::with_capacity(self.locked_ts.len());
let guards: Vec<RwLockReadGuard<Vec<T>>> = self
.locked_ts
.iter()
.map(|locked_t| locked_t.read().unwrap())
.collect();
let n = guards.iter().map(|guard| guard.len()).min().unwrap();
for i in 0..n {
ts.clear();
for t in &guards {
ts.push(t[i].clone());
process_ts(&ts);
}
}
}
}
What I don't like about this solution is that each time Process::process
is called, ts: Vec<T>
and guards: Vec<RwLockReadGuard<Vec<T>>>
is allocated. I can get rid of ts
:
struct ProcessReuseTs {
locked_ts: Vec<RwLock<Vec<T>>>,
reusable_ts: Vec<T>,
}
impl ProcessReuseTs {
pub fn process(&mut self) {
let guards: Vec<RwLockReadGuard<Vec<T>>> = self
.locked_ts
.iter()
.map(|locked_t| locked_t.read().unwrap())
.collect();
let n = guards.iter().map(|guard| guard.len()).min().unwrap();
for i in 0..n {
self.reusable_ts.clear();
for t in &guards {
self.reusable_ts.push(t[i].clone());
process_ts(&self.reusable_ts);
}
}
}
}
But how can I extract guards
?
use std::sync::{RwLock, RwLockReadGuard};
#[derive(Clone)]
pub struct T;
pub fn process_ts(ts: &[T]) {
unimplemented!();
}
struct ProcessReuseBoth {
locked_ts: Vec<RwLock<Vec<T>>>,
reusable_ts: Vec<T>,
reusable_guards: Vec<RwLockReadGuard<Vec<T>>>,
}
impl ProcessReuseBoth {
pub fn process(&mut self) {
self.reusable_guards.clear();
self.reusable_guards.extend(
self.locked_ts
.iter()
.map(|locked_t| locked_t.read().unwrap()),
);
let n = self
.reusable_guards
.iter()
.map(|guard| guard.len())
.min()
.unwrap();
for i in 0..n {
self.reusable_ts.clear();
for t in &self.reusable_guards {
self.reusable_ts.push(t[i].clone());
process_ts(&self.reusable_ts);
}
}
self.reusable_guards.clear();
}
}
pub fn main() {
unimplemented!()
}
doesn't compile with
error[E0106]: missing lifetime specifier
--> src/main.rs:13:26
|
13 | reusable_guards: Vec<RwLockReadGuard<Vec<T>>>,
|