<commit_before>// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Implementation of string finding in ropes.

use std::cmp::min;

use memchr::{memchr, memchr2, memchr3};

use rope::{len_utf8_from_first_byte, RopeInfo};
use tree::Cursor;

/// The result of a [`find`][find] operation.
///
/// [find]: fn.find.html
pub enum FindResult {
    /// The pattern was found at this position.
    Found(usize),
    /// The pattern was not found.
    NotFound,
    /// The cursor has been advanced by some amount. The pattern is not
    /// found before the new cursor, but may be at or beyond it.
    TryAgain,
}

/// A policy for case matching. There may be more choices in the future (for
/// example, an even more forgiving mode that ignores accents, or possibly
/// handling Unicode normalization).
pub enum CaseMatching {
    /// Require an exact codepoint-for-codepoint match (implies case sensitivity).
    Exact,
    /// Case insensitive match. Guaranteed to work for the ASCII case, and
    /// reasonably well otherwise (it is currently defined in terms of the
    /// `to_lowercase` methods in the Rust standard library).
    CaseInsensitive,
}

/// Finds a pattern string in the rope referenced by the cursor, starting at
/// the current location of the cursor (and finding the first match). Both
/// case sensitive and case insensitive matching is provided, controlled by
/// the `cm` parameter.
///
/// On success, the cursor is updated to immediately follow the found string.
/// On failure, the cursor's position is indeterminate.
///
/// Can panic if `pat` is empty.
pub fn find(cursor: &mut Cursor<RopeInfo>, cm: CaseMatching, pat: &str) -> Option<usize> {
    match find_progress(cursor, cm, pat, usize::max_value()) {
        FindResult::Found(pos) => Some(pos),
        FindResult::NotFound => None,
        FindResult::TryAgain => unreachable!("find_progress got stuck"),
    }
}

/// A variant of [`find`][find] that makes a bounded amount of progress, then either
/// returns or suspends (returning `TryAgain`).
///
/// The `num_steps` parameter controls the number of "steps" processed per
/// call. The unit of "step" is not formally defined but is typically
/// scanning one leaf (using a memchr-like scan) or testing one candidate
/// when scanning produces a result. It should be empirically tuned for a
/// balance between overhead and impact on interactive performance, but the
/// exact value is probably not critical.
///
/// [find]: fn.find.html
pub fn find_progress(cursor: &mut Cursor<RopeInfo>, cm: CaseMatching, pat: &str,
    num_steps: usize) -> FindResult
{
    match cm {
        CaseMatching::Exact => {
            let b = pat.as_bytes()[0];
            let scanner = |s: &str| memchr(b, s.as_bytes());
            let matcher = compare_cursor_str;
            let cl = len_utf8_from_first_byte(b);
            find_progress_iter(cursor, pat, &scanner, &matcher, num_steps, cl)
        }
        CaseMatching::CaseInsensitive => {
            let pat_lower = pat.to_lowercase();
            let b = pat_lower.as_bytes()[0];
            let matcher = compare_cursor_str_casei;
            if b == b'i' {
                // 0xC4 is first utf-8 byte of 'İ'
                let scanner = |s: &str| memchr3(b'i', b'I', 0xC4, s.as_bytes());
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps, 1)
            } else if b == b'k' {
                // 0xE2 is first utf-8 byte of u+212A (kelvin sign)
                let scanner = |s: &str| memchr3(b'k', b'K', 0xE2, s.as_bytes());
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps, 1)
            } else if b >= b'a' && b <= b'z' {
                let scanner = |s: &str| memchr2(b, b - 0x20, s.as_bytes());
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps, 1)
            } else if b < 0x80 {
                let scanner = |s: &str| memchr(b, s.as_bytes());
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps, 1)
            } else {
                let c = pat.chars().next().unwrap();
                let cl = c.len_utf8();
                let scanner = |s: &str| scan_lowercase(c, s);
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps, cl)
            }
        }
    }
}

// Run the core repeatedly until there is a result, up to a certain number of steps.
fn find_progress_iter(cursor: &mut Cursor<RopeInfo>, pat: &str,
        scanner: &Fn(&str) -> Option<usize>,
        matcher: &Fn(&mut Cursor<RopeInfo>, &str) -> bool,
        num_steps: usize,
        first_cp_len: usize
    ) -> FindResult
{
    for _ in 0..num_steps {
        match find_core(cursor, pat, scanner, matcher, first_cp_len) {
            FindResult::TryAgain => (),
            result => return result,
        }
    }
    FindResult::TryAgain
}

// The core of the find algorithm. It takes a "scanner", which quickly
// scans through a single leaf searching for some prefix of the pattern,
// then a "matcher" which confirms that such a candidate actually matches
// in the full rope.
fn find_core(cursor: &mut Cursor<RopeInfo>, pat: &str,
        scanner: &Fn(&str) -> Option<usize>,
        matcher: &Fn(&mut Cursor<RopeInfo>, &str) -> bool,
        first_cp_len: usize
    ) -> FindResult
{
    let orig_pos = cursor.pos();
    if let Some((leaf, pos_in_leaf)) = cursor.get_leaf() {
        if let Some(off) = scanner(&leaf[pos_in_leaf..]) {
            let candidate_pos = orig_pos + off;
            cursor.set(candidate_pos);
            if matcher(cursor, pat) {
                return FindResult::Found(candidate_pos);
            } else {
                cursor.set(candidate_pos + first_cp_len);
            }
        } else {
            let _ = cursor.next_leaf();
        }
        FindResult::TryAgain
    } else {
        FindResult::NotFound
    }
}

/// Compare whether the substring beginning at the current cursor location
/// is equal to the provided string. Leaves the cursor at an indeterminate
/// position on failure, but the end of the string on success.
pub fn compare_cursor_str(cursor: &mut Cursor<RopeInfo>, mut pat: &str) -> bool {
    if pat.is_empty() {
        return true;
    }
    let success_pos = cursor.pos() + pat.len();
    while let Some((leaf, pos_in_leaf)) = cursor.get_leaf() {
        let n = min(pat.len(), leaf.len() - pos_in_leaf);
        if leaf.as_bytes()[pos_in_leaf..pos_in_leaf + n] != pat.as_bytes()[..n] {
            return false;
        }
        pat = &pat[n..];
        if pat.is_empty() {
            cursor.set(success_pos);
            return true;
        }
        let _ = cursor.next_leaf();
    }
    false
}

/// Like `compare_cursor_str` but case invariant (using to_lowercase() to
/// normalize both strings before comparison).
fn compare_cursor_str_casei(cursor: &mut Cursor<RopeInfo>, pat: &str) -> bool {
    let mut pat_iter = pat.chars();
    let mut c = pat_iter.next().unwrap();
    loop {
        if let Some(rope_c) = cursor.next_codepoint() {
            for lc_c in rope_c.to_lowercase() {
                if c != lc_c {
                    return false;
                }
                if let Some(next_c) = pat_iter.next() {
                    c = next_c;
                } else {
                    return true;
                }
            }
        } else {
            // end of string before pattern is complete
            return false;
        }
    }
}

/// Scan for a codepoint that, after conversion to lowercase, matches the probe.
fn scan_lowercase(probe: char, s: &str) -> Option<usize> {
    for (i, c) in s.char_indices() {
        if c.to_lowercase().next().unwrap() == probe {
            return Some(i);
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::CaseMatching::{Exact, CaseInsensitive};
    use tree::Cursor;
    use rope::Rope;

    #[test]
    fn find_small() {
        let a = Rope::from("Löwe 老虎 Léopard");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, Exact, "L"), Some(0));
        assert_eq!(find(&mut c, Exact, "L"), Some(13));
        assert_eq!(find(&mut c, Exact, "L"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "Léopard"), Some(13));
        assert_eq!(find(&mut c, Exact, "Léopard"), None);
        c.set(0);
        // Note: these two characters both start with 0xE8 in utf-8
        assert_eq!(find(&mut c, Exact, "老虎"), Some(6));
        assert_eq!(find(&mut c, Exact, "老虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "虎"), Some(9));
        assert_eq!(find(&mut c, Exact, "虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "Tiger"), None);
    }

    #[test]
    fn find_medium() {
        let mut s = String::new();
        for _ in 0..4000 {
            s.push('x');
        }
        s.push_str("Löwe 老虎 Léopard");
        let a = Rope::from(&s);
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, Exact, "L"), Some(4000));
        assert_eq!(find(&mut c, Exact, "L"), Some(4013));
        assert_eq!(find(&mut c, Exact, "L"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "Léopard"), Some(4013));
        assert_eq!(find(&mut c, Exact, "Léopard"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "老虎"), Some(4006));
        assert_eq!(find(&mut c, Exact, "老虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "虎"), Some(4009));
        assert_eq!(find(&mut c, Exact, "虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "Tiger"), None);
    }

    #[test]
    fn find_casei_small() {
        let a = Rope::from("Löwe 老虎 Léopard");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "l"), Some(0));
        assert_eq!(find(&mut c, CaseInsensitive, "l"), Some(13));
        assert_eq!(find(&mut c, CaseInsensitive, "l"), None);
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "léopard"), Some(13));
        assert_eq!(find(&mut c, CaseInsensitive, "léopard"), None);
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "LÉOPARD"), Some(13));
        assert_eq!(find(&mut c, CaseInsensitive, "LÉOPARD"), None);
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "老虎"), Some(6));
        assert_eq!(find(&mut c, CaseInsensitive, "老虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "Tiger"), None);
    }

    #[test]
    fn find_casei_ascii_nonalpha() {
        let a = Rope::from("![cfg(test)]");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "(test)"), Some(5));
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "(TEST)"), Some(5));
    }

    #[test]
    fn find_casei_special() {
        let a = Rope::from("İ");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "i̇"), Some(0));

        let a = Rope::from("i̇");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "İ"), Some(0));

        let a = Rope::from("\u{212A}");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "k"), Some(0));

        let a = Rope::from("k");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "\u{212A}"), Some(0));
    }

    #[test]
    fn compare_cursor_str_small() {
        let a = Rope::from("Löwe 老虎 Léopard");
        let mut c = Cursor::new(&a, 0);
        let pat = "Löwe 老虎 Léopard";
        assert!(compare_cursor_str(&mut c, pat));
        assert_eq!(c.pos(), pat.len());
        c.set(0);
        let pat = "Löwe";
        assert!(compare_cursor_str(&mut c, pat));
        assert_eq!(c.pos(), pat.len());
        c.set(0);
        // Empty string is valid for compare_cursor_str (but not find)
        let pat = "";
        assert!(compare_cursor_str(&mut c, pat));
        assert_eq!(c.pos(), pat.len());
        c.set(0);
        assert!(!compare_cursor_str(&mut c, "Löwe 老虎 Léopardfoo"));
    }

    #[test]
    fn compare_cursor_str_medium() {
        let mut s = String::new();
        for _ in 0..4000 {
            s.push('x');
        }
        s.push_str("Löwe 老虎 Léopard");
        let a = Rope::from(&s);
        let mut c = Cursor::new(&a, 0);
        assert!(compare_cursor_str(&mut c, &s));
        assert_eq!(c.pos(), s.len());
        c.set(2000);
        assert!(compare_cursor_str(&mut c, &s[2000..]));
        assert_eq!(c.pos(), s.len());
    }
}
<commit_msg>Fix over-aggressive codepoint length optimization<commit_after>// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Implementation of string finding in ropes.

use std::cmp::min;

use memchr::{memchr, memchr2, memchr3};

use rope::{BaseMetric, RopeInfo};
use tree::Cursor;

/// The result of a [`find`][find] operation.
///
/// [find]: fn.find.html
pub enum FindResult {
    /// The pattern was found at this position.
    Found(usize),
    /// The pattern was not found.
    NotFound,
    /// The cursor has been advanced by some amount. The pattern is not
    /// found before the new cursor, but may be at or beyond it.
    TryAgain,
}

/// A policy for case matching. There may be more choices in the future (for
/// example, an even more forgiving mode that ignores accents, or possibly
/// handling Unicode normalization).
pub enum CaseMatching {
    /// Require an exact codepoint-for-codepoint match (implies case sensitivity).
    Exact,
    /// Case insensitive match. Guaranteed to work for the ASCII case, and
    /// reasonably well otherwise (it is currently defined in terms of the
    /// `to_lowercase` methods in the Rust standard library).
    CaseInsensitive,
}

/// Finds a pattern string in the rope referenced by the cursor, starting at
/// the current location of the cursor (and finding the first match). Both
/// case sensitive and case insensitive matching is provided, controlled by
/// the `cm` parameter.
///
/// On success, the cursor is updated to immediately follow the found string.
/// On failure, the cursor's position is indeterminate.
///
/// Can panic if `pat` is empty.
pub fn find(cursor: &mut Cursor<RopeInfo>, cm: CaseMatching, pat: &str) -> Option<usize> {
    match find_progress(cursor, cm, pat, usize::max_value()) {
        FindResult::Found(pos) => Some(pos),
        FindResult::NotFound => None,
        FindResult::TryAgain => unreachable!("find_progress got stuck"),
    }
}

/// A variant of [`find`][find] that makes a bounded amount of progress, then either
/// returns or suspends (returning `TryAgain`).
///
/// The `num_steps` parameter controls the number of "steps" processed per
/// call. The unit of "step" is not formally defined but is typically
/// scanning one leaf (using a memchr-like scan) or testing one candidate
/// when scanning produces a result. It should be empirically tuned for a
/// balance between overhead and impact on interactive performance, but the
/// exact value is probably not critical.
///
/// [find]: fn.find.html
pub fn find_progress(cursor: &mut Cursor<RopeInfo>, cm: CaseMatching, pat: &str,
    num_steps: usize) -> FindResult
{
    match cm {
        CaseMatching::Exact => {
            let b = pat.as_bytes()[0];
            let scanner = |s: &str| memchr(b, s.as_bytes());
            let matcher = compare_cursor_str;
            find_progress_iter(cursor, pat, &scanner, &matcher, num_steps)
        }
        CaseMatching::CaseInsensitive => {
            let pat_lower = pat.to_lowercase();
            let b = pat_lower.as_bytes()[0];
            let matcher = compare_cursor_str_casei;
            if b == b'i' {
                // 0xC4 is first utf-8 byte of 'İ'
                let scanner = |s: &str| memchr3(b'i', b'I', 0xC4, s.as_bytes());
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps)
            } else if b == b'k' {
                // 0xE2 is first utf-8 byte of u+212A (kelvin sign)
                let scanner = |s: &str| memchr3(b'k', b'K', 0xE2, s.as_bytes());
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps)
            } else if b >= b'a' && b <= b'z' {
                let scanner = |s: &str| memchr2(b, b - 0x20, s.as_bytes());
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps)
            } else if b < 0x80 {
                let scanner = |s: &str| memchr(b, s.as_bytes());
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps)
            } else {
                let c = pat.chars().next().unwrap();
                let scanner = |s: &str| scan_lowercase(c, s);
                find_progress_iter(cursor, &pat_lower, &scanner, &matcher, num_steps)
            }
        }
    }
}

// Run the core repeatedly until there is a result, up to a certain number of steps.
fn find_progress_iter(cursor: &mut Cursor<RopeInfo>, pat: &str,
        scanner: &Fn(&str) -> Option<usize>,
        matcher: &Fn(&mut Cursor<RopeInfo>, &str) -> bool,
        num_steps: usize
    ) -> FindResult
{
    for _ in 0..num_steps {
        match find_core(cursor, pat, scanner, matcher) {
            FindResult::TryAgain => (),
            result => return result,
        }
    }
    FindResult::TryAgain
}

// The core of the find algorithm. It takes a "scanner", which quickly
// scans through a single leaf searching for some prefix of the pattern,
// then a "matcher" which confirms that such a candidate actually matches
// in the full rope.
fn find_core(cursor: &mut Cursor<RopeInfo>, pat: &str,
        scanner: &Fn(&str) -> Option<usize>,
        matcher: &Fn(&mut Cursor<RopeInfo>, &str) -> bool
    ) -> FindResult
{
    let orig_pos = cursor.pos();
    if let Some((leaf, pos_in_leaf)) = cursor.get_leaf() {
        if let Some(off) = scanner(&leaf[pos_in_leaf..]) {
            let candidate_pos = orig_pos + off;
            cursor.set(candidate_pos);
            if matcher(cursor, pat) {
                return FindResult::Found(candidate_pos);
            } else {
                // Advance cursor to next codepoint.
                // Note: could be optimized in some cases but general case is sometimes needed.
                cursor.set(candidate_pos);
                cursor.next::<BaseMetric>();
            }
        } else {
            let _ = cursor.next_leaf();
        }
        FindResult::TryAgain
    } else {
        FindResult::NotFound
    }
}

/// Compare whether the substring beginning at the current cursor location
/// is equal to the provided string. Leaves the cursor at an indeterminate
/// position on failure, but the end of the string on success.
pub fn compare_cursor_str(cursor: &mut Cursor<RopeInfo>, mut pat: &str) -> bool {
    if pat.is_empty() {
        return true;
    }
    let success_pos = cursor.pos() + pat.len();
    while let Some((leaf, pos_in_leaf)) = cursor.get_leaf() {
        let n = min(pat.len(), leaf.len() - pos_in_leaf);
        if leaf.as_bytes()[pos_in_leaf..pos_in_leaf + n] != pat.as_bytes()[..n] {
            return false;
        }
        pat = &pat[n..];
        if pat.is_empty() {
            cursor.set(success_pos);
            return true;
        }
        let _ = cursor.next_leaf();
    }
    false
}

/// Like `compare_cursor_str` but case invariant (using to_lowercase() to
/// normalize both strings before comparison).
fn compare_cursor_str_casei(cursor: &mut Cursor<RopeInfo>, pat: &str) -> bool {
    let mut pat_iter = pat.chars();
    let mut c = pat_iter.next().unwrap();
    loop {
        if let Some(rope_c) = cursor.next_codepoint() {
            for lc_c in rope_c.to_lowercase() {
                if c != lc_c {
                    return false;
                }
                if let Some(next_c) = pat_iter.next() {
                    c = next_c;
                } else {
                    return true;
                }
            }
        } else {
            // end of string before pattern is complete
            return false;
        }
    }
}

/// Scan for a codepoint that, after conversion to lowercase, matches the probe.
fn scan_lowercase(probe: char, s: &str) -> Option<usize> {
    for (i, c) in s.char_indices() {
        if c.to_lowercase().next().unwrap() == probe {
            return Some(i);
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::CaseMatching::{Exact, CaseInsensitive};
    use tree::Cursor;
    use rope::Rope;

    #[test]
    fn find_small() {
        let a = Rope::from("Löwe 老虎 Léopard");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, Exact, "L"), Some(0));
        assert_eq!(find(&mut c, Exact, "L"), Some(13));
        assert_eq!(find(&mut c, Exact, "L"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "Léopard"), Some(13));
        assert_eq!(find(&mut c, Exact, "Léopard"), None);
        c.set(0);
        // Note: these two characters both start with 0xE8 in utf-8
        assert_eq!(find(&mut c, Exact, "老虎"), Some(6));
        assert_eq!(find(&mut c, Exact, "老虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "虎"), Some(9));
        assert_eq!(find(&mut c, Exact, "虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "Tiger"), None);
    }

    #[test]
    fn find_medium() {
        let mut s = String::new();
        for _ in 0..4000 {
            s.push('x');
        }
        s.push_str("Löwe 老虎 Léopard");
        let a = Rope::from(&s);
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, Exact, "L"), Some(4000));
        assert_eq!(find(&mut c, Exact, "L"), Some(4013));
        assert_eq!(find(&mut c, Exact, "L"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "Léopard"), Some(4013));
        assert_eq!(find(&mut c, Exact, "Léopard"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "老虎"), Some(4006));
        assert_eq!(find(&mut c, Exact, "老虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "虎"), Some(4009));
        assert_eq!(find(&mut c, Exact, "虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, Exact, "Tiger"), None);
    }

    #[test]
    fn find_casei_small() {
        let a = Rope::from("Löwe 老虎 Léopard");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "l"), Some(0));
        assert_eq!(find(&mut c, CaseInsensitive, "l"), Some(13));
        assert_eq!(find(&mut c, CaseInsensitive, "l"), None);
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "léopard"), Some(13));
        assert_eq!(find(&mut c, CaseInsensitive, "léopard"), None);
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "LÉOPARD"), Some(13));
        assert_eq!(find(&mut c, CaseInsensitive, "LÉOPARD"), None);
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "老虎"), Some(6));
        assert_eq!(find(&mut c, CaseInsensitive, "老虎"), None);
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "Tiger"), None);
    }

    #[test]
    fn find_casei_ascii_nonalpha() {
        let a = Rope::from("![cfg(test)]");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "(test)"), Some(5));
        c.set(0);
        assert_eq!(find(&mut c, CaseInsensitive, "(TEST)"), Some(5));
    }

    #[test]
    fn find_casei_special() {
        let a = Rope::from("İ");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "i̇"), Some(0));

        let a = Rope::from("i̇");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "İ"), Some(0));

        let a = Rope::from("\u{212A}");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "k"), Some(0));

        let a = Rope::from("k");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "\u{212A}"), Some(0));
    }

    #[test]
    fn find_casei_0xc4() {
        let a = Rope::from("\u{0100}I");
        let mut c = Cursor::new(&a, 0);
        assert_eq!(find(&mut c, CaseInsensitive, "i"), Some(2));
    }

    #[test]
    fn compare_cursor_str_small() {
        let a = Rope::from("Löwe 老虎 Léopard");
        let mut c = Cursor::new(&a, 0);
        let pat = "Löwe 老虎 Léopard";
        assert!(compare_cursor_str(&mut c, pat));
        assert_eq!(c.pos(), pat.len());
        c.set(0);
        let pat = "Löwe";
        assert!(compare_cursor_str(&mut c, pat));
        assert_eq!(c.pos(), pat.len());
        c.set(0);
        // Empty string is valid for compare_cursor_str (but not find)
        let pat = "";
        assert!(compare_cursor_str(&mut c, pat));
        assert_eq!(c.pos(), pat.len());
        c.set(0);
        assert!(!compare_cursor_str(&mut c, "Löwe 老虎 Léopardfoo"));
    }

    #[test]
    fn compare_cursor_str_medium() {
        let mut s = String::new();
        for _ in 0..4000 {
            s.push('x');
        }
        s.push_str("Löwe 老虎 Léopard");
        let a = Rope::from(&s);
        let mut c = Cursor::new(&a, 0);
        assert!(compare_cursor_str(&mut c, &s));
        assert_eq!(c.pos(), s.len());
        c.set(2000);
        assert!(compare_cursor_str(&mut c, &s[2000..]));
        assert_eq!(c.pos(), s.len());
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::path::Path;
use std::borrow::Borrow;
use std::ops::Deref;

use semver::Version;
use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    store_location: PathBuf,
    id: PathBuf,
}

impl StoreId {

    pub fn storified(self, store: &Store) -> StoreId {
        if self.starts_with(store.path()) {
            debug!("Not storifying {:?}, because it is already.", self);
            self
        } else {
            debug!("Create new store id out of: {:?} and {:?}", store.path(), self.id);

            let new_id = StoreId { store_location: store.path().clone(), self.id };

            debug!("Created: '{:?}'", new_id);
            new_id
        }
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        let mut base = self.store_location;
        base.push(self.id);
        base
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.0.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.0.to_string_lossy()),
        }
    }

}

impl Deref for StoreId {
    type Target = PathBuf;

    fn deref(&self) -> &PathBuf {
        &self.0
    }

}

impl From<PathBuf> for StoreId {

    fn from(pb: PathBuf) -> StoreId {
        StoreId(pb)
    }

}

impl From<String> for StoreId {

    fn from(string: String) -> StoreId {
        StoreId(string.into())
    }

}

impl AsRef<Path> for StoreId {

    fn as_ref(&self) -> &Path {
        self.0.as_ref()
    }

}

impl Borrow<Path> for StoreId {

    fn borrow(&self) -> &Path {
        self.0.borrow()
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        StoreId(self)
    }
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(SEK::StorePathLacksVersion.into());
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.starts_with('/') {
        path.push(&path_elem[1..]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    StoreId::from(self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<commit_msg>Rewrite Display for StoreId<commit_after>use std::path::PathBuf;
use std::path::Path;
use std::borrow::Borrow;
use std::ops::Deref;

use semver::Version;
use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    store_location: PathBuf,
    id: PathBuf,
}

impl StoreId {

    pub fn storified(self, store: &Store) -> StoreId {
        if self.starts_with(store.path()) {
            debug!("Not storifying {:?}, because it is already.", self);
            self
        } else {
            debug!("Create new store id out of: {:?} and {:?}", store.path(), self.id);

            let new_id = StoreId { store_location: store.path().clone(), self.id };

            debug!("Created: '{:?}'", new_id);
            new_id
        }
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        let mut base = self.store_location;
        base.push(self.id);
        base
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.id.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.id.to_string_lossy()),
        }
    }

}

impl Deref for StoreId {
    type Target = PathBuf;

    fn deref(&self) -> &PathBuf {
        &self.0
    }

}

impl From<PathBuf> for StoreId {

    fn from(pb: PathBuf) -> StoreId {
        StoreId(pb)
    }

}

impl From<String> for StoreId {

    fn from(string: String) -> StoreId {
        StoreId(string.into())
    }

}

impl AsRef<Path> for StoreId {

    fn as_ref(&self) -> &Path {
        self.0.as_ref()
    }

}

impl Borrow<Path> for StoreId {

    fn borrow(&self) -> &Path {
        self.0.borrow()
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        StoreId(self)
    }
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(SEK::StorePathLacksVersion.into());
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.starts_with('/') {
        path.push(&path_elem[1..]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    StoreId::from(self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<|endoftext|>


<commit_before>extern crate getopts;
use std::io::Write;

pub struct HelpText<'a> {
    pub name : &'a str,
    pub version : &'a str,
    pub syntax : &'a str,
    pub summary : &'a str,
    pub long_help : &'a str,
    pub display_usage : bool
}

pub struct CoreOptions<'a> {
    options : getopts::Options,
    help_text : HelpText<'a>
}

impl<'a> CoreOptions<'a> {
    pub fn new(help_text: HelpText<'a>) -> Self {
        let mut ret = CoreOptions {
            options : getopts::Options::new(),
            help_text : help_text
        };
        ret.options
            .optflag("", "help", "print usage information")
            .optflag("", "version", "print name and version number");
        ret
    }
    pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optopt(short_name, long_name, desc, hint);
        self
    }
    pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
        self.options.optflag(short_name, long_name, desc);
        self
    }
    pub fn usage(&self, summary : &str) -> String {
        self.options.usage(summary)
    }
    pub fn parse(&mut self, args : Vec<String>) -> getopts::Matches {
        let matches = match self.options.parse(&args[1..]) {
            Ok(m) => { Some(m) },
            Err(f) => {
                pipe_write!(&mut ::std::io::stderr(), "{}: error: ", self.help_text.name);
                pipe_writeln!(&mut ::std::io::stderr(), "{}", f);
                ::std::process::exit(1);
            }
        }.unwrap();
        if matches.opt_present("help") {
            let usage_str = if self.help_text.display_usage {
                    format!("\n {}\n\n Reference\n",
                        self.options.usage(self.help_text.summary)
                    ).replace("Options:", " Options:")
                } else { String::new() };
            print!("
 {0} {1}

 {0} {2}
{3}{4}
", self.help_text.name, self.help_text.version, self.help_text.syntax, usage_str, self.help_text.long_help);
            exit!(0);
        } else if matches.opt_present("version") {
            println!("{} {}", self.help_text.name, self.help_text.version);
            exit!(0);
        }
        matches
    }
}

#[macro_export]
macro_rules! new_coreopts {
    ($syntax: expr, $summary: expr, $long_help: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: true
        })
    );
    ($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: $display_usage
        })
    );
}
<commit_msg>uucore: add support for optflagopt to coreopts<commit_after>extern crate getopts;
use std::io::Write;

pub struct HelpText<'a> {
    pub name : &'a str,
    pub version : &'a str,
    pub syntax : &'a str,
    pub summary : &'a str,
    pub long_help : &'a str,
    pub display_usage : bool
}

pub struct CoreOptions<'a> {
    options : getopts::Options,
    help_text : HelpText<'a>
}

impl<'a> CoreOptions<'a> {
    pub fn new(help_text: HelpText<'a>) -> Self {
        let mut ret = CoreOptions {
            options : getopts::Options::new(),
            help_text : help_text
        };
        ret.options
            .optflag("", "help", "print usage information")
            .optflag("", "version", "print name and version number");
        ret
    }
    pub fn optflagopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optflagopt(short_name, long_name, desc, hint);
        self
    }
    pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
        self.options.optflag(short_name, long_name, desc);
        self
    }
    pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optopt(short_name, long_name, desc, hint);
        self
    }
    pub fn usage(&self, summary : &str) -> String {
        self.options.usage(summary)
    }
    pub fn parse(&mut self, args : Vec<String>) -> getopts::Matches {
        let matches = match self.options.parse(&args[1..]) {
            Ok(m) => { Some(m) },
            Err(f) => {
                pipe_write!(&mut ::std::io::stderr(), "{}: error: ", self.help_text.name);
                pipe_writeln!(&mut ::std::io::stderr(), "{}", f);
                ::std::process::exit(1);
            }
        }.unwrap();
        if matches.opt_present("help") {
            let usage_str = if self.help_text.display_usage {
                    format!("\n {}\n\n Reference\n",
                        self.options.usage(self.help_text.summary)
                    ).replace("Options:", " Options:")
                } else { String::new() };
            print!("
 {0} {1}

 {0} {2}
{3}{4}
", self.help_text.name, self.help_text.version, self.help_text.syntax, usage_str, self.help_text.long_help);
            exit!(0);
        } else if matches.opt_present("version") {
            println!("{} {}", self.help_text.name, self.help_text.version);
            exit!(0);
        }
        matches
    }
}

#[macro_export]
macro_rules! new_coreopts {
    ($syntax: expr, $summary: expr, $long_help: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: true
        })
    );
    ($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: $display_usage
        })
    );
}
<|endoftext|>


<commit_before>use super::{Index, Range};
use small;
use std::{cmp::Ordering, u8};

fn numeric_range<'a>(
    start: isize,
    end: isize,
    step: isize,
    inclusive: bool,
    nb_digits: usize,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };

    if step == 0 || (start < end && step < 0) || (start > end && step > 0) {
        None
    } else {
        let (x, y, ordering) = if start < end {
            (start, end, Ordering::Greater)
        } else {
            (end, start, Ordering::Less)
        };

        let iter = (x..y).scan(start, move |index, _| {
            if end.cmp(index) == ordering {
                let index_holder = *index;
                *index += step; // This step adds
                Some(format!("{:0width$}", index_holder, width = nb_digits).into())
            } else {
                None
            }
        });

        Some(Box::new(iter))
    }
}

#[inline]
fn byte_is_valid_range(b: u8) -> bool { (b >= b'a' && b <= b'z') || (b >= b'A' && b <= b'Z') }

fn char_range<'a>(
    start: u8,
    end: u8,
    step: isize,
    inclusive: bool,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let char_step = step.checked_abs()?;
    if !byte_is_valid_range(start) || !byte_is_valid_range(end) || step == 0 || char_step > u8::MAX as isize {
        return None;
    }

    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };
    let (x, y, ordering) = if start < end {
        (start, end, Ordering::Greater)
    } else {
        (end, start, Ordering::Less)
    };

    let iter = (x..y).scan(start, move |index, _| {
        if end.cmp(index) == ordering {
            let index_holder = *index;
            *index = match ordering {
                Ordering::Greater => index.wrapping_add(char_step as u8),
                Ordering::Less => index.wrapping_sub(char_step as u8),
                _ => unreachable!(),
            };
            Some((index_holder as char).to_string().into())
        } else {
            None
        }
    });

    Some(Box::new(iter))
}

fn count_minimum_digits(a: &str) -> usize {
    for c in a.chars() {
        match c {
            '-' => (),
            '0' => return a.len(),
            '1'...'9' => break,
            _ => panic!("count_minimum_digits should only be called for a valid number."),
        }
    }
    0
}

fn finish(inclusive: bool, start_str: &str, end_str: &str, step: isize) -> Option<Box<Iterator<Item = small::String>>> {
    if let (Ok(start), Ok(end)) = (start_str.parse::<isize>(), end_str.parse::<isize>())  {
        let step = if step == 1 {
            if start < end { step } else { -step }
        } else {
            step
        };
        let nb_digits = usize::max(count_minimum_digits(start_str), count_minimum_digits(end_str));
        numeric_range(start, end, step, inclusive, nb_digits)
    } else {
        char_range(start_str.bytes().next()?, end_str.bytes().next()?, step, inclusive)
    }
}

// TODO: Make this an iterator structure.
// In a range we allow the following syntax:
//      Exclusive nonstepped: {start..end}
//      Inclusive nonstepped: {start...end}
//      Exclusive stepped: {start..step..end}
//      Inclusive stepped: {start..step...end}
pub fn parse_range(input: &str) -> Option<Box<Iterator<Item = small::String>>> {
    let mut bytes_iterator = input.bytes().enumerate();
    let separator = bytes_iterator.by_ref().take_while(|&(i, b)| match b {
        b'a'...b'z' | b'-' | b'A'...b'Z' if i == 0 => true,
        b'0'...b'9' | b'.' => true,
        _ => false,
    }).position(|(_, b)| b == b'.')?;
    let start_str = &input[..separator];
    // The next byte has to be a dot to be valid range
    // syntax
    bytes_iterator.next().filter(|&(_, b)| b == b'.')?;

    // if the next byte is a dot we're certain it is an inclusive
    // unstepped range otherwise it has to be [-0-9a-zA-Z]
    bytes_iterator.next().and_then(|(i, b)| match b {
        b'.' | b'=' => {
            // this can only be an inclusive range
            finish(true, start_str, &input[i+1..], 1)
        }
        b'0'...b'9' | b'-' | b'a'...b'z' | b'A'...b'Z' => {
            // further processing needed to find out if we're reading a step or
            // the end of an exclusive range. Step until we find another dot or
            // the iterator ends
            let start = i;
            if let Some(end) = bytes_iterator.position(|(_, b)| b == b'.') {
                // stepped range input[start..read - 1] contains the step
                // size
                let step = (&input[start..end]).parse::<isize>().ok()?;
                // count the dots to determine inclusive/exclusive
                let dots = bytes_iterator.take_while(|&(_, b)| b == b'.').count();
                finish(dots == 2, start_str, &input[i..], step)
            } else {
                // exhausted the iterator without finding anything new means
                // exclusive unstepped range
                finish(false, start_str, &input[start..], 1)
            }
        }
        // not a valid byte for ranges
        _ => None,
    })
}

pub fn parse_index_range(input: &str) -> Option<Range> {
    let mut bytes_iterator = input.bytes().enumerate();
    while let Some((id, byte)) = bytes_iterator.next() {
        match byte {
            b'0'...b'9' | b'-' => continue,
            b'.' => {
                let first = &input[..id];

                let mut dots = 1;
                let mut last_byte = 0;

                for (_, byte) in bytes_iterator {
                    last_byte = byte;
                    if byte == b'.' {
                        dots += 1
                    } else {
                        break;
                    }
                }

                if dots < 2 || dots > 3 {
                    break;
                }

                let inclusive = dots == 3 || (dots == 2 && last_byte == b'=');

                let end = &input[id + if inclusive { 3 } else { 2 }..];

                return if first.is_empty() && !end.is_empty() {
                    end.parse::<isize>().map(|end| Range::to(Index::new(end))).ok()
                } else if end.is_empty() {
                    first.parse::<isize>().map(|start| Range::from(Index::new(start))).ok()
                } else {
                    first
                        .parse::<isize>()
                        .and_then(|start| end.parse::<isize>().map(|end| (start, end)))
                        .map(|(start, end)| {
                            if inclusive {
                                Range::inclusive(Index::new(start), Index::new(end))
                            } else {
                                Range::exclusive(Index::new(start), Index::new(end))
                            }
                        })
                        .ok()
                };

            }
            _ => break,
        }
    }

    None
}
<commit_msg>Keep track of used bytes<commit_after>use super::{Index, Range};
use small;
use std::{cmp::Ordering, u8};

fn numeric_range<'a>(
    start: isize,
    end: isize,
    step: isize,
    inclusive: bool,
    nb_digits: usize,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };

    if step == 0 || (start < end && step < 0) || (start > end && step > 0) {
        None
    } else {
        let (x, y, ordering) = if start < end {
            (start, end, Ordering::Greater)
        } else {
            (end, start, Ordering::Less)
        };

        let iter = (x..y).scan(start, move |index, _| {
            if end.cmp(index) == ordering {
                let index_holder = *index;
                *index += step; // This step adds
                Some(format!("{:0width$}", index_holder, width = nb_digits).into())
            } else {
                None
            }
        });

        Some(Box::new(iter))
    }
}

#[inline]
fn byte_is_valid_range(b: u8) -> bool { (b >= b'a' && b <= b'z') || (b >= b'A' && b <= b'Z') }

fn char_range<'a>(
    start: u8,
    end: u8,
    step: isize,
    inclusive: bool,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let char_step = step.checked_abs()?;
    if !byte_is_valid_range(start) || !byte_is_valid_range(end) || step == 0 || char_step > u8::MAX as isize {
        return None;
    }

    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };
    let (x, y, ordering) = if start < end {
        (start, end, Ordering::Greater)
    } else {
        (end, start, Ordering::Less)
    };

    let iter = (x..y).scan(start, move |index, _| {
        if end.cmp(index) == ordering {
            let index_holder = *index;
            *index = match ordering {
                Ordering::Greater => index.wrapping_add(char_step as u8),
                Ordering::Less => index.wrapping_sub(char_step as u8),
                _ => unreachable!(),
            };
            Some((index_holder as char).to_string().into())
        } else {
            None
        }
    });

    Some(Box::new(iter))
}

fn count_minimum_digits(a: &str) -> usize {
    for c in a.chars() {
        match c {
            '-' => (),
            '0' => return a.len(),
            '1'...'9' => break,
            _ => panic!("count_minimum_digits should only be called for a valid number."),
        }
    }
    0
}

fn finish(inclusive: bool, start_str: &str, end_str: &str, step: isize) -> Option<Box<Iterator<Item = small::String>>> {
    if let (Ok(start), Ok(end)) = (start_str.parse::<isize>(), end_str.parse::<isize>())  {
        let step = if step == 1 {
            if start < end { step } else { -step }
        } else {
            step
        };
        let nb_digits = usize::max(count_minimum_digits(start_str), count_minimum_digits(end_str));
        numeric_range(start, end, step, inclusive, nb_digits)
    } else {
        char_range(start_str.bytes().next()?, end_str.bytes().next()?, step, inclusive)
    }
}

// TODO: Make this an iterator structure.
// In a range we allow the following syntax:
//      Exclusive nonstepped: {start..end}
//      Inclusive nonstepped: {start...end}
//      Exclusive stepped: {start..step..end}
//      Inclusive stepped: {start..step...end}
pub fn parse_range(input: &str) -> Option<Box<Iterator<Item = small::String>>> {
    let mut bytes_iterator = input.bytes().enumerate();
    let separator = bytes_iterator.by_ref().take_while(|&(i, b)| match b {
        b'a'...b'z' | b'-' | b'A'...b'Z' if i == 0 => true,
        b'0'...b'9' | b'.' => true,
        _ => false,
    }).position(|(_, b)| b == b'.')?;
    let start_str = &input[..separator];
    // The next byte has to be a dot to be valid range
    // syntax
    bytes_iterator.next().filter(|&(_, b)| b == b'.')?;

    // if the next byte is a dot we're certain it is an inclusive
    // unstepped range otherwise it has to be [-0-9a-zA-Z]
    bytes_iterator.next().and_then(|(start, b)| match b {
        b'.' | b'=' => {
            // this can only be an inclusive range
            finish(true, start_str, &input[start + 1..], 1)
        }
        b'0'...b'9' | b'-' | b'a'...b'z' | b'A'...b'Z' => {
            // further processing needed to find out if we're reading a step or
            // the end of an exclusive range. Step until we find another dot or
            // the iterator ends
            if let Some(end) = bytes_iterator.position(|(_, b)| b == b'.') {
                // stepped range input[start..read - 1] contains the step
                // size
                let step = (&input[start..=start + end]).parse::<isize>().ok()?;
                // count the dots to determine inclusive/exclusive
                let dots = bytes_iterator.take_while(|&(_, b)| b == b'.').count() + 1;
                finish(dots == 3, start_str, &input[start + end + dots + 1..], step)
            } else {
                // exhausted the iterator without finding anything new means
                // exclusive unstepped range
                finish(false, start_str, &input[start..], 1)
            }
        }
        // not a valid byte for ranges
        _ => None,
    })
}

pub fn parse_index_range(input: &str) -> Option<Range> {
    let mut bytes_iterator = input.bytes().enumerate();
    while let Some((id, byte)) = bytes_iterator.next() {
        match byte {
            b'0'...b'9' | b'-' => continue,
            b'.' => {
                let first = &input[..id];

                let mut dots = 1;
                let mut last_byte = 0;

                for (_, byte) in bytes_iterator {
                    last_byte = byte;
                    if byte == b'.' {
                        dots += 1
                    } else {
                        break;
                    }
                }

                if dots < 2 || dots > 3 {
                    break;
                }

                let inclusive = dots == 3 || (dots == 2 && last_byte == b'=');

                let end = &input[id + if inclusive { 3 } else { 2 }..];

                return if first.is_empty() && !end.is_empty() {
                    end.parse::<isize>().map(|end| Range::to(Index::new(end))).ok()
                } else if end.is_empty() {
                    first.parse::<isize>().map(|start| Range::from(Index::new(start))).ok()
                } else {
                    first
                        .parse::<isize>()
                        .and_then(|start| end.parse::<isize>().map(|end| (start, end)))
                        .map(|(start, end)| {
                            if inclusive {
                                Range::inclusive(Index::new(start), Index::new(end))
                            } else {
                                Range::exclusive(Index::new(start), Index::new(end))
                            }
                        })
                        .ok()
                };

            }
            _ => break,
        }
    }

    None
}
<|endoftext|>


<commit_before>use traits::operations::{Transpose, ApproxEq};
use traits::structure::{ColSlice, Eye, Indexable, Diag, SquareMat, BaseFloat};
use traits::geometry::Norm;
use std::cmp::min;
use std::ops::{Mul, Add, Sub};

/// Get the householder matrix corresponding to a reflexion to the hyperplane
/// defined by `vec`. It can be a reflexion contained in a subspace.
///
/// # Arguments
/// * `dim` - the dimension of the space the resulting matrix operates in
/// * `start` - the starting dimension of the subspace of the reflexion
/// * `vec` - the vector defining the reflection.
pub fn householder_matrix<N, V, M>(dim: usize, start: usize, vec: V) -> M
    where N: BaseFloat,
          M: Eye + Indexable<(usize, usize), N>,
          V: Indexable<usize, N> {
    let mut qk : M = Eye::new_identity(dim);
    let subdim = vec.shape();

    let stop = subdim + start;

    assert!(dim >= stop);

    for j in (start .. stop) {
        for i in (start .. stop) {
            unsafe {
                let vv = vec.unsafe_at(i - start) * vec.unsafe_at(j - start);
                let qkij = qk.unsafe_at((i, j));
                qk.unsafe_set((i, j), qkij - vv - vv);
            }
        }
    }
    qk
}

/// QR decomposition using Householder reflections.
///
/// # Arguments
/// * `m` - matrix to decompose
pub fn qr<N, V, M>(m: &M) -> (M, M)
    where N: BaseFloat,
          V: Indexable<usize, N> + Norm<N>,
          M: Copy + Eye + ColSlice<V> + Transpose + Indexable<(usize, usize), N> +
             Mul<M, Output = M> {
    let (rows, cols) = m.shape();
    assert!(rows >= cols);
    let mut q : M = Eye::new_identity(rows);
    let mut r = *m;

    for ite in 0..min(rows - 1, cols) {
        let mut v = r.col_slice(ite, ite, rows);
        let alpha =
            if unsafe { v.unsafe_at(ite) } >= ::zero() {
                -Norm::norm(&v)
            }
            else {
                Norm::norm(&v)
            };
        unsafe {
            let x = v.unsafe_at(0);
            v.unsafe_set(0, x - alpha);
        }
        if !::is_zero(&v.normalize_mut()) {
            let qk: M = householder_matrix(rows, ite, v);
            r = qk * r;
            q = q * Transpose::transpose(&qk);
        }
    }

    (q, r)
}

/// Eigendecomposition of a square matrix using the qr algorithm.
pub fn eigen_qr<N, V, VS, M>(m: &M, eps: &N, niter: usize) -> (M, V)
    where N:  BaseFloat,
          VS: Indexable<usize, N> + Norm<N>,
          M:  Indexable<(usize, usize), N> + SquareMat<N, V> + Add<M, Output = M> +
              Sub<M, Output = M> + ColSlice<VS> +
              ApproxEq<N> + Copy {
    let mut eigenvectors: M = ::one::<M>();
    let mut eigenvalues = *m;
    // let mut shifter: M = Eye::new_identity(rows);

    let mut iter = 0;
    for _ in 0..niter {
        let mut stop = true;

        for j in 0..::dim::<M>() {
            for i in 0..j {
                if unsafe { eigenvalues.unsafe_at((i, j)) }.abs() >= *eps {
                    stop = false;
                    break;
                }
            }

            for i in j + 1..::dim::<M>() {
                if unsafe { eigenvalues.unsafe_at((i, j)) }.abs() >= *eps {
                    stop = false;
                    break;
                }
            }
        }

        if stop {
            break;
        }
        iter = iter + 1;

        let (q, r) = qr(&eigenvalues);;

        eigenvalues  = r * q;
        eigenvectors = eigenvectors * q;
    }

    (eigenvectors, eigenvalues.diag())
}

/// Cholesky decomposition G of a square symmetric positive definite matrix A, such that A = G * G^T
///
/// # Arguments
/// * `m` - square symmetric positive definite matrix to decompose
pub fn cholesky<N, V, VS, M>(m: &M) -> Result<M, &'static str>
    where N:  BaseFloat,
          VS: Indexable<usize, N> + Norm<N>,
          M:  Indexable<(usize, usize), N> + SquareMat<N, V> + Add<M, Output = M> +
              Sub<M, Output = M> + ColSlice<VS> +
              ApproxEq<N> + Copy {

    let mut out = m.clone().transpose();

    if !ApproxEq::approx_eq(&out, &m) {
        return Err("Cholesky: Input matrix is not symmetric");
    }

    for i in 0..out.nrows() {
        for j in 0..(i+1) {

            let mut sum: N = out[(i,j)];

            for k in 0..j {
                sum = sum - out[(i, k)] * out[(j, k)];
            }

            if i > j {
                out[(i, j)] = sum / out[(j, j)];
            }
            else if sum > N::zero() {
                out[(i,i)] = sum.sqrt();
            }
            else {
                return Err("Cholesky: Input matrix is not positive definite to machine precision");
            }
        }
    }

    for i in 0..out.nrows() {
        for j in i+1..out.ncols() {
            out[(i,j)] = N::zero();
        }

    }

    return Ok(out);
}<commit_msg>Minor codding style fixes.<commit_after>use traits::operations::{Transpose, ApproxEq};
use traits::structure::{ColSlice, Eye, Indexable, Diag, SquareMat, BaseFloat};
use traits::geometry::Norm;
use std::cmp::min;
use std::ops::{Mul, Add, Sub};

/// Get the householder matrix corresponding to a reflexion to the hyperplane
/// defined by `vec`. It can be a reflexion contained in a subspace.
///
/// # Arguments
/// * `dim` - the dimension of the space the resulting matrix operates in
/// * `start` - the starting dimension of the subspace of the reflexion
/// * `vec` - the vector defining the reflection.
pub fn householder_matrix<N, V, M>(dim: usize, start: usize, vec: V) -> M
    where N: BaseFloat,
          M: Eye + Indexable<(usize, usize), N>,
          V: Indexable<usize, N> {
    let mut qk : M = Eye::new_identity(dim);
    let subdim = vec.shape();

    let stop = subdim + start;

    assert!(dim >= stop);

    for j in (start .. stop) {
        for i in (start .. stop) {
            unsafe {
                let vv = vec.unsafe_at(i - start) * vec.unsafe_at(j - start);
                let qkij = qk.unsafe_at((i, j));
                qk.unsafe_set((i, j), qkij - vv - vv);
            }
        }
    }
    qk
}

/// QR decomposition using Householder reflections.
///
/// # Arguments
/// * `m` - matrix to decompose
pub fn qr<N, V, M>(m: &M) -> (M, M)
    where N: BaseFloat,
          V: Indexable<usize, N> + Norm<N>,
          M: Copy + Eye + ColSlice<V> + Transpose + Indexable<(usize, usize), N> +
             Mul<M, Output = M> {
    let (rows, cols) = m.shape();
    assert!(rows >= cols);
    let mut q : M = Eye::new_identity(rows);
    let mut r = *m;

    for ite in 0..min(rows - 1, cols) {
        let mut v = r.col_slice(ite, ite, rows);
        let alpha =
            if unsafe { v.unsafe_at(ite) } >= ::zero() {
                -Norm::norm(&v)
            }
            else {
                Norm::norm(&v)
            };
        unsafe {
            let x = v.unsafe_at(0);
            v.unsafe_set(0, x - alpha);
        }
        if !::is_zero(&v.normalize_mut()) {
            let qk: M = householder_matrix(rows, ite, v);
            r = qk * r;
            q = q * Transpose::transpose(&qk);
        }
    }

    (q, r)
}

/// Eigendecomposition of a square matrix using the qr algorithm.
pub fn eigen_qr<N, V, VS, M>(m: &M, eps: &N, niter: usize) -> (M, V)
    where N:  BaseFloat,
          VS: Indexable<usize, N> + Norm<N>,
          M:  Indexable<(usize, usize), N> + SquareMat<N, V> + Add<M, Output = M> +
              Sub<M, Output = M> + ColSlice<VS> +
              ApproxEq<N> + Copy {
    let mut eigenvectors: M = ::one::<M>();
    let mut eigenvalues = *m;
    // let mut shifter: M = Eye::new_identity(rows);

    let mut iter = 0;
    for _ in 0..niter {
        let mut stop = true;

        for j in 0..::dim::<M>() {
            for i in 0..j {
                if unsafe { eigenvalues.unsafe_at((i, j)) }.abs() >= *eps {
                    stop = false;
                    break;
                }
            }

            for i in j + 1..::dim::<M>() {
                if unsafe { eigenvalues.unsafe_at((i, j)) }.abs() >= *eps {
                    stop = false;
                    break;
                }
            }
        }

        if stop {
            break;
        }
        iter = iter + 1;

        let (q, r) = qr(&eigenvalues);;

        eigenvalues  = r * q;
        eigenvectors = eigenvectors * q;
    }

    (eigenvectors, eigenvalues.diag())
}

/// Cholesky decomposition G of a square symmetric positive definite matrix A, such that A = G * G^T
///
/// # Arguments
/// * `m` - square symmetric positive definite matrix to decompose
pub fn cholesky<N, V, VS, M>(m: &M) -> Result<M, &'static str>
    where N:  BaseFloat,
          VS: Indexable<usize, N> + Norm<N>,
          M:  Indexable<(usize, usize), N> + SquareMat<N, V> + Add<M, Output = M> +
              Sub<M, Output = M> + ColSlice<VS> +
              ApproxEq<N> + Copy {

    let mut out = m.clone().transpose();

    if !ApproxEq::approx_eq(&out, &m) {
        return Err("Cholesky: Input matrix is not symmetric");
    }

    for i in 0 .. out.nrows() {
        for j in 0 .. (i + 1) {

            let mut sum: N = out[(i, j)];

            for k in 0 .. j {
                sum = sum - out[(i, k)] * out[(j, k)];
            }

            if i > j {
                out[(i, j)] = sum / out[(j, j)];
            }
            else if sum > N::zero() {
                out[(i, i)] = sum.sqrt();
            }
            else {
                return Err("Cholesky: Input matrix is not positive definite to machine precision");
            }
        }
    }

    for i in 0 .. out.nrows() {
        for j in i + 1 .. out.ncols() {
            out[(i, j)] = N::zero();
        }
    }

    return Ok(out);
}
<|endoftext|>


<commit_before>#![cfg(feature = "serde-1")]
extern crate arrayvec;
extern crate serde_test;

mod array_vec {
    use arrayvec::ArrayVec;

    use serde_test::{Token, assert_tokens};

    #[test]
    fn test_ser_de_empty() {
        let vec = ArrayVec::<[u32; 0]>::new();

        assert_tokens(&vec, &[
            Token::Seq { len: Some(0) },
            Token::SeqEnd,
        ]);
    }

    #[test]
    fn test_ser_de() {
        let mut vec = ArrayVec::<[u32; 3]>::new();
        vec.push(20);
        vec.push(55);
        vec.push(123);

        assert_tokens(&vec, &[
            Token::Seq { len: Some(3) },
            Token::U32(20),
            Token::U32(55),
            Token::U32(123),
            Token::SeqEnd,
        ]);
    }
}

mod array_string {
    use arrayvec::ArrayString;

    use serde_test::{Token, assert_tokens};

    #[test]
    fn test_ser_de_empty() {
        let string = ArrayString::<[u8; 0]>::new();

        assert_tokens(&string, &[
            Token::Str(""),
        ]);
    }

    #[test]
    fn test_ser_de() {
        let string = ArrayString::<[u8; 9]>::from("1234 abcd")
            .expect("expected exact specified capacity to be enough");

        assert_tokens(&string, &[
            Token::Str("1234 abcd"),
        ]);
    }
}
<commit_msg>Add failure tests for serde implementations<commit_after>#![cfg(feature = "serde-1")]
extern crate arrayvec;
extern crate serde_test;

mod array_vec {
    use arrayvec::ArrayVec;

    use serde_test::{Token, assert_tokens, assert_de_tokens_error};

    #[test]
    fn test_ser_de_empty() {
        let vec = ArrayVec::<[u32; 0]>::new();

        assert_tokens(&vec, &[
            Token::Seq { len: Some(0) },
            Token::SeqEnd,
        ]);
    }

    #[test]
    fn test_ser_de() {
        let mut vec = ArrayVec::<[u32; 3]>::new();
        vec.push(20);
        vec.push(55);
        vec.push(123);

        assert_tokens(&vec, &[
            Token::Seq { len: Some(3) },
            Token::U32(20),
            Token::U32(55),
            Token::U32(123),
            Token::SeqEnd,
        ]);
    }

    #[test]
    fn test_de_too_large() {
        assert_de_tokens_error::<ArrayVec<[u32; 2]>>(&[
            Token::Seq { len: Some(3) },
            Token::U32(13),
            Token::U32(42),
            Token::U32(68),
        ], "invalid length 3, expected an array with no more than 2 items");
    }
}

mod array_string {
    use arrayvec::ArrayString;

    use serde_test::{Token, assert_tokens, assert_de_tokens_error};

    #[test]
    fn test_ser_de_empty() {
        let string = ArrayString::<[u8; 0]>::new();

        assert_tokens(&string, &[
            Token::Str(""),
        ]);
    }

    #[test]
    fn test_ser_de() {
        let string = ArrayString::<[u8; 9]>::from("1234 abcd")
            .expect("expected exact specified capacity to be enough");

        assert_tokens(&string, &[
            Token::Str("1234 abcd"),
        ]);
    }

    #[test]
    fn test_de_too_large() {
        assert_de_tokens_error::<ArrayString<[u8; 2]>>(&[
            Token::Str("afd")
        ], "invalid length 3, expected a string no more than 2 bytes long");
    }
}
<|endoftext|>


<commit_before>//! Solve linear problem using LU decomposition

use crate::{error::*, layout::MatrixLayout, *};
use cauchy::*;
use num_traits::{ToPrimitive, Zero};

pub trait Solve_: Scalar + Sized {
    /// Computes the LU factorization of a general `m x n` matrix `a` using
    /// partial pivoting with row interchanges.
    ///
    /// $ PA = LU $
    ///
    /// Error
    /// ------
    /// - `LapackComputationalFailure { return_code }` when the matrix is singular
    ///   - Division by zero will occur if it is used to solve a system of equations
    ///     because `U[(return_code-1, return_code-1)]` is exactly zero.
    fn lu(l: MatrixLayout, a: &mut [Self]) -> Result<Pivot>;

    fn inv(l: MatrixLayout, a: &mut [Self], p: &Pivot) -> Result<()>;

    fn solve(l: MatrixLayout, t: Transpose, a: &[Self], p: &Pivot, b: &mut [Self]) -> Result<()>;
}

macro_rules! impl_solve {
    ($scalar:ty, $getrf:path, $getri:path, $getrs:path) => {
        impl Solve_ for $scalar {
            fn lu(l: MatrixLayout, a: &mut [Self]) -> Result<Pivot> {
                let (row, col) = l.size();
                assert_eq!(a.len() as i32, row * col);
                if row == 0 || col == 0 {
                    // Do nothing for empty matrix
                    return Ok(Vec::new());
                }
                let k = ::std::cmp::min(row, col);
                let mut ipiv = unsafe { vec_uninit(k as usize) };
                let mut info = 0;
                unsafe { $getrf(l.lda(), l.len(), a, l.lda(), &mut ipiv, &mut info) };
                info.as_lapack_result()?;
                Ok(ipiv)
            }

            fn inv(l: MatrixLayout, a: &mut [Self], ipiv: &Pivot) -> Result<()> {
                let (n, _) = l.size();

                // calc work size
                let mut info = 0;
                let mut work_size = [Self::zero()];
                unsafe { $getri(n, a, l.lda(), ipiv, &mut work_size, -1, &mut info) };
                info.as_lapack_result()?;

                // actual
                let lwork = work_size[0].to_usize().unwrap();
                let mut work = unsafe { vec_uninit(lwork) };
                unsafe {
                    $getri(
                        l.len(),
                        a,
                        l.lda(),
                        ipiv,
                        &mut work,
                        lwork as i32,
                        &mut info,
                    )
                };
                info.as_lapack_result()?;

                Ok(())
            }

            fn solve(
                l: MatrixLayout,
                t: Transpose,
                a: &[Self],
                ipiv: &Pivot,
                b: &mut [Self],
            ) -> Result<()> {
                let t = match l {
                    MatrixLayout::C { .. } => match t {
                        Transpose::No => Transpose::Transpose,
                        Transpose::Transpose | Transpose::Hermite => Transpose::No,
                    },
                    _ => t,
                };
                let (n, _) = l.size();
                let nrhs = 1;
                let ldb = l.lda();
                let mut info = 0;
                unsafe { $getrs(t as u8, n, nrhs, a, l.lda(), ipiv, b, ldb, &mut info) };
                info.as_lapack_result()?;
                Ok(())
            }
        }
    };
} // impl_solve!

impl_solve!(f64, lapack::dgetrf, lapack::dgetri, lapack::dgetrs);
impl_solve!(f32, lapack::sgetrf, lapack::sgetri, lapack::sgetrs);
impl_solve!(c64, lapack::zgetrf, lapack::zgetri, lapack::zgetrs);
impl_solve!(c32, lapack::cgetrf, lapack::cgetri, lapack::cgetrs);
<commit_msg>Fix Inverse/InverseInto for empty matrices<commit_after>//! Solve linear problem using LU decomposition

use crate::{error::*, layout::MatrixLayout, *};
use cauchy::*;
use num_traits::{ToPrimitive, Zero};

pub trait Solve_: Scalar + Sized {
    /// Computes the LU factorization of a general `m x n` matrix `a` using
    /// partial pivoting with row interchanges.
    ///
    /// $ PA = LU $
    ///
    /// Error
    /// ------
    /// - `LapackComputationalFailure { return_code }` when the matrix is singular
    ///   - Division by zero will occur if it is used to solve a system of equations
    ///     because `U[(return_code-1, return_code-1)]` is exactly zero.
    fn lu(l: MatrixLayout, a: &mut [Self]) -> Result<Pivot>;

    fn inv(l: MatrixLayout, a: &mut [Self], p: &Pivot) -> Result<()>;

    fn solve(l: MatrixLayout, t: Transpose, a: &[Self], p: &Pivot, b: &mut [Self]) -> Result<()>;
}

macro_rules! impl_solve {
    ($scalar:ty, $getrf:path, $getri:path, $getrs:path) => {
        impl Solve_ for $scalar {
            fn lu(l: MatrixLayout, a: &mut [Self]) -> Result<Pivot> {
                let (row, col) = l.size();
                assert_eq!(a.len() as i32, row * col);
                if row == 0 || col == 0 {
                    // Do nothing for empty matrix
                    return Ok(Vec::new());
                }
                let k = ::std::cmp::min(row, col);
                let mut ipiv = unsafe { vec_uninit(k as usize) };
                let mut info = 0;
                unsafe { $getrf(l.lda(), l.len(), a, l.lda(), &mut ipiv, &mut info) };
                info.as_lapack_result()?;
                Ok(ipiv)
            }

            fn inv(l: MatrixLayout, a: &mut [Self], ipiv: &Pivot) -> Result<()> {
                let (n, _) = l.size();
                if n == 0 {
                    // Do nothing for empty matrices.
                    return Ok(());
                }

                // calc work size
                let mut info = 0;
                let mut work_size = [Self::zero()];
                unsafe { $getri(n, a, l.lda(), ipiv, &mut work_size, -1, &mut info) };
                info.as_lapack_result()?;

                // actual
                let lwork = work_size[0].to_usize().unwrap();
                let mut work = unsafe { vec_uninit(lwork) };
                unsafe {
                    $getri(
                        l.len(),
                        a,
                        l.lda(),
                        ipiv,
                        &mut work,
                        lwork as i32,
                        &mut info,
                    )
                };
                info.as_lapack_result()?;

                Ok(())
            }

            fn solve(
                l: MatrixLayout,
                t: Transpose,
                a: &[Self],
                ipiv: &Pivot,
                b: &mut [Self],
            ) -> Result<()> {
                let t = match l {
                    MatrixLayout::C { .. } => match t {
                        Transpose::No => Transpose::Transpose,
                        Transpose::Transpose | Transpose::Hermite => Transpose::No,
                    },
                    _ => t,
                };
                let (n, _) = l.size();
                let nrhs = 1;
                let ldb = l.lda();
                let mut info = 0;
                unsafe { $getrs(t as u8, n, nrhs, a, l.lda(), ipiv, b, ldb, &mut info) };
                info.as_lapack_result()?;
                Ok(())
            }
        }
    };
} // impl_solve!

impl_solve!(f64, lapack::dgetrf, lapack::dgetri, lapack::dgetrs);
impl_solve!(f32, lapack::sgetrf, lapack::sgetri, lapack::sgetrs);
impl_solve!(c64, lapack::zgetrf, lapack::zgetri, lapack::zgetrs);
impl_solve!(c32, lapack::cgetrf, lapack::cgetri, lapack::cgetrs);
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

// Some crumminess to make sure we link correctly

#[cfg(target_os = "linux")]
#[link(name = "pthread")]
#[link(name = "js_static")]
#[link(name = "stdc++")]
#[link(name = "z")]
extern { }

#[cfg(target_os = "macos")]
#[link(name = "js_static")]
#[link(name = "stdc++")]
#[link(name = "z")]
extern { }

// Avoid hard linking with stdc++ in android ndk cross toolchain so that
// the ELF header will have an entry for libstdc++ and we will know to
// open it explicitly.
//It is hard to find location of android system libs in this rust source file
//and also we need to size down for mobile app packaging
#[cfg(target_os = "android")]
#[link(name = "mozjs")]
#[link_args="-lstdc++"]
#[link(name = "z")]
extern { }
<commit_msg>Link NSPR.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

// Some crumminess to make sure we link correctly

#[cfg(target_os = "linux")]
#[link(name = "pthread")]
#[link(name = "nspr4")]
#[link(name = "js_static")]
#[link(name = "stdc++")]
#[link(name = "z")]
extern { }

#[cfg(target_os = "macos")]
#[link(name = "nspr4")]
#[link(name = "js_static")]
#[link(name = "stdc++")]
#[link(name = "z")]
extern { }

// Avoid hard linking with stdc++ in android ndk cross toolchain so that
// the ELF header will have an entry for libstdc++ and we will know to
// open it explicitly.
//It is hard to find location of android system libs in this rust source file
//and also we need to size down for mobile app packaging
#[cfg(target_os = "android")]
#[link(name = "mozjs")]
#[link_args="-lstdc++"]
#[link(name = "z")]
extern { }
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use base::{
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
    kCFAllocatorDefault,
};
use std::cast;
use std::libc::c_void;
use std::ptr;
use std::vec;
use std::iterator::Enumerate;

pub type CFArrayRetainCallBack = *u8;
pub type CFArrayReleaseCallBack = *u8;
pub type CFArrayCopyDescriptionCallBack = *u8;
pub type CFArrayEqualCallBack = *u8;

pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFArrayRetainCallBack,
    release: CFArrayReleaseCallBack,
    copyDescription: CFArrayCopyDescriptionCallBack,
    equal: CFArrayEqualCallBack,
}

struct __CFArray { private: () }
pub type CFArrayRef = *__CFArray;

impl AbstractCFTypeRef for CFArrayRef {
    fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
    fn type_id() -> CFTypeID { unsafe { CFArrayGetTypeID() } }
}

// FIXME: Should be a newtype struct, but that fails due to a Rust compiler bug.
pub struct CFArray<ElemRefType> {
    contents: CFWrapper<CFArrayRef, ElemRefType, ()>
}

pub struct CFArrayIterator<'self, ElemRefType> {
    priv array: &'self CFArray<ElemRefType>,
    priv index: uint,
}

impl<'self, ElemRefType: AbstractCFTypeRef> Iterator<ElemRefType> for CFArrayIterator<'self, ElemRefType> {
    fn next(&mut self) -> Option<ElemRefType> {
        if self.index >= self.array.len() {
            None
        } else {
            let v = self.array[self.index];
            self.index += 1;
            Some(v)
        }
    }
}

impl<ElemRefType:AbstractCFTypeRef> CFArray<ElemRefType> {
    pub fn wrap_shared(array: CFArrayRef) -> CFArray<ElemRefType> {
        CFArray {
            contents: CFWrapper::wrap_shared(array)
        }
    }

    pub fn wrap_owned(array: CFArrayRef) -> CFArray<ElemRefType> {
        CFArray {
            contents: CFWrapper::wrap_owned(array)
        }
    }

    pub fn new(elems: &[ElemRefType]) -> CFArray<ElemRefType> {
        let array_ref: CFArrayRef;
        let elems_refs = do elems.map |e: &ElemRefType| { e.as_type_ref() };

        unsafe {
            array_ref = CFArrayCreate(kCFAllocatorDefault,
                                      cast::transmute::<*CFTypeRef, **c_void>(vec::raw::to_ptr(elems_refs)),
                                      elems.len() as CFIndex,
                                      ptr::to_unsafe_ptr(&kCFTypeArrayCallBacks));
        }

        CFArray {
            contents: CFWrapper::wrap_owned(array_ref)
        }
    }

    // Careful; the loop body must wrap the reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    pub fn each<'t>(&'t self) -> CFArrayIterator<'t, ElemRefType> {
        CFArrayIterator {
            array: self,
            index: 0
        }
    }

    // Careful; the loop body must wrap the reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    pub fn eachi<'t>(&'t self) -> Enumerate<CFArrayIterator<'t, ElemRefType>> {
        self.each().enumerate()
    }

    pub fn len(&self) -> uint {
        unsafe {
            return CFArrayGetCount(*self.contents.borrow_ref()) as uint;
        }
    }
}

impl<ElemRefType:AbstractCFTypeRef> Index<uint,ElemRefType> for CFArray<ElemRefType> {
    // Careful; the caller must wrap any returned reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    fn index(&self, idx: &uint) -> ElemRefType {
        assert!(*idx < self.len());
        unsafe {
            let elem = CFArrayGetValueAtIndex(*self.contents.borrow_ref(), *idx as CFIndex);
            // Don't return a wrapped thing, since we don't know whether
            // it needs base::wrap_shared() or base::wrap_owned()
            cast::transmute::<*c_void,ElemRefType>(elem)
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFArray.h
     */
    static kCFTypeArrayCallBacks: CFArrayCallBacks;

    fn CFArrayCreate(allocator: CFAllocatorRef, values: **c_void,
                     numValues: CFIndex, callBacks: *CFArrayCallBacks) -> CFArrayRef;
    // CFArrayCreateCopy
    // CFArrayBSearchValues
    // CFArrayContainsValue
    fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
    // CFArrayGetCountOfValue
    // CFArrayGetFirstIndexOfValue
    // CFArrayGetLastIndexOfValue
    // CFArrayGetValues
    fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *c_void;
    // CFArrayApplyFunction
    fn CFArrayGetTypeID() -> CFTypeID;
}

#[test]
fn should_box_and_unbox() {
    use number::{CFNumber, CFNumberRef};

    let one = CFNumber::new(1 as i32);
    let two = CFNumber::new(2 as i32);
    let thr = CFNumber::new(3 as i32);
    let fou = CFNumber::new(4 as i32);
    let fiv = CFNumber::new(5 as i32);

    let arr = CFArray::new([
        *one.contents.borrow_ref(),
        *two.contents.borrow_ref(),
        *thr.contents.borrow_ref(),
        *fou.contents.borrow_ref(),
        *fiv.contents.borrow_ref()
    ]);

    let mut sum = 0i32;

    for elem in arr.iter() {
        sum += CFNumber::wrap_shared(elem).to_i32();
    }

    assert!(sum == 15);

    for elem in arr.iter() {
        sum += CFNumber::wrap_shared(elem).to_i32();
    }

    assert!(sum == 30);
}
<commit_msg>Fix warnings.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use base::{
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
    kCFAllocatorDefault,
};
use std::cast;
use std::libc::c_void;
use std::ptr;
use std::vec;
use std::iterator::Enumerate;

pub type CFArrayRetainCallBack = *u8;
pub type CFArrayReleaseCallBack = *u8;
pub type CFArrayCopyDescriptionCallBack = *u8;
pub type CFArrayEqualCallBack = *u8;

pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFArrayRetainCallBack,
    release: CFArrayReleaseCallBack,
    copyDescription: CFArrayCopyDescriptionCallBack,
    equal: CFArrayEqualCallBack,
}

struct __CFArray { private: () }
pub type CFArrayRef = *__CFArray;

impl AbstractCFTypeRef for CFArrayRef {
    fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
    fn type_id() -> CFTypeID { unsafe { CFArrayGetTypeID() } }
}

// FIXME: Should be a newtype struct, but that fails due to a Rust compiler bug.
pub struct CFArray<ElemRefType> {
    contents: CFWrapper<CFArrayRef, ElemRefType, ()>
}

pub struct CFArrayIterator<'self, ElemRefType> {
    priv array: &'self CFArray<ElemRefType>,
    priv index: uint,
}

impl<'self, ElemRefType: AbstractCFTypeRef> Iterator<ElemRefType> for CFArrayIterator<'self, ElemRefType> {
    fn next(&mut self) -> Option<ElemRefType> {
        if self.index >= self.array.len() {
            None
        } else {
            let v = self.array[self.index];
            self.index += 1;
            Some(v)
        }
    }
}

impl<ElemRefType:AbstractCFTypeRef> CFArray<ElemRefType> {
    pub fn wrap_shared(array: CFArrayRef) -> CFArray<ElemRefType> {
        CFArray {
            contents: CFWrapper::wrap_shared(array)
        }
    }

    pub fn wrap_owned(array: CFArrayRef) -> CFArray<ElemRefType> {
        CFArray {
            contents: CFWrapper::wrap_owned(array)
        }
    }

    pub fn new(elems: &[ElemRefType]) -> CFArray<ElemRefType> {
        let array_ref: CFArrayRef;
        let elems_refs = do elems.map |e: &ElemRefType| { e.as_type_ref() };

        unsafe {
            array_ref = CFArrayCreate(kCFAllocatorDefault,
                                      cast::transmute::<*CFTypeRef, **c_void>(vec::raw::to_ptr(elems_refs)),
                                      elems.len() as CFIndex,
                                      ptr::to_unsafe_ptr(&kCFTypeArrayCallBacks));
        }

        CFArray {
            contents: CFWrapper::wrap_owned(array_ref)
        }
    }

    // Careful; the loop body must wrap the reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    pub fn each<'t>(&'t self) -> CFArrayIterator<'t, ElemRefType> {
        CFArrayIterator {
            array: self,
            index: 0
        }
    }

    // Careful; the loop body must wrap the reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    pub fn eachi<'t>(&'t self) -> Enumerate<CFArrayIterator<'t, ElemRefType>> {
        self.each().enumerate()
    }

    pub fn len(&self) -> uint {
        unsafe {
            return CFArrayGetCount(*self.contents.borrow_ref()) as uint;
        }
    }
}

impl<ElemRefType:AbstractCFTypeRef> Index<uint,ElemRefType> for CFArray<ElemRefType> {
    // Careful; the caller must wrap any returned reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    fn index(&self, idx: &uint) -> ElemRefType {
        assert!(*idx < self.len());
        unsafe {
            let elem = CFArrayGetValueAtIndex(*self.contents.borrow_ref(), *idx as CFIndex);
            // Don't return a wrapped thing, since we don't know whether
            // it needs base::wrap_shared() or base::wrap_owned()
            cast::transmute::<*c_void,ElemRefType>(elem)
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFArray.h
     */
    static kCFTypeArrayCallBacks: CFArrayCallBacks;

    fn CFArrayCreate(allocator: CFAllocatorRef, values: **c_void,
                     numValues: CFIndex, callBacks: *CFArrayCallBacks) -> CFArrayRef;
    // CFArrayCreateCopy
    // CFArrayBSearchValues
    // CFArrayContainsValue
    fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
    // CFArrayGetCountOfValue
    // CFArrayGetFirstIndexOfValue
    // CFArrayGetLastIndexOfValue
    // CFArrayGetValues
    fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *c_void;
    // CFArrayApplyFunction
    fn CFArrayGetTypeID() -> CFTypeID;
}

#[test]
fn should_box_and_unbox() {
    use number::CFNumber;

    let one = CFNumber::new(1 as i32);
    let two = CFNumber::new(2 as i32);
    let thr = CFNumber::new(3 as i32);
    let fou = CFNumber::new(4 as i32);
    let fiv = CFNumber::new(5 as i32);

    let arr = CFArray::new([
        *one.contents.borrow_ref(),
        *two.contents.borrow_ref(),
        *thr.contents.borrow_ref(),
        *fou.contents.borrow_ref(),
        *fiv.contents.borrow_ref()
    ]);

    let mut sum = 0i32;

    for elem in arr.iter() {
        sum += CFNumber::wrap_shared(elem).to_i32();
    }

    assert!(sum == 15);

    for elem in arr.iter() {
        sum += CFNumber::wrap_shared(elem).to_i32();
    }

    assert!(sum == 30);
}
<|endoftext|>


<commit_before>#![ cfg_attr( not( feature = "use_std" ), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/wtest_basic/latest/wtest_basic/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

//!
//! Tools for writing and running tests.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

/// Dependencies.
pub mod dependency
{
  pub use ::paste;
  pub use ::trybuild;
  pub use ::anyhow;
  pub use ::rustversion;
  pub use ::meta_tools;
  pub use ::mem_tools;
  pub use ::typing_tools;
  pub use ::num_traits;
  pub use ::diagnostics_tools;
}

pub use dependency::*;
use ::meta_tools::mod_interface;

mod_interface!
{
  /// Basics.
  layer basic;
  /// Helpers.
  layer helper;

  exposed use ::meta_tools as meta;
  exposed use ::mem_tools as mem;
  exposed use ::typing_tools as typing;
  exposed use ::data_type as dt;
  exposed use ::diagnostics_tools as diagnostics;

  // use ::meta_tools;
  use ::mem_tools;
  use ::typing_tools;
  use ::data_type;
  use ::diagnostics_tools;

  prelude use ::meta_tools::
  {
    impls,
    index,
    tests_impls,
    tests_impls_optional,
    tests_index,
  };
  prelude use ::typing_tools::{ implements };
}

// qqq : for Dima : add negative test that wtest_basic::exposed::exposed does not exist
<commit_msg>test_basic : better use<commit_after>#![ cfg_attr( not( feature = "use_std" ), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/wtest_basic/latest/wtest_basic/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

//!
//! Tools for writing and running tests.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

/// Dependencies.
pub mod dependency
{
  pub use ::paste;
  pub use ::trybuild;
  pub use ::anyhow;
  pub use ::rustversion;
  pub use ::meta_tools;
  pub use ::mem_tools;
  pub use ::typing_tools;
  pub use ::num_traits;
  pub use ::diagnostics_tools;
}

pub use dependency::*;
use ::meta_tools::mod_interface;

mod_interface!
{
  /// Basics.
  layer basic;
  /// Helpers.
  layer helper;

  exposed use ::meta_tools as meta;
  exposed use ::mem_tools as mem;
  exposed use ::typing_tools as typing;
  exposed use ::data_type as dt;
  exposed use ::diagnostics_tools as diagnostics;

  // use super::exposed::meta;
  use super::exposed::mem;
  use super::exposed::typing;
  use super::exposed::dt;
  use super::exposed::diagnostics;

  // // use ::meta_tools;
  // use ::mem_tools;
  // use ::typing_tools;
  // use ::data_type;
  // use ::diagnostics_tools;

  prelude use ::meta_tools::
  {
    impls,
    index,
    tests_impls,
    tests_impls_optional,
    tests_index,
  };
  prelude use ::typing_tools::{ implements };
}

// qqq : for Dima : add negative test that wtest_basic::exposed::exposed does not exist
<|endoftext|>