]> git.lizzy.rs Git - rust.git/blob - src/librustc/ich/caching_codemap_view.rs
Regression test for issue #54477.
[rust.git] / src / librustc / ich / caching_codemap_view.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use rustc_data_structures::sync::Lrc;
12 use syntax::source_map::SourceMap;
13 use syntax_pos::{BytePos, SourceFile};
14
15 #[derive(Clone)]
16 struct CacheEntry {
17     time_stamp: usize,
18     line_number: usize,
19     line_start: BytePos,
20     line_end: BytePos,
21     file: Lrc<SourceFile>,
22     file_index: usize,
23 }
24
25 #[derive(Clone)]
26 pub struct CachingSourceMapView<'cm> {
27     source_map: &'cm SourceMap,
28     line_cache: [CacheEntry; 3],
29     time_stamp: usize,
30 }
31
32 impl<'cm> CachingSourceMapView<'cm> {
33     pub fn new(source_map: &'cm SourceMap) -> CachingSourceMapView<'cm> {
34         let files = source_map.files();
35         let first_file = files[0].clone();
36         let entry = CacheEntry {
37             time_stamp: 0,
38             line_number: 0,
39             line_start: BytePos(0),
40             line_end: BytePos(0),
41             file: first_file,
42             file_index: 0,
43         };
44
45         CachingSourceMapView {
46             source_map,
47             line_cache: [entry.clone(), entry.clone(), entry],
48             time_stamp: 0,
49         }
50     }
51
52     pub fn byte_pos_to_line_and_col(&mut self,
53                                     pos: BytePos)
54                                     -> Option<(Lrc<SourceFile>, usize, BytePos)> {
55         self.time_stamp += 1;
56
57         // Check if the position is in one of the cached lines
58         for cache_entry in self.line_cache.iter_mut() {
59             if pos >= cache_entry.line_start && pos < cache_entry.line_end {
60                 cache_entry.time_stamp = self.time_stamp;
61
62                 return Some((cache_entry.file.clone(),
63                              cache_entry.line_number,
64                              pos - cache_entry.line_start));
65             }
66         }
67
68         // No cache hit ...
69         let mut oldest = 0;
70         for index in 1 .. self.line_cache.len() {
71             if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp {
72                 oldest = index;
73             }
74         }
75
76         let cache_entry = &mut self.line_cache[oldest];
77
78         // If the entry doesn't point to the correct file, fix it up
79         if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos {
80             let file_valid;
81             if self.source_map.files().len() > 0 {
82                 let file_index = self.source_map.lookup_source_file_idx(pos);
83                 let file = self.source_map.files()[file_index].clone();
84
85                 if pos >= file.start_pos && pos < file.end_pos {
86                     cache_entry.file = file;
87                     cache_entry.file_index = file_index;
88                     file_valid = true;
89                 } else {
90                     file_valid = false;
91                 }
92             } else {
93                 file_valid = false;
94             }
95
96             if !file_valid {
97                 return None;
98             }
99         }
100
101         let line_index = cache_entry.file.lookup_line(pos).unwrap();
102         let line_bounds = cache_entry.file.line_bounds(line_index);
103
104         cache_entry.line_number = line_index + 1;
105         cache_entry.line_start = line_bounds.0;
106         cache_entry.line_end = line_bounds.1;
107         cache_entry.time_stamp = self.time_stamp;
108
109         return Some((cache_entry.file.clone(),
110                      cache_entry.line_number,
111                      pos - cache_entry.line_start));
112     }
113 }