// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(non_camel_case_types)] use std::cell::RefCell; use std::collections::HashMap; use std::hash::{Hash, Hasher}; use syntax::ast; use syntax::visit; use syntax::visit::Visitor; use time; pub fn time(do_it: bool, what: &str, u: U, f: |U| -> T) -> T { local_data_key!(depth: uint); if !do_it { return f(u); } let old = depth.get().map(|d| *d).unwrap_or(0); depth.replace(Some(old + 1)); let start = time::precise_time_s(); let rv = f(u); let end = time::precise_time_s(); println!("{}time: {:3.3f} s\t{}", " ".repeat(old), end - start, what); depth.replace(Some(old)); rv } pub fn indent(op: || -> R) -> R { // Use in conjunction with the log post-processor like `src/etc/indenter` // to make debug output more readable. debug!(">>"); let r = op(); debug!("<< (Result = {:?})", r); r } pub struct Indenter { _cannot_construct_outside_of_this_module: () } impl Drop for Indenter { fn drop(&mut self) { debug!("<<"); } } pub fn indenter() -> Indenter { debug!(">>"); Indenter { _cannot_construct_outside_of_this_module: () } } struct LoopQueryVisitor<'a> { p: |&ast::Expr_|: 'a -> bool, flag: bool, } impl<'a, 'v> Visitor<'v> for LoopQueryVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { self.flag |= (self.p)(&e.node); match e.node { // Skip inner loops, since a break in the inner loop isn't a // break inside the outer loop ast::ExprLoop(..) | ast::ExprWhile(..) | ast::ExprForLoop(..) => {} _ => visit::walk_expr(self, e) } } } // Takes a predicate p, returns true iff p is true for any subexpressions // of b -- skipping any inner loops (loop, while, loop_body) pub fn loop_query(b: &ast::Block, p: |&ast::Expr_| -> bool) -> bool { let mut v = LoopQueryVisitor { p: p, flag: false, }; visit::walk_block(&mut v, b); return v.flag; } struct BlockQueryVisitor<'a> { p: |&ast::Expr|: 'a -> bool, flag: bool, } impl<'a, 'v> Visitor<'v> for BlockQueryVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { self.flag |= (self.p)(e); visit::walk_expr(self, e) } } // Takes a predicate p, returns true iff p is true for any subexpressions // of b -- skipping any inner loops (loop, while, loop_body) pub fn block_query(b: &ast::Block, p: |&ast::Expr| -> bool) -> bool { let mut v = BlockQueryVisitor { p: p, flag: false, }; visit::walk_block(&mut v, &*b); return v.flag; } // K: Eq + Hash, V, S, H: Hasher pub fn can_reach,T:Eq+Clone+Hash>( edges_map: &HashMap,H>, source: T, destination: T) -> bool { /*! * Determines whether there exists a path from `source` to * `destination`. The graph is defined by the `edges_map`, which * maps from a node `S` to a list of its adjacent nodes `T`. * * Efficiency note: This is implemented in an inefficient way * because it is typically invoked on very small graphs. If the graphs * become larger, a more efficient graph representation and algorithm * would probably be advised. */ if source == destination { return true; } // Do a little breadth-first-search here. The `queue` list // doubles as a way to detect if we've seen a particular FR // before. Note that we expect this graph to be an *extremely // shallow* tree. let mut queue = vec!(source); let mut i = 0; while i < queue.len() { match edges_map.find(queue.get(i)) { Some(edges) => { for target in edges.iter() { if *target == destination { return true; } if !queue.iter().any(|x| x == target) { queue.push((*target).clone()); } } } None => {} } i += 1; } return false; } /// Memoizes a one-argument closure using the given RefCell containing /// a type implementing MutableMap to serve as a cache. /// /// In the future the signature of this function is expected to be: /// ``` /// pub fn memoized>( /// cache: &RefCell, /// f: &|&: T| -> U /// ) -> impl |&: T| -> U { /// ``` /// but currently it is not possible. /// /// # Example /// ``` /// struct Context { /// cache: RefCell> /// } /// /// fn factorial(ctxt: &Context, n: uint) -> uint { /// memoized(&ctxt.cache, n, |n| match n { /// 0 | 1 => n, /// _ => factorial(ctxt, n - 2) + factorial(ctxt, n - 1) /// }) /// } /// ``` #[inline(always)] pub fn memoized>( cache: &RefCell, arg: T, f: |T| -> U ) -> U { memoized_with_key(cache, arg, f, |arg| arg.clone()) } #[inline(always)] pub fn memoized_with_key>( cache: &RefCell, arg: T, f: |T| -> U, k: |&T| -> K ) -> U { let key = k(&arg); let result = cache.borrow().find(&key).map(|result| result.clone()); match result { Some(result) => result, None => { let result = f(arg); cache.borrow_mut().insert(key, result.clone()); result } } }