<commit_before>//! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified. Libraries, however,
//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by
//! default.
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//!         System.alloc(layout)
//!     }
//!
//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//!         System.dealloc(ptr, layout)
//!     }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//!     // This `Vec` will allocate memory through `GLOBAL` above
//!     let mut v = Vec::new();
//!     v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.

#![deny(unsafe_op_in_unsafe_fn)]
#![stable(feature = "alloc_module", since = "1.28.0")]

use core::intrinsics;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};

use crate::sys_common::util::dumb_print;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;

/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by default
/// work as if they had this definition:
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
///     let a = Box::new(4); // Allocates from the system allocator.
///     println!("{}", a);
/// }
/// ```
///
/// You can also define your own wrapper around `System` if you'd like, such as
/// keeping track of the number of all bytes allocated:
///
/// ```rust
/// use std::alloc::{System, GlobalAlloc, Layout};
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
///
/// struct Counter;
///
/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
///
/// unsafe impl GlobalAlloc for Counter {
///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
///         let ret = System.alloc(layout);
///         if !ret.is_null() {
///             ALLOCATED.fetch_add(layout.size(), SeqCst);
///         }
///         return ret
///     }
///
///     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
///         System.dealloc(ptr, layout);
///         ALLOCATED.fetch_sub(layout.size(), SeqCst);
///     }
/// }
///
/// #[global_allocator]
/// static A: Counter = Counter;
///
/// fn main() {
///     println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
/// }
/// ```
///
/// It can also be used directly to allocate memory independently of whatever
/// global allocator has been selected for a Rust program. For example if a Rust
/// program opts in to using jemalloc as the global allocator, `System` will
/// still allocate memory using `malloc` and `HeapAlloc`.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[derive(Debug, Default, Copy, Clone)]
pub struct System;

impl System {
    #[inline]
    fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocErr> {
        match layout.size() {
            0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
            // SAFETY: `layout` is non-zero in size,
            size => unsafe {
                let raw_ptr = if zeroed {
                    GlobalAlloc::alloc_zeroed(self, layout)
                } else {
                    GlobalAlloc::alloc(self, layout)
                };
                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                Ok(NonNull::slice_from_raw_parts(ptr, size))
            },
        }
    }

    #[inline]
    fn grow_impl(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        zeroed: bool,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        debug_assert!(
            new_size >= layout.size(),
            "`new_size` must be greater than or equal to `layout.size()`"
        );

        match layout.size() {
            // SAFETY: the caller must ensure that the `new_size` does not overflow.
            // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
            0 => unsafe {
                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                self.alloc_impl(new_layout, zeroed)
            },

            // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
            // as required by safety conditions. Other conditions must be upheld by the caller
            old_size => unsafe {
                // `realloc` probably checks for `new_size >= size` or something similar.
                intrinsics::assume(new_size >= layout.size());

                let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                if zeroed {
                    raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
                }
                Ok(NonNull::slice_from_raw_parts(ptr, new_size))
            },
        }
    }
}

#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl AllocRef for System {
    #[inline]
    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
        self.alloc_impl(layout, false)
    }

    #[inline]
    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
        self.alloc_impl(layout, true)
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        if layout.size() != 0 {
            // SAFETY: `layout` is non-zero in size,
            // other conditions must be upheld by the caller
            unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) }
        }
    }

    #[inline]
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        self.grow_impl(ptr, layout, new_size, false)
    }

    #[inline]
    unsafe fn grow_zeroed(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        self.grow_impl(ptr, layout, new_size, true)
    }

    #[inline]
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        debug_assert!(
            new_size <= layout.size(),
            "`new_size` must be smaller than or equal to `layout.size()`"
        );

        match new_size {
            // SAFETY: conditions must be upheld by the caller
            0 => unsafe {
                self.dealloc(ptr, layout);
                Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0))
            },

            // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
            new_size => unsafe {
                // `realloc` probably checks for `new_size <= size` or something similar.
                intrinsics::assume(new_size <= layout.size());

                let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                Ok(NonNull::slice_from_raw_parts(ptr, new_size))
            },
        }
    }
}

static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
/// The allocation error hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
}

fn default_alloc_error_hook(layout: Layout) {
    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}

#[cfg(not(test))]
#[doc(hidden)]
#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "none")]
pub fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) =
        if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
    hook(layout);
    crate::process::abort()
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
pub mod __default_lib_allocator {
    use super::{GlobalAlloc, Layout, System};
    // These magic symbol names are used as a fallback for implementing the
    // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs`) when there is
    // no `#[global_allocator]` attribute.

    // for symbol names src/librustc_ast/expand/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc(layout)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::dealloc`.
        unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_realloc(
        ptr: *mut u8,
        old_size: usize,
        align: usize,
        new_size: usize,
    ) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::realloc`.
        unsafe {
            let old_layout = Layout::from_size_align_unchecked(old_size, align);
            System.realloc(ptr, old_layout, new_size)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc_zeroed`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc_zeroed(layout)
        }
    }
}
<commit_msg>Add comment, which was removed by accident (again)<commit_after>//! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified. Libraries, however,
//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by
//! default.
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//!         System.alloc(layout)
//!     }
//!
//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//!         System.dealloc(ptr, layout)
//!     }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//!     // This `Vec` will allocate memory through `GLOBAL` above
//!     let mut v = Vec::new();
//!     v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.

#![deny(unsafe_op_in_unsafe_fn)]
#![stable(feature = "alloc_module", since = "1.28.0")]

use core::intrinsics;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};

use crate::sys_common::util::dumb_print;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;

/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by default
/// work as if they had this definition:
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
///     let a = Box::new(4); // Allocates from the system allocator.
///     println!("{}", a);
/// }
/// ```
///
/// You can also define your own wrapper around `System` if you'd like, such as
/// keeping track of the number of all bytes allocated:
///
/// ```rust
/// use std::alloc::{System, GlobalAlloc, Layout};
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
///
/// struct Counter;
///
/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
///
/// unsafe impl GlobalAlloc for Counter {
///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
///         let ret = System.alloc(layout);
///         if !ret.is_null() {
///             ALLOCATED.fetch_add(layout.size(), SeqCst);
///         }
///         return ret
///     }
///
///     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
///         System.dealloc(ptr, layout);
///         ALLOCATED.fetch_sub(layout.size(), SeqCst);
///     }
/// }
///
/// #[global_allocator]
/// static A: Counter = Counter;
///
/// fn main() {
///     println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
/// }
/// ```
///
/// It can also be used directly to allocate memory independently of whatever
/// global allocator has been selected for a Rust program. For example if a Rust
/// program opts in to using jemalloc as the global allocator, `System` will
/// still allocate memory using `malloc` and `HeapAlloc`.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[derive(Debug, Default, Copy, Clone)]
pub struct System;

impl System {
    #[inline]
    fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocErr> {
        match layout.size() {
            0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
            // SAFETY: `layout` is non-zero in size,
            size => unsafe {
                let raw_ptr = if zeroed {
                    GlobalAlloc::alloc_zeroed(self, layout)
                } else {
                    GlobalAlloc::alloc(self, layout)
                };
                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                Ok(NonNull::slice_from_raw_parts(ptr, size))
            },
        }
    }

    #[inline]
    fn grow_impl(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        zeroed: bool,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        debug_assert!(
            new_size >= layout.size(),
            "`new_size` must be greater than or equal to `layout.size()`"
        );

        match layout.size() {
            // SAFETY: the caller must ensure that the `new_size` does not overflow.
            // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
            0 => unsafe {
                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                self.alloc_impl(new_layout, zeroed)
            },

            // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
            // as required by safety conditions. Other conditions must be upheld by the caller
            old_size => unsafe {
                // `realloc` probably checks for `new_size >= size` or something similar.
                intrinsics::assume(new_size >= layout.size());

                let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                if zeroed {
                    raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
                }
                Ok(NonNull::slice_from_raw_parts(ptr, new_size))
            },
        }
    }
}

// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl,
// which is in `std::sys::*::alloc`.
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl AllocRef for System {
    #[inline]
    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
        self.alloc_impl(layout, false)
    }

    #[inline]
    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
        self.alloc_impl(layout, true)
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        if layout.size() != 0 {
            // SAFETY: `layout` is non-zero in size,
            // other conditions must be upheld by the caller
            unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) }
        }
    }

    #[inline]
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        self.grow_impl(ptr, layout, new_size, false)
    }

    #[inline]
    unsafe fn grow_zeroed(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        self.grow_impl(ptr, layout, new_size, true)
    }

    #[inline]
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
    ) -> Result<NonNull<[u8]>, AllocErr> {
        debug_assert!(
            new_size <= layout.size(),
            "`new_size` must be smaller than or equal to `layout.size()`"
        );

        match new_size {
            // SAFETY: conditions must be upheld by the caller
            0 => unsafe {
                self.dealloc(ptr, layout);
                Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0))
            },

            // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
            new_size => unsafe {
                // `realloc` probably checks for `new_size <= size` or something similar.
                intrinsics::assume(new_size <= layout.size());

                let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                Ok(NonNull::slice_from_raw_parts(ptr, new_size))
            },
        }
    }
}

static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
/// The allocation error hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
}

fn default_alloc_error_hook(layout: Layout) {
    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}

#[cfg(not(test))]
#[doc(hidden)]
#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "none")]
pub fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) =
        if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
    hook(layout);
    crate::process::abort()
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
pub mod __default_lib_allocator {
    use super::{GlobalAlloc, Layout, System};
    // These magic symbol names are used as a fallback for implementing the
    // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs`) when there is
    // no `#[global_allocator]` attribute.

    // for symbol names src/librustc_ast/expand/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc(layout)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::dealloc`.
        unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_realloc(
        ptr: *mut u8,
        old_size: usize,
        align: usize,
        new_size: usize,
    ) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::realloc`.
        unsafe {
            let old_layout = Layout::from_size_align_unchecked(old_size, align);
            System.realloc(ptr, old_layout, new_size)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc_zeroed`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc_zeroed(layout)
        }
    }
}
<|endoftext|>


<commit_before>pub use giftr::refs::functional::Ref as Ref;
use giftr::ispine::*;
use std::default::Default;
use std::fmt::Debug;

//use std::mem::replace;
use std::iter::Iterator;
//use std::rc::Rc;

#[derive(Clone, Debug)]
pub struct SpineList<T: Clone> {
    len : usize,
    spine : ISpine<T>,
}

impl <T: Clone+Debug> SpineList<T> {
    pub fn new() -> SpineList<T> {
        SpineList { len: 0, spine: Default::default() }
    }

    pub fn prepend(&mut self, x: T) {
        self.len += 1;
        self.spine.add(x);
    }

    pub fn append(&mut self, x:T) {
        self.len += 1;
        if let Some(ref mut l) = self.spine.at().last() {
            l.insert(x);
            return
        }
        self.spine.add(x)
    }

    pub fn pop_front(&mut self) -> Option<T> {
        if let Some(x) = self.spine.pop1() {
            println!("popped {:?}, len was {}", x, self.len);
            self.len -= 1;
            Some(x)
        } else {
            None
        }
    }

    pub fn pop_back(&mut self) -> Option<T> {
        let len = self.len();
        if let Some(x) = self.spine.take_from(len-1).pop1() {
            self.len -= 1;
            Some(x)
        } else {
            None
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn iter(&self) -> Iter<T> {
        Iter { cur: self.spine.clone() }
    }

    pub fn to_iter(mut self) -> Iter<T> {
        let SpineList { len: _, spine: spine } = self;
        Iter { cur: spine }
    }
}

use std::marker::PhantomData;
pub struct Iter<T: Clone> {
    cur: ISpine<T>,
}

impl <T: Clone> Iterator for Iter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.cur.pop1()
    }
}

mod test {
    use giftr::refs::*;
    use super::{Ref, SpineList};
    #[test]
    fn lst_len() {
        println!("=== LST_LEN ==============");
        let mut lst = Ref::new(SpineList::<i32>::new());
        assert_eq!(0, lst.len());

        lst.prepend(1);
        assert_eq!(1, lst.len());

        lst.prepend(2);
        assert_eq!(2, lst.len());

        lst.prepend(3);
        assert_eq!(3, lst.len());

        lst.pop_front();
        assert_eq!(2, lst.len());
    }

    #[test]
    fn lst_pop_front() {
        println!("=== LST_LEN ==============");
        let mut lst = Ref::new(SpineList::new());
        lst.prepend(3);
        lst.prepend(2);
        lst.prepend(1);

        assert_eq!(Some(1), lst.pop_front());
        assert_eq!(Some(2), lst.pop_front());
        assert_eq!(Some(3), lst.pop_front());
        assert_eq!(None, lst.pop_front());
        assert_eq!(None, lst.pop_front());
    }

    #[test]
    fn lst_append() {
        let mut lst = SpineList::<i32>::new();
        lst.append(1);
        lst.append(2);
        lst.append(3);

        assert_eq!(Some(1), lst.pop_front());
        assert_eq!(Some(2), lst.pop_front());
        assert_eq!(Some(3), lst.pop_front());
        assert_eq!(None,    lst.pop_front());
        assert_eq!(None,    lst.pop_front());
    }

    #[test]
    fn lst_pop_back() {
        println!("=== LST_LEN ==============");
        let mut lst = Ref::new(SpineList::new());
        lst.prepend(3);
        lst.prepend(2);
        lst.prepend(1);
        println!("lst= {:?}", lst);

        assert_eq!(Some(3), lst.pop_back());
        assert_eq!(Some(2), lst.pop_back());
        assert_eq!(Some(1), lst.pop_back());
        assert_eq!(None, lst.pop_front());
        assert_eq!(None, lst.pop_front());
    }

    #[test]
    fn lst_copy() {
        println!("=== LST_COPY ==============");
        let mut lst1 = Ref::new(SpineList::new());
        lst1.prepend(1);
        let lst2 : Ref<SpineList<i32>>;
        lst1.prepend(2);

        lst2 = lst1.clone();

        lst1.prepend(3);

        assert!(3 == lst1.len());
        assert!(2 == lst2.len());
    }

    #[test]
    fn lst_iter() {
        let mut lst1 = Ref::new(SpineList::new());
        lst1.prepend(3);
        lst1.prepend(2);
        lst1.prepend(1);

        let mut cnt = 1;
        for v in lst1.iter() {
            println!("v={}, cnt={}", v, cnt);
            assert_eq!(v, cnt);
            cnt = cnt+1;
        }
    }

}

#[cfg(test)]
mod bench {
    use test;
    use test::Bencher;
    use giftr::refs::*;
    use super::{Ref, SpineList};

    #[bench]
    fn lst_append(b: &mut Bencher) {
        let mut lst1 : Ref<SpineList<i32>> = Ref::new(SpineList::new());
        let size = 10000;
        for i in 0..size {
            lst1.append(i);
        }
        b.iter(
            || {
                test::black_box(lst1.append(1));
            }
        );
    }

    #[bench]
    fn lst_prepend(b: &mut Bencher) {
        let mut lst1 : SpineList<i32> = SpineList::new();
        let size = 10000;
        for i in 0..size {
            lst1.append(i);
        }
        b.iter(
            || {
                test::black_box(lst1.prepend(1));
            }
        );
    }

    #[bench]
    fn lst_len(b: &mut Bencher) {
        let mut lst1 : SpineList<i32> = SpineList::new();
        let size = 10000;
        for i in 0..size {
            lst1.append(i);
        }
        b.iter(
            || {
                test::black_box(lst1.len());
            }
        );
    }

}
<commit_msg>add vector microbenchmarks for comparison<commit_after>pub use giftr::refs::functional::Ref as Ref;
use giftr::ispine::*;
use std::default::Default;
use std::fmt::Debug;

//use std::mem::replace;
use std::iter::Iterator;
//use std::rc::Rc;

#[derive(Clone, Debug)]
pub struct SpineList<T: Clone> {
    len : usize,
    spine : ISpine<T>,
}

impl <T: Clone+Debug> SpineList<T> {
    pub fn new() -> SpineList<T> {
        SpineList { len: 0, spine: Default::default() }
    }

    pub fn prepend(&mut self, x: T) {
        self.len += 1;
        self.spine.add(x);
    }

    pub fn append(&mut self, x:T) {
        self.len += 1;
        if let Some(ref mut l) = self.spine.at().last() {
            l.insert(x);
            return
        }
        self.spine.add(x)
    }

    pub fn pop_front(&mut self) -> Option<T> {
        if let Some(x) = self.spine.pop1() {
            println!("popped {:?}, len was {}", x, self.len);
            self.len -= 1;
            Some(x)
        } else {
            None
        }
    }

    pub fn pop_back(&mut self) -> Option<T> {
        let len = self.len();
        if let Some(x) = self.spine.take_from(len-1).pop1() {
            self.len -= 1;
            Some(x)
        } else {
            None
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn iter(&self) -> Iter<T> {
        Iter { cur: self.spine.clone() }
    }

    pub fn to_iter(mut self) -> Iter<T> {
        let SpineList { len: _, spine: spine } = self;
        Iter { cur: spine }
    }
}

use std::marker::PhantomData;
pub struct Iter<T: Clone> {
    cur: ISpine<T>,
}

impl <T: Clone> Iterator for Iter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.cur.pop1()
    }
}

mod test {
    use giftr::refs::*;
    use super::{Ref, SpineList};
    #[test]
    fn lst_len() {
        println!("=== LST_LEN ==============");
        let mut lst = Ref::new(SpineList::<i32>::new());
        assert_eq!(0, lst.len());

        lst.prepend(1);
        assert_eq!(1, lst.len());

        lst.prepend(2);
        assert_eq!(2, lst.len());

        lst.prepend(3);
        assert_eq!(3, lst.len());

        lst.pop_front();
        assert_eq!(2, lst.len());
    }

    #[test]
    fn lst_pop_front() {
        println!("=== LST_LEN ==============");
        let mut lst = Ref::new(SpineList::new());
        lst.prepend(3);
        lst.prepend(2);
        lst.prepend(1);

        assert_eq!(Some(1), lst.pop_front());
        assert_eq!(Some(2), lst.pop_front());
        assert_eq!(Some(3), lst.pop_front());
        assert_eq!(None, lst.pop_front());
        assert_eq!(None, lst.pop_front());
    }

    #[test]
    fn lst_append() {
        let mut lst = SpineList::<i32>::new();
        lst.append(1);
        lst.append(2);
        lst.append(3);

        assert_eq!(Some(1), lst.pop_front());
        assert_eq!(Some(2), lst.pop_front());
        assert_eq!(Some(3), lst.pop_front());
        assert_eq!(None,    lst.pop_front());
        assert_eq!(None,    lst.pop_front());
    }

    #[test]
    fn lst_pop_back() {
        println!("=== LST_LEN ==============");
        let mut lst = Ref::new(SpineList::new());
        lst.prepend(3);
        lst.prepend(2);
        lst.prepend(1);
        println!("lst= {:?}", lst);

        assert_eq!(Some(3), lst.pop_back());
        assert_eq!(Some(2), lst.pop_back());
        assert_eq!(Some(1), lst.pop_back());
        assert_eq!(None, lst.pop_front());
        assert_eq!(None, lst.pop_front());
    }

    #[test]
    fn lst_copy() {
        println!("=== LST_COPY ==============");
        let mut lst1 = Ref::new(SpineList::new());
        lst1.prepend(1);
        let lst2 : Ref<SpineList<i32>>;
        lst1.prepend(2);

        lst2 = lst1.clone();

        lst1.prepend(3);

        assert!(3 == lst1.len());
        assert!(2 == lst2.len());
    }

    #[test]
    fn lst_iter() {
        let mut lst1 = Ref::new(SpineList::new());
        lst1.prepend(3);
        lst1.prepend(2);
        lst1.prepend(1);

        let mut cnt = 1;
        for v in lst1.iter() {
            println!("v={}, cnt={}", v, cnt);
            assert_eq!(v, cnt);
            cnt = cnt+1;
        }
    }

}

#[cfg(test)]
mod bench {
    use test;
    use test::Bencher;
    use giftr::refs::*;
    use super::{Ref, SpineList};

    #[bench]
    fn lst_append(b: &mut Bencher) {
        let mut lst1 : Ref<SpineList<i32>> = Ref::new(SpineList::new());
        let size = 10000;
        for i in 0..size {
            lst1.append(i);
        }
        b.iter(
            || {
                test::black_box(lst1.append(1));
            }
        );
    }

    #[bench]
    fn lst_prepend(b: &mut Bencher) {
        let mut lst1 : SpineList<i32> = SpineList::new();
        let size = 10000;
        for i in 0..size {
            lst1.append(i);
        }
        b.iter(
            || {
                test::black_box(lst1.prepend(1));
            }
        );
    }

    #[bench]
    fn lst_len(b: &mut Bencher) {
        let mut lst1 : SpineList<i32> = SpineList::new();
        let size = 10000;
        for i in 0..size {
            lst1.append(i);
        }
        b.iter(
            || {
                test::black_box(lst1.len());
            }
        );
    }

}

#[cfg(test)]
mod vecbench {
    use test;
    use test::Bencher;

    #[bench]
    fn lst_append(b: &mut Bencher) {
        let mut lst1  = (Vec::new());
        let size = 10000;
        for i in 0..size {
            lst1.push(i);
        }
        b.iter(
            || {
                test::black_box(lst1.push(1));
            }
        );
    }

    #[bench]
    fn lst_prepend(b: &mut Bencher) {
        let mut lst1 = Vec::new();
        let size = 10000;
        for i in 0..size {
            lst1.insert(0, i);
        }
        b.iter(
            || {
                test::black_box(lst1.push(1));
            }
        );
    }

    #[bench]
    fn lst_len(b: &mut Bencher) {
        let mut lst1 = Vec::new();
        let size = 10000;
        for i in 0..size {
            lst1.push(i);
        }
        b.iter(
            || {
                test::black_box(lst1.len());
            }
        );
    }

}
<|endoftext|>


<commit_before>use Graph;

use num::{self, Zero};

use std::ops::Index;
use std::collections::HashMap;
use std::collections::hash_map::Keys;

pub type NodeId = usize;
type ListId = usize;
type Outgoing<'a, W> = Keys<'a, usize, W>;

pub struct AdjacencyMapNode<V, W> {
    pub value: V,
    pub outgoing: HashMap<NodeId, W>,
}

pub struct AdjacencyMap<V, W> {
    nodes: Vec<AdjacencyMapNode<V, W>>,
    map: HashMap<NodeId, ListId>,
}

impl<V, W> AdjacencyMap<V, W> {
    pub fn new() -> AdjacencyMap<V, W> {
        AdjacencyMap {
            nodes: Vec::new(),
            map: HashMap::new(),
        }
    }

    pub fn add_node(&mut self, node_id: NodeId, value: V) {
        let list_id = self.nodes.len();
        self.nodes.push(AdjacencyMapNode {
            value: value,
            outgoing: HashMap::new(),
        });
        self.map.insert(node_id, list_id);
    }

    pub fn add_edge(&mut self, from: NodeId, to: NodeId, weight: W) {
        self.nodes[self.map[from]].outgoing.insert(to, weight);
    }
}

impl<V, W> Index<NodeId> for AdjacencyMap<V, W> {
    type Output = AdjacencyMapNode<V, W>;

    fn index(&self, index: &NodeId) -> &AdjacencyMapNode<V, W> {
        &self.nodes[self.map[*index]]
    }
}

impl<'a, N, W> Graph for &'a AdjacencyMap<N, W> where W: Zero + Clone {
    type Node = NodeId;
    type Weight = W;
    type Neighbours = Outgoing<'a, W>;

    fn weight(&self, from: &NodeId, to: &NodeId) -> Option<W> {
        match self.map.get(from) {
            Some(node) => self.nodes[*node].outgoing.get(to).map(|w| w.clone()),
            None => None,
        }
    }

    fn neighbours(&self, node: &NodeId) -> Outgoing<'a, W> {
        self.nodes[*node].outgoing.keys()
    }

    fn heuristic(&self, _: &NodeId, _: &NodeId) -> W {
        num::zero()
    }
}
<commit_msg>Rename type alias to be clearer.<commit_after>use Graph;

use num::{self, Zero};

use std::ops::Index;
use std::collections::HashMap;
use std::collections::hash_map::Keys;

pub type NodeId = usize;
type ListId = usize;

pub struct AdjacencyMapNode<V, W> {
    pub value: V,
    pub outgoing: HashMap<NodeId, W>,
}

pub struct AdjacencyMap<V, W> {
    nodes: Vec<AdjacencyMapNode<V, W>>,
    map: HashMap<NodeId, ListId>,
}

impl<V, W> AdjacencyMap<V, W> {
    pub fn new() -> AdjacencyMap<V, W> {
        AdjacencyMap {
            nodes: Vec::new(),
            map: HashMap::new(),
        }
    }

    pub fn add_node(&mut self, node_id: NodeId, value: V) {
        let list_id = self.nodes.len();
        self.nodes.push(AdjacencyMapNode {
            value: value,
            outgoing: HashMap::new(),
        });
        self.map.insert(node_id, list_id);
    }

    pub fn add_edge(&mut self, from: NodeId, to: NodeId, weight: W) {
        self.nodes[self.map[from]].outgoing.insert(to, weight);
    }
}

impl<V, W> Index<NodeId> for AdjacencyMap<V, W> {
    type Output = AdjacencyMapNode<V, W>;

    fn index(&self, index: &NodeId) -> &AdjacencyMapNode<V, W> {
        &self.nodes[self.map[*index]]
    }
}

type OutgoingIter<'a, W> = Keys<'a, usize, W>;

impl<'a, N, W> Graph for &'a AdjacencyMap<N, W> where W: Zero + Clone {
    type Node = NodeId;
    type Weight = W;
    type Neighbours = OutgoingIter<'a, W>;

    fn weight(&self, from: &NodeId, to: &NodeId) -> Option<W> {
        match self.map.get(from) {
            Some(node) => self.nodes[*node].outgoing.get(to).map(|w| w.clone()),
            None => None,
        }
    }

    fn neighbours(&self, node: &NodeId) -> OutgoingIter<'a, W> {
        self.nodes[*node].outgoing.keys()
    }

    fn heuristic(&self, _: &NodeId, _: &NodeId) -> W {
        num::zero()
    }
}
<|endoftext|>


<commit_before>// Implementation adapted from Python version:
// https://github.com/commonsmachinery/blockhash-python/blob/e8b009d/blockhash.py
// Main site: http://blockhash.io
use image::{GenericImageView, Pixel};

use {BitSet, Image, HashBytes};

use std::cmp::Ordering;
use std::ops::AddAssign;
use std::mem;

const FLOAT_EQ_MARGIN: f32 = 0.001;

pub fn blockhash<I: Image, B: HashBytes>(img: &I, width: u32, height: u32) -> B {
    assert_eq!(width % 4, 0, "width must be multiple of 4");
    assert_eq!(height % 4, 0, "height must be multiple of 4");

    let (iwidth, iheight) = img.dimensions();

    // Skip the floating point math if it's unnecessary
    if iwidth % width == 0 && iheight % height == 0 {
        blockhash_fast(img, width, height)
    } else {
        blockhash_slow(img, width, height)
    }
}

macro_rules! gen_hash {
    ($imgty:ty, $valty:ty, $blocks: expr, $width:expr, $block_width:expr, $block_height:expr, $eq_fn:expr) => ({
        #[allow(deprecated)] // deprecated as of 0.22
        let channel_count = <<$imgty as GenericImageView>::Pixel as Pixel>::channel_count() as u32;

        let group_len = ($width * 4) as usize;

        let block_area = $block_width * $block_height;

        let cmp_factor = match channel_count {
            3 | 4 => 255u32 as $valty * 3u32 as $valty,
            2 | 1 => 255u32 as $valty,
            _ => panic!("Unrecognized channel count from Image: {}", channel_count),
        }
            * block_area
            / (2u32 as $valty);

        let medians: Vec<$valty> = $blocks.chunks(group_len).map(get_median).collect();

        BitSet::from_bools(
            $blocks.chunks(group_len).zip(medians)
            .flat_map(|(blocks, median)|
                blocks.iter().map(move |&block|
                    block > median ||
                        ($eq_fn(block, median) && median > cmp_factor)
                )
            )
        )
    })
}

fn block_adder<'a, T: AddAssign + 'a>(blocks: &'a mut [T], width: u32) -> impl FnMut(u32, u32, T) + 'a {
    move |x, y, add| (blocks[(y as usize) * (width as usize) + (x as usize)] += add)
}

fn blockhash_slow<I: Image, B: HashBytes>(img: &I, hwidth: u32, hheight: u32) -> B {
    let mut blocks = vec![0f32; (hwidth * hheight) as usize];

    let (iwidth, iheight) = img.dimensions();

    // Block dimensions, in pixels
    let (block_width, block_height) = (iwidth as f32 / hwidth as f32, iheight as f32 / hheight as f32);

    img.foreach_pixel8(|x, y, px| {
        let mut add_to_block = block_adder(&mut blocks, hwidth);

        let px_sum = sum_px(px) as f32;

        let (x, y) = (x as f32, y as f32);

        let block_x = x / block_width;
        let block_y = y / block_height;

        let x_mod = x + 1. % block_width;
        let y_mod = y + 1. % block_height;

        // terminology is mostly arbitrary as long as we're consistent
        // if `x` evenly divides `block_height`, this weight will be 0
        // so we don't double the sum as `block_top` will equal `block_bottom`
        let weight_left = x_mod.fract();
        let weight_right = 1. - weight_left;
        let weight_top = y_mod.fract();
        let weight_bottom = 1. - weight_top;

        let block_left = block_x.floor() as u32;
        let block_top = block_y.floor() as u32;

        let block_right = if x_mod.trunc() == 0. {
            block_x.ceil() as u32
        } else {
            block_left
        };

        let block_bottom = if y_mod.trunc() == 0. {
            block_y.ceil() as u32
        } else {
            block_top
        };

        add_to_block(block_left, block_top, px_sum * weight_left * weight_top);
        add_to_block(block_left, block_bottom, px_sum * weight_left * weight_bottom);
        add_to_block(block_right, block_top, px_sum * weight_right * weight_top);
        add_to_block(block_right, block_bottom, px_sum * weight_right * weight_bottom);
    });

    gen_hash!(I, f32, blocks, hwidth, block_width, block_height,
        |l: f32, r: f32| (l - r).abs() < FLOAT_EQ_MARGIN)
}

fn blockhash_fast<I: Image, B: HashBytes>(img: &I, hwidth: u32, hheight: u32) -> B {
    let mut blocks = vec![0u32; (hwidth * hheight) as usize];
    let (iwidth, iheight) = img.dimensions();

    let (block_width, block_height) = (iwidth / hwidth, iheight / hheight);

    img.foreach_pixel8(|x, y, px| {
        let mut add_to_block = block_adder(&mut blocks, hwidth);

        let px_sum = sum_px(px);

        let block_x = x / block_width;
        let block_y = y / block_width;

        add_to_block(block_x, block_y, px_sum);
    });

    gen_hash!(I, u32, blocks, hwidth, block_width, block_height, |l, r| l == r)
}

#[inline(always)]
fn sum_px(chans: &[u8]) -> u32 {
    // Branch prediction should eliminate the match after a few iterations
    match chans.len() {
        4 => if chans[3] == 0 { 255 * 3 } else { sum_px(&chans[..3]) },
        3 => chans.iter().map(|&x| x as u32).sum(),
        2 => if chans[1] == 0 { 255 } else { chans[0] as u32 },
        1 => chans[0] as u32,
        channels => panic!("Unsupported channel count in image: {}", channels),
    }
}

fn get_median<T: PartialOrd + Copy>(data: &[T]) -> T {
    let mut scratch = data.to_owned();
    let median = scratch.len() / 2;
    *qselect_inplace(&mut scratch, median)
}

const SORT_THRESH: usize = 8;

fn qselect_inplace<T: PartialOrd>(data: &mut [T], k: usize) -> &mut T {
    let len = data.len();

    assert!(k < len, "Called qselect_inplace with k = {} and data length: {}", k, len);

    if len < SORT_THRESH {
        data.sort_by(|left, right| left.partial_cmp(right).unwrap_or(Ordering::Less));
        return &mut data[k];
    }

    let pivot_idx = partition(data);

    if k == pivot_idx {
        &mut data[pivot_idx]
    } else if k < pivot_idx {
        qselect_inplace(&mut data[..pivot_idx], k)
    } else {
        qselect_inplace(&mut data[pivot_idx + 1..], k - pivot_idx - 1)
    }
}

fn partition<T: PartialOrd>(data: &mut [T]) -> usize {
    let len = data.len();

    let pivot_idx = {
        let first = (&data[0], 0);
        let mid = (&data[len / 2], len / 2);
        let last = (&data[len - 1], len - 1);

        median_of_3(&first, &mid, &last).1
    };

    data.swap(pivot_idx, len - 1);

    let mut curr = 0;

    for i in 0 .. len - 1 {
        if &data[i] < &data[len - 1] {
            data.swap(i, curr);
            curr += 1;
        }
    }

    data.swap(curr, len - 1);

    curr
}

fn median_of_3<T: PartialOrd>(mut x: T, mut y: T, mut z: T) -> T {
    if x > y {
        mem::swap(&mut x, &mut y);
    }

    if x > z {
        mem::swap(&mut x, &mut z);
    }

    if x > z {
        mem::swap(&mut y, &mut z);
    }

    y
}
<commit_msg>Fix wrong calculation in blockhash_fast<commit_after>// Implementation adapted from Python version:
// https://github.com/commonsmachinery/blockhash-python/blob/e8b009d/blockhash.py
// Main site: http://blockhash.io
use image::{GenericImageView, Pixel};

use {BitSet, Image, HashBytes};

use std::cmp::Ordering;
use std::ops::AddAssign;
use std::mem;

const FLOAT_EQ_MARGIN: f32 = 0.001;

pub fn blockhash<I: Image, B: HashBytes>(img: &I, width: u32, height: u32) -> B {
    assert_eq!(width % 4, 0, "width must be multiple of 4");
    assert_eq!(height % 4, 0, "height must be multiple of 4");

    let (iwidth, iheight) = img.dimensions();

    // Skip the floating point math if it's unnecessary
    if iwidth % width == 0 && iheight % height == 0 {
        blockhash_fast(img, width, height)
    } else {
        blockhash_slow(img, width, height)
    }
}

macro_rules! gen_hash {
    ($imgty:ty, $valty:ty, $blocks: expr, $width:expr, $block_width:expr, $block_height:expr, $eq_fn:expr) => ({
        #[allow(deprecated)] // deprecated as of 0.22
        let channel_count = <<$imgty as GenericImageView>::Pixel as Pixel>::channel_count() as u32;

        let group_len = ($width * 4) as usize;

        let block_area = $block_width * $block_height;

        let cmp_factor = match channel_count {
            3 | 4 => 255u32 as $valty * 3u32 as $valty,
            2 | 1 => 255u32 as $valty,
            _ => panic!("Unrecognized channel count from Image: {}", channel_count),
        }
            * block_area
            / (2u32 as $valty);

        let medians: Vec<$valty> = $blocks.chunks(group_len).map(get_median).collect();

        BitSet::from_bools(
            $blocks.chunks(group_len).zip(medians)
            .flat_map(|(blocks, median)|
                blocks.iter().map(move |&block|
                    block > median ||
                        ($eq_fn(block, median) && median > cmp_factor)
                )
            )
        )
    })
}

fn block_adder<'a, T: AddAssign + 'a>(blocks: &'a mut [T], width: u32) -> impl FnMut(u32, u32, T) + 'a {
    move |x, y, add| (blocks[(y as usize) * (width as usize) + (x as usize)] += add)
}

fn blockhash_slow<I: Image, B: HashBytes>(img: &I, hwidth: u32, hheight: u32) -> B {
    let mut blocks = vec![0f32; (hwidth * hheight) as usize];

    let (iwidth, iheight) = img.dimensions();

    // Block dimensions, in pixels
    let (block_width, block_height) = (iwidth as f32 / hwidth as f32, iheight as f32 / hheight as f32);

    img.foreach_pixel8(|x, y, px| {
        let mut add_to_block = block_adder(&mut blocks, hwidth);

        let px_sum = sum_px(px) as f32;

        let (x, y) = (x as f32, y as f32);

        let block_x = x / block_width;
        let block_y = y / block_height;

        let x_mod = x + 1. % block_width;
        let y_mod = y + 1. % block_height;

        // terminology is mostly arbitrary as long as we're consistent
        // if `x` evenly divides `block_height`, this weight will be 0
        // so we don't double the sum as `block_top` will equal `block_bottom`
        let weight_left = x_mod.fract();
        let weight_right = 1. - weight_left;
        let weight_top = y_mod.fract();
        let weight_bottom = 1. - weight_top;

        let block_left = block_x.floor() as u32;
        let block_top = block_y.floor() as u32;

        let block_right = if x_mod.trunc() == 0. {
            block_x.ceil() as u32
        } else {
            block_left
        };

        let block_bottom = if y_mod.trunc() == 0. {
            block_y.ceil() as u32
        } else {
            block_top
        };

        add_to_block(block_left, block_top, px_sum * weight_left * weight_top);
        add_to_block(block_left, block_bottom, px_sum * weight_left * weight_bottom);
        add_to_block(block_right, block_top, px_sum * weight_right * weight_top);
        add_to_block(block_right, block_bottom, px_sum * weight_right * weight_bottom);
    });

    gen_hash!(I, f32, blocks, hwidth, block_width, block_height,
        |l: f32, r: f32| (l - r).abs() < FLOAT_EQ_MARGIN)
}

fn blockhash_fast<I: Image, B: HashBytes>(img: &I, hwidth: u32, hheight: u32) -> B {
    let mut blocks = vec![0u32; (hwidth * hheight) as usize];
    let (iwidth, iheight) = img.dimensions();

    let (block_width, block_height) = (iwidth / hwidth, iheight / hheight);

    img.foreach_pixel8(|x, y, px| {
        let mut add_to_block = block_adder(&mut blocks, hwidth);

        let px_sum = sum_px(px);

        let block_x = x / block_width;
        let block_y = y / block_height;

        add_to_block(block_x, block_y, px_sum);
    });

    gen_hash!(I, u32, blocks, hwidth, block_width, block_height, |l, r| l == r)
}

#[inline(always)]
fn sum_px(chans: &[u8]) -> u32 {
    // Branch prediction should eliminate the match after a few iterations
    match chans.len() {
        4 => if chans[3] == 0 { 255 * 3 } else { sum_px(&chans[..3]) },
        3 => chans.iter().map(|&x| x as u32).sum(),
        2 => if chans[1] == 0 { 255 } else { chans[0] as u32 },
        1 => chans[0] as u32,
        channels => panic!("Unsupported channel count in image: {}", channels),
    }
}

fn get_median<T: PartialOrd + Copy>(data: &[T]) -> T {
    let mut scratch = data.to_owned();
    let median = scratch.len() / 2;
    *qselect_inplace(&mut scratch, median)
}

const SORT_THRESH: usize = 8;

fn qselect_inplace<T: PartialOrd>(data: &mut [T], k: usize) -> &mut T {
    let len = data.len();

    assert!(k < len, "Called qselect_inplace with k = {} and data length: {}", k, len);

    if len < SORT_THRESH {
        data.sort_by(|left, right| left.partial_cmp(right).unwrap_or(Ordering::Less));
        return &mut data[k];
    }

    let pivot_idx = partition(data);

    if k == pivot_idx {
        &mut data[pivot_idx]
    } else if k < pivot_idx {
        qselect_inplace(&mut data[..pivot_idx], k)
    } else {
        qselect_inplace(&mut data[pivot_idx + 1..], k - pivot_idx - 1)
    }
}

fn partition<T: PartialOrd>(data: &mut [T]) -> usize {
    let len = data.len();

    let pivot_idx = {
        let first = (&data[0], 0);
        let mid = (&data[len / 2], len / 2);
        let last = (&data[len - 1], len - 1);

        median_of_3(&first, &mid, &last).1
    };

    data.swap(pivot_idx, len - 1);

    let mut curr = 0;

    for i in 0 .. len - 1 {
        if &data[i] < &data[len - 1] {
            data.swap(i, curr);
            curr += 1;
        }
    }

    data.swap(curr, len - 1);

    curr
}

fn median_of_3<T: PartialOrd>(mut x: T, mut y: T, mut z: T) -> T {
    if x > y {
        mem::swap(&mut x, &mut y);
    }

    if x > z {
        mem::swap(&mut x, &mut z);
    }

    if x > z {
        mem::swap(&mut y, &mut z);
    }

    y
}
<|endoftext|>


<commit_before>use story_builder::article_provider::*;
use std::rc::Rc;
use std::borrow::Borrow;
use std::ops::Deref;
use std::sync::Arc;
use std::thread;
use std::thread::JoinHandle;
use std::collections::HashSet;

pub struct StoryBuilder {
    article_provider: Arc<(ArticleProvider + Send + Sync)>,
    max_depth: u8,
    visited_nodes: Arc<HashSet<String>>,
}

impl StoryBuilder  {
    pub fn new(article_provider: Arc<(ArticleProvider + Send + Sync)>) -> StoryBuilder {
        StoryBuilder {
            article_provider,
            max_depth: 5, // default value for now
            visited_nodes: Arc::new(HashSet::new()),
        }
    }

    pub fn build_story(&mut self, start_topic: &str , end_topic: &str) -> Result<String, String> {
        let start_topic = start_topic.to_lowercase();
        let end_topic = end_topic.to_lowercase();
        // If one of the topics is an empty string, do not try to make a story out of it.
        if start_topic == "" {
            return Err("Missing start topic.".to_owned());
        }
        if end_topic == "" {
            return Err("Missing end topic.".to_owned());
        }

        // If both topics are the same,
        // there is no point in trying to figure out the story.
        if start_topic == end_topic {
            return Err("No story to build; same start and end topics.".to_owned());
        }

        // Load the first article
        let start_article = match self.article_provider.get(&start_topic) {
            Some(start_article) => start_article,
            None => {return Err(self.build_suggestions_msg(&start_topic));},
        };
        Arc::get_mut(&mut self.visited_nodes).unwrap().insert(start_topic);
        // Load the end article
        match self.article_provider.get(&end_topic) {
            Some(end_topic) => end_topic,
            None => {return Err(self.build_suggestions_msg(&end_topic));},
        };

        /* To build a story, we need to build a tree starting at the start_article
           node and going down in a "breadth-first" way; that way, once we find
           the end note, we know it is the shortest path to it. Also, going depth-first
           will be impossibly long to complete sincethe depth of the wikipedia
           article tree is almost infinite. */
        /* We look for a paragraph that holds a reference to our end topic
           somewhere in the last level we fetched: */
        let mut last_level: Vec<Rc<ArticleNode>> = vec![Rc::new(ArticleNode::new(start_article))]; // starts with start article
        for i in 0..self.max_depth { // To prevent overloading the system, stop after X level deep
            // Start by loading the next level of articles:
            if i > 0 {
                // Any other iteration: go one level deeper:
                let mut current_level = vec![];
                for rc_article_node in last_level.iter() {
                    /* Iterate on each paragraph of this article, then map on it to
                       get the article for each related topic in it. */
                    let rc_local = rc_article_node.clone();
                    let article = rc_local.deref();
                    for paragraph in article.get_paragraphs().iter() {
                        // First: spawn all threads first
                        let mut threads: Vec<JoinHandle<Option<Box<Article + Send + Sync>>>> = Vec::new();
                        for topic in paragraph.topics.iter() {
                            let topic = topic.to_lowercase();
                            if !Arc::get_mut(&mut self.visited_nodes).unwrap().contains(&topic) {
                                // Do not access the same article more than once!!
                                let article_provider = self.article_provider.clone();
                                let topic_for_thread = topic.to_owned();
                                threads.push(thread::spawn(move || {
                                    article_provider.get(&topic_for_thread)
                                }));
                                Arc::get_mut(&mut self.visited_nodes).unwrap().insert(topic);
                            }
                        }
                        // Then, join them up one at a time.
                        for t in threads.into_iter() {
                            match t.join().unwrap() {
                                Some(content) => {
                                    let mut new_node = ArticleNode::new(content);
                                    new_node.attach_to(rc_local.clone(), &paragraph.text);
                                    current_level.push(Rc::new(new_node));
                                },
                                None => (),
                            }
                        }
                    }
                }
                last_level = current_level;
            }
            // Replace the previous level with this level.

            for article_node in last_level.iter() {
                if let Some(text) = StoryBuilder::find_text_for_topic_in_article(article_node.deref().deref().borrow(), &end_topic) {
                    // Found the topic. Format and return.
                    return Ok(StoryBuilder::build_final_text(article_node.clone(), text, &end_topic));
                }
            }
        }

        Err(format!("Reached depth of <{}> without finding <{}>. Stopping search.", self.max_depth, end_topic).to_owned())
    }

    fn build_suggestions_msg(&self, topic: &str) -> String {
        let mut msg = String::from(format!("Cannot find wikipedia article for <{}>, try one of the following suggestions:\r\n", topic));
        for sugg in self.article_provider.search(topic) {
            msg.push_str(&format!("- {}\r\n", &sugg));
        }

        msg
    }

    fn find_text_for_topic_in_article<'b>(article: &'b (Article + Send + Sync), topic: &str) -> Option<&'b str> {
        if let Some(paragraph) = article.get_paragraphs().iter().find(|par| {
            // if any of the topics in the paragraph is <end>, return it.
            par.topics.iter().any(|t| {&t.to_lowercase() == topic})
        }) {
            // We found the paragraph; return it directly.
            return Some(&paragraph.text);
        } else {
            None
        }
    }

    fn build_final_text(article_node: Rc<ArticleNode>, final_text: &str, final_topic: &str) -> String {
        let mut texts: Vec<String> = Vec::new();
        let mut last_topic = final_topic.to_owned();
        texts.push(format!("{}\r\n", final_text));
        {
            let n: &ArticleNode = article_node.borrow();
            if let Some(n_text) = n.text() {
                let new_topic = n.get_topic().to_owned();
                texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                last_topic = new_topic;
                texts.push(format!("{}\r\n", n_text));
            }
        }

        let mut node = article_node;
        loop {
            node = match node.parent() {
                Some(rc) => {
                    {
                        let n: &ArticleNode = rc.borrow();
                        if let Some(n_text) = n.text() {
                            let new_topic = n.get_topic().to_owned();
                            texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                            last_topic = new_topic;
                            texts.push(format!("{}\r\n", n_text));
                        }
                    }
                    rc
                },
                _ => {
                    let new_topic = node.get_topic().to_owned();
                    texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                    return texts.into_iter().rev().collect();
                },
            }
        }
    }
}

struct ArticleNode {
    data: Box<Article + Send + Sync>,
    parent: Option<Rc<ArticleNode>>,
    text: Option<String>,
}

impl ArticleNode {
    fn new(data: Box<Article + Send + Sync>) -> ArticleNode {
        ArticleNode {
            data,
            parent: None,
            text: None,
        }
    }
    fn attach_to(&mut self, parent: Rc<ArticleNode>, paragraph_text: &str) {
        self.parent = Some(parent);
        self.text = Some(String::from(paragraph_text));
    }
    fn parent(&self) -> Option<Rc<ArticleNode>> {
        self.parent.clone()
    }
    fn text(&self) -> Option<String> {
        self.text.clone()
    }
}

impl <'n> Deref for ArticleNode {
    type Target = Box<Article + Send + Sync>;

    fn deref(&self) -> &Box<Article + Send + Sync> {
        &self.data
    }
}

#[cfg(test)]
mod tests;
<commit_msg>visited_nodes does not have to be "Arc".<commit_after>use story_builder::article_provider::*;
use std::rc::Rc;
use std::borrow::Borrow;
use std::ops::Deref;
use std::sync::Arc;
use std::thread;
use std::thread::JoinHandle;
use std::collections::HashSet;

pub struct StoryBuilder {
    article_provider: Arc<(ArticleProvider + Send + Sync)>,
    max_depth: u8,
    visited_nodes: HashSet<String>,
}

impl StoryBuilder  {
    pub fn new(article_provider: Arc<(ArticleProvider + Send + Sync)>) -> StoryBuilder {
        StoryBuilder {
            article_provider,
            max_depth: 5, // default value for now
            visited_nodes: HashSet::new(),
        }
    }

    pub fn build_story(&mut self, start_topic: &str , end_topic: &str) -> Result<String, String> {
        let start_topic = start_topic.to_lowercase();
        let end_topic = end_topic.to_lowercase();
        // If one of the topics is an empty string, do not try to make a story out of it.
        if start_topic == "" {
            return Err("Missing start topic.".to_owned());
        }
        if end_topic == "" {
            return Err("Missing end topic.".to_owned());
        }

        // If both topics are the same,
        // there is no point in trying to figure out the story.
        if start_topic == end_topic {
            return Err("No story to build; same start and end topics.".to_owned());
        }

        // Load the first article
        let start_article = match self.article_provider.get(&start_topic) {
            Some(start_article) => start_article,
            None => {return Err(self.build_suggestions_msg(&start_topic));},
        };
        self.visited_nodes.insert(start_topic);
        // Load the end article
        match self.article_provider.get(&end_topic) {
            Some(end_topic) => end_topic,
            None => {return Err(self.build_suggestions_msg(&end_topic));},
        };

        /* To build a story, we need to build a tree starting at the start_article
           node and going down in a "breadth-first" way; that way, once we find
           the end note, we know it is the shortest path to it. Also, going depth-first
           will be impossibly long to complete sincethe depth of the wikipedia
           article tree is almost infinite. */
        /* We look for a paragraph that holds a reference to our end topic
           somewhere in the last level we fetched: */
        let mut last_level: Vec<Rc<ArticleNode>> = vec![Rc::new(ArticleNode::new(start_article))]; // starts with start article
        for i in 0..self.max_depth { // To prevent overloading the system, stop after X level deep
            // Start by loading the next level of articles:
            if i > 0 {
                // Any other iteration: go one level deeper:
                let mut current_level = vec![];
                for rc_article_node in last_level.iter() {
                    /* Iterate on each paragraph of this article, then map on it to
                       get the article for each related topic in it. */
                    let rc_local = rc_article_node.clone();
                    let article = rc_local.deref();
                    for paragraph in article.get_paragraphs().iter() {
                        // First: spawn all threads first
                        let mut threads: Vec<JoinHandle<Option<Box<Article + Send + Sync>>>> = Vec::new();
                        for topic in paragraph.topics.iter() {
                            let topic = topic.to_lowercase();
                            if !self.visited_nodes.contains(&topic) {
                                // Do not access the same article more than once!!
                                let article_provider = self.article_provider.clone();
                                let topic_for_thread = topic.to_owned();
                                threads.push(thread::spawn(move || {
                                    article_provider.get(&topic_for_thread)
                                }));
                                self.visited_nodes.insert(topic);
                            }
                        }
                        // Then, join them up one at a time.
                        for t in threads.into_iter() {
                            match t.join().unwrap() {
                                Some(content) => {
                                    let mut new_node = ArticleNode::new(content);
                                    new_node.attach_to(rc_local.clone(), &paragraph.text);
                                    current_level.push(Rc::new(new_node));
                                },
                                None => (),
                            }
                        }
                    }
                }
                last_level = current_level;
            }
            // Replace the previous level with this level.

            for article_node in last_level.iter() {
                if let Some(text) = StoryBuilder::find_text_for_topic_in_article(article_node.deref().deref().borrow(), &end_topic) {
                    // Found the topic. Format and return.
                    return Ok(StoryBuilder::build_final_text(article_node.clone(), text, &end_topic));
                }
            }
        }

        Err(format!("Reached depth of <{}> without finding <{}>. Stopping search.", self.max_depth, end_topic).to_owned())
    }

    fn build_suggestions_msg(&self, topic: &str) -> String {
        let mut msg = String::from(format!("Cannot find wikipedia article for <{}>, try one of the following suggestions:\r\n", topic));
        for sugg in self.article_provider.search(topic) {
            msg.push_str(&format!("- {}\r\n", &sugg));
        }

        msg
    }

    fn find_text_for_topic_in_article<'b>(article: &'b (Article + Send + Sync), topic: &str) -> Option<&'b str> {
        if let Some(paragraph) = article.get_paragraphs().iter().find(|par| {
            // if any of the topics in the paragraph is <end>, return it.
            par.topics.iter().any(|t| {&t.to_lowercase() == topic})
        }) {
            // We found the paragraph; return it directly.
            return Some(&paragraph.text);
        } else {
            None
        }
    }

    fn build_final_text(article_node: Rc<ArticleNode>, final_text: &str, final_topic: &str) -> String {
        let mut texts: Vec<String> = Vec::new();
        let mut last_topic = final_topic.to_owned();
        texts.push(format!("{}\r\n", final_text));
        {
            let n: &ArticleNode = article_node.borrow();
            if let Some(n_text) = n.text() {
                let new_topic = n.get_topic().to_owned();
                texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                last_topic = new_topic;
                texts.push(format!("{}\r\n", n_text));
            }
        }

        let mut node = article_node;
        loop {
            node = match node.parent() {
                Some(rc) => {
                    {
                        let n: &ArticleNode = rc.borrow();
                        if let Some(n_text) = n.text() {
                            let new_topic = n.get_topic().to_owned();
                            texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                            last_topic = new_topic;
                            texts.push(format!("{}\r\n", n_text));
                        }
                    }
                    rc
                },
                _ => {
                    let new_topic = node.get_topic().to_owned();
                    texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                    return texts.into_iter().rev().collect();
                },
            }
        }
    }
}

struct ArticleNode {
    data: Box<Article + Send + Sync>,
    parent: Option<Rc<ArticleNode>>,
    text: Option<String>,
}

impl ArticleNode {
    fn new(data: Box<Article + Send + Sync>) -> ArticleNode {
        ArticleNode {
            data,
            parent: None,
            text: None,
        }
    }
    fn attach_to(&mut self, parent: Rc<ArticleNode>, paragraph_text: &str) {
        self.parent = Some(parent);
        self.text = Some(String::from(paragraph_text));
    }
    fn parent(&self) -> Option<Rc<ArticleNode>> {
        self.parent.clone()
    }
    fn text(&self) -> Option<String> {
        self.text.clone()
    }
}

impl <'n> Deref for ArticleNode {
    type Target = Box<Article + Send + Sync>;

    fn deref(&self) -> &Box<Article + Send + Sync> {
        &self.data
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>extern crate getopts;

use std::ascii::AsciiExt;
use std::cmp::min as min;
use std::os;
use std::io;

fn main() {
  let input_args = os::args();

  let args = match parse_args(&input_args) {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  println!("Initial search: \"{}\"", args.initial_search);

  let choices = read_choices();

  println!("");
  println!("Choices:");
  for choice in choices.iter() {
    println!("{}", choice);
  }
}

struct Args {
  initial_search: String,
  help: bool,
}

fn parse_args(args: &Vec<String>) -> Option<Args> {
  let opts = [
    getopts::optflag("h", "help", "Show this message"),
    getopts::optopt("s", "search", "Specify an initial search string", "SEARCH"),
  ];

  let matches = match getopts::getopts(args.tail(), &opts) {
    Ok(m) => m,
    Err(f) => {
      println!("{}", f);
      print_usage(args[0].as_slice(), &opts);
      return None;
    }
  };

  let initial_search = match matches.opt_str("search") {
    Some(x) => x.clone(),
    None => String::from_str(""),
  };

  let help = matches.opt_present("help");
  if help {
    print_usage(args[0].as_slice(), &opts);
  }

  Some(Args { initial_search: initial_search, help: help })
}

fn print_usage(program: &str, opts: &[getopts::OptGroup]) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", getopts::usage(brief.as_slice(), opts));
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  loop {
    match stdin.read_line() {
      Ok(x) => lines.push(String::from_str(x.as_slice().trim())),
      Err(_) => break,
    }
  }

  lines
}

fn score(choice: &str, query: &str) -> f64 {
  if query.len() == 0 {
    return 1.0;
  }
  if choice.len() == 0 {
    return 0.0;
  }

  let query = query.to_ascii_lowercase();
  let choice = choice.to_ascii_lowercase();

  match compute_match_length(choice.as_slice(), query.as_slice()) {
    None => return 0.0,
    Some(match_length) => {
      let score = query.len() as f64 / match_length as f64;
      return score as f64 / choice.len() as f64;
    }
  }
}

fn compute_match_length(string: &str, chars: &str) -> Option<usize> {
  let first_char = chars.char_at(0);
  let rest = chars.slice(1, chars.len());
  let indices = find_char_in_string(string, first_char);

  let mut current_min: Option<usize> = None;
  for i in indices.iter() {
    let last_index = find_end_of_match(string, rest, *i);
    if last_index.is_some() {
      let idx = last_index.unwrap() - *i + 1;
      if current_min.is_some() {
        let cm = min(current_min.unwrap(), idx);
        current_min = Some(cm);
      } else {
        current_min = Some(idx)
      }
    }
  }
  return current_min;
}

fn find_char_in_string(string: &str, char: char) -> Vec<usize> {
  let mut indices = Vec::new();
  let mut i = 0;
  for c in string.chars() {
    if c == char {
      indices.push(i);
    }
    i = i + 1;
  }
  return indices;
}

fn find_end_of_match(string: &str, rest_of_query: &str, first_index: usize) -> Option<usize> {
  let mut last_index = first_index + 1;
  for c in rest_of_query.chars() {
    let current_substring = string.slice_chars(last_index, string.len());
    match current_substring.find(c) {
      None => return None,
      Some(ref i) => {
        last_index += *i + 1;
      }
    }
  }
  return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
  assert_eq!(find_end_of_match("a", "a", 0), None);
  assert_eq!(find_end_of_match("ba", "a", 1), None);
  assert_eq!(find_end_of_match("aaa", "aa", 0), Some(2));
  assert_eq!(find_end_of_match("aaa", "b", 0), None);
  assert_eq!(find_end_of_match("this is a long match", "this is a match", 0), None);
  assert_eq!(find_end_of_match("this is a long match", "his is a match", 0), Some(19));
}

#[test]
fn basic_scoring() {
  assert_eq!(score("", "a"), 0.0);
  assert_eq!(score("a", ""), 1.0);
  assert_eq!(score("short", "longer"), 0.0);
  assert_eq!(score("a", "b"), 0.0);
  assert_eq!(score("ab", "ac"), 0.0);

  assert!(score("a", "a") > 0.0);
  assert!(score("ab", "a") > 0.0);
  assert!(score("ba", "a") > 0.0);
  assert!(score("bab", "a") > 0.0);
  assert!(score("babababab", "aaaa") > 0.0);

  assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
  assert_eq!(score("ab", "ab"), 0.5);
  assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
  assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
  assert!(score("/! symbols $^", "/!$^") > 0.0);

  assert_eq!(score("a", "A"), 1.0);
  assert_eq!(score("A", "a"), 1.0);

  assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
  assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
  assert!(score("README.md", "em") > score("benchmark.rb", "em"));
  assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

  assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
  assert!(score("foo", "foo") > score("longer foo", "foo"));
  assert!(score("foo", "foo") > score("foo longer", "foo"));
  assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

  assert!(score("long 12 long", "12") > score("1 long 2", "12"));

  assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
  assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<commit_msg>Minor tweaks<commit_after>extern crate getopts;

use std::ascii::AsciiExt;
use std::cmp::min;
use std::os;
use std::io;

fn main() {
  let input_args = os::args();

  let args = match parse_args(&input_args) {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  println!("Initial search: \"{}\"", args.initial_search);

  let choices = read_choices();

  println!("");
  println!("Choices:");
  for choice in choices.iter() {
    println!("{}", choice);
  }
}

struct Args {
  initial_search: String,
  help: bool,
}

fn parse_args(args: &Vec<String>) -> Option<Args> {
  let opts = [
    getopts::optflag("h", "help", "Show this message"),
    getopts::optopt("s", "search", "Specify an initial search string", "SEARCH"),
  ];

  let matches = match getopts::getopts(args.tail(), &opts) {
    Ok(m) => m,
    Err(f) => {
      println!("{}", f);
      print_usage(args[0].as_slice(), &opts);
      return None;
    }
  };

  let initial_search = match matches.opt_str("search") {
    Some(x) => x.clone(),
    None => String::from_str(""),
  };

  let help = matches.opt_present("help");
  if help {
    print_usage(args[0].as_slice(), &opts);
  }

  Some(Args { initial_search: initial_search, help: help })
}

fn print_usage(program: &str, opts: &[getopts::OptGroup]) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", getopts::usage(brief.as_slice(), opts));
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  loop {
    match stdin.read_line() {
      Ok(x) => lines.push(String::from_str(x.as_slice().trim())),
      Err(_) => break,
    }
  }

  lines
}

fn score(choice: &str, query: &str) -> f64 {
  if query.len() == 0 {
    return 1.0;
  }
  if choice.len() == 0 {
    return 0.0;
  }

  let query = query.to_ascii_lowercase();
  let choice = choice.to_ascii_lowercase();

  match compute_match_length(choice.as_slice(), query.as_slice()) {
    None => return 0.0,
    Some(match_length) => {
      let score = query.len() as f64 / match_length as f64;
      return score as f64 / choice.len() as f64;
    }
  }
}

fn compute_match_length(string: &str, chars: &str) -> Option<usize> {
  let first_char = chars.char_at(0);
  let rest = chars.slice(1, chars.len());
  let indices = find_char_in_string(string, first_char);

  let mut current_min = None;
  for i in indices.iter() {
    let last_index = find_end_of_match(string, rest, *i);
    if last_index.is_some() {
      let idx = last_index.unwrap() - *i + 1;
      if current_min.is_some() {
        let cm = min(current_min.unwrap(), idx);
        current_min = Some(cm);
      } else {
        current_min = Some(idx)
      }
    }
  }
  return current_min;
}

fn find_char_in_string(string: &str, char: char) -> Vec<usize> {
  let mut indices = Vec::new();
  let mut i = 0;
  for c in string.chars() {
    if c == char {
      indices.push(i);
    }
    i = i + 1;
  }
  return indices;
}

fn find_end_of_match(string: &str, rest_of_query: &str, first_index: usize) -> Option<usize> {
  let mut last_index = first_index + 1;
  for c in rest_of_query.chars() {
    let current_substring = string.slice_chars(last_index, string.len());
    match current_substring.find(c) {
      None => return None,
      Some(ref i) => {
        last_index += *i + 1;
      }
    }
  }
  return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
  assert_eq!(find_end_of_match("a", "a", 0), None);
  assert_eq!(find_end_of_match("ba", "a", 1), None);
  assert_eq!(find_end_of_match("aaa", "aa", 0), Some(2));
  assert_eq!(find_end_of_match("aaa", "b", 0), None);
  assert_eq!(find_end_of_match("this is a long match", "this is a match", 0), None);
  assert_eq!(find_end_of_match("this is a long match", "his is a match", 0), Some(19));
}

#[test]
fn basic_scoring() {
  assert_eq!(score("", "a"), 0.0);
  assert_eq!(score("a", ""), 1.0);
  assert_eq!(score("short", "longer"), 0.0);
  assert_eq!(score("a", "b"), 0.0);
  assert_eq!(score("ab", "ac"), 0.0);

  assert!(score("a", "a") > 0.0);
  assert!(score("ab", "a") > 0.0);
  assert!(score("ba", "a") > 0.0);
  assert!(score("bab", "a") > 0.0);
  assert!(score("babababab", "aaaa") > 0.0);

  assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
  assert_eq!(score("ab", "ab"), 0.5);
  assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
  assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
  assert!(score("/! symbols $^", "/!$^") > 0.0);

  assert_eq!(score("a", "A"), 1.0);
  assert_eq!(score("A", "a"), 1.0);

  assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
  assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
  assert!(score("README.md", "em") > score("benchmark.rb", "em"));
  assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

  assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
  assert!(score("foo", "foo") > score("longer foo", "foo"));
  assert!(score("foo", "foo") > score("foo longer", "foo"));
  assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

  assert!(score("long 12 long", "12") > score("1 long 2", "12"));

  assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
  assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

use aster::AstBuilder;

use syntax::ast;
use syntax::visit;

use internals::ast::Item;
use internals::attr;

// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &ast::Generics) -> ast::Generics {
    ast::Generics {
        ty_params: generics.ty_params.iter().map(|ty_param| {
            ast::TyParam {
                default: None,
                .. ty_param.clone()
            }}).collect(),
        .. generics.clone()
    }
}

pub fn with_where_predicates(
    builder: &AstBuilder,
    generics: &ast::Generics,
    predicates: &[ast::WherePredicate],
) -> ast::Generics {
    builder.from_generics(generics.clone())
        .with_predicates(predicates.to_vec())
        .build()
}

pub fn with_where_predicates_from_fields<F>(
    builder: &AstBuilder,
    item: &Item,
    generics: &ast::Generics,
    from_field: F,
) -> ast::Generics
    where F: Fn(&attr::Field) -> Option<&[ast::WherePredicate]>,
{
    builder.from_generics(generics.clone())
        .with_predicates(
            item.body.all_fields()
                .flat_map(|field| from_field(&field.attrs))
                .flat_map(|predicates| predicates.to_vec()))
        .build()
}

// Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true.
//
// For example, the following struct needs the bound `A: Serialize, B: Serialize`.
//
//     struct S<'b, A, B: 'b, C> {
//         a: A,
//         b: Option<&'b B>
//         #[serde(skip_serializing)]
//         c: C,
//     }
pub fn with_bound<F>(
    builder: &AstBuilder,
    item: &Item,
    generics: &ast::Generics,
    filter: F,
    bound: &ast::Path,
) -> ast::Generics
    where F: Fn(&attr::Field) -> bool,
{
    struct FindTyParams {
        // Set of all generic type parameters on the current struct (A, B, C in
        // the example). Initialized up front.
        all_ty_params: HashSet<ast::Ident>,
        // Set of generic type parameters used in fields for which filter
        // returns true (A and B in the example). Filled in as the visitor sees
        // them.
        relevant_ty_params: HashSet<ast::Ident>,
    }
    impl visit::Visitor for FindTyParams {
        fn visit_path(&mut self, path: &ast::Path, _id: ast::NodeId) {
            if !path.global && path.segments.len() == 1 {
                let id = path.segments[0].identifier;
                if self.all_ty_params.contains(&id) {
                    self.relevant_ty_params.insert(id);
                }
            }
            visit::walk_path(self, path);
        }
    }

    let all_ty_params: HashSet<_> = generics.ty_params.iter()
        .map(|ty_param| ty_param.ident)
        .collect();

    let relevant_tys = item.body.all_fields()
        .filter(|&field| filter(&field.attrs))
        .map(|field| &field.ty);

    let mut visitor = FindTyParams {
        all_ty_params: all_ty_params,
        relevant_ty_params: HashSet::new(),
    };
    for ty in relevant_tys {
        visit::walk_ty(&mut visitor, ty);
    }

    builder.from_generics(generics.clone())
        .with_predicates(
            generics.ty_params.iter()
                .map(|ty_param| ty_param.ident)
                .filter(|id| visitor.relevant_ty_params.contains(id))
                .map(|id| builder.where_predicate()
                    // the type parameter that is being bounded e.g. T
                    .bound().build(builder.ty().id(id))
                    // the bound e.g. Serialize
                    .bound().trait_(bound.clone()).build()
                    .build()))
        .build()
}
<commit_msg>unhygienize the generic parameter comparison<commit_after>use std::collections::HashSet;

use aster::AstBuilder;

use syntax::ast;
use syntax::visit;

use internals::ast::Item;
use internals::attr;

// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &ast::Generics) -> ast::Generics {
    ast::Generics {
        ty_params: generics.ty_params.iter().map(|ty_param| {
            ast::TyParam {
                default: None,
                .. ty_param.clone()
            }}).collect(),
        .. generics.clone()
    }
}

pub fn with_where_predicates(
    builder: &AstBuilder,
    generics: &ast::Generics,
    predicates: &[ast::WherePredicate],
) -> ast::Generics {
    builder.from_generics(generics.clone())
        .with_predicates(predicates.to_vec())
        .build()
}

pub fn with_where_predicates_from_fields<F>(
    builder: &AstBuilder,
    item: &Item,
    generics: &ast::Generics,
    from_field: F,
) -> ast::Generics
    where F: Fn(&attr::Field) -> Option<&[ast::WherePredicate]>,
{
    builder.from_generics(generics.clone())
        .with_predicates(
            item.body.all_fields()
                .flat_map(|field| from_field(&field.attrs))
                .flat_map(|predicates| predicates.to_vec()))
        .build()
}

// Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true.
//
// For example, the following struct needs the bound `A: Serialize, B: Serialize`.
//
//     struct S<'b, A, B: 'b, C> {
//         a: A,
//         b: Option<&'b B>
//         #[serde(skip_serializing)]
//         c: C,
//     }
pub fn with_bound<F>(
    builder: &AstBuilder,
    item: &Item,
    generics: &ast::Generics,
    filter: F,
    bound: &ast::Path,
) -> ast::Generics
    where F: Fn(&attr::Field) -> bool,
{
    struct FindTyParams {
        // Set of all generic type parameters on the current struct (A, B, C in
        // the example). Initialized up front.
        all_ty_params: HashSet<ast::Name>,
        // Set of generic type parameters used in fields for which filter
        // returns true (A and B in the example). Filled in as the visitor sees
        // them.
        relevant_ty_params: HashSet<ast::Name>,
    }
    impl visit::Visitor for FindTyParams {
        fn visit_path(&mut self, path: &ast::Path, _id: ast::NodeId) {
            if !path.global && path.segments.len() == 1 {
                let id = path.segments[0].identifier.name;
                if self.all_ty_params.contains(&id) {
                    self.relevant_ty_params.insert(id);
                }
            }
            visit::walk_path(self, path);
        }
    }

    let all_ty_params: HashSet<_> = generics.ty_params.iter()
        .map(|ty_param| ty_param.ident.name)
        .collect();

    let relevant_tys = item.body.all_fields()
        .filter(|&field| filter(&field.attrs))
        .map(|field| &field.ty);

    let mut visitor = FindTyParams {
        all_ty_params: all_ty_params,
        relevant_ty_params: HashSet::new(),
    };
    for ty in relevant_tys {
        visit::walk_ty(&mut visitor, ty);
    }

    builder.from_generics(generics.clone())
        .with_predicates(
            generics.ty_params.iter()
                .map(|ty_param| ty_param.ident.name)
                .filter(|id| visitor.relevant_ty_params.contains(id))
                .map(|id| builder.where_predicate()
                    // the type parameter that is being bounded e.g. T
                    .bound().build(builder.ty().id(id))
                    // the bound e.g. Serialize
                    .bound().trait_(bound.clone()).build()
                    .build()))
        .build()
}
<|endoftext|>