// Copyright (C) 2014 by Alexandru Cojocaru // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . use std::io; use std::iter; use std::cmp::Ordering::*; struct Tst { l: Option>>, d: Option>>, r: Option>>, c: char, v: Option, } impl Tst { fn new(c: char) -> Tst { Tst { l: None, d: None, r: None, c: c, v: None } } } fn insert<'a, V> (t: &'a mut Option>>, key: &str, val: V) -> () { let (c, nkey) = key.slice_shift_char().unwrap(); if t.is_none () { *t = Some (Box::new(Tst::new (c))); } match *t { Some (ref mut r) => { match c.cmp(&r.c) { Less => { insert (&mut r.l, key, val); } Greater => { insert (&mut r.r, key, val); } Equal => { if ! nkey.is_empty () { insert (&mut r.d, nkey, val); } else { r.v = Some(val); } } } return; } None => { panic!("cannot happen"); } } } fn get_mut<'r, V> (t: &'r mut Option>>, key: &str) -> Option<&'r mut V> { let (c, nkey) = key.slice_shift_char().unwrap(); match *t { Some (ref mut r) => { match c.cmp(&r.c) { Less => get_mut (&mut r.l, key), Greater => get_mut (&mut r.r, key), Equal => { if nkey.is_empty () { r.v.as_mut() } else { get_mut (&mut r.d, nkey) } } } } None => None, } } fn addword<'a> (widx: &mut Option>>>, word: &str, idx: u32) { if match get_mut (widx, word) { Some(idxs) => { if idxs[idxs.len()-1] != idx { idxs.push(idx); } false } None => true, } { insert (widx, word, vec![idx]); } else { () } } fn index (widx: &mut Option>>>) { use std::io::BufRead; use std::ascii::AsciiExt; let mut npage = 1; let mut nline = 1; let stdin = io::stdin(); let sl = stdin.lock().lines(); for l in sl { for w in l.unwrap().split(|c: char| !c.is_alphabetic()).filter(|w| !w.is_empty()) { addword (widx, &w.to_ascii_lowercase(), npage); } nline += 1; if nline > 40 { npage += 1; nline = 1; } } } fn print (k: &str, v: &Vec) { if v.len() > 100 { return; } print!("{}: ", k); print! ("{}", v[0]); for i in v[1..v.len()].iter () { print!(", {}", i); } println!(""); } fn tstiter(t: &Option>>>, f: F, key: &mut String) where F: Fn(&str, &Vec) { match *t { Some(ref r) => { if r.v.is_some () { key.push (r.c); f (key, r.v.as_ref().unwrap ()); key.pop (); } if r.l.is_some () { tstiter (&r.l, |k,v| f(k,v), key); } if r.d.is_some () { key.push (r.c); tstiter (&r.d, |k,v| f(k,v), key); key.pop (); } if r.r.is_some () { tstiter (&r.r, |k,v| f(k,v), key); } } None => (), } } fn main () { let mut widx: Option>>> = None; index (&mut widx); tstiter (&widx, print, &mut String::new()); }