use crate::source_map::SourceMap; use crate::{BytePos, SourceFile}; use rustc_data_structures::sync::Lrc; #[derive(Clone)] struct CacheEntry { time_stamp: usize, line_number: usize, line_start: BytePos, line_end: BytePos, file: Lrc, file_index: usize, } #[derive(Clone)] pub struct CachingSourceMapView<'cm> { source_map: &'cm SourceMap, line_cache: [CacheEntry; 3], time_stamp: usize, } impl<'cm> CachingSourceMapView<'cm> { pub fn new(source_map: &'cm SourceMap) -> CachingSourceMapView<'cm> { let files = source_map.files(); let first_file = files[0].clone(); let entry = CacheEntry { time_stamp: 0, line_number: 0, line_start: BytePos(0), line_end: BytePos(0), file: first_file, file_index: 0, }; CachingSourceMapView { source_map, line_cache: [entry.clone(), entry.clone(), entry], time_stamp: 0, } } pub fn byte_pos_to_line_and_col( &mut self, pos: BytePos, ) -> Option<(Lrc, usize, BytePos)> { self.time_stamp += 1; // Check if the position is in one of the cached lines for cache_entry in self.line_cache.iter_mut() { if pos >= cache_entry.line_start && pos < cache_entry.line_end { cache_entry.time_stamp = self.time_stamp; return Some(( cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line_start, )); } } // No cache hit ... let mut oldest = 0; for index in 1..self.line_cache.len() { if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp { oldest = index; } } let cache_entry = &mut self.line_cache[oldest]; // If the entry doesn't point to the correct file, fix it up if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { let file_valid; if self.source_map.files().len() > 0 { let file_index = self.source_map.lookup_source_file_idx(pos); let file = self.source_map.files()[file_index].clone(); if pos >= file.start_pos && pos < file.end_pos { cache_entry.file = file; cache_entry.file_index = file_index; file_valid = true; } else { file_valid = false; } } else { file_valid = false; } if !file_valid { return None; } } let line_index = cache_entry.file.lookup_line(pos).unwrap(); let line_bounds = cache_entry.file.line_bounds(line_index); cache_entry.line_number = line_index + 1; cache_entry.line_start = line_bounds.0; cache_entry.line_end = line_bounds.1; cache_entry.time_stamp = self.time_stamp; return Some(( cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line_start, )); } }