LINUX.ORG.RU

История изменений

Исправление khrundel, (текущая версия) :

Мой адаптированный вариант со скипвайлами:

use std::fs;
use std::fs::File;
use std::io::prelude::*;

struct Lexer<'a>{
    left: &'a str
}

impl<'a> Lexer<'a>{
    fn new(source:&'a str)->Lexer<'a> {
        Lexer{left : source}
    }
    
    fn next (&mut self) -> Option<&'a str> {
        let iter = self.left.char_indices();
        let mut iter = iter.skip_while(|i| i.1 == ' ');
        if let Some((start_index, c)) = iter.next() {
            let end_index = match c {
                'A'...'Z' | 'a'...'z' => if let Some((e, _)) = iter
                                                                .skip_while(|i| i.1 >= 'A' && i.1 <= 'Z' || i.1 >= 'a' && i.1 <= 'z')
                                                                .next() { e } else { self.left.len() },
                _ => if let Some((e, _)) = iter.next() { e } else { self.left.len() },
            };
            let t = self.left;
            self.left = &t[end_index..];
            return Some(&t[start_index..end_index]);
        }
        None
    }
}

fn main() {
    let metadata = fs::metadata("data").unwrap();
    let mut f = File::open("data").expect("file not found.");

    let mut text = String::with_capacity(metadata.len() as usize);
    f.read_to_string(&mut text)
        .expect("error reading file.");

    let mut lexer = Lexer::new(&text);

    let mut commas_count = 0;
    let mut words_count = 0;
    while let Some(token) = lexer.next() {
        if token.chars().next() == Some(',') {
            commas_count += 1;
        } else {
            words_count += 1;
        }
    }
    println!("Итого: {} слов и {} запятых", words_count, commas_count);
}

Размер файла в 100 раз увеличил, чтоб время более-менее нормально занимало.

Результат:

~/rust-workspace/rust-lexer$ time ./clexer 
Итого: 350000001 слов и 250000000 запятых

real	0m9,187s
user	0m8,153s
sys	0m1,024s
~/rust-workspace/rust-lexer$ time ./target/release/rust-lexer
Итого: 350000001 слов и 250000000 запятых

real	0m9,733s
user	0m8,106s
sys	0m1,619s
В общем на 5% отстаёт, но зато поддерживает юникод. Ну и лямбды явно заинлайнены. Причём отставание за счёт системного времени. Уж не знаю на что, сначала думал что из-за реаллокаций строки, но тут с ранним выделением, а системное время всё равно больше.

Исходная версия khrundel, :

Мой адаптированный вариант со скипвайлами:

use std::fs;
use std::fs::File;
use std::io::prelude::*;

struct Lexer<'a>{
    left: &'a str
}

impl<'a> Lexer<'a>{
    fn new(source:&'a str)->Lexer<'a> {
        Lexer{left : source}
    }
    
    fn next (&mut self) -> Option<&'a str> {
        let iter = self.left.char_indices();
        let mut iter = iter.skip_while(|i| i.1 == ' ');
        if let Some((start_index, c)) = iter.next() {
            let end_index = match c {
                'A'...'Z' | 'a'...'z' => if let Some((e, _)) = iter
                                                                .skip_while(|i| i.1 >= 'A' && i.1 <= 'Z' || i.1 >= 'a' && i.1 <= 'z')
                                                                .next() { e } else { self.left.len() },
                _ => if let Some((e, _)) = iter.next() { e } else { self.left.len() },
            };
            let t = self.left;
            self.left = &t[end_index..];
            return Some(&t[start_index..end_index]);
        }
        None
    }
}

fn main() {
    let metadata = fs::metadata("data").unwrap();
    let mut f = File::open("data").expect("file not found.");

    let mut text = String::with_capacity(metadata.len() as usize);
    f.read_to_string(&mut text)
        .expect("error reading file.");

    let mut lexer = Lexer::new(&text);

    let mut commas_count = 0;
    let mut words_count = 0;
    while let Some(token) = lexer.next() {
        if token.chars().next() == Some(',') {
            commas_count += 1;
        } else {
            words_count += 1;
        }
    }
    println!("Итого: {} слов и {} запятых", words_count, commas_count);
}

Размер файла в 100 раз увеличил, чтоб время более-менее нормально занимало.

Результат:

~/rust-workspace/rust-lexer$ time ./clexer 
Итого: 350000001 слов и 250000000 запятых

real	0m9,187s
user	0m8,153s
sys	0m1,024s
~/rust-workspace/rust-lexer$ time ./target/release/rust-lexer
Итого: 350000001 слов и 250000000 запятых

real	0m9,733s
user	0m8,106s
sys	0m1,619s
В общем на 5% отстаёт, но зато поддерживает юникод. Ну и лямбды явно заинлайнены.