about summary refs log tree commit diff
path: root/src/libsyntax_pos
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo>2018-05-23 15:59:42 +0200
committerMichael Woerister <michaelwoerister@posteo>2018-06-27 14:00:34 +0200
commit257d279fe47bbf3431c76f0942654c1bcf60d501 (patch)
treeb7230231778da7b5345f80ea6565c67ce9b14843 /src/libsyntax_pos
parentc20824323cf7ed6ad95cb8d7b780a7934927a753 (diff)
downloadrust-257d279fe47bbf3431c76f0942654c1bcf60d501.tar.gz
rust-257d279fe47bbf3431c76f0942654c1bcf60d501.zip
Make FileMap::{lines, multibyte_chars, non_narrow_chars} non-mutable.
Diffstat (limited to 'src/libsyntax_pos')
-rw-r--r--src/libsyntax_pos/lib.rs158
1 files changed, 88 insertions, 70 deletions
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 756e0c059a7..266737dd7b6 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -779,11 +779,11 @@ pub struct FileMap {
     /// The end position of this source in the CodeMap
     pub end_pos: BytePos,
     /// Locations of lines beginnings in the source code
-    pub lines: Lock<Vec<BytePos>>,
+    pub lines: Vec<BytePos>,
     /// Locations of multi-byte characters in the source code
-    pub multibyte_chars: Lock<Vec<MultiByteChar>>,
+    pub multibyte_chars: Vec<MultiByteChar>,
     /// Width of characters that are not narrow in the source code
-    pub non_narrow_chars: Lock<Vec<NonNarrowChar>>,
+    pub non_narrow_chars: Vec<NonNarrowChar>,
     /// A hash of the filename, used for speeding up the incr. comp. hashing.
     pub name_hash: u128,
 }
@@ -797,7 +797,7 @@ impl Encodable for FileMap {
             s.emit_struct_field("start_pos", 4, |s| self.start_pos.encode(s))?;
             s.emit_struct_field("end_pos", 5, |s| self.end_pos.encode(s))?;
             s.emit_struct_field("lines", 6, |s| {
-                let lines = self.lines.borrow();
+                let lines = &self.lines[..];
                 // store the length
                 s.emit_u32(lines.len() as u32)?;
 
@@ -843,10 +843,10 @@ impl Encodable for FileMap {
                 Ok(())
             })?;
             s.emit_struct_field("multibyte_chars", 7, |s| {
-                (*self.multibyte_chars.borrow()).encode(s)
+                self.multibyte_chars.encode(s)
             })?;
             s.emit_struct_field("non_narrow_chars", 8, |s| {
-                (*self.non_narrow_chars.borrow()).encode(s)
+                self.non_narrow_chars.encode(s)
             })?;
             s.emit_struct_field("name_hash", 9, |s| {
                 self.name_hash.encode(s)
@@ -914,9 +914,9 @@ impl Decodable for FileMap {
                 src: None,
                 src_hash,
                 external_src: Lock::new(ExternalSource::AbsentOk),
-                lines: Lock::new(lines),
-                multibyte_chars: Lock::new(multibyte_chars),
-                non_narrow_chars: Lock::new(non_narrow_chars),
+                lines,
+                multibyte_chars,
+                non_narrow_chars,
                 name_hash,
             })
         })
@@ -949,6 +949,9 @@ impl FileMap {
         };
         let end_pos = start_pos.to_usize() + src.len();
 
+        let (lines, multibyte_chars, non_narrow_chars) =
+            Self::find_newlines_and_special_chars(&src[..], start_pos);
+
         FileMap {
             name,
             name_was_remapped,
@@ -959,34 +962,81 @@ impl FileMap {
             external_src: Lock::new(ExternalSource::Unneeded),
             start_pos,
             end_pos: Pos::from_usize(end_pos),
-            lines: Lock::new(Vec::new()),
-            multibyte_chars: Lock::new(Vec::new()),
-            non_narrow_chars: Lock::new(Vec::new()),
+            lines,
+            multibyte_chars,
+            non_narrow_chars,
             name_hash,
         }
     }
 
-    /// EFFECT: register a start-of-line offset in the
-    /// table of line-beginnings.
-    /// UNCHECKED INVARIANT: these offsets must be added in the right
-    /// order and must be in the right places; there is shared knowledge
-    /// about what ends a line between this file and parse.rs
-    /// WARNING: pos param here is the offset relative to start of CodeMap,
-    /// and CodeMap will append a newline when adding a filemap without a newline at the end,
-    /// so the safe way to call this is with value calculated as
-    /// filemap.start_pos + newline_offset_relative_to_the_start_of_filemap.
-    pub fn next_line(&self, pos: BytePos) {
-        // the new charpos must be > the last one (or it's the first one).
-        let mut lines = self.lines.borrow_mut();
-        let line_len = lines.len();
-        assert!(line_len == 0 || ((*lines)[line_len - 1] < pos));
-        lines.push(pos);
+    fn find_newlines_and_special_chars(src: &str, filemap_start_pos: BytePos)
+        -> (Vec<BytePos>, Vec<MultiByteChar>, Vec<NonNarrowChar>) {
+
+        let mut index = 0;
+        let mut lines = vec![filemap_start_pos];
+        let mut multibyte_chars = vec![];
+        let mut non_narrow_chars = vec![];
+
+        while index < src.len() {
+            let byte_pos = BytePos::from_usize(index) + filemap_start_pos;
+            let byte = src.as_bytes()[index];
+
+            if byte.is_ascii() {
+                match byte {
+                    b'\n' => {
+                        lines.push(byte_pos + BytePos(1));
+                    }
+                    b'\t' => {
+                        // Tabs will consume 4 columns.
+                        non_narrow_chars.push(NonNarrowChar::new(byte_pos, 4));
+                    }
+                    c => if c.is_ascii_control() {
+                        // Assume control characters are zero width.
+                        non_narrow_chars.push(NonNarrowChar::new(byte_pos, 0));
+                    }
+                }
+
+                index += 1;
+            } else {
+                let c = (&src[index..]).chars().next().unwrap();
+                let c_len = c.len_utf8();
+
+                if c_len > 1 {
+                    assert!(c_len >=2 && c_len <= 4);
+                    let mbc = MultiByteChar {
+                        pos: byte_pos,
+                        bytes: c_len,
+                    };
+                    multibyte_chars.push(mbc);
+                }
+
+                // Assume control characters are zero width.
+                // FIXME: How can we decide between `width` and `width_cjk`?
+                let c_width = unicode_width::UnicodeWidthChar::width(c).unwrap_or(0);
+
+                if c_width != 1 {
+                    non_narrow_chars.push(NonNarrowChar::new(byte_pos, c_width));
+                }
+
+                index += c_len;
+            }
+        }
+
+        // The loop above optimistically registers a new line *after* each of \n
+        // it encounters. If that point is already outside the filemap, remove
+        // it again.
+        if let Some(&last_line_start) = lines.last() {
+            if last_line_start == filemap_start_pos + BytePos::from_usize(src.len()) {
+                lines.pop();
+            }
+        }
+
+        (lines, multibyte_chars, non_narrow_chars)
     }
 
     /// Return the BytePos of the beginning of the current line.
     pub fn line_begin_pos(&self) -> BytePos {
-        let lines = self.lines.borrow();
-        match lines.last() {
+        match self.lines.last() {
             Some(&line_pos) => line_pos,
             None => self.start_pos,
         }
@@ -1040,8 +1090,7 @@ impl FileMap {
         }
 
         let begin = {
-            let lines = self.lines.borrow();
-            let line = if let Some(line) = lines.get(line_number) {
+            let line = if let Some(line) = self.lines.get(line_number) {
                 line
             } else {
                 return None;
@@ -1059,35 +1108,6 @@ impl FileMap {
         }
     }
 
-    pub fn record_multibyte_char(&self, pos: BytePos, bytes: usize) {
-        assert!(bytes >=2 && bytes <= 4);
-        let mbc = MultiByteChar {
-            pos,
-            bytes,
-        };
-        self.multibyte_chars.borrow_mut().push(mbc);
-    }
-
-    #[inline]
-    pub fn record_width(&self, pos: BytePos, ch: char) {
-        let width = match ch {
-            '\t' =>
-                // Tabs will consume 4 columns.
-                4,
-            '\n' =>
-                // Make newlines take one column so that displayed spans can point them.
-                1,
-            ch =>
-                // Assume control characters are zero width.
-                // FIXME: How can we decide between `width` and `width_cjk`?
-                unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0),
-        };
-        // Only record non-narrow characters.
-        if width != 1 {
-            self.non_narrow_chars.borrow_mut().push(NonNarrowChar::new(pos, width));
-        }
-    }
-
     pub fn is_real_file(&self) -> bool {
         self.name.is_real()
     }
@@ -1100,7 +1120,7 @@ impl FileMap {
         self.end_pos.0 - self.start_pos.0
     }
     pub fn count_lines(&self) -> usize {
-        self.lines.borrow().len()
+        self.lines.len()
     }
 
     /// Find the line containing the given position. The return value is the
@@ -1108,13 +1128,12 @@ impl FileMap {
     /// number. If the filemap is empty or the position is located before the
     /// first line, None is returned.
     pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
-        let lines = self.lines.borrow();
-        if lines.len() == 0 {
+        if self.lines.len() == 0 {
             return None;
         }
 
-        let line_index = lookup_line(&lines[..], pos);
-        assert!(line_index < lines.len() as isize);
+        let line_index = lookup_line(&self.lines[..], pos);
+        assert!(line_index < self.lines.len() as isize);
         if line_index >= 0 {
             Some(line_index as usize)
         } else {
@@ -1127,12 +1146,11 @@ impl FileMap {
             return (self.start_pos, self.end_pos);
         }
 
-        let lines = self.lines.borrow();
-        assert!(line_index < lines.len());
-        if line_index == (lines.len() - 1) {
-            (lines[line_index], self.end_pos)
+        assert!(line_index < self.lines.len());
+        if line_index == (self.lines.len() - 1) {
+            (self.lines[line_index], self.end_pos)
         } else {
-            (lines[line_index], lines[line_index + 1])
+            (self.lines[line_index], self.lines[line_index + 1])
         }
     }