linked lists

This commit is contained in:
Jana Dönszelmann 2026-03-20 10:44:20 +01:00
parent 8eab2502c7
commit 430c62c120
No known key found for this signature in database
12 changed files with 783 additions and 544 deletions

View file

@ -4,18 +4,17 @@ use std::{
io::{self, BufRead, BufReader},
mem,
path::{Path, PathBuf},
sync::Arc,
rc::Rc,
sync::{
OnceLock,
mpsc::{Receiver, sync_channel},
mpsc::{Receiver, channel},
},
thread,
};
use crate::tui::{
model::{LogEntry, RawLogEntry},
processing::{FilterList, LogStream},
};
use dumpster::sync::Gc;
use crate::tui::model::{ChildInfo, LogEntry, RawLogEntry};
struct LogFileEntryGenerator {
file: BufReader<File>,
@ -45,38 +44,61 @@ impl LogFileEntryGenerator {
}
}
fn next_entry(&mut self) -> Option<Arc<LogEntry>> {
let mut stack = Vec::<(RawLogEntry, Vec<Arc<LogEntry>>)>::new();
let mut curr = Vec::<Arc<LogEntry>>::new();
fn next_entry(&mut self, prev: Option<Gc<LogEntry>>) -> Option<Gc<LogEntry>> {
let mut stack = Vec::<(RawLogEntry, Option<Gc<LogEntry>>, Option<Gc<LogEntry>>)>::new();
let mut curr_first = None;
let mut curr_last = prev;
loop {
let entry = self.next_raw_entry()?;
let new_entry = Arc::new(match entry.fields.message() {
let new_entry = Gc::new(match entry.fields.message() {
Some("enter") => {
stack.push((entry, mem::take(&mut curr)));
stack.push((entry, curr_first.take(), curr_last.take()));
continue;
}
Some("exit") => {
// TODO: does it match?
let Some((enter, prev)) = stack.pop() else {
let Some((enter, prev_first, prev_last)) = stack.pop() else {
panic!("exit before entry");
};
let sub_entries = mem::replace(&mut curr, prev);
let first_child = mem::replace(&mut curr_first, prev_first);
let last_child = mem::replace(&mut curr_last, prev_last);
let prev = curr_last.clone();
let next = OnceLock::new();
LogEntry::Sub {
enter: enter,
sub_entries,
enter,
exit: entry,
count_sub: OnceLock::new(),
children: Gc::new(ChildInfo {
first_child,
last_child,
prev,
next,
}),
}
}
_ => LogEntry::Single { raw: entry },
_ => {
let prev = curr_last.clone();
let next = OnceLock::new();
LogEntry::Single { entry, prev, next }
}
});
if stack.is_empty() {
return Some(new_entry);
} else if let Some(last) = &mut curr_last {
last.initialize_next().get_or_init({
let new_entry = new_entry.clone();
move || new_entry
});
*last = new_entry;
} else {
curr.push(new_entry);
assert!(curr_first.is_none());
curr_first = Some(new_entry.clone());
curr_last = Some(new_entry);
}
}
}
@ -85,30 +107,38 @@ impl LogFileEntryGenerator {
struct Inner {
pub path: PathBuf,
entry_generator: Receiver<Arc<LogEntry>>,
cached_entries: Vec<Arc<LogEntry>>,
first: Option<Gc<LogEntry>>,
}
#[derive(Clone)]
pub struct LogfileReader(Arc<RefCell<Inner>>);
pub struct LogfileReader(Rc<RefCell<Inner>>);
impl LogfileReader {
pub fn new(p: &Path) -> io::Result<Self> {
let (tx, rx) = sync_channel(1000);
let file = File::open(p)?;
let mut generator = LogFileEntryGenerator {
file: BufReader::new(File::open(p)?),
file: BufReader::new(file),
};
thread::spawn(move || {
while let Some(i) = generator.next_entry() {
tx.send(i).unwrap();
}
});
let first = generator.next_entry(None);
Ok(Self(Arc::new(RefCell::new(Inner {
if let Some(mut curr_last) = first.clone() {
thread::spawn(move || {
while let Some(new) = generator.next_entry(Some(curr_last.clone())) {
assert!(new.prev().is_some());
curr_last.initialize_next().get_or_init({
let new = new.clone();
|| new
});
curr_last = new;
}
});
}
Ok(Self(Rc::new(RefCell::new(Inner {
path: p.to_path_buf(),
cached_entries: Vec::new(),
entry_generator: rx,
first,
}))))
}
@ -116,55 +146,7 @@ impl LogfileReader {
self.0.borrow().path.clone()
}
fn fill_buf_to_access_index(&mut self, n: usize) -> Option<Arc<LogEntry>> {
while self.0.borrow().cached_entries.len() <= n {
let entry = self.0.borrow().entry_generator.recv().ok()?;
self.0.borrow_mut().cached_entries.push(entry);
}
Some(Arc::clone(&self.0.borrow().cached_entries[n]))
}
pub fn iter(&self) -> LogFileReaderStream {
LogFileReaderStream {
reader: self.clone(),
curr: 0,
}
}
}
pub struct LogFileReaderStream {
reader: LogfileReader,
curr: usize,
}
impl LogStream for LogFileReaderStream {
fn next(&mut self, _fl: &FilterList) -> Option<(Arc<LogEntry>, usize)> {
let entry = self.reader.fill_buf_to_access_index(self.curr)?;
self.curr += 1;
Some((entry, 0))
}
fn prev(&mut self, _fl: &FilterList) -> Option<(Arc<LogEntry>, usize)> {
if self.curr == 0 {
return None;
}
let entry = self.reader.fill_buf_to_access_index(self.curr)?;
self.curr -= 1;
Some((entry, 0))
}
fn clone(&self) -> Box<dyn LogStream> {
Box::new(Self {
reader: self.reader.clone(),
curr: self.curr,
})
}
fn enclosing_log_entry(&self) -> Option<(Arc<LogEntry>, usize)> {
None
pub fn first(&self) -> Option<Gc<LogEntry>> {
self.0.borrow().first.clone()
}
}