diff options
Diffstat (limited to 'libanalysis/src')
-rw-r--r-- | libanalysis/src/arena.rs | 42 | ||||
-rw-r--r-- | libanalysis/src/lib.rs | 89 |
2 files changed, 54 insertions, 77 deletions
diff --git a/libanalysis/src/arena.rs b/libanalysis/src/arena.rs deleted file mode 100644 index fc0c25c54..000000000 --- a/libanalysis/src/arena.rs +++ /dev/null | |||
@@ -1,42 +0,0 @@ | |||
1 | use parking_lot::RwLock; | ||
2 | |||
3 | const CHUNK_LEN: usize = 16; | ||
4 | |||
5 | pub struct Arena<T> { | ||
6 | chunks: RwLock<Vec<Vec<T>>>, | ||
7 | } | ||
8 | |||
9 | impl<T> Arena<T> { | ||
10 | pub fn new(&self) -> Arena<T> { | ||
11 | Arena { | ||
12 | chunks: RwLock::new(vec![Vec::with_capacity(CHUNK_LEN)]), | ||
13 | } | ||
14 | } | ||
15 | |||
16 | pub fn push(&self, value: T) -> usize { | ||
17 | let mut guard = self.chunks.write(); | ||
18 | let mut idx = (guard.len() - 1) * CHUNK_LEN; | ||
19 | let chunk = { | ||
20 | if guard.last().unwrap().len() == CHUNK_LEN { | ||
21 | guard.push(Vec::with_capacity(CHUNK_LEN)); | ||
22 | } | ||
23 | guard.last_mut().unwrap() | ||
24 | }; | ||
25 | assert!(chunk.len() < chunk.capacity()); | ||
26 | idx += chunk.len(); | ||
27 | chunk.push(value); | ||
28 | idx | ||
29 | } | ||
30 | |||
31 | pub fn get(&self, idx: usize) -> &T { | ||
32 | let chunk_idx = idx / CHUNK_LEN; | ||
33 | let chunk_off = idx - chunk_idx * CHUNK_LEN; | ||
34 | let guard = self.chunks.read(); | ||
35 | let value = &guard[chunk_idx][chunk_off]; | ||
36 | unsafe { | ||
37 | // We are careful to not move values in chunks, | ||
38 | // so this hopefully is safe | ||
39 | ::std::mem::transmute::<&T, &T>(value) | ||
40 | } | ||
41 | } | ||
42 | } | ||
diff --git a/libanalysis/src/lib.rs b/libanalysis/src/lib.rs index 417a544ca..6a946a0b0 100644 --- a/libanalysis/src/lib.rs +++ b/libanalysis/src/lib.rs | |||
@@ -2,9 +2,11 @@ extern crate failure; | |||
2 | extern crate parking_lot; | 2 | extern crate parking_lot; |
3 | #[macro_use] | 3 | #[macro_use] |
4 | extern crate log; | 4 | extern crate log; |
5 | extern crate once_cell; | ||
5 | extern crate libsyntax2; | 6 | extern crate libsyntax2; |
7 | extern crate libeditor; | ||
6 | 8 | ||
7 | mod arena; | 9 | use once_cell::sync::OnceCell; |
8 | 10 | ||
9 | use std::{ | 11 | use std::{ |
10 | fs, | 12 | fs, |
@@ -14,6 +16,7 @@ use std::{ | |||
14 | }; | 16 | }; |
15 | use parking_lot::RwLock; | 17 | use parking_lot::RwLock; |
16 | use libsyntax2::ast; | 18 | use libsyntax2::ast; |
19 | use libeditor::LineIndex; | ||
17 | 20 | ||
18 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 21 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
19 | 22 | ||
@@ -39,7 +42,6 @@ impl WorldState { | |||
39 | pub fn change_overlay(&mut self, path: PathBuf, text: Option<String>) { | 42 | pub fn change_overlay(&mut self, path: PathBuf, text: Option<String>) { |
40 | let data = self.data_mut(); | 43 | let data = self.data_mut(); |
41 | data.file_map.get_mut().remove(&path); | 44 | data.file_map.get_mut().remove(&path); |
42 | data.fs_map.get_mut().remove(&path); | ||
43 | if let Some(text) = text { | 45 | if let Some(text) = text { |
44 | data.mem_map.insert(path, Arc::new(text)); | 46 | data.mem_map.insert(path, Arc::new(text)); |
45 | } else { | 47 | } else { |
@@ -49,11 +51,9 @@ impl WorldState { | |||
49 | 51 | ||
50 | fn data_mut(&mut self) -> &mut WorldData { | 52 | fn data_mut(&mut self) -> &mut WorldData { |
51 | if Arc::get_mut(&mut self.data).is_none() { | 53 | if Arc::get_mut(&mut self.data).is_none() { |
52 | let fs_map = self.data.fs_map.read().clone(); | ||
53 | let file_map = self.data.file_map.read().clone(); | 54 | let file_map = self.data.file_map.read().clone(); |
54 | self.data = Arc::new(WorldData { | 55 | self.data = Arc::new(WorldData { |
55 | mem_map: self.data.mem_map.clone(), | 56 | mem_map: self.data.mem_map.clone(), |
56 | fs_map: RwLock::new(fs_map), | ||
57 | file_map: RwLock::new(file_map), | 57 | file_map: RwLock::new(file_map), |
58 | }); | 58 | }); |
59 | } | 59 | } |
@@ -64,43 +64,57 @@ impl WorldState { | |||
64 | 64 | ||
65 | impl World { | 65 | impl World { |
66 | pub fn file_syntax(&self, path: &Path) -> Result<ast::File> { | 66 | pub fn file_syntax(&self, path: &Path) -> Result<ast::File> { |
67 | { | 67 | let data = self.file_data(path)?; |
68 | let guard = self.data.file_map.read(); | 68 | let syntax = data.syntax |
69 | if let Some(file) = guard.get(path) { | 69 | .get_or_init(|| { |
70 | return Ok(file.clone()); | 70 | trace!("parsing: {}", path.display()); |
71 | } | 71 | ast::File::parse(self.file_text(path, &data)) |
72 | } | 72 | }).clone(); |
73 | let file = self.with_file_text(path, |text| { | 73 | Ok(syntax) |
74 | trace!("parsing file: {}", path.display()); | ||
75 | ast::File::parse(text) | ||
76 | })?; | ||
77 | let mut guard = self.data.file_map.write(); | ||
78 | let file = guard.entry(path.to_owned()) | ||
79 | .or_insert(file) | ||
80 | .clone(); | ||
81 | Ok(file) | ||
82 | } | 74 | } |
83 | 75 | ||
84 | fn with_file_text<F: FnOnce(&str) -> R, R>(&self, path: &Path, f: F) -> Result<R> { | 76 | pub fn file_line_index(&self, path: &Path) -> Result<LineIndex> { |
85 | if let Some(text) = self.data.mem_map.get(path) { | 77 | let data = self.file_data(path)?; |
86 | return Ok(f(&*text)); | 78 | let index = data.lines |
79 | .get_or_init(|| { | ||
80 | trace!("calc line index: {}", path.display()); | ||
81 | LineIndex::new(self.file_text(path, &data)) | ||
82 | }); | ||
83 | Ok(index.clone()) | ||
84 | } | ||
85 | |||
86 | fn file_text<'a>(&'a self, path: &Path, file_data: &'a FileData) -> &'a str { | ||
87 | match file_data.text.as_ref() { | ||
88 | Some(text) => text.as_str(), | ||
89 | None => self.data.mem_map[path].as_str() | ||
87 | } | 90 | } |
91 | } | ||
88 | 92 | ||
93 | fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { | ||
89 | { | 94 | { |
90 | let guard = self.data.fs_map.read(); | 95 | let guard = self.data.file_map.read(); |
91 | if let Some(text) = guard.get(path) { | 96 | if let Some(data) = guard.get(path) { |
92 | return Ok(f(&*text)); | 97 | return Ok(data.clone()); |
93 | } | 98 | } |
94 | } | 99 | } |
95 | trace!("loading file from disk: {}", path.display()); | 100 | |
96 | let text = fs::read_to_string(path)?; | 101 | let text = if self.data.mem_map.contains_key(path) { |
97 | { | 102 | None |
98 | let mut guard = self.data.fs_map.write(); | 103 | } else { |
104 | trace!("loading file from disk: {}", path.display()); | ||
105 | Some(fs::read_to_string(path)?) | ||
106 | }; | ||
107 | let res = { | ||
108 | let mut guard = self.data.file_map.write(); | ||
99 | guard.entry(path.to_owned()) | 109 | guard.entry(path.to_owned()) |
100 | .or_insert_with(|| Arc::new(text)); | 110 | .or_insert_with(|| Arc::new(FileData { |
101 | } | 111 | text, |
102 | let guard = self.data.fs_map.read(); | 112 | syntax: OnceCell::new(), |
103 | Ok(f(&guard[path])) | 113 | lines: OnceCell::new(), |
114 | })) | ||
115 | .clone() | ||
116 | }; | ||
117 | Ok(res) | ||
104 | } | 118 | } |
105 | } | 119 | } |
106 | 120 | ||
@@ -108,6 +122,11 @@ impl World { | |||
108 | #[derive(Default)] | 122 | #[derive(Default)] |
109 | struct WorldData { | 123 | struct WorldData { |
110 | mem_map: HashMap<PathBuf, Arc<String>>, | 124 | mem_map: HashMap<PathBuf, Arc<String>>, |
111 | fs_map: RwLock<HashMap<PathBuf, Arc<String>>>, | 125 | file_map: RwLock<HashMap<PathBuf, Arc<FileData>>>, |
112 | file_map: RwLock<HashMap<PathBuf, ast::File>>, | 126 | } |
127 | |||
128 | struct FileData { | ||
129 | text: Option<String>, | ||
130 | syntax: OnceCell<ast::File>, | ||
131 | lines: OnceCell<LineIndex>, | ||
113 | } | 132 | } |