about summary refs log tree commit diff
path: root/src/libsyntax_pos/caching_source_map_view.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax_pos/caching_source_map_view.rs')
-rw-r--r--src/libsyntax_pos/caching_source_map_view.rs103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/libsyntax_pos/caching_source_map_view.rs b/src/libsyntax_pos/caching_source_map_view.rs
new file mode 100644
index 00000000000..82371730876
--- /dev/null
+++ b/src/libsyntax_pos/caching_source_map_view.rs
@@ -0,0 +1,103 @@
+use rustc_data_structures::sync::Lrc;
+use crate::source_map::SourceMap;
+use crate::{BytePos, SourceFile};
+
+#[derive(Clone)]
+struct CacheEntry {
+    time_stamp: usize,
+    line_number: usize,
+    line_start: BytePos,
+    line_end: BytePos,
+    file: Lrc<SourceFile>,
+    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<SourceFile>, 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));
+    }
+}