]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
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 | ||
0531ce1d | 11 | use rustc_data_structures::sync::Lrc; |
b7449926 XL |
12 | use syntax::source_map::SourceMap; |
13 | use syntax_pos::{BytePos, SourceFile}; | |
9e0c209e SL |
14 | |
15 | #[derive(Clone)] | |
16 | struct CacheEntry { | |
17 | time_stamp: usize, | |
18 | line_number: usize, | |
19 | line_start: BytePos, | |
20 | line_end: BytePos, | |
b7449926 | 21 | file: Lrc<SourceFile>, |
7cac9316 | 22 | file_index: usize, |
9e0c209e SL |
23 | } |
24 | ||
ea8adc8c | 25 | #[derive(Clone)] |
b7449926 XL |
26 | pub struct CachingSourceMapView<'cm> { |
27 | source_map: &'cm SourceMap, | |
9e0c209e SL |
28 | line_cache: [CacheEntry; 3], |
29 | time_stamp: usize, | |
30 | } | |
31 | ||
b7449926 XL |
32 | impl<'cm> CachingSourceMapView<'cm> { |
33 | pub fn new(source_map: &'cm SourceMap) -> CachingSourceMapView<'cm> { | |
34 | let files = source_map.files(); | |
7cac9316 | 35 | let first_file = files[0].clone(); |
9e0c209e SL |
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, | |
7cac9316 | 42 | file_index: 0, |
9e0c209e SL |
43 | }; |
44 | ||
b7449926 XL |
45 | CachingSourceMapView { |
46 | source_map, | |
0bf4aa26 | 47 | line_cache: [entry.clone(), entry.clone(), entry], |
9e0c209e SL |
48 | time_stamp: 0, |
49 | } | |
50 | } | |
51 | ||
9e0c209e SL |
52 | pub fn byte_pos_to_line_and_col(&mut self, |
53 | pos: BytePos) | |
b7449926 | 54 | -> Option<(Lrc<SourceFile>, usize, BytePos)> { |
9e0c209e SL |
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; | |
7cac9316 | 61 | |
9e0c209e SL |
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; | |
b7449926 XL |
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(); | |
9e0c209e SL |
84 | |
85 | if pos >= file.start_pos && pos < file.end_pos { | |
86 | cache_entry.file = file; | |
7cac9316 | 87 | cache_entry.file_index = file_index; |
9e0c209e SL |
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 | } |