aboutsummaryrefslogtreecommitdiff
path: root/libanalysis
diff options
context:
space:
mode:
Diffstat (limited to 'libanalysis')
-rw-r--r--libanalysis/Cargo.toml2
-rw-r--r--libanalysis/src/arena.rs42
-rw-r--r--libanalysis/src/lib.rs89
3 files changed, 56 insertions, 77 deletions
diff --git a/libanalysis/Cargo.toml b/libanalysis/Cargo.toml
index 737463258..2beea5640 100644
--- a/libanalysis/Cargo.toml
+++ b/libanalysis/Cargo.toml
@@ -7,4 +7,6 @@ authors = ["Aleksey Kladov <[email protected]>"]
7log = "0.4.2" 7log = "0.4.2"
8failure = "0.1.2" 8failure = "0.1.2"
9parking_lot = "0.6.3" 9parking_lot = "0.6.3"
10once_cell = "0.1.4"
10libsyntax2 = { path = "../" } 11libsyntax2 = { path = "../" }
12libeditor = { path = "../libeditor" }
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 @@
1use parking_lot::RwLock;
2
3const CHUNK_LEN: usize = 16;
4
5pub struct Arena<T> {
6 chunks: RwLock<Vec<Vec<T>>>,
7}
8
9impl<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;
2extern crate parking_lot; 2extern crate parking_lot;
3#[macro_use] 3#[macro_use]
4extern crate log; 4extern crate log;
5extern crate once_cell;
5extern crate libsyntax2; 6extern crate libsyntax2;
7extern crate libeditor;
6 8
7mod arena; 9use once_cell::sync::OnceCell;
8 10
9use std::{ 11use std::{
10 fs, 12 fs,
@@ -14,6 +16,7 @@ use std::{
14}; 16};
15use parking_lot::RwLock; 17use parking_lot::RwLock;
16use libsyntax2::ast; 18use libsyntax2::ast;
19use libeditor::LineIndex;
17 20
18pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 21pub 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
65impl World { 65impl 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)]
109struct WorldData { 123struct 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
128struct FileData {
129 text: Option<String>,
130 syntax: OnceCell<ast::File>,
131 lines: OnceCell<LineIndex>,
113} 132}