<commit_before>use std::cmp::Ordering;
use std::cmp::Ordering::*;
use std::cmp::{min, max};
use std::mem::{size_of, swap};
use std::ptr;

/// The smallest number of elements that may be quicksorted.
/// Must be at least 9.
const MIN_QUICKSORT_ELEMS: usize = 10;

/// The maximum number of elements to be insertion sorted.
const MAX_INSERTION_SORT_ELEMS: usize = 42;

/// Controls the number of elements to be insertion sorted.
/// Higher values give more insertion sorted elements.
const INSERTION_SORT_FACTOR: usize = 450;

pub fn sort_by<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) {
    if maybe_insertion_sort(v, compare) { return; }
    let heapsort_depth = (3 * log2(v.len())) / 2;
    do_introsort(v, compare, 0, heapsort_depth);
}

pub fn sort<T: Ord>(v: &mut [T]) {
    sort_by(v, &|a, b| a.cmp(b));
}

fn introsort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C, rec: u32, heapsort_depth: u32) {
    if maybe_insertion_sort(v, compare) { return; }
    do_introsort(v, compare, rec, heapsort_depth);
}

fn do_introsort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C, rec: u32, heapsort_depth: u32) {
    macro_rules! maybe_swap(
        ($v: expr, $a: expr, $b: expr, $compare: expr) => {
            if compare_idxs($v, *$a, *$b, $compare) == Greater {
                swap($a, $b);
            }
        }
    );

    if rec > heapsort_depth {
        heapsort(v, compare);
        return;
    }

    let n = v.len();

    // Pivot selection algorithm based on Java's DualPivotQuicksort.

    // Fast approximation of n / 7
    let seventh = (n / 8) + (n / 64) + 1;

    // Pick five element evenly spaced around the middle (inclusive) of the slice.
    let mut e3 = n / 2;
    let mut e2 = e3 - seventh;
    let mut e1 = e3 - 2*seventh;
    let mut e4 = e3 + seventh;
    let mut e5 = e3 + 2*seventh;

    // Sort them with a sorting network.
    unsafe {
        maybe_swap!(v, &mut e1, &mut e2, compare);
        maybe_swap!(v, &mut e4, &mut e5, compare);
        maybe_swap!(v, &mut e3, &mut e5, compare);
        maybe_swap!(v, &mut e3, &mut e4, compare);
        maybe_swap!(v, &mut e2, &mut e5, compare);
        maybe_swap!(v, &mut e1, &mut e4, compare);
        maybe_swap!(v, &mut e1, &mut e3, compare);
        maybe_swap!(v, &mut e2, &mut e4, compare);
        maybe_swap!(v, &mut e2, &mut e3, compare);
    }

    if unsafe { compare_idxs(v, e1, e2, compare) != Equal &&
                compare_idxs(v, e2, e3, compare) != Equal &&
                compare_idxs(v, e3, e4, compare) != Equal &&
                compare_idxs(v, e4, e5, compare) != Equal } {
        // No consecutive pivot candidates are the same, meaning there is some variaton.
        dual_pivot_sort(v, (e1, e2, e3, e4, e5), compare, rec, heapsort_depth);
    } else {
        // Two consecutive pivots candidates where the same.
        // There are probably many similar elements.
        single_pivot_sort(v, e3, compare, rec, heapsort_depth);
    }
}

fn maybe_insertion_sort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) -> bool {
    let n = v.len();
    if n <= 1 {
        return true;
    }

    let threshold = min(MAX_INSERTION_SORT_ELEMS,
                        max(MIN_QUICKSORT_ELEMS, INSERTION_SORT_FACTOR / size_of::<T>()));
    if n <= threshold {
        insertion_sort(v, compare);
        return true;
    }
    return false;
}

pub fn insertion_sort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) {
    let mut i = 1;
    let n = v.len();
    while i < n {
        let mut j = i;
        while j > 0 && unsafe { compare_idxs(v, j-1, j, compare) } == Greater {
            unsafe { unsafe_swap(v, j, j-1); }
            j -= 1;
        }
        i += 1;
    }
}

fn dual_pivot_sort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], pivots: (usize, usize, usize, usize, usize),
                                                 compare: &C, rec: u32, heapsort_depth: u32) {
    let (_, p1, _, p2, _) = pivots;
    let n = v.len();

    let lp = 0;
    let rp = n - 1;

    v.swap(p1, lp);
    v.swap(p2, rp);

    let mut lesser = 1;
    let mut greater = n - 2;

    unsafe {
        // Skip elements that are already in the correct position
        while compare_idxs(v, lesser, lp, compare) == Less { lesser += 1; }
        while compare_idxs(v, greater, rp, compare) == Greater { greater -= 1; }

        let mut k = lesser;
        // XXX We make some unecessary swaps since we can't leave uninitialized values
        // in `v` in case `compare` unwinds.
        while k <= greater {
            if compare_idxs(v, k, lp, compare) == Less {
                unsafe_swap(v, k, lesser);
                lesser += 1;
            } else {
                let cmp = compare_idxs(v, k, rp, compare);
                if cmp == Greater || cmp == Equal {
                    while k < greater && compare_idxs(v, greater, rp, compare) == Greater {
                        greater -= 1;
                    }
                    unsafe_swap(v, k, greater);
                    greater -= 1;
                    if compare_idxs(v, k, lp, compare) == Less {
                        unsafe_swap(v, k, lesser);
                        lesser += 1;
                    }
                }
            }
            k += 1;
        }
    }

    lesser -= 1;
    greater += 1;

    // Swap back pivots
    unsafe {
        unsafe_swap(v, lp, lesser);
        unsafe_swap(v, rp, greater);
    }

    introsort(&mut v[..lesser], compare, rec + 1, heapsort_depth);
    introsort(&mut v[lesser+1..greater], compare, rec + 1, heapsort_depth);
    introsort(&mut v[greater+1..], compare, rec + 1, heapsort_depth);
}

fn single_pivot_sort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], pivot: usize, compare: &C, rec: u32, heapsort_depth: u32) {
    let (l, r) = fat_partition(v, pivot, compare);
    let n = v.len();
    if l > 1 {
        introsort(&mut v[..l], compare, rec + 1, heapsort_depth);
    }
    if r > 1 {
        introsort(&mut v[n - r..], compare, rec + 1, heapsort_depth);
    }
}

/// Partitions elements, using the element at `pivot` as pivot.
/// After partitioning, the array looks as following:
/// <<<<<==>>>
/// Return (number of < elements, number of > elements)
fn fat_partition<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], pivot: usize, compare: &C) -> (usize, usize)  {
    let mut a = 0;
    let mut b = a;
    let mut c = v.len() - 1;
    let mut d = c;
    v.swap(0, pivot);
    loop {
        while b <= c {
            let r = compare_idxs_safe(v, b, 0, compare);
            if r == Greater { break; }
            if r == Equal {
                unsafe { unsafe_swap(v, a, b); }
                a += 1;
            }
            b += 1;
        }
        while c >= b {
            let r = compare_idxs_safe(v, c, 0, compare);
            if r == Less { break; }
            if r == Equal {
                unsafe { unsafe_swap(v, c, d); }
                d -= 1;
            }
            c -= 1;
        }
        if b > c { break; }
        unsafe { unsafe_swap(v, b, c); }
        b += 1;
        c -= 1;
    }

    let n = v.len();
    let l = min(a, b - a);
    unsafe { swap_many(v, 0, b - l, l); }
    let r = min(d - c, n - 1 - d);
    unsafe { swap_many(v, b, n - r, r); }

    return (b - a, d - c);
}

unsafe fn swap_many<T>(v: &mut [T], a: usize, b: usize, n: usize) {
    let mut i = 0;
    while i < n {
        unsafe_swap(v, a + i, b + i);
        i += 1;
    }
}

#[cold]
#[inline(never)]
pub fn heapsort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) {
    let mut end = v.len() as isize;
    heapify(v, compare);
    while end > 0 {
        end -= 1;
        v.swap(0, end as usize);
        siftdown_range(v, 0, end as usize, compare);
    }
}

fn heapify<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) {
    let mut n = (v.len() as isize).wrapping_sub(1) / 4;
    while n >= 0 {
        siftdown(v, n as usize, compare);
        n -= 1;
    }
}

fn siftup<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], start: usize, mut pos: usize, compare: &C) {
    unsafe {
        let new = ptr::read(v.get_unchecked_mut(pos));

        let mut parent = pos.wrapping_sub(1) / 4;

        while pos > start && compare(&new, v.get_unchecked(parent)) == Greater {
            let x = ptr::read(v.get_unchecked_mut(parent));
            ptr::write(v.get_unchecked_mut(pos), x);
            pos = parent;
            parent = (pos - 1) / 4;
        }
        ptr::write(v.get_unchecked_mut(pos), new);
    }
}

fn siftdown_range<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], mut pos: usize, end: usize, compare: &C) {
    unsafe {
        let start = pos;
        let new = ptr::read(v.get_unchecked_mut(pos));

        let mut m_left = 4 * pos + 2;
        while m_left < end {
            let left = m_left - 1;
            let m_right = m_left + 1;
            let right = m_left + 2;
            let largest_left = if compare_idxs(v, left, m_left, compare) == Less {
                m_left
            } else {
                left
            };
            let largest_right = if right < end && compare_idxs(v, m_right, right, compare) == Less {
                right
            } else {
                m_right
            };
            let child = if m_right < end && compare_idxs(v, largest_left, largest_right, compare) == Less {
                largest_right
            } else {
                largest_left
            };
            let x = ptr::read(v.get_unchecked_mut(child));
            ptr::write(v.get_unchecked_mut(pos), x);
            pos = child;
            m_left = 4 * pos + 2;
        }
        let left = m_left - 1;
        if left < end {
            let x = ptr::read(v.get_unchecked_mut(left));
            ptr::write(v.get_unchecked_mut(pos), x);
            pos = left;
        }

        ptr::write(v.get_unchecked_mut(pos), new);
        siftup(v, start, pos, compare);
    }
}

fn siftdown<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], pos: usize, compare: &C) {
    let len = v.len();
    siftdown_range(v, pos, len, compare);
}

fn log2(x: usize) -> u32 {
    if x <= 1 { return 0; }
    let n = x.leading_zeros();
    size_of::<usize>() as u32 * 8 - n
}

#[inline(always)]
unsafe fn compare_idxs<T, C: Fn(&T, &T) -> Ordering>(v: &[T], a: usize, b: usize, compare: &C) -> Ordering {
    let x = v.get_unchecked(a);
    let y = v.get_unchecked(b);
    compare(x, y)
}

#[inline(always)]
fn compare_idxs_safe<T, C: Fn(&T, &T) -> Ordering>(v: &[T], a: usize, b: usize, compare: &C) -> Ordering {
    compare(&v[a], &v[b])
}

#[inline(always)]
unsafe fn unsafe_swap<T>(v: &mut[T], a: usize, b: usize) {
    ptr::swap(v.get_unchecked_mut(a) as *mut T, v.get_unchecked_mut(b) as *mut T);
}
<commit_msg>Allow the parent to be OOR.<commit_after>use std::cmp::Ordering;
use std::cmp::Ordering::*;
use std::cmp::{min, max};
use std::mem::{size_of, swap};
use std::ptr;

/// The smallest number of elements that may be quicksorted.
/// Must be at least 9.
const MIN_QUICKSORT_ELEMS: usize = 10;

/// The maximum number of elements to be insertion sorted.
const MAX_INSERTION_SORT_ELEMS: usize = 42;

/// Controls the number of elements to be insertion sorted.
/// Higher values give more insertion sorted elements.
const INSERTION_SORT_FACTOR: usize = 450;

pub fn sort_by<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) {
    if maybe_insertion_sort(v, compare) { return; }
    let heapsort_depth = (3 * log2(v.len())) / 2;
    do_introsort(v, compare, 0, heapsort_depth);
}

pub fn sort<T: Ord>(v: &mut [T]) {
    sort_by(v, &|a, b| a.cmp(b));
}

fn introsort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C, rec: u32, heapsort_depth: u32) {
    if maybe_insertion_sort(v, compare) { return; }
    do_introsort(v, compare, rec, heapsort_depth);
}

fn do_introsort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C, rec: u32, heapsort_depth: u32) {
    macro_rules! maybe_swap(
        ($v: expr, $a: expr, $b: expr, $compare: expr) => {
            if compare_idxs($v, *$a, *$b, $compare) == Greater {
                swap($a, $b);
            }
        }
    );

    if rec > heapsort_depth {
        heapsort(v, compare);
        return;
    }

    let n = v.len();

    // Pivot selection algorithm based on Java's DualPivotQuicksort.

    // Fast approximation of n / 7
    let seventh = (n / 8) + (n / 64) + 1;

    // Pick five element evenly spaced around the middle (inclusive) of the slice.
    let mut e3 = n / 2;
    let mut e2 = e3 - seventh;
    let mut e1 = e3 - 2*seventh;
    let mut e4 = e3 + seventh;
    let mut e5 = e3 + 2*seventh;

    // Sort them with a sorting network.
    unsafe {
        maybe_swap!(v, &mut e1, &mut e2, compare);
        maybe_swap!(v, &mut e4, &mut e5, compare);
        maybe_swap!(v, &mut e3, &mut e5, compare);
        maybe_swap!(v, &mut e3, &mut e4, compare);
        maybe_swap!(v, &mut e2, &mut e5, compare);
        maybe_swap!(v, &mut e1, &mut e4, compare);
        maybe_swap!(v, &mut e1, &mut e3, compare);
        maybe_swap!(v, &mut e2, &mut e4, compare);
        maybe_swap!(v, &mut e2, &mut e3, compare);
    }

    if unsafe { compare_idxs(v, e1, e2, compare) != Equal &&
                compare_idxs(v, e2, e3, compare) != Equal &&
                compare_idxs(v, e3, e4, compare) != Equal &&
                compare_idxs(v, e4, e5, compare) != Equal } {
        // No consecutive pivot candidates are the same, meaning there is some variaton.
        dual_pivot_sort(v, (e1, e2, e3, e4, e5), compare, rec, heapsort_depth);
    } else {
        // Two consecutive pivots candidates where the same.
        // There are probably many similar elements.
        single_pivot_sort(v, e3, compare, rec, heapsort_depth);
    }
}

fn maybe_insertion_sort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) -> bool {
    let n = v.len();
    if n <= 1 {
        return true;
    }

    let threshold = min(MAX_INSERTION_SORT_ELEMS,
                        max(MIN_QUICKSORT_ELEMS, INSERTION_SORT_FACTOR / size_of::<T>()));
    if n <= threshold {
        insertion_sort(v, compare);
        return true;
    }
    return false;
}

pub fn insertion_sort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) {
    let mut i = 1;
    let n = v.len();
    while i < n {
        let mut j = i;
        while j > 0 && unsafe { compare_idxs(v, j-1, j, compare) } == Greater {
            unsafe { unsafe_swap(v, j, j-1); }
            j -= 1;
        }
        i += 1;
    }
}

fn dual_pivot_sort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], pivots: (usize, usize, usize, usize, usize),
                                                 compare: &C, rec: u32, heapsort_depth: u32) {
    let (_, p1, _, p2, _) = pivots;
    let n = v.len();

    let lp = 0;
    let rp = n - 1;

    v.swap(p1, lp);
    v.swap(p2, rp);

    let mut lesser = 1;
    let mut greater = n - 2;

    unsafe {
        // Skip elements that are already in the correct position
        while compare_idxs(v, lesser, lp, compare) == Less { lesser += 1; }
        while compare_idxs(v, greater, rp, compare) == Greater { greater -= 1; }

        let mut k = lesser;
        // XXX We make some unecessary swaps since we can't leave uninitialized values
        // in `v` in case `compare` unwinds.
        while k <= greater {
            if compare_idxs(v, k, lp, compare) == Less {
                unsafe_swap(v, k, lesser);
                lesser += 1;
            } else {
                let cmp = compare_idxs(v, k, rp, compare);
                if cmp == Greater || cmp == Equal {
                    while k < greater && compare_idxs(v, greater, rp, compare) == Greater {
                        greater -= 1;
                    }
                    unsafe_swap(v, k, greater);
                    greater -= 1;
                    if compare_idxs(v, k, lp, compare) == Less {
                        unsafe_swap(v, k, lesser);
                        lesser += 1;
                    }
                }
            }
            k += 1;
        }
    }

    lesser -= 1;
    greater += 1;

    // Swap back pivots
    unsafe {
        unsafe_swap(v, lp, lesser);
        unsafe_swap(v, rp, greater);
    }

    introsort(&mut v[..lesser], compare, rec + 1, heapsort_depth);
    introsort(&mut v[lesser+1..greater], compare, rec + 1, heapsort_depth);
    introsort(&mut v[greater+1..], compare, rec + 1, heapsort_depth);
}

fn single_pivot_sort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], pivot: usize, compare: &C, rec: u32, heapsort_depth: u32) {
    let (l, r) = fat_partition(v, pivot, compare);
    let n = v.len();
    if l > 1 {
        introsort(&mut v[..l], compare, rec + 1, heapsort_depth);
    }
    if r > 1 {
        introsort(&mut v[n - r..], compare, rec + 1, heapsort_depth);
    }
}

/// Partitions elements, using the element at `pivot` as pivot.
/// After partitioning, the array looks as following:
/// <<<<<==>>>
/// Return (number of < elements, number of > elements)
fn fat_partition<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], pivot: usize, compare: &C) -> (usize, usize)  {
    let mut a = 0;
    let mut b = a;
    let mut c = v.len() - 1;
    let mut d = c;
    v.swap(0, pivot);
    loop {
        while b <= c {
            let r = compare_idxs_safe(v, b, 0, compare);
            if r == Greater { break; }
            if r == Equal {
                unsafe { unsafe_swap(v, a, b); }
                a += 1;
            }
            b += 1;
        }
        while c >= b {
            let r = compare_idxs_safe(v, c, 0, compare);
            if r == Less { break; }
            if r == Equal {
                unsafe { unsafe_swap(v, c, d); }
                d -= 1;
            }
            c -= 1;
        }
        if b > c { break; }
        unsafe { unsafe_swap(v, b, c); }
        b += 1;
        c -= 1;
    }

    let n = v.len();
    let l = min(a, b - a);
    unsafe { swap_many(v, 0, b - l, l); }
    let r = min(d - c, n - 1 - d);
    unsafe { swap_many(v, b, n - r, r); }

    return (b - a, d - c);
}

unsafe fn swap_many<T>(v: &mut [T], a: usize, b: usize, n: usize) {
    let mut i = 0;
    while i < n {
        unsafe_swap(v, a + i, b + i);
        i += 1;
    }
}

#[cold]
#[inline(never)]
pub fn heapsort<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) {
    let mut end = v.len() as isize;
    heapify(v, compare);
    while end > 0 {
        end -= 1;
        v.swap(0, end as usize);
        siftdown_range(v, 0, end as usize, compare);
    }
}

fn heapify<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], compare: &C) {
    let mut n = (v.len() as isize).wrapping_sub(1) / 4;
    while n >= 0 {
        siftdown(v, n as usize, compare);
        n -= 1;
    }
}

fn siftup<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], start: usize, mut pos: usize, compare: &C) {
    unsafe {
        let new = ptr::read(v.get_unchecked_mut(pos));

        let mut parent = pos.wrapping_sub(1) / 4;

        while pos > start && compare(&new, v.get_unchecked(parent)) == Greater {
            let x = ptr::read(v.get_unchecked_mut(parent));
            ptr::write(v.get_unchecked_mut(pos), x);
            pos = parent;
            parent = pos.wrapping_sub(1) / 4;
        }
        ptr::write(v.get_unchecked_mut(pos), new);
    }
}

fn siftdown_range<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], mut pos: usize, end: usize, compare: &C) {
    unsafe {
        let start = pos;
        let new = ptr::read(v.get_unchecked_mut(pos));

        let mut m_left = 4 * pos + 2;
        while m_left < end {
            let left = m_left - 1;
            let m_right = m_left + 1;
            let right = m_left + 2;
            let largest_left = if compare_idxs(v, left, m_left, compare) == Less {
                m_left
            } else {
                left
            };
            let largest_right = if right < end && compare_idxs(v, m_right, right, compare) == Less {
                right
            } else {
                m_right
            };
            let child = if m_right < end && compare_idxs(v, largest_left, largest_right, compare) == Less {
                largest_right
            } else {
                largest_left
            };
            let x = ptr::read(v.get_unchecked_mut(child));
            ptr::write(v.get_unchecked_mut(pos), x);
            pos = child;
            m_left = 4 * pos + 2;
        }
        let left = m_left - 1;
        if left < end {
            let x = ptr::read(v.get_unchecked_mut(left));
            ptr::write(v.get_unchecked_mut(pos), x);
            pos = left;
        }

        ptr::write(v.get_unchecked_mut(pos), new);
        siftup(v, start, pos, compare);
    }
}

fn siftdown<T, C: Fn(&T, &T) -> Ordering>(v: &mut [T], pos: usize, compare: &C) {
    let len = v.len();
    siftdown_range(v, pos, len, compare);
}

fn log2(x: usize) -> u32 {
    if x <= 1 { return 0; }
    let n = x.leading_zeros();
    size_of::<usize>() as u32 * 8 - n
}

#[inline(always)]
unsafe fn compare_idxs<T, C: Fn(&T, &T) -> Ordering>(v: &[T], a: usize, b: usize, compare: &C) -> Ordering {
    let x = v.get_unchecked(a);
    let y = v.get_unchecked(b);
    compare(x, y)
}

#[inline(always)]
fn compare_idxs_safe<T, C: Fn(&T, &T) -> Ordering>(v: &[T], a: usize, b: usize, compare: &C) -> Ordering {
    compare(&v[a], &v[b])
}

#[inline(always)]
unsafe fn unsafe_swap<T>(v: &mut[T], a: usize, b: usize) {
    ptr::swap(v.get_unchecked_mut(a) as *mut T, v.get_unchecked_mut(b) as *mut T);
}
<|endoftext|>


<commit_before>#![feature(non_ascii_idents)]
// use variable names from paper, namely registers M
#![allow(non_snake_case)]

use std::num::Float;
use std::io::BufferedReader;
use std::io::File;

extern crate hll;

#[test]
fn can_estimate_a_small_range_subset_of_the_system_dictionary () {
    let path = Path::new("/usr/share/dict/words");
    let mut file = BufferedReader::new(File::open(&path));
    let mut store = hll::HLL::ctor(0.0040625);
    let mut count = 0f64;
    let actual = 60000.0f64;
    println!("store: {}", store);

    for line in file.lines() {
        count += 1.0;
        if count > actual {
            break;
        }
        store.insert(&line.unwrap());
    }

    let count = store.count();
    let error = 1.04 / 65536.0f64.sqrt();

    if  (1.0 - (count / actual)) > error {
        panic!("expected {} to be within {} of {} (but was {})", count, error, actual, 1.0 - (count / actual));
    }
}

<commit_msg>remove old test file<commit_after><|endoftext|>


<commit_before>use openssl::ssl::{self, SslMethod, SslConnectorBuilder};
use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;

use super::*;

#[test]
fn connect_google() {
    let builder = TlsConnector::builder().unwrap().build().unwrap();
    let s = TcpStream::connect("google.com:443").unwrap();
    let mut socket = builder.connect("google.com", s).unwrap();

    socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut result = vec![];
    socket.read_to_end(&mut result).unwrap();

    println!("{}", String::from_utf8_lossy(&result));
    assert!(result.starts_with(b"HTTP/1.0"));
    assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
}

#[test]
fn connect_bad_hostname() {
    let builder = TlsConnector::builder().unwrap().build().unwrap();
    let s = TcpStream::connect("wrong.host.badssl.com:443").unwrap();
    assert!(builder.connect("wrong.host.badssl.com", s).is_err());
}

#[test]
fn server() {
    let buf = include_bytes!("../test/identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let builder = TlsAcceptor::builder(pkcs12).unwrap().build().unwrap();

    let listener = TcpListener::bind("0.0.0.0:0").unwrap();
    let port = listener.local_addr().unwrap().port();

    thread::spawn(move || {
        let socket = listener.accept().unwrap().0;
        let mut socket = builder.accept(socket).unwrap();

        let mut buf = [0; 5];
        socket.read_exact(&mut buf).unwrap();
        assert_eq!(&buf, b"hello");

        socket.write_all(b"world").unwrap();
    });

    let socket = TcpStream::connect(("localhost", port)).unwrap();
    let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
    builder.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
    let connector = builder.build();
    let mut socket = connector.connect("foobar.com", socket).unwrap();
    println!("{}", socket.ssl().current_cipher().unwrap().description());
    socket.write_all(b"hello").unwrap();
    let mut buf = vec![];
    socket.read_to_end(&mut buf).unwrap();
    assert_eq!(buf, b"world");
}

#[test]
fn server_tls11_only() {
    let buf = include_bytes!("../test/identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let mut builder = TlsAcceptor::builder(pkcs12).unwrap();
    builder.supported_protocols(&[Protocol::Tlsv11]).unwrap();
    let builder = builder.build().unwrap();

    let listener = TcpListener::bind("0.0.0.0:0").unwrap();
    let port = listener.local_addr().unwrap().port();

    let j = thread::spawn(move || {
        let socket = listener.accept().unwrap().0;
        let mut socket = builder.accept(socket).unwrap();

        let mut buf = [0; 5];
        socket.read_exact(&mut buf).unwrap();
        assert_eq!(&buf, b"hello");

        socket.write_all(b"world").unwrap();
    });

    let socket = TcpStream::connect(("localhost", port)).unwrap();
    let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
    builder.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
    let options = ssl::SSL_OP_NO_SSLV3 | ssl::SSL_OP_NO_TLSV1 | ssl::SSL_OP_NO_TLSV1_2;
    builder.builder_mut().set_options(options);
    let connector = builder.build();
    let mut socket = connector.connect("foobar.com", socket).unwrap();
    println!("{}", socket.ssl().current_cipher().unwrap().description());
    socket.write_all(b"hello").unwrap();
    let mut buf = vec![];
    socket.read_to_end(&mut buf).unwrap();
    assert_eq!(buf, b"world");

    j.join().unwrap();
}

#[test]
fn server_no_shared_protocol() {
    let buf = include_bytes!("../test/identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let mut builder = TlsAcceptor::builder(pkcs12).unwrap();
    builder.supported_protocols(&[Protocol::Tlsv11]).unwrap();
    let builder = builder.build().unwrap();

    let listener = TcpListener::bind("0.0.0.0:0").unwrap();
    let port = listener.local_addr().unwrap().port();

    let j = thread::spawn(move || {
        let socket = listener.accept().unwrap().0;
        assert!(builder.accept(socket).is_err());
    });

    let socket = TcpStream::connect(("localhost", port)).unwrap();
    let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
    builder.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
    let options = ssl::SSL_OP_NO_SSLV3 | ssl::SSL_OP_NO_TLSV1 | ssl::SSL_OP_NO_TLSV1_1;
    builder.builder_mut().set_options(options);
    let connector = builder.build();
    assert!(connector.connect("foobar.com", socket).is_err());

    j.join().unwrap();
}

#[test]
fn shutdown() {
    let buf = include_bytes!("../test/identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let builder = TlsAcceptor::builder(pkcs12).unwrap().build().unwrap();

    let listener = TcpListener::bind("0.0.0.0:0").unwrap();
    let port = listener.local_addr().unwrap().port();

    let j = thread::spawn(move || {
        let socket = listener.accept().unwrap().0;
        let mut socket = builder.accept(socket).unwrap();

        let mut buf = [0; 5];
        socket.read_exact(&mut buf).unwrap();
        assert_eq!(&buf, b"hello");

        assert_eq!(socket.read(&mut buf).unwrap(), 0);
    });

    let socket = TcpStream::connect(("localhost", port)).unwrap();
    let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
    builder.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
    let connector = builder.build();
    let mut socket = connector.connect("foobar.com", socket).unwrap();
    println!("{}", socket.ssl().current_cipher().unwrap().description());
    socket.write_all(b"hello").unwrap();
    socket.shutdown().unwrap();

    j.join().unwrap();
}
<commit_msg>Simplify test a bit<commit_after>use openssl::ssl::{self, SslMethod, SslConnectorBuilder};
use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;

use super::*;

#[test]
fn connect_google() {
    let builder = TlsConnector::builder().unwrap().build().unwrap();
    let s = TcpStream::connect("google.com:443").unwrap();
    let mut socket = builder.connect("google.com", s).unwrap();

    socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut result = vec![];
    socket.read_to_end(&mut result).unwrap();

    println!("{}", String::from_utf8_lossy(&result));
    assert!(result.starts_with(b"HTTP/1.0"));
    assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
}

#[test]
fn connect_bad_hostname() {
    let builder = TlsConnector::builder().unwrap().build().unwrap();
    let s = TcpStream::connect("wrong.host.badssl.com:443").unwrap();
    assert!(builder.connect("wrong.host.badssl.com", s).is_err());
}

#[test]
fn server() {
    let buf = include_bytes!("../test/identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let builder = TlsAcceptor::builder(pkcs12).unwrap().build().unwrap();

    let listener = TcpListener::bind("0.0.0.0:0").unwrap();
    let port = listener.local_addr().unwrap().port();

    thread::spawn(move || {
        let socket = listener.accept().unwrap().0;
        let mut socket = builder.accept(socket).unwrap();

        let mut buf = [0; 5];
        socket.read_exact(&mut buf).unwrap();
        assert_eq!(&buf, b"hello");

        socket.write_all(b"world").unwrap();
    });

    let socket = TcpStream::connect(("localhost", port)).unwrap();
    let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
    builder.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
    let connector = builder.build();
    let mut socket = connector.connect("foobar.com", socket).unwrap();
    println!("{}", socket.ssl().current_cipher().unwrap().description());
    socket.write_all(b"hello").unwrap();
    let mut buf = vec![];
    socket.read_to_end(&mut buf).unwrap();
    assert_eq!(buf, b"world");
}

#[test]
fn server_tls11_only() {
    let buf = include_bytes!("../test/identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let mut builder = TlsAcceptor::builder(pkcs12).unwrap();
    builder.supported_protocols(&[Protocol::Tlsv11]).unwrap();
    let builder = builder.build().unwrap();

    let listener = TcpListener::bind("0.0.0.0:0").unwrap();
    let port = listener.local_addr().unwrap().port();

    let j = thread::spawn(move || {
        let socket = listener.accept().unwrap().0;
        let mut socket = builder.accept(socket).unwrap();

        let mut buf = [0; 5];
        socket.read_exact(&mut buf).unwrap();
        assert_eq!(&buf, b"hello");

        socket.write_all(b"world").unwrap();
    });

    let socket = TcpStream::connect(("localhost", port)).unwrap();
    let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
    builder.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
    let options = ssl::SSL_OP_NO_SSLV3 | ssl::SSL_OP_NO_TLSV1 | ssl::SSL_OP_NO_TLSV1_2;
    builder.builder_mut().set_options(options);
    let connector = builder.build();
    let mut socket = connector.connect("foobar.com", socket).unwrap();
    println!("{}", socket.ssl().current_cipher().unwrap().description());
    socket.write_all(b"hello").unwrap();
    let mut buf = vec![];
    socket.read_to_end(&mut buf).unwrap();
    assert_eq!(buf, b"world");

    j.join().unwrap();
}

#[test]
fn server_no_shared_protocol() {
    let buf = include_bytes!("../test/identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let mut builder = TlsAcceptor::builder(pkcs12).unwrap();
    builder.supported_protocols(&[Protocol::Tlsv11]).unwrap();
    let builder = builder.build().unwrap();

    let listener = TcpListener::bind("0.0.0.0:0").unwrap();
    let port = listener.local_addr().unwrap().port();

    let j = thread::spawn(move || {
        let socket = listener.accept().unwrap().0;
        assert!(builder.accept(socket).is_err());
    });

    let socket = TcpStream::connect(("localhost", port)).unwrap();
    let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
    builder.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
    let options = ssl::SSL_OP_NO_TLSV1_1;
    builder.builder_mut().set_options(options);
    let connector = builder.build();
    assert!(connector.connect("foobar.com", socket).is_err());

    j.join().unwrap();
}

#[test]
fn shutdown() {
    let buf = include_bytes!("../test/identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let builder = TlsAcceptor::builder(pkcs12).unwrap().build().unwrap();

    let listener = TcpListener::bind("0.0.0.0:0").unwrap();
    let port = listener.local_addr().unwrap().port();

    let j = thread::spawn(move || {
        let socket = listener.accept().unwrap().0;
        let mut socket = builder.accept(socket).unwrap();

        let mut buf = [0; 5];
        socket.read_exact(&mut buf).unwrap();
        assert_eq!(&buf, b"hello");

        assert_eq!(socket.read(&mut buf).unwrap(), 0);
    });

    let socket = TcpStream::connect(("localhost", port)).unwrap();
    let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
    builder.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
    let connector = builder.build();
    let mut socket = connector.connect("foobar.com", socket).unwrap();
    println!("{}", socket.ssl().current_cipher().unwrap().description());
    socket.write_all(b"hello").unwrap();
    socket.shutdown().unwrap();

    j.join().unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2015 Michael 'ExpHP' Lamparski
//
// Licensed under the terms of the MIT License, available at:
//  http://opensource.org/licenses/MIT
// and also included in the file COPYING at the root of this distribution.
// This file may not be copied, modified, or distributed except according
// to those terms.

extern crate num;
extern crate test;

use std::collections::hash_map::{HashMap,Hasher};
use std::default::Default;
use std::num::{ToPrimitive,FromPrimitive}; // and regret it
use std::hash::Hash;
use std::ops::Shr;

use num::bigint::{ToBigUint,BigUint};
use num::{Zero,One,Integer};
use std::num::Float;

use test::Bencher;

/// Performs an integer square root, returning the largest integer whose square is not
///  greater than the argument.
pub fn isqrt<T>(n: T) -> T
 where T: Clone + FromPrimitive + ToPrimitive + Zero + One + Integer + Shr<usize, Output=T>,
{
	isqrt_fast(n.clone()).or_else(
		|| Some(isqrt_safe(n.clone()))
	).unwrap()
}

//-------------------------------
// isqrt helper methods

fn isqrt_fast<T>(x: T) -> Option<T>
 where T: FromPrimitive + ToPrimitive,
{
	x.to_f64().and_then(|f| {
		// Mantissa is 52 bits, and the square root takes half as many bits, so this
		//  may be a bit conservative.  The main concern is to avoid handling very
		//  large BigInts which may lose more than half of their precision.
		if f > 20f64.exp2() {
			None                 // Number too large, bail out!
		} else {
			FromPrimitive::from_f64(f.sqrt().floor())
		}
	})
}

fn isqrt_safe<T>(n: T) -> T
 where T: Clone + FromPrimitive + ToPrimitive + Zero + One + Integer + Shr<usize, Output=T>,
{
	if n.is_zero() { return Zero::zero(); }
	let mut x = n.clone();
	let mut y = (x.clone() + n.clone() / x.clone()) >> One::one();
	while y < x {
		x = y.clone();
		y = (x.clone() + n.clone() / x.clone()) >> One::one();
	}
	return x;
}

#[bench]
fn bench_fast(b: &mut Bencher) {
	b.iter(|| {
		range(0us, 1000us).map(|a| {isqrt_fast::<usize>(a).unwrap()}).collect::<Vec<usize>>()
	})
}

#[bench]
fn bench_safe(b: &mut Bencher) {
	b.iter(|| {
		range(0us, 1000us).map(isqrt_safe::<usize>).collect::<Vec<usize>>()
	})
}

#[test]
fn test_isqrt_consistency()
{
	(0us..1000).map(|x| {
		let bigX = x.to_biguint().unwrap();
		assert_eq!(isqrt_fast(x),            Some(isqrt_safe(x)));
		assert_eq!(isqrt_fast(bigX.clone()), Some(isqrt_safe(bigX.clone())));
	});
}

#[cfg(test)]
mod tests {
	extern crate test;
	use super::*;
	use std::num::FromPrimitive;
	use std::num::ToPrimitive;
	use num::bigint::{ToBigUint,BigUint};

	// need to test isqrt with BigInt more rigorously

}
<commit_msg>Adding notes on sqrt benchmark<commit_after>// Copyright 2015 Michael 'ExpHP' Lamparski
//
// Licensed under the terms of the MIT License, available at:
//  http://opensource.org/licenses/MIT
// and also included in the file COPYING at the root of this distribution.
// This file may not be copied, modified, or distributed except according
// to those terms.

extern crate num;
extern crate test;

use std::collections::hash_map::{HashMap,Hasher};
use std::default::Default;
use std::num::{ToPrimitive,FromPrimitive}; // and regret it
use std::hash::Hash;
use std::ops::Shr;

use num::bigint::{ToBigUint,BigUint};
use num::{Zero,One,Integer};
use std::num::Float;

use test::Bencher;

/// Performs an integer square root, returning the largest integer whose square is not
///  greater than the argument.
pub fn isqrt<T>(n: T) -> T
 where T: Clone + FromPrimitive + ToPrimitive + Zero + One + Integer + Shr<usize, Output=T>,
{
	isqrt_fast(n.clone()).or_else(
		|| Some(isqrt_safe(n.clone()))
	).unwrap()
}

//-------------------------------
// isqrt helper methods

fn isqrt_fast<T>(x: T) -> Option<T>
 where T: FromPrimitive + ToPrimitive,
{
	x.to_f64().and_then(|f| {
		// Mantissa is 52 bits, and the square root takes half as many bits, so this
		//  may be a bit conservative.  The main concern is to avoid handling very
		//  large BigInts which may lose more than half of their precision.
		if f > 20f64.exp2() {
			None                 // Number too large, bail out!
		} else {
			FromPrimitive::from_f64(f.sqrt().floor())
		}
	})
}

fn isqrt_safe<T>(n: T) -> T
 where T: Clone + FromPrimitive + ToPrimitive + Zero + One + Integer + Shr<usize, Output=T>,
{
	// NOTE: while I'd like to remove the Shr bound, replacing '>> 1' with '/ 2' makes this
	//       algorithm take twice as long for BigInts :/
	if n.is_zero() { return Zero::zero(); }
	let mut x = n.clone();
	let mut y = (x.clone() + n.clone() / x.clone()) >> One::one();
	while y < x {
		x = y.clone();
		y = (x.clone() + n.clone() / x.clone()) >> One::one();
	}
	return x;
}

#[bench]
fn bench_fast(b: &mut Bencher) {
	b.iter(|| {
		range(0us, 1000us).map(|a| {isqrt_fast::<usize>(a).unwrap()}).collect::<Vec<usize>>()
	})
}

#[bench]
fn bench_safe(b: &mut Bencher) {
	b.iter(|| {
		range(0us, 1000us).map(isqrt_safe::<usize>).collect::<Vec<usize>>()
	})
}

#[bench]
fn bench_safe_bigint(b: &mut Bencher) {
	b.iter(|| {
		range(0us, 1000us).map(|a| isqrt_safe::<BigUint>(FromPrimitive::from_uint(a).unwrap())).collect::<Vec<BigUint>>()
	})
}

#[bench]
fn bench_safe_massive_bigint(b: &mut Bencher) {
	use std::rand::XorShiftRng;
	use num::bigint::RandBigInt;
	let mut r = XorShiftRng::new_unseeded();
	b.iter(|| {
		range(0us, 100us).map(|_| {
			isqrt_safe::<BigUint>(r.gen_biguint(100us))
		}).collect::<Vec<BigUint>>()
	})
}

#[test]
fn test_isqrt_consistency()
{
	(0us..1000).map(|x| {
		let bigX = x.to_biguint().unwrap();
		assert_eq!(isqrt_fast(x),            Some(isqrt_safe(x)));
		assert_eq!(isqrt_fast(bigX.clone()), Some(isqrt_safe(bigX.clone())));
	});
}

#[cfg(test)]
mod tests {
	extern crate test;
	use super::*;
	use std::num::FromPrimitive;
	use std::num::ToPrimitive;
	use num::bigint::{ToBigUint,BigUint};

	// need to test isqrt with BigInt more rigorously

}
<|endoftext|>


<commit_before>use std::fmt;
use std::mem::transmute;
use std::ops::Deref;

use llvm_sys::prelude::*;
use llvm_sys::core::*;
use llvm_sys::*;

use super::*;

/// Enumeration of all the base types of the LLVM type system.
#[allow(non_camel_case_types)]
#[repr(C)]
pub enum Kind {
    Void = 0,
    Half,
    Float,
    Double,
    X86_FP80,
    FP128,
    PPC_FP128,
    Label,
    Metadata,
    X86_MMX,
    Token,

    Integer,
    Function,
    Struct,
    Array,
    Pointer,
    Vector,
}

/// Should always be used as `&Type`.
///
/// `Type`s are owned by `Context` instances such that only one instance of a
/// specific `Type` exists per `Context`, e.g. only 1 `Type` for `i64` exists
/// per context. `Type`s are also never mutated and never destroyed, living for
/// the lifetime of the `Context` that owns them.
// TODO: can this be made into an unsized type?
pub struct Type(LLVMType);

impl<'a> Into<&'a Type> for LLVMTypeRef {
    fn into(self) -> &'a Type {
        unsafe { transmute::<LLVMTypeRef, &Type>(self) }
    }
}

impl<'a> From<&'a Type> for LLVMTypeRef {
    fn from(ty: &'a Type) -> LLVMTypeRef {
        unsafe { transmute::<&Type, LLVMTypeRef>(ty) }
    }
}

impl Type {
    pub fn kind(&self) -> Kind {
        unsafe { transmute(LLVMGetTypeKind(self.into())) }
    }

    pub fn is_sized(&self) -> bool {
        unsafe { LLVMTypeIsSized(self.into()) == 1 }
    }
}

// This counts as the llvm::Type::print method from the C++ API, though the C++
// version has more options.
impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let s_ptr = LLVMPrintTypeToString(self.into());
            let r = write!(
                f,
                "{}",
                c_str_to_str!(s_ptr)
            );
            LLVMDisposeMessage(s_ptr);
            r
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "llvm::Type({})", self)
    }
}

impl PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        LLVMTypeRef::from(self) == LLVMTypeRef::from(other)
    }
}

impl Eq for Type {}

macro_rules! impl_type {
    ($t:ty) => {
        impl<'a> Into<&'a $t> for LLVMTypeRef {
            fn into(self) -> &'a $t {
                unsafe { transmute::<LLVMTypeRef, &$t>(self) }
            }
        }

        impl<'a> From<&'a $t> for LLVMTypeRef {
            fn from(ty: &'a $t) -> LLVMTypeRef {
                unsafe { transmute::<&$t, LLVMTypeRef>(ty) }
            }
        }

        impl Deref for $t {
            type Target = Type;

            fn deref(&self) -> &Self::Target {
                unsafe { transmute::<&Self, &Self::Target>(self) }
            }
        }
    }
}

// Base types:

pub struct Void(Type);
impl_type!(Void);

pub struct Half(Type);
impl_type!(Half);

pub struct Float(Type);
impl_type!(Float);

pub struct Double(Type);
impl_type!(Double);

#[allow(non_camel_case_types)]
pub struct X86_FP80(Type);
impl_type!(X86_FP80);

#[allow(non_camel_case_types)]
pub struct FP128(Type);
impl_type!(FP128);

#[allow(non_camel_case_types)]
pub struct PPC_FP128(Type);
impl_type!(PPC_FP128);

pub struct Label(Type);
impl_type!(Label);

pub struct Metadata(Type);
impl_type!(Metadata);

#[allow(non_camel_case_types)]
pub struct X86_MMX(Type);
impl_type!(X86_MMX);

pub struct Token(Type);
impl_type!(Token);

/// Integer types are constructed with a size. Construct them with the methods
/// that `Context` provides.

pub struct Integer(Type);
impl_type!(Integer);

/// A function type is a tuple consisting of a return type and an array of
/// parameter types.
// TODO: check how varargs work

pub struct Function(Type);
impl_type!(Function);

impl Function {
    pub fn new<'a>(return_type: &'a Type, param_types: &[&'a Type], is_var_args: bool) -> &'a Function {
        unsafe {
            LLVMFunctionType(
                return_type.into(),
                transmute::<*const &Type, *mut LLVMTypeRef>(param_types.as_ptr()),
                param_types.len() as u32,
                is_var_args as LLVMBool
            ).into()
        }
    }
}

// TODO: Struct, Array, Pointer, Vector

/// Represents a LLVM Context Type
pub trait ContextType {
    fn get_type_in_context<'a>(context: &'a Context) -> &'a Type;
}

macro_rules! impl_context_type {
    ($t: ty, $to_type_in_context: ident) => {
        impl ContextType for $t {
            fn get_type_in_context<'a>(context: &'a Context) -> &'a Type {
                unsafe {
                    $to_type_in_context(context.ptr).into()
                }
            }
        }
    }
}

impl_context_type!(bool, LLVMInt1TypeInContext);
// This might actually not be true, Not sure
impl_context_type!(char, LLVMInt8TypeInContext);
impl_context_type!(u8, LLVMInt8TypeInContext);
impl_context_type!(u16, LLVMInt16TypeInContext);
impl_context_type!(u32, LLVMInt32TypeInContext);
impl_context_type!(u64, LLVMInt64TypeInContext);
impl_context_type!(i8, LLVMInt8TypeInContext);
impl_context_type!(i16, LLVMInt16TypeInContext);
impl_context_type!(i32, LLVMInt32TypeInContext);
impl_context_type!(i64, LLVMInt64TypeInContext);
impl_context_type!(f32, LLVMFloatTypeInContext);
impl_context_type!(f64, LLVMDoubleTypeInContext);
//TODO: Function Types
//TODO: Structure Types
//TODO: Sequential Types
//TODO: Other Types
<commit_msg>rustfmt < types.rs<commit_after>use std::fmt;
use std::mem::transmute;
use std::ops::Deref;

use llvm_sys::prelude::*;
use llvm_sys::core::*;
use llvm_sys::*;

use super::*;

/// Enumeration of all the base types of the LLVM type system.
#[allow(non_camel_case_types)]
#[repr(C)]
pub enum Kind {
    Void = 0,
    Half,
    Float,
    Double,
    X86_FP80,
    FP128,
    PPC_FP128,
    Label,
    Metadata,
    X86_MMX,
    Token,

    Integer,
    Function,
    Struct,
    Array,
    Pointer,
    Vector,
}

/// Should always be used as `&Type`.
///
/// `Type`s are owned by `Context` instances such that only one instance of a
/// specific `Type` exists per `Context`, e.g. only 1 `Type` for `i64` exists
/// per context. `Type`s are also never mutated and never destroyed, living for
/// the lifetime of the `Context` that owns them.
// TODO: can this be made into an unsized type?
pub struct Type(LLVMType);

impl<'a> Into<&'a Type> for LLVMTypeRef {
    fn into(self) -> &'a Type {
        unsafe { transmute::<LLVMTypeRef, &Type>(self) }
    }
}

impl<'a> From<&'a Type> for LLVMTypeRef {
    fn from(ty: &'a Type) -> LLVMTypeRef {
        unsafe { transmute::<&Type, LLVMTypeRef>(ty) }
    }
}

impl Type {
    pub fn kind(&self) -> Kind {
        unsafe { transmute(LLVMGetTypeKind(self.into())) }
    }

    pub fn is_sized(&self) -> bool {
        unsafe { LLVMTypeIsSized(self.into()) == 1 }
    }
}

// This counts as the llvm::Type::print method from the C++ API, though the C++
// version has more options.
impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let s_ptr = LLVMPrintTypeToString(self.into());
            let r = write!(f, "{}", c_str_to_str!(s_ptr));
            LLVMDisposeMessage(s_ptr);
            r
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "llvm::Type({})", self)
    }
}

impl PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        LLVMTypeRef::from(self) == LLVMTypeRef::from(other)
    }
}

impl Eq for Type {}

macro_rules! impl_type {
    ($t:ty) => {
        impl<'a> Into<&'a $t> for LLVMTypeRef {
            fn into(self) -> &'a $t {
                unsafe { transmute::<LLVMTypeRef, &$t>(self) }
            }
        }

        impl<'a> From<&'a $t> for LLVMTypeRef {
            fn from(ty: &'a $t) -> LLVMTypeRef {
                unsafe { transmute::<&$t, LLVMTypeRef>(ty) }
            }
        }

        impl Deref for $t {
            type Target = Type;

            fn deref(&self) -> &Self::Target {
                unsafe { transmute::<&Self, &Self::Target>(self) }
            }
        }
    }
}

// Base types:

pub struct Void(Type);
impl_type!(Void);

pub struct Half(Type);
impl_type!(Half);

pub struct Float(Type);
impl_type!(Float);

pub struct Double(Type);
impl_type!(Double);

#[allow(non_camel_case_types)]
pub struct X86_FP80(Type);
impl_type!(X86_FP80);

#[allow(non_camel_case_types)]
pub struct FP128(Type);
impl_type!(FP128);

#[allow(non_camel_case_types)]
pub struct PPC_FP128(Type);
impl_type!(PPC_FP128);

pub struct Label(Type);
impl_type!(Label);

pub struct Metadata(Type);
impl_type!(Metadata);

#[allow(non_camel_case_types)]
pub struct X86_MMX(Type);
impl_type!(X86_MMX);

pub struct Token(Type);
impl_type!(Token);

/// Integer types are constructed with a size. Construct them with the methods
/// that `Context` provides.
pub struct Integer(Type);
impl_type!(Integer);

/// A function type is a tuple consisting of a return type and an array of
/// parameter types.
// TODO: check how varargs work

pub struct Function(Type);
impl_type!(Function);

impl Function {
    pub fn new<'a>(
        return_type: &'a Type,
        param_types: &[&'a Type],
        is_var_args: bool,
    ) -> &'a Function {
        unsafe {
            LLVMFunctionType(
                return_type.into(),
                transmute::<*const &Type, *mut LLVMTypeRef>(param_types.as_ptr()),
                param_types.len() as u32,
                is_var_args as LLVMBool,
            ).into()
        }
    }
}

// TODO: Struct, Array, Pointer, Vector

/// Represents a LLVM Context Type
pub trait ContextType {
    fn get_type_in_context<'a>(context: &'a Context) -> &'a Type;
}

macro_rules! impl_context_type {
    ($t: ty, $to_type_in_context: ident) => {
        impl ContextType for $t {
            fn get_type_in_context<'a>(context: &'a Context) -> &'a Type {
                unsafe {
                    $to_type_in_context(context.ptr).into()
                }
            }
        }
    }
}

impl_context_type!(bool, LLVMInt1TypeInContext);
// This might actually not be true, Not sure
impl_context_type!(char, LLVMInt8TypeInContext);
impl_context_type!(u8, LLVMInt8TypeInContext);
impl_context_type!(u16, LLVMInt16TypeInContext);
impl_context_type!(u32, LLVMInt32TypeInContext);
impl_context_type!(u64, LLVMInt64TypeInContext);
impl_context_type!(i8, LLVMInt8TypeInContext);
impl_context_type!(i16, LLVMInt16TypeInContext);
impl_context_type!(i32, LLVMInt32TypeInContext);
impl_context_type!(i64, LLVMInt64TypeInContext);
impl_context_type!(f32, LLVMFloatTypeInContext);
impl_context_type!(f64, LLVMDoubleTypeInContext);
//TODO: Function Types
//TODO: Structure Types
//TODO: Sequential Types
//TODO: Other Types
<|endoftext|>


<commit_before>

use syntax::ptr::P;
use syntax::ast;
use syntax::ast::*;
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use syntax::codemap::Span;

/// Handles all the linting of funky types
#[allow(missing_copy_implementations)]
pub struct TypePass;

declare_lint!(pub BOX_VEC, Warn,
              "Warn on usage of Box<Vec<T>>");
declare_lint!(pub LINKEDLIST, Warn,
              "Warn on usage of LinkedList");

/// Matches a type with a provided string, and returns its type parameters if successful
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
    match ty.node {
        TyPath(_, Path {segments: ref seg, ..}) => {
            // So ast::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.as_str() == *b) {
                match seg[..].last() {
                    Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
                        Some(&a.types[..])
                    }
                    _ => None
                }
            } else {
                None
            }
        },
        _ => None
    }
}

/// Lets me span a note only if the lint is shown
pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, note: &str) {
    cx.span_lint(lint, span, msg);
    if cx.current_level(lint) != Level::Allow {
        cx.sess().span_note(span, note);
    }
}

impl LintPass for TypePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(BOX_VEC, LINKEDLIST)
    }

    fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) {
        {
            // In case stuff gets moved around
            use std::boxed::Box;
            use std::vec::Vec;
        }
        match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first())
          .map(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"]))
          .map(|_| {
            span_note_and_lint(cx, BOX_VEC, ty.span,
                              "You seem to be trying to use Box<Vec<T>>. Did you mean to use Vec<T>?",
                              "Vec<T> is already on the heap, Box<Vec<T>> makes an extra allocation");
          });
        {
            // In case stuff gets moved around
            use collections::linked_list::LinkedList as DL1;
            use std::collections::linked_list::LinkedList as DL2;
            use std::collections::linked_list::LinkedList as DL3;
        }
        let dlists = [vec!["std","collections","linked_list","LinkedList"],
                      vec!["std","collections","linked_list","LinkedList"],
                      vec!["collections","linked_list","LinkedList"]];
        for path in dlists.iter() {
            if match_ty_unwrap(ty, &path[..]).is_some() {
                span_note_and_lint(cx, LINKEDLIST, ty.span,
                                   "I see you're using a LinkedList! Perhaps you meant some other data structure?",
                                   "A RingBuf might work.");
                return;
            }
        }
    }
}
<commit_msg>Fix Box<Vec<T>> test.<commit_after>

use syntax::ptr::P;
use syntax::ast;
use syntax::ast::*;
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use syntax::codemap::Span;

/// Handles all the linting of funky types
#[allow(missing_copy_implementations)]
pub struct TypePass;

declare_lint!(pub BOX_VEC, Warn,
              "Warn on usage of Box<Vec<T>>");
declare_lint!(pub LINKEDLIST, Warn,
              "Warn on usage of LinkedList");

/// Matches a type with a provided string, and returns its type parameters if successful
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
    match ty.node {
        TyPath(_, Path {segments: ref seg, ..}) => {
            // So ast::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.as_str() == *b) {
                match seg[..].last() {
                    Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
                        Some(&a.types[..])
                    }
                    _ => None
                }
            } else {
                None
            }
        },
        _ => None
    }
}

/// Lets me span a note only if the lint is shown
pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, note: &str) {
    cx.span_lint(lint, span, msg);
    if cx.current_level(lint) != Level::Allow {
        cx.sess().span_note(span, note);
    }
}

impl LintPass for TypePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(BOX_VEC, LINKEDLIST)
    }

    fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) {
        {
            // In case stuff gets moved around
            use std::boxed::Box;
            use std::vec::Vec;
        }
        match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first())
          .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"]))
          .map(|_| {
            span_note_and_lint(cx, BOX_VEC, ty.span,
                              "You seem to be trying to use Box<Vec<T>>. Did you mean to use Vec<T>?",
                              "Vec<T> is already on the heap, Box<Vec<T>> makes an extra allocation");
          });
        {
            // In case stuff gets moved around
            use collections::linked_list::LinkedList as DL1;
            use std::collections::linked_list::LinkedList as DL2;
            use std::collections::linked_list::LinkedList as DL3;
        }
        let dlists = [vec!["std","collections","linked_list","LinkedList"],
                      vec!["std","collections","linked_list","LinkedList"],
                      vec!["collections","linked_list","LinkedList"]];
        for path in dlists.iter() {
            if match_ty_unwrap(ty, &path[..]).is_some() {
                span_note_and_lint(cx, LINKEDLIST, ty.span,
                                   "I see you're using a LinkedList! Perhaps you meant some other data structure?",
                                   "A RingBuf might work.");
                return;
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]
#![deny(clippy)]

/// Test that we lint if we use a binding with a single leading underscore
fn prefix_underscore(_foo: u32) -> u32 {
    _foo + 1 //~ ERROR used binding which is prefixed with an underscore
}

/// Test that we lint even if the use is within a macro expansion
fn in_macro(_foo: u32) {
    println!("{}", _foo); //~ ERROR used binding which is prefixed with an underscore
}

/// Test that we do not lint if the underscore is not a prefix
fn non_prefix_underscore(some_foo: u32) -> u32 {
    some_foo + 1
}

/// Test that we do not lint if we do not use the binding (simple case)
fn unused_underscore_simple(_foo: u32) -> u32 {
    1
}

#[deny(unused_variables)]
/// Test that we do not lint if we do not use the binding (complex case). This checks for
/// compatibility with the built-in `unused_variables` lint.
fn unused_underscore_complex(mut _foo: u32) -> u32 {
    _foo += 1;
    _foo = 2;
    1
}

///Test that we do not lint for multiple underscores
fn multiple_underscores(__foo: u32) -> u32 {
    __foo + 1
}

// Non-variable bindings with preceding underscore
fn _fn_test() {}
struct _StructTest;
enum _EnumTest {
    _FieldA,
    _FieldB(_StructTest)
}

/// Test that we do not lint for non-variable bindings
fn non_variables() {
    _fn_test();
    let _s = _StructTest;
    let _e = match _EnumTest::_FieldB(_StructTest) {
        _EnumTest::_FieldA => 0,
        _EnumTest::_FieldB(_st) => 1,
    };
    let f = _fn_test;
    f();
}

fn main() {
    let foo = 0u32;
    // tests of unused_underscore lint
    let _ = prefix_underscore(foo);
    in_macro(foo);
    // possible false positives
    let _ = non_prefix_underscore(foo);
    let _ = unused_underscore_simple(foo);
    let _ = unused_underscore_complex(foo);
    let _ = multiple_underscores(foo);
    non_variables();
}
<commit_msg>Add test for struct fields<commit_after>#![feature(plugin)]
#![plugin(clippy)]
#![deny(clippy)]

/// Test that we lint if we use a binding with a single leading underscore
fn prefix_underscore(_foo: u32) -> u32 {
    _foo + 1 //~ ERROR used binding which is prefixed with an underscore
}

/// Test that we lint even if the use is within a macro expansion
fn in_macro(_foo: u32) {
    println!("{}", _foo); //~ ERROR used binding which is prefixed with an underscore
}

// Struct for testing use of fields prefixed with an underscore
struct StructFieldTest {
    _underscore_field: u32,
}

/// Test that we lint the use of a struct field which is prefixed with an underscore
fn in_struct_field() {
    let mut s = StructFieldTest { _underscore_field: 0 };
    s._underscore_field += 1; //~ Error used binding which is prefixed with an underscore
}

/// Test that we do not lint if the underscore is not a prefix
fn non_prefix_underscore(some_foo: u32) -> u32 {
    some_foo + 1
}

/// Test that we do not lint if we do not use the binding (simple case)
fn unused_underscore_simple(_foo: u32) -> u32 {
    1
}

/// Test that we do not lint if we do not use the binding (complex case). This checks for
/// compatibility with the built-in `unused_variables` lint.
fn unused_underscore_complex(mut _foo: u32) -> u32 {
    _foo += 1;
    _foo = 2;
    1
}

///Test that we do not lint for multiple underscores
fn multiple_underscores(__foo: u32) -> u32 {
    __foo + 1
}

// Non-variable bindings with preceding underscore
fn _fn_test() {}
struct _StructTest;
enum _EnumTest {
    _FieldA,
    _FieldB(_StructTest)
}

/// Test that we do not lint for non-variable bindings
fn non_variables() {
    _fn_test();
    let _s = _StructTest;
    let _e = match _EnumTest::_FieldB(_StructTest) {
        _EnumTest::_FieldA => 0,
        _EnumTest::_FieldB(_st) => 1,
    };
    let f = _fn_test;
    f();
}

fn main() {
    let foo = 0u32;
    // tests of unused_underscore lint
    let _ = prefix_underscore(foo);
    in_macro(foo);
    in_struct_field();
    // possible false positives
    let _ = non_prefix_underscore(foo);
    let _ = unused_underscore_simple(foo);
    let _ = unused_underscore_complex(foo);
    let _ = multiple_underscores(foo);
    non_variables();
}
<|endoftext|>


<commit_before>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 super::*;
use block::{Block, RcBlock};
use std::mem;

#[cfg(feature = "dispatch_queue")]
use dispatch;

type MTLSharedEventNotificationBlock<'a> = RcBlock<(&'a SharedEventRef, u64), ()>;

pub enum MTLEvent {}

foreign_obj_type! {
    type CType = MTLEvent;
    pub struct Event;
    pub struct EventRef;
}

impl EventRef {
    pub fn device(&self) -> &DeviceRef {
        unsafe { msg_send![self, device] }
    }
}

pub enum MTLSharedEvent {}

foreign_obj_type! {
    type CType = MTLSharedEvent;
    pub struct SharedEvent;
    pub struct SharedEventRef;
    type ParentType = EventRef;
}

impl SharedEventRef {
    pub fn signaled_value(&self) -> u64 {
        unsafe { msg_send![self, signaledValue] }
    }

    pub fn set_signaled_value(&self, new_value: u64) {
        unsafe { msg_send![self, setSignaledValue: new_value] }
    }

    /// Schedules a notification handler to be called after the shareable event’s signal value
    /// equals or exceeds a given value.
    pub fn notify(
        &self,
        listener: &SharedEventListenerRef,
        value: u64,
        block: MTLSharedEventNotificationBlock,
    ) {
        unsafe {
            // If the block doesn't have a signature, this segfaults.
            // Taken from https://github.com/servo/pathfinder/blob/e858c8dc1d8ff02a5b603e21e09a64d6b3e11327/metal/src/lib.rs#L2327
            let block = mem::transmute::<
                MTLSharedEventNotificationBlock,
                *mut BlockBase<(&SharedEventRef, u64), ()>,
            >(block);
            (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE;
            (*block).extra = &BLOCK_EXTRA;
            let () = msg_send![self, notifyListener:listener atValue:value block:block];
            mem::forget(block);
        }

        extern "C" fn dtor(_: *mut BlockBase<(&SharedEventRef, u64), ()>) {}

        const SIGNATURE: &[u8] = b"v16@?0Q8\0";
        const SIGNATURE_PTR: *const i8 = &SIGNATURE[0] as *const u8 as *const i8;
        static mut BLOCK_EXTRA: BlockExtra<(&SharedEventRef, u64), ()> = BlockExtra {
            unknown0: 0 as *mut i32,
            unknown1: 0 as *mut i32,
            unknown2: 0 as *mut i32,
            dtor,
            signature: &SIGNATURE_PTR,
        };
    }
}

pub enum MTLSharedEventListener {}

foreign_obj_type! {
    type CType = MTLSharedEventListener;
    pub struct SharedEventListener;
    pub struct SharedEventListenerRef;
}

impl SharedEventListener {
    pub unsafe fn from_queue_handle(queue: dispatch_queue_t) -> Self {
        let listener: SharedEventListener = msg_send![class!(MTLSharedEventListener), alloc];
        let ptr: *mut Object = msg_send![listener.as_ref(), initWithDispatchQueue: queue];
        if ptr.is_null() {
            panic!("[MTLSharedEventListener alloc] initWithDispatchQueue failed");
        }
        listener
    }

    #[cfg(feature = "dispatch")]
    pub fn from_queue(queue: &dispatch::Queue) -> Self {
        unsafe {
            let raw_queue = std::mem::transmute::<&dispatch::Queue, *const dispatch_queue_t>(queue);
            Self::from_queue_handle(*raw_queue)
        }
    }
}

pub enum MTLFence {}

foreign_obj_type! {
    type CType = MTLFence;
    pub struct Fence;
    pub struct FenceRef;
}

impl FenceRef {
    pub fn device(&self) -> &DeviceRef {
        unsafe { msg_send![self, device] }
    }

    pub fn label(&self) -> &str {
        unsafe {
            let label = msg_send![self, label];
            crate::nsstring_as_str(label)
        }
    }

    pub fn set_label(&self, label: &str) {
        unsafe {
            let nslabel = crate::nsstring_from_str(label);
            let () = msg_send![self, setLabel: nslabel];
        }
    }
}

#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLRenderStages {
    Vertex = 0,
    Fragment = 1,
}

const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000;
const BLOCK_HAS_SIGNATURE: i32 = 0x40000000;

#[repr(C)]
struct BlockBase<A, R> {
    isa: *const std::ffi::c_void,                             // 0x00
    flags: i32,                                               // 0x08
    _reserved: i32,                                           // 0x0c
    invoke: unsafe extern "C" fn(*mut Block<A, R>, ...) -> R, // 0x10
    extra: *const BlockExtra<A, R>,                           // 0x18
}

type BlockExtraDtor<A, R> = extern "C" fn(*mut BlockBase<A, R>);

#[repr(C)]
struct BlockExtra<A, R> {
    unknown0: *mut i32,          // 0x00
    unknown1: *mut i32,          // 0x08
    unknown2: *mut i32,          // 0x10
    dtor: BlockExtraDtor<A, R>,  // 0x18
    signature: *const *const i8, // 0x20
}
<commit_msg>Fix incorrect MTLRenderStages constants<commit_after>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 super::*;
use block::{Block, RcBlock};
use std::mem;

#[cfg(feature = "dispatch_queue")]
use dispatch;

type MTLSharedEventNotificationBlock<'a> = RcBlock<(&'a SharedEventRef, u64), ()>;

pub enum MTLEvent {}

foreign_obj_type! {
    type CType = MTLEvent;
    pub struct Event;
    pub struct EventRef;
}

impl EventRef {
    pub fn device(&self) -> &DeviceRef {
        unsafe { msg_send![self, device] }
    }
}

pub enum MTLSharedEvent {}

foreign_obj_type! {
    type CType = MTLSharedEvent;
    pub struct SharedEvent;
    pub struct SharedEventRef;
    type ParentType = EventRef;
}

impl SharedEventRef {
    pub fn signaled_value(&self) -> u64 {
        unsafe { msg_send![self, signaledValue] }
    }

    pub fn set_signaled_value(&self, new_value: u64) {
        unsafe { msg_send![self, setSignaledValue: new_value] }
    }

    /// Schedules a notification handler to be called after the shareable event’s signal value
    /// equals or exceeds a given value.
    pub fn notify(
        &self,
        listener: &SharedEventListenerRef,
        value: u64,
        block: MTLSharedEventNotificationBlock,
    ) {
        unsafe {
            // If the block doesn't have a signature, this segfaults.
            // Taken from https://github.com/servo/pathfinder/blob/e858c8dc1d8ff02a5b603e21e09a64d6b3e11327/metal/src/lib.rs#L2327
            let block = mem::transmute::<
                MTLSharedEventNotificationBlock,
                *mut BlockBase<(&SharedEventRef, u64), ()>,
            >(block);
            (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE;
            (*block).extra = &BLOCK_EXTRA;
            let () = msg_send![self, notifyListener:listener atValue:value block:block];
            mem::forget(block);
        }

        extern "C" fn dtor(_: *mut BlockBase<(&SharedEventRef, u64), ()>) {}

        const SIGNATURE: &[u8] = b"v16@?0Q8\0";
        const SIGNATURE_PTR: *const i8 = &SIGNATURE[0] as *const u8 as *const i8;
        static mut BLOCK_EXTRA: BlockExtra<(&SharedEventRef, u64), ()> = BlockExtra {
            unknown0: 0 as *mut i32,
            unknown1: 0 as *mut i32,
            unknown2: 0 as *mut i32,
            dtor,
            signature: &SIGNATURE_PTR,
        };
    }
}

pub enum MTLSharedEventListener {}

foreign_obj_type! {
    type CType = MTLSharedEventListener;
    pub struct SharedEventListener;
    pub struct SharedEventListenerRef;
}

impl SharedEventListener {
    pub unsafe fn from_queue_handle(queue: dispatch_queue_t) -> Self {
        let listener: SharedEventListener = msg_send![class!(MTLSharedEventListener), alloc];
        let ptr: *mut Object = msg_send![listener.as_ref(), initWithDispatchQueue: queue];
        if ptr.is_null() {
            panic!("[MTLSharedEventListener alloc] initWithDispatchQueue failed");
        }
        listener
    }

    #[cfg(feature = "dispatch")]
    pub fn from_queue(queue: &dispatch::Queue) -> Self {
        unsafe {
            let raw_queue = std::mem::transmute::<&dispatch::Queue, *const dispatch_queue_t>(queue);
            Self::from_queue_handle(*raw_queue)
        }
    }
}

pub enum MTLFence {}

foreign_obj_type! {
    type CType = MTLFence;
    pub struct Fence;
    pub struct FenceRef;
}

impl FenceRef {
    pub fn device(&self) -> &DeviceRef {
        unsafe { msg_send![self, device] }
    }

    pub fn label(&self) -> &str {
        unsafe {
            let label = msg_send![self, label];
            crate::nsstring_as_str(label)
        }
    }

    pub fn set_label(&self, label: &str) {
        unsafe {
            let nslabel = crate::nsstring_from_str(label);
            let () = msg_send![self, setLabel: nslabel];
        }
    }
}

#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLRenderStages {
    Vertex = 1,
    Fragment = 2,
}

const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000;
const BLOCK_HAS_SIGNATURE: i32 = 0x40000000;

#[repr(C)]
struct BlockBase<A, R> {
    isa: *const std::ffi::c_void,                             // 0x00
    flags: i32,                                               // 0x08
    _reserved: i32,                                           // 0x0c
    invoke: unsafe extern "C" fn(*mut Block<A, R>, ...) -> R, // 0x10
    extra: *const BlockExtra<A, R>,                           // 0x18
}

type BlockExtraDtor<A, R> = extern "C" fn(*mut BlockBase<A, R>);

#[repr(C)]
struct BlockExtra<A, R> {
    unknown0: *mut i32,          // 0x00
    unknown1: *mut i32,          // 0x08
    unknown2: *mut i32,          // 0x10
    dtor: BlockExtraDtor<A, R>,  // 0x18
    signature: *const *const i8, // 0x20
}
<|endoftext|>


<commit_before>use std::collections::BinaryHeap;
use std::cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering};
use std::sync::{Arc, Mutex, Condvar};
use std::thread::Thread;
use std::thunk::Thunk;
use std::time::Duration;

use time;

enum JobType {
    Once(Thunk<'static>),
    FixedRate {
        f: Box<FnMut() + Send + 'static>,
        rate: Duration,
    },
}

struct Job {
    type_: JobType,
    time: u64,
}

impl PartialOrd for Job {
    fn partial_cmp(&self, other: &Job) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Job {
    fn cmp(&self, other: &Job) -> Ordering {
        // reverse because BinaryHeap's a max heap
        self.time.cmp(&other.time).reverse()
    }
}

impl PartialEq for Job {
    fn eq(&self, other: &Job) -> bool {
        self.time == other.time
    }
}

impl Eq for Job {}

struct InnerPool {
    queue: BinaryHeap<Job>,
    shutdown: bool,
}

struct SharedPool {
    inner: Mutex<InnerPool>,
    cvar: Condvar,
}

impl SharedPool {
    fn run(&self, job: Job) {
        let mut inner = self.inner.lock().unwrap();

        // Calls from the pool itself will never hit this, but calls from workers might
        if inner.shutdown {
            return;
        }

        match inner.queue.peek() {
            None => self.cvar.notify_all(),
            Some(e) if e.time > job.time => self.cvar.notify_all(),
            _ => {}
        };
        inner.queue.push(job);
    }
}

pub struct ScheduledThreadPool {
    shared: Arc<SharedPool>,
}

impl Drop for ScheduledThreadPool {
    fn drop(&mut self) {
        self.shared.inner.lock().unwrap().shutdown = true;
        self.shared.cvar.notify_all();
    }
}

impl ScheduledThreadPool {
    pub fn new(size: usize) -> ScheduledThreadPool {
        assert!(size > 0, "size must be positive");

        let inner = InnerPool {
            queue: BinaryHeap::new(),
            shutdown: false,
        };

        let shared = SharedPool {
            inner: Mutex::new(inner),
            cvar: Condvar::new(),
        };

        let pool = ScheduledThreadPool {
            shared: Arc::new(shared),
        };

        for _ in (0..size) {
            let mut worker = Worker {
                shared: pool.shared.clone(),
            };

            Thread::spawn(move || worker.run());
        }

        pool
    }

    #[allow(unused)]
    pub fn run<F>(&self, job: F) where F: FnOnce() + Send + 'static {
        self.run_after(Duration::zero(), job)
    }

    pub fn run_after<F>(&self, dur: Duration, job: F) where F: FnOnce() + Send + 'static {
        let job = Job {
            type_: JobType::Once(Thunk::new(job)),
            time: (time::precise_time_ns() as i64 + dur.num_nanoseconds().unwrap()) as u64,
        };
        self.shared.run(job)
    }

    #[allow(unused)]
    pub fn run_at_fixed_rate<F>(&self, rate: Duration, f: F) where F: FnMut() + Send + 'static {
        let job = Job {
            type_: JobType::FixedRate { f: Box::new(f), rate: rate },
            time: (time::precise_time_ns() as i64 + rate.num_nanoseconds().unwrap()) as u64,
        };
        self.shared.run(job)
    }

    pub fn clear(&self) {
        self.shared.inner.lock().unwrap().queue.clear();
    }
}

struct Worker {
    shared: Arc<SharedPool>,
}

impl Drop for Worker {
    fn drop(&mut self) {
        // Start up a new worker if this one's going away due to a panic from a job
        if Thread::panicking() {
            let mut worker = Worker {
                shared: self.shared.clone(),
            };
            Thread::spawn(move || worker.run());
        }
    }
}

impl Worker {
    fn run(&mut self) {
        loop {
            match self.get_job() {
                Some(job) => self.run_job(job),
                None => break,
            }
        }
    }

    fn get_job(&self) -> Option<Job> {
        enum Need {
            Wait,
            WaitTimeout(Duration),
        }

        let mut inner = self.shared.inner.lock().unwrap();
        loop {
            let now = time::precise_time_ns();

            let need = match inner.queue.peek() {
                None if inner.shutdown => return None,
                None => Need::Wait,
                Some(e) if e.time <= now => break,
                Some(e) => Need::WaitTimeout(Duration::nanoseconds(e.time as i64 - now as i64)),
            };

            inner = match need {
                Need::Wait => self.shared.cvar.wait(inner).unwrap(),
                Need::WaitTimeout(t) => self.shared.cvar.wait_timeout(inner, t).unwrap().0,
            };
        }

        Some(inner.queue.pop().unwrap())
    }

    fn run_job(&self, job: Job) {
        match job.type_ {
            JobType::Once(f) => f.invoke(()),
            JobType::FixedRate { mut f, rate } => {
                f();
                let new_job = Job {
                    type_: JobType::FixedRate { f: f, rate: rate },
                    time: (job.time as i64 + rate.num_nanoseconds().unwrap()) as u64,
                };
                self.shared.run(new_job)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::iter::AdditiveIterator;
    use std::sync::mpsc::channel;
    use std::sync::{Arc, Barrier};
    use std::time::Duration;

    use super::ScheduledThreadPool;

    const TEST_TASKS: usize = 4;

    #[test]
    fn test_works() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);

        let (tx, rx) = channel();
        for _ in range(0, TEST_TASKS) {
            let tx = tx.clone();
            pool.run(move|| {
                tx.send(1us).unwrap();
            });
        }

        assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS);
    }

    #[test]
    #[should_fail(expected = "size must be positive")]
    fn test_zero_tasks_panic() {
        ScheduledThreadPool::new(0);
    }

    #[test]
    fn test_recovery_from_subtask_panic() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);

        // Panic all the existing threads.
        let waiter = Arc::new(Barrier::new(TEST_TASKS as usize));
        for _ in range(0, TEST_TASKS) {
            let waiter = waiter.clone();
            pool.run(move || -> () {
                waiter.wait();
                panic!();
            });
        }

        // Ensure new threads were spawned to compensate.
        let (tx, rx) = channel();
        let waiter = Arc::new(Barrier::new(TEST_TASKS as usize));
        for _ in range(0, TEST_TASKS) {
            let tx = tx.clone();
            let waiter = waiter.clone();
            pool.run(move || {
                waiter.wait();
                tx.send(1us).unwrap();
            });
        }

        assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS);
    }

    #[test]
    fn test_run_after() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);
        let (tx, rx) = channel();

        let tx1 = tx.clone();
        pool.run_after(Duration::seconds(1), move || tx1.send(1us).unwrap());
        pool.run_after(Duration::milliseconds(500), move || tx.send(2us).unwrap());

        assert_eq!(2, rx.recv().unwrap());
        assert_eq!(1, rx.recv().unwrap());
    }

    #[test]
    fn test_jobs_complete_after_drop() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);
        let (tx, rx) = channel();

        let tx1 = tx.clone();
        pool.run_after(Duration::seconds(1), move || tx1.send(1us).unwrap());
        pool.run_after(Duration::milliseconds(500), move || tx.send(2us).unwrap());

        drop(pool);

        assert_eq!(2, rx.recv().unwrap());
        assert_eq!(1, rx.recv().unwrap());
    }

    #[test]
    fn test_fixed_delay_jobs_stop_after_drop() {
        let pool = Arc::new(ScheduledThreadPool::new(TEST_TASKS));
        let (tx, rx) = channel();
        let (tx2, rx2) = channel();

        let mut pool2 = Some(pool.clone());
        let mut i = 0i32;
        pool.run_at_fixed_rate(Duration::milliseconds(500), move || {
            i += 1;
            tx.send(i).unwrap();
            rx2.recv().unwrap();
            if i == 2 {
                drop(pool2.take().unwrap());
            }
        });
        drop(pool);

        assert_eq!(Ok(1), rx.recv());
        tx2.send(()).unwrap();
        assert_eq!(Ok(2), rx.recv());
        tx2.send(()).unwrap();
        assert!(rx.recv().is_err());
    }
}
<commit_msg>Suffixes "us" and "is" are now "usize" and "isize"<commit_after>use std::collections::BinaryHeap;
use std::cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering};
use std::sync::{Arc, Mutex, Condvar};
use std::thread::Thread;
use std::thunk::Thunk;
use std::time::Duration;

use time;

enum JobType {
    Once(Thunk<'static>),
    FixedRate {
        f: Box<FnMut() + Send + 'static>,
        rate: Duration,
    },
}

struct Job {
    type_: JobType,
    time: u64,
}

impl PartialOrd for Job {
    fn partial_cmp(&self, other: &Job) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Job {
    fn cmp(&self, other: &Job) -> Ordering {
        // reverse because BinaryHeap's a max heap
        self.time.cmp(&other.time).reverse()
    }
}

impl PartialEq for Job {
    fn eq(&self, other: &Job) -> bool {
        self.time == other.time
    }
}

impl Eq for Job {}

struct InnerPool {
    queue: BinaryHeap<Job>,
    shutdown: bool,
}

struct SharedPool {
    inner: Mutex<InnerPool>,
    cvar: Condvar,
}

impl SharedPool {
    fn run(&self, job: Job) {
        let mut inner = self.inner.lock().unwrap();

        // Calls from the pool itself will never hit this, but calls from workers might
        if inner.shutdown {
            return;
        }

        match inner.queue.peek() {
            None => self.cvar.notify_all(),
            Some(e) if e.time > job.time => self.cvar.notify_all(),
            _ => {}
        };
        inner.queue.push(job);
    }
}

pub struct ScheduledThreadPool {
    shared: Arc<SharedPool>,
}

impl Drop for ScheduledThreadPool {
    fn drop(&mut self) {
        self.shared.inner.lock().unwrap().shutdown = true;
        self.shared.cvar.notify_all();
    }
}

impl ScheduledThreadPool {
    pub fn new(size: usize) -> ScheduledThreadPool {
        assert!(size > 0, "size must be positive");

        let inner = InnerPool {
            queue: BinaryHeap::new(),
            shutdown: false,
        };

        let shared = SharedPool {
            inner: Mutex::new(inner),
            cvar: Condvar::new(),
        };

        let pool = ScheduledThreadPool {
            shared: Arc::new(shared),
        };

        for _ in (0..size) {
            let mut worker = Worker {
                shared: pool.shared.clone(),
            };

            Thread::spawn(move || worker.run());
        }

        pool
    }

    #[allow(unused)]
    pub fn run<F>(&self, job: F) where F: FnOnce() + Send + 'static {
        self.run_after(Duration::zero(), job)
    }

    pub fn run_after<F>(&self, dur: Duration, job: F) where F: FnOnce() + Send + 'static {
        let job = Job {
            type_: JobType::Once(Thunk::new(job)),
            time: (time::precise_time_ns() as i64 + dur.num_nanoseconds().unwrap()) as u64,
        };
        self.shared.run(job)
    }

    #[allow(unused)]
    pub fn run_at_fixed_rate<F>(&self, rate: Duration, f: F) where F: FnMut() + Send + 'static {
        let job = Job {
            type_: JobType::FixedRate { f: Box::new(f), rate: rate },
            time: (time::precise_time_ns() as i64 + rate.num_nanoseconds().unwrap()) as u64,
        };
        self.shared.run(job)
    }

    pub fn clear(&self) {
        self.shared.inner.lock().unwrap().queue.clear();
    }
}

struct Worker {
    shared: Arc<SharedPool>,
}

impl Drop for Worker {
    fn drop(&mut self) {
        // Start up a new worker if this one's going away due to a panic from a job
        if Thread::panicking() {
            let mut worker = Worker {
                shared: self.shared.clone(),
            };
            Thread::spawn(move || worker.run());
        }
    }
}

impl Worker {
    fn run(&mut self) {
        loop {
            match self.get_job() {
                Some(job) => self.run_job(job),
                None => break,
            }
        }
    }

    fn get_job(&self) -> Option<Job> {
        enum Need {
            Wait,
            WaitTimeout(Duration),
        }

        let mut inner = self.shared.inner.lock().unwrap();
        loop {
            let now = time::precise_time_ns();

            let need = match inner.queue.peek() {
                None if inner.shutdown => return None,
                None => Need::Wait,
                Some(e) if e.time <= now => break,
                Some(e) => Need::WaitTimeout(Duration::nanoseconds(e.time as i64 - now as i64)),
            };

            inner = match need {
                Need::Wait => self.shared.cvar.wait(inner).unwrap(),
                Need::WaitTimeout(t) => self.shared.cvar.wait_timeout(inner, t).unwrap().0,
            };
        }

        Some(inner.queue.pop().unwrap())
    }

    fn run_job(&self, job: Job) {
        match job.type_ {
            JobType::Once(f) => f.invoke(()),
            JobType::FixedRate { mut f, rate } => {
                f();
                let new_job = Job {
                    type_: JobType::FixedRate { f: f, rate: rate },
                    time: (job.time as i64 + rate.num_nanoseconds().unwrap()) as u64,
                };
                self.shared.run(new_job)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::iter::AdditiveIterator;
    use std::sync::mpsc::channel;
    use std::sync::{Arc, Barrier};
    use std::time::Duration;

    use super::ScheduledThreadPool;

    const TEST_TASKS: usize = 4;

    #[test]
    fn test_works() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);

        let (tx, rx) = channel();
        for _ in range(0, TEST_TASKS) {
            let tx = tx.clone();
            pool.run(move|| {
                tx.send(1usize).unwrap();
            });
        }

        assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS);
    }

    #[test]
    #[should_fail(expected = "size must be positive")]
    fn test_zero_tasks_panic() {
        ScheduledThreadPool::new(0);
    }

    #[test]
    fn test_recovery_from_subtask_panic() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);

        // Panic all the existing threads.
        let waiter = Arc::new(Barrier::new(TEST_TASKS as usize));
        for _ in range(0, TEST_TASKS) {
            let waiter = waiter.clone();
            pool.run(move || -> () {
                waiter.wait();
                panic!();
            });
        }

        // Ensure new threads were spawned to compensate.
        let (tx, rx) = channel();
        let waiter = Arc::new(Barrier::new(TEST_TASKS as usize));
        for _ in range(0, TEST_TASKS) {
            let tx = tx.clone();
            let waiter = waiter.clone();
            pool.run(move || {
                waiter.wait();
                tx.send(1usize).unwrap();
            });
        }

        assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS);
    }

    #[test]
    fn test_run_after() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);
        let (tx, rx) = channel();

        let tx1 = tx.clone();
        pool.run_after(Duration::seconds(1), move || tx1.send(1usize).unwrap());
        pool.run_after(Duration::milliseconds(500), move || tx.send(2usize).unwrap());

        assert_eq!(2, rx.recv().unwrap());
        assert_eq!(1, rx.recv().unwrap());
    }

    #[test]
    fn test_jobs_complete_after_drop() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);
        let (tx, rx) = channel();

        let tx1 = tx.clone();
        pool.run_after(Duration::seconds(1), move || tx1.send(1usize).unwrap());
        pool.run_after(Duration::milliseconds(500), move || tx.send(2usize).unwrap());

        drop(pool);

        assert_eq!(2, rx.recv().unwrap());
        assert_eq!(1, rx.recv().unwrap());
    }

    #[test]
    fn test_fixed_delay_jobs_stop_after_drop() {
        let pool = Arc::new(ScheduledThreadPool::new(TEST_TASKS));
        let (tx, rx) = channel();
        let (tx2, rx2) = channel();

        let mut pool2 = Some(pool.clone());
        let mut i = 0i32;
        pool.run_at_fixed_rate(Duration::milliseconds(500), move || {
            i += 1;
            tx.send(i).unwrap();
            rx2.recv().unwrap();
            if i == 2 {
                drop(pool2.take().unwrap());
            }
        });
        drop(pool);

        assert_eq!(Ok(1), rx.recv());
        tx2.send(()).unwrap();
        assert_eq!(Ok(2), rx.recv());
        tx2.send(()).unwrap();
        assert!(rx.recv().is_err());
    }
}
<|endoftext|>


<commit_before>use std::slice;

use libc::{c_void, c_uint, c_double, c_int, size_t};

use symbols::{ZopfliGetDistExtraBits, ZopfliGetLengthExtraBits, ZopfliGetLengthSymbol, ZopfliGetDistSymbol, ZOPFLI_NUM_LL, ZOPFLI_NUM_D};

/// Cost model which should exactly match fixed tree.
/// type: CostModelFun
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn GetCostFixed(litlen: c_uint, dist: c_uint, _unused: c_void) -> c_double {
    let result = if dist == 0 {
        if litlen <= 143 {
            8
        } else {
            9
        }
    } else {
        let dbits = ZopfliGetDistExtraBits(dist as c_int);
        let lbits = ZopfliGetLengthExtraBits(litlen as c_int);
        let lsym = ZopfliGetLengthSymbol(litlen as c_int);
        let mut cost = 0;
        if lsym <= 279 {
            cost += 7;
        } else {
            cost += 8;
        }
        cost += 5;  // Every dist symbol has length 5.
        cost + dbits + lbits
    };
    result as c_double
}

/// Cost model based on symbol statistics.
/// type: CostModelFun
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn GetCostStat(litlen: c_uint, dist: c_uint, context: *const c_void) -> c_double {
    let stats = unsafe {
        assert!(!context.is_null());
        &*(context as *const SymbolStats)
    };
    if dist == 0 {
        stats.ll_symbols[litlen as usize]
    } else {
        let lsym = ZopfliGetLengthSymbol(litlen as c_int) as usize;
        let lbits = ZopfliGetLengthExtraBits(litlen as c_int) as c_double;
        let dsym = ZopfliGetDistSymbol(dist as c_int) as usize;
        let dbits = ZopfliGetDistExtraBits(dist as c_int) as c_double;
        stats.ll_symbols[lsym] + lbits + stats.d_symbols[dsym] + dbits
    }
}

#[repr(C)]
pub struct RanState {
    m_w: c_uint,
    m_z: c_uint,
}

#[repr(C)]
pub struct SymbolStats {
  /* The literal and length symbols. */
  litlens: [size_t; ZOPFLI_NUM_LL],
  /* The 32 unique dist symbols, not the 32768 possible dists. */
  dists: [size_t; ZOPFLI_NUM_D],

  /* Length of each lit/len symbol in bits. */
  ll_symbols: [c_double; ZOPFLI_NUM_LL],
  /* Length of each dist symbol in bits. */
  d_symbols: [c_double; ZOPFLI_NUM_D],
}

/// Get random number: "Multiply-With-Carry" generator of G. Marsaglia
pub fn random_marsaglia(state_ptr: *mut RanState) -> c_uint {
    let state = unsafe {
        assert!(!state_ptr.is_null());
        &mut *state_ptr
    };

    state.m_z = 36969 * (state.m_z & 65535) + (state.m_z >> 16);
    state.m_w = 18000 * (state.m_w & 65535) + (state.m_w >> 16);
    (state.m_z << 16) + state.m_w // 32-bit result.
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn InitRanState(state_ptr: *mut RanState) {
    let state = unsafe {
        assert!(!state_ptr.is_null());
        &mut *state_ptr
    };
    state.m_w = 1;
    state.m_z = 2;
}

pub fn randomize_freqs(state_ptr: *mut RanState, freqs_ptr: *mut size_t, n: c_int) {
    let freqs = unsafe {
        assert!(!freqs_ptr.is_null());
        slice::from_raw_parts_mut(freqs_ptr, n as usize)
    };
    let mut i: usize = 0;
    let end = n as usize;
    while i < end {
        if (random_marsaglia(state_ptr) >> 4) % 3 == 0 {
            let index = random_marsaglia(state_ptr) % n as c_uint;
            freqs[i] = freqs[index as usize];
        }
        i += 1;
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn RandomizeStatFreqs(state_ptr: *mut RanState, stats_ptr: *mut SymbolStats) {
    let stats = unsafe {
        assert!(!stats_ptr.is_null());
        &mut *stats_ptr
    };

    randomize_freqs(state_ptr, stats.litlens.as_mut_ptr(), ZOPFLI_NUM_LL as c_int);
    randomize_freqs(state_ptr, stats.dists.as_mut_ptr(), ZOPFLI_NUM_D as c_int);
    stats.litlens[256] = 1; // End symbol.
}
<commit_msg>Make random a method on RunState<commit_after>use std::slice;

use libc::{c_void, c_uint, c_double, c_int, size_t};

use symbols::{ZopfliGetDistExtraBits, ZopfliGetLengthExtraBits, ZopfliGetLengthSymbol, ZopfliGetDistSymbol, ZOPFLI_NUM_LL, ZOPFLI_NUM_D};

/// Cost model which should exactly match fixed tree.
/// type: CostModelFun
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn GetCostFixed(litlen: c_uint, dist: c_uint, _unused: c_void) -> c_double {
    let result = if dist == 0 {
        if litlen <= 143 {
            8
        } else {
            9
        }
    } else {
        let dbits = ZopfliGetDistExtraBits(dist as c_int);
        let lbits = ZopfliGetLengthExtraBits(litlen as c_int);
        let lsym = ZopfliGetLengthSymbol(litlen as c_int);
        let mut cost = 0;
        if lsym <= 279 {
            cost += 7;
        } else {
            cost += 8;
        }
        cost += 5;  // Every dist symbol has length 5.
        cost + dbits + lbits
    };
    result as c_double
}

/// Cost model based on symbol statistics.
/// type: CostModelFun
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn GetCostStat(litlen: c_uint, dist: c_uint, context: *const c_void) -> c_double {
    let stats = unsafe {
        assert!(!context.is_null());
        &*(context as *const SymbolStats)
    };
    if dist == 0 {
        stats.ll_symbols[litlen as usize]
    } else {
        let lsym = ZopfliGetLengthSymbol(litlen as c_int) as usize;
        let lbits = ZopfliGetLengthExtraBits(litlen as c_int) as c_double;
        let dsym = ZopfliGetDistSymbol(dist as c_int) as usize;
        let dbits = ZopfliGetDistExtraBits(dist as c_int) as c_double;
        stats.ll_symbols[lsym] + lbits + stats.d_symbols[dsym] + dbits
    }
}

#[repr(C)]
pub struct RanState {
    m_w: c_uint,
    m_z: c_uint,
}

impl RanState {
    /// Get random number: "Multiply-With-Carry" generator of G. Marsaglia
    pub fn random_marsaglia(&mut self) -> c_uint {
        self.m_z = 36969 * (self.m_z & 65535) + (self.m_z >> 16);
        self.m_w = 18000 * (self.m_w & 65535) + (self.m_w >> 16);
        (self.m_z << 16) + self.m_w // 32-bit result.
    }
}

#[repr(C)]
pub struct SymbolStats {
  /* The literal and length symbols. */
  litlens: [size_t; ZOPFLI_NUM_LL],
  /* The 32 unique dist symbols, not the 32768 possible dists. */
  dists: [size_t; ZOPFLI_NUM_D],

  /* Length of each lit/len symbol in bits. */
  ll_symbols: [c_double; ZOPFLI_NUM_LL],
  /* Length of each dist symbol in bits. */
  d_symbols: [c_double; ZOPFLI_NUM_D],
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn InitRanState(state_ptr: *mut RanState) {
    let state = unsafe {
        assert!(!state_ptr.is_null());
        &mut *state_ptr
    };
    state.m_w = 1;
    state.m_z = 2;
}

pub fn randomize_freqs(state_ptr: *mut RanState, freqs_ptr: *mut size_t, n: c_int) {
    let freqs = unsafe {
        assert!(!freqs_ptr.is_null());
        slice::from_raw_parts_mut(freqs_ptr, n as usize)
    };
    let state = unsafe {
        assert!(!state_ptr.is_null());
        &mut *state_ptr
    };

    let mut i: usize = 0;
    let end = n as usize;

    while i < end {
        if (state.random_marsaglia() >> 4) % 3 == 0 {
            let index = state.random_marsaglia() % n as c_uint;
            freqs[i] = freqs[index as usize];
        }
        i += 1;
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn RandomizeStatFreqs(state_ptr: *mut RanState, stats_ptr: *mut SymbolStats) {
    let stats = unsafe {
        assert!(!stats_ptr.is_null());
        &mut *stats_ptr
    };

    randomize_freqs(state_ptr, stats.litlens.as_mut_ptr(), ZOPFLI_NUM_LL as c_int);
    randomize_freqs(state_ptr, stats.dists.as_mut_ptr(), ZOPFLI_NUM_D as c_int);
    stats.litlens[256] = 1; // End symbol.
}
<|endoftext|>