<commit_before>//! Target information

use super::prelude::*;

#[repr(C)]
pub enum LLVMByteOrdering {
    LLVMBigEndian = 0,
    LLVMLittleEndian = 1,
}

pub enum LLVMOpaqueTargetData {}
pub type LLVMTargetDataRef = *mut LLVMOpaqueTargetData;

pub enum LLVMOpaqueTargetLibraryInfotData {}
pub type LLVMTargetLibraryInfoRef = *mut LLVMOpaqueTargetLibraryInfotData;

extern "C" {
    pub fn LLVMInitializeAMDGPUTargetInfo();
    pub fn LLVMInitializeAMDGPUTarget();
    pub fn LLVMInitializeAMDGPUTargetMC();
    pub fn LLVMInitializeAMDGPUAsmPrinter();
    pub fn LLVMInitializeAMDGPUAsmParser();
    // Disassembler?

    pub fn LLVMInitializeSystemZTargetInfo();
    pub fn LLVMInitializeSystemZTarget();
    pub fn LLVMInitializeSystemZTargetMC();
    pub fn LLVMInitializeSystemZAsmPrinter();
    pub fn LLVMInitializeSystemZAsmParser();
    pub fn LLVMInitializeSystemZDisassembler();

    pub fn LLVMInitializeHexagonTargetInfo();
    pub fn LLVMInitializeHexagonTarget();
    pub fn LLVMInitializeHexagonTargetMC();
    pub fn LLVMInitializeHexagonAsmPrinter();
    // AsmParser?
    pub fn LLVMInitializeHexagonDisassembler();

    pub fn LLVMInitializeNVPTXTargetInfo();
    pub fn LLVMInitializeNVPTXTarget();
    pub fn LLVMInitializeNVPTXTargetMC();
    pub fn LLVMInitializeNVPTXAsmPrinter();
    // AsmParser?

    pub fn LLVMInitializeCppBackendTargetInfo();
    pub fn LLVMInitializeCppBackendTarget();
    pub fn LLVMInitializeCppBackendTargetMC();
    // AsmPrinter?
    // AsmParser?

    pub fn LLVMInitializeMSP430TargetInfo();
    pub fn LLVMInitializeMSP430Target();
    pub fn LLVMInitializeMSP430TargetMC();
    pub fn LLVMInitializeMSP430AsmPrinter();
    // AsmParser?

    pub fn LLVMInitializeXCoreTargetInfo();
    pub fn LLVMInitializeXCoreTarget();
    pub fn LLVMInitializeXCoreTargetMC();
    pub fn LLVMInitializeXCoreAsmPrinter();
    // AsmParser?
    pub fn LLVMInitializeXCoreDisassembler();

    pub fn LLVMInitializeMipsTargetInfo();
    pub fn LLVMInitializeMipsTarget();
    pub fn LLVMInitializeMipsTargetMC();
    pub fn LLVMInitializeMipsAsmPrinter();
    pub fn LLVMInitializeMipsAsmParser();
    pub fn LLVMInitializeMipsDisassembler();

    pub fn LLVMInitializeAArch64TargetInfo();
    pub fn LLVMInitializeAArch64Target();
    pub fn LLVMInitializeAArch64TargetMC();
    pub fn LLVMInitializeAArch64AsmPrinter();
    pub fn LLVMInitializeAArch64AsmParser();
    pub fn LLVMInitializeAArch64Disassembler();

    pub fn LLVMInitializeARMTargetInfo();
    pub fn LLVMInitializeARMTarget();
    pub fn LLVMInitializeARMTargetMC();
    pub fn LLVMInitializeARMAsmPrinter();
    pub fn LLVMInitializeARMAsmParser();
    pub fn LLVMInitializeARMDisassembler();

    pub fn LLVMInitializePowerPCTargetInfo();
    pub fn LLVMInitializePowerPCTarget();
    pub fn LLVMInitializePowerPCTargetMC();
    pub fn LLVMInitializePowerPCAsmPrinter();
    pub fn LLVMInitializePowerPCAsmParser();
    pub fn LLVMInitializePowerPCDisassembler();

    pub fn LLVMInitializeSparcTargetInfo();
    pub fn LLVMInitializeSparcTarget();
    pub fn LLVMInitializeSparcTargetMC();
    pub fn LLVMInitializeSparcAsmPrinter();
    pub fn LLVMInitializeSparcAsmParser();
    pub fn LLVMInitializeSparcDisassembler();

    pub fn LLVMInitializeX86TargetInfo();
    pub fn LLVMInitializeX86Target();
    pub fn LLVMInitializeX86TargetMC();
    pub fn LLVMInitializeX86AsmPrinter();
    pub fn LLVMInitializeX86AsmParser();
    pub fn LLVMInitializeX86Disassembler();

    pub fn LLVMInitializeBPFTargetInfo();
    pub fn LLVMInitializeBPFTarget();
    pub fn LLVMInitializeBPFTargetMC();
    pub fn LLVMInitializeBPFAsmPrinter();
    // No AsmParser
    pub fn LLVMInitializeBPFDisassembler();
}

extern "C" {
    /// Get the data layout for a module.
    pub fn LLVMGetModuleDataLayout(M: LLVMModuleRef) -> LLVMTargetDataRef;
    /// Set the data layout for a module.
    pub fn LLVMSetModuleDataLayout(M: LLVMModuleRef, R: LLVMTargetDataRef);
    /// Create target data from a target layout string.
    pub fn LLVMCreateTargetData(StringRep: *const ::libc::c_char) -> LLVMTargetDataRef;
    pub fn LLVMAddTargetLibraryInfo(TLI: LLVMTargetLibraryInfoRef, PM: LLVMPassManagerRef);
    pub fn LLVMCopyStringRepOfTargetData(TD: LLVMTargetDataRef) -> *mut ::libc::c_char;
    pub fn LLVMByteOrder(TD: LLVMTargetDataRef) -> LLVMByteOrdering;
    pub fn LLVMPointerSize(TD: LLVMTargetDataRef) -> ::libc::c_uint;
    pub fn LLVMPointerSizeForAS(TD: LLVMTargetDataRef, AS: ::libc::c_uint) -> ::libc::c_uint;
    pub fn LLVMIntPtrType(TD: LLVMTargetDataRef) -> LLVMTypeRef;
    pub fn LLVMIntPtrTypeForAS(TD: LLVMTargetDataRef, AS: ::libc::c_uint) -> LLVMTypeRef;
    pub fn LLVMIntPtrTypeInContext(C: LLVMContextRef, TD: LLVMTargetDataRef) -> LLVMTypeRef;
    pub fn LLVMIntPtrTypeForASInContext(C: LLVMContextRef,
                                        TD: LLVMTargetDataRef,
                                        AS: ::libc::c_uint)
                                        -> LLVMTypeRef;
    pub fn LLVMSizeOfTypeInBits(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_ulonglong;
    pub fn LLVMStoreSizeOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_ulonglong;
    pub fn LLVMABISizeOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_ulonglong;
    pub fn LLVMABIAlignmentOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_uint;
    pub fn LLVMCallFrameAlignmentOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_uint;
    pub fn LLVMPreferredAlignmentOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_uint;
    pub fn LLVMPreferredAlignmentOfGlobal(TD: LLVMTargetDataRef,
                                          GlobalVar: LLVMValueRef)
                                          -> ::libc::c_uint;
    pub fn LLVMElementAtOffset(TD: LLVMTargetDataRef,
                               StructTy: LLVMTypeRef,
                               Offset: ::libc::c_ulonglong)
                               -> ::libc::c_uint;
    pub fn LLVMOffsetOfElement(TD: LLVMTargetDataRef,
                               StructTy: LLVMTypeRef,
                               Element: ::libc::c_uint)
                               -> ::libc::c_ulonglong;
    pub fn LLVMDisposeTargetData(TD: LLVMTargetDataRef);
}

// Functions from our target wrappers, since the C interface defines them with
// macros (wrappers/target.c).
extern "C" {
    pub fn LLVM_InitializeAllTargetInfos();
    pub fn LLVM_InitializeAllTargets();
    pub fn LLVM_InitializeAllTargetMCs();
    pub fn LLVM_InitializeAllAsmPrinters();
    pub fn LLVM_InitializeAllAsmParsers();
    pub fn LLVM_InitializeAllDisassemblers();

    /// Returns 1 on failure.
    pub fn LLVM_InitializeNativeTarget() -> LLVMBool;
    /// Returns 1 on failure.
    pub fn LLVM_InitializeNativeAsmParser() -> LLVMBool;
    /// Returns 1 on failure.
    pub fn LLVM_InitializeNativeAsmPrinter() -> LLVMBool;
    /// Returns 1 on failure.
    pub fn LLVM_InitializeNativeDisassembler() -> LLVMBool;
}
<commit_msg>Add Lanai and RISCV target bindings.<commit_after>//! Target information

use super::prelude::*;

#[repr(C)]
pub enum LLVMByteOrdering {
    LLVMBigEndian = 0,
    LLVMLittleEndian = 1,
}

pub enum LLVMOpaqueTargetData {}
pub type LLVMTargetDataRef = *mut LLVMOpaqueTargetData;

pub enum LLVMOpaqueTargetLibraryInfotData {}
pub type LLVMTargetLibraryInfoRef = *mut LLVMOpaqueTargetLibraryInfotData;

extern "C" {
    pub fn LLVMInitializeAMDGPUTargetInfo();
    pub fn LLVMInitializeAMDGPUTarget();
    pub fn LLVMInitializeAMDGPUTargetMC();
    pub fn LLVMInitializeAMDGPUAsmPrinter();
    pub fn LLVMInitializeAMDGPUAsmParser();
    // Disassembler?

    pub fn LLVMInitializeSystemZTargetInfo();
    pub fn LLVMInitializeSystemZTarget();
    pub fn LLVMInitializeSystemZTargetMC();
    pub fn LLVMInitializeSystemZAsmPrinter();
    pub fn LLVMInitializeSystemZAsmParser();
    pub fn LLVMInitializeSystemZDisassembler();

    pub fn LLVMInitializeHexagonTargetInfo();
    pub fn LLVMInitializeHexagonTarget();
    pub fn LLVMInitializeHexagonTargetMC();
    pub fn LLVMInitializeHexagonAsmPrinter();
    // AsmParser?
    pub fn LLVMInitializeHexagonDisassembler();

    pub fn LLVMInitializeNVPTXTargetInfo();
    pub fn LLVMInitializeNVPTXTarget();
    pub fn LLVMInitializeNVPTXTargetMC();
    pub fn LLVMInitializeNVPTXAsmPrinter();
    // AsmParser?

    pub fn LLVMInitializeCppBackendTargetInfo();
    pub fn LLVMInitializeCppBackendTarget();
    pub fn LLVMInitializeCppBackendTargetMC();
    // AsmPrinter?
    // AsmParser?

    pub fn LLVMInitializeMSP430TargetInfo();
    pub fn LLVMInitializeMSP430Target();
    pub fn LLVMInitializeMSP430TargetMC();
    pub fn LLVMInitializeMSP430AsmPrinter();
    // AsmParser?

    pub fn LLVMInitializeXCoreTargetInfo();
    pub fn LLVMInitializeXCoreTarget();
    pub fn LLVMInitializeXCoreTargetMC();
    pub fn LLVMInitializeXCoreAsmPrinter();
    // AsmParser?
    pub fn LLVMInitializeXCoreDisassembler();

    pub fn LLVMInitializeMipsTargetInfo();
    pub fn LLVMInitializeMipsTarget();
    pub fn LLVMInitializeMipsTargetMC();
    pub fn LLVMInitializeMipsAsmPrinter();
    pub fn LLVMInitializeMipsAsmParser();
    pub fn LLVMInitializeMipsDisassembler();

    pub fn LLVMInitializeAArch64TargetInfo();
    pub fn LLVMInitializeAArch64Target();
    pub fn LLVMInitializeAArch64TargetMC();
    pub fn LLVMInitializeAArch64AsmPrinter();
    pub fn LLVMInitializeAArch64AsmParser();
    pub fn LLVMInitializeAArch64Disassembler();

    pub fn LLVMInitializeARMTargetInfo();
    pub fn LLVMInitializeARMTarget();
    pub fn LLVMInitializeARMTargetMC();
    pub fn LLVMInitializeARMAsmPrinter();
    pub fn LLVMInitializeARMAsmParser();
    pub fn LLVMInitializeARMDisassembler();

    pub fn LLVMInitializePowerPCTargetInfo();
    pub fn LLVMInitializePowerPCTarget();
    pub fn LLVMInitializePowerPCTargetMC();
    pub fn LLVMInitializePowerPCAsmPrinter();
    pub fn LLVMInitializePowerPCAsmParser();
    pub fn LLVMInitializePowerPCDisassembler();

    pub fn LLVMInitializeSparcTargetInfo();
    pub fn LLVMInitializeSparcTarget();
    pub fn LLVMInitializeSparcTargetMC();
    pub fn LLVMInitializeSparcAsmPrinter();
    pub fn LLVMInitializeSparcAsmParser();
    pub fn LLVMInitializeSparcDisassembler();

    pub fn LLVMInitializeX86TargetInfo();
    pub fn LLVMInitializeX86Target();
    pub fn LLVMInitializeX86TargetMC();
    pub fn LLVMInitializeX86AsmPrinter();
    pub fn LLVMInitializeX86AsmParser();
    pub fn LLVMInitializeX86Disassembler();

    pub fn LLVMInitializeBPFTargetInfo();
    pub fn LLVMInitializeBPFTarget();
    pub fn LLVMInitializeBPFTargetMC();
    pub fn LLVMInitializeBPFAsmPrinter();
    // No AsmParser
    pub fn LLVMInitializeBPFDisassembler();

    pub fn LLVMInitializeLanaiTargetInfo();
    pub fn LLVMInitializeLanaiTarget();
    pub fn LLVMInitializeLanaiTargetMC();
    pub fn LLVMInitializeLanaiAsmPrinter();
    pub fn LLVMInitializeLanaiAsmParser();
    pub fn LLVMInitializeLanaiDisassembler();

    pub fn LLVMInitializeRISCVTargetInfo();
    pub fn LLVMInitializeRISCVTarget();
    pub fn LLVMInitializeRISCVTargetMC();
    // No AsmPrinter
    // No AsmParser
    // No Disassembler
}

extern "C" {
    /// Get the data layout for a module.
    pub fn LLVMGetModuleDataLayout(M: LLVMModuleRef) -> LLVMTargetDataRef;
    /// Set the data layout for a module.
    pub fn LLVMSetModuleDataLayout(M: LLVMModuleRef, R: LLVMTargetDataRef);
    /// Create target data from a target layout string.
    pub fn LLVMCreateTargetData(StringRep: *const ::libc::c_char) -> LLVMTargetDataRef;
    pub fn LLVMAddTargetLibraryInfo(TLI: LLVMTargetLibraryInfoRef, PM: LLVMPassManagerRef);
    pub fn LLVMCopyStringRepOfTargetData(TD: LLVMTargetDataRef) -> *mut ::libc::c_char;
    pub fn LLVMByteOrder(TD: LLVMTargetDataRef) -> LLVMByteOrdering;
    pub fn LLVMPointerSize(TD: LLVMTargetDataRef) -> ::libc::c_uint;
    pub fn LLVMPointerSizeForAS(TD: LLVMTargetDataRef, AS: ::libc::c_uint) -> ::libc::c_uint;
    pub fn LLVMIntPtrType(TD: LLVMTargetDataRef) -> LLVMTypeRef;
    pub fn LLVMIntPtrTypeForAS(TD: LLVMTargetDataRef, AS: ::libc::c_uint) -> LLVMTypeRef;
    pub fn LLVMIntPtrTypeInContext(C: LLVMContextRef, TD: LLVMTargetDataRef) -> LLVMTypeRef;
    pub fn LLVMIntPtrTypeForASInContext(C: LLVMContextRef,
                                        TD: LLVMTargetDataRef,
                                        AS: ::libc::c_uint)
                                        -> LLVMTypeRef;
    pub fn LLVMSizeOfTypeInBits(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_ulonglong;
    pub fn LLVMStoreSizeOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_ulonglong;
    pub fn LLVMABISizeOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_ulonglong;
    pub fn LLVMABIAlignmentOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_uint;
    pub fn LLVMCallFrameAlignmentOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_uint;
    pub fn LLVMPreferredAlignmentOfType(TD: LLVMTargetDataRef, Ty: LLVMTypeRef) -> ::libc::c_uint;
    pub fn LLVMPreferredAlignmentOfGlobal(TD: LLVMTargetDataRef,
                                          GlobalVar: LLVMValueRef)
                                          -> ::libc::c_uint;
    pub fn LLVMElementAtOffset(TD: LLVMTargetDataRef,
                               StructTy: LLVMTypeRef,
                               Offset: ::libc::c_ulonglong)
                               -> ::libc::c_uint;
    pub fn LLVMOffsetOfElement(TD: LLVMTargetDataRef,
                               StructTy: LLVMTypeRef,
                               Element: ::libc::c_uint)
                               -> ::libc::c_ulonglong;
    pub fn LLVMDisposeTargetData(TD: LLVMTargetDataRef);
}

// Functions from our target wrappers, since the C interface defines them with
// macros (wrappers/target.c).
extern "C" {
    pub fn LLVM_InitializeAllTargetInfos();
    pub fn LLVM_InitializeAllTargets();
    pub fn LLVM_InitializeAllTargetMCs();
    pub fn LLVM_InitializeAllAsmPrinters();
    pub fn LLVM_InitializeAllAsmParsers();
    pub fn LLVM_InitializeAllDisassemblers();

    /// Returns 1 on failure.
    pub fn LLVM_InitializeNativeTarget() -> LLVMBool;
    /// Returns 1 on failure.
    pub fn LLVM_InitializeNativeAsmParser() -> LLVMBool;
    /// Returns 1 on failure.
    pub fn LLVM_InitializeNativeAsmPrinter() -> LLVMBool;
    /// Returns 1 on failure.
    pub fn LLVM_InitializeNativeDisassembler() -> LLVMBool;
}
<|endoftext|>


<commit_before>//! Functions for performing template matching.
use definitions::Image;
use rect::Rect;
use integral_image::{integral_squared_image, sum_image_pixels};
use image::{GenericImage, GrayImage, Luma};

/// Method used to compute the matching score between a template and an image region.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum MatchTemplateMethod {
    /// Sum of the squares of the difference between image and template pixel
    /// intensities.
    SumOfSquaredErrors,
    /// Divides the sum computed using `SumOfSquaredErrors` by a normalization term.
    SumOfSquaredErrorsNormalized,
}

/// Slides a `template` over an `image` and scores the match at each point using
/// the requested `method`.
///
/// The returned image has dimensions `image.width() - template.width() + 1` by
/// `image.height() - template.height() + 1`.
///
/// # Panics
///
/// If either dimension of `template` is not strictly less than the corresponding dimension
/// of `image`.
pub fn match_template(image: &GrayImage, template: &GrayImage, method: MatchTemplateMethod) -> Image<Luma<f32>> {
    let (image_width, image_height) = image.dimensions();
    let (template_width, template_height) = template.dimensions();

    assert!(image_width > template_width, "image width must strictly exceed template width");
    assert!(image_height > template_height, "image height must strictly exceed template height");

    let should_normalize = method == MatchTemplateMethod::SumOfSquaredErrorsNormalized;
    let image_squared_integral = if should_normalize { Some(integral_squared_image(&image)) } else { None };
    let template_squared_sum = if should_normalize { Some(sum_squares(&template)) } else { None };

    let mut result = Image::new(image_width - template_width + 1, image_height - template_height + 1);

    for y in 0..result.height() {
        for x in 0..result.width() {
            let mut score = 0f32;

            for dy in 0..template_height {
                for dx in 0..template_width {
                    let image_value = unsafe { image.unsafe_get_pixel(x + dx, y + dy)[0] as f32 };
                    let template_value = unsafe { template.unsafe_get_pixel(dx, dy)[0] as f32 };
                    score += (image_value - template_value).powf(2.0);
                }
            }

            if let (&Some(ref i), &Some(t)) = (&image_squared_integral, &template_squared_sum) {
                let region = Rect::at(x as i32, y as i32).of_size(template_width, template_height);
                let norm = normalization_term(i, t, region);
                score /= norm;
            }

            result.put_pixel(x, y, Luma([score]));
        }
    }

    result
}

fn sum_squares(template: &GrayImage) -> f32 {
    template.iter().map(|p| *p as f32 * *p as f32).sum()
}

/// Returns the square root of the product of the sum of squares of
/// pixel intensities in template and the provided region of image.
fn normalization_term(
    image_squared_integral: &Image<Luma<u32>>,
    template_squared_sum: f32,
    region: Rect) -> f32 {
    let image_sum = sum_image_pixels(
        image_squared_integral,
        region.left() as u32,
        region.top() as u32,
        region.right() as u32,
        region.bottom() as u32
    ) as f32;
    (image_sum * template_squared_sum).sqrt()
}

#[cfg(test)]
mod tests {
    use super::*;
    use utils::gray_bench_image;
    use image::GrayImage;
    use test::{Bencher, black_box};

    #[test]
    #[should_panic]
    fn match_template_panics_if_image_width_does_not_exceed_template_width() {
        let _ = match_template(&GrayImage::new(5, 5), &GrayImage::new(5, 4), MatchTemplateMethod::SumOfSquaredErrors);
    }

    #[test]
    #[should_panic]
    fn match_template_panics_if_image_height_does_not_exceed_template_height() {
        let _ = match_template(&GrayImage::new(5, 5), &GrayImage::new(4, 5), MatchTemplateMethod::SumOfSquaredErrors);
    }

    #[test]
    fn match_template_accepts_valid_template_size() {
        let _ = match_template(&GrayImage::new(5, 5), &GrayImage::new(4, 4), MatchTemplateMethod::SumOfSquaredErrors);
    }

    #[test]
    fn match_template_sum_of_squared_errors() {
        let image = gray_image!(
            1, 4, 2;
            2, 1, 3;
            3, 3, 4
        );
        let template = gray_image!(
            1, 2;
            3, 4
        );

        let actual = match_template(&image, &template, MatchTemplateMethod::SumOfSquaredErrors);
        let expected = gray_image!(type: f32,
            14.0, 14.0;
            3.0, 1.0
        );

        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn match_template_sum_of_squared_errors_normalized() {
        let image = gray_image!(
            1, 4, 2;
            2, 1, 3;
            3, 3, 4
        );
        let template = gray_image!(
            1, 2;
            3, 4
        );

        let actual = match_template(&image, &template, MatchTemplateMethod::SumOfSquaredErrorsNormalized);
        let tss = 30f32;
        let expected = gray_image!(type: f32,
            14.0 / (22.0 * tss).sqrt(), 14.0 / (30.0 * tss).sqrt();
            3.0 / (23.0 * tss).sqrt(), 1.0 / (35.0 * tss).sqrt()
        );

        assert_pixels_eq!(actual, expected);
    }

    macro_rules! bench_match_template {
        ($name:ident, image_size: $s:expr, template_size: $t:expr, method: $m:expr) => {
            #[bench]
            fn $name(b: &mut Bencher) {
                let image = gray_bench_image($s, $s);
                let template = gray_bench_image($t, $t);
                b.iter(|| {
                    let result = match_template(&image, &template, MatchTemplateMethod::SumOfSquaredErrors);
                    black_box(result);
                })
            }
        }
    }

    bench_match_template!(
        bench_match_template_s100_t1_sse,
        image_size: 100,
        template_size: 1,
        method: MatchTemplateMethod::SumOfSquaredErrors);

    bench_match_template!(
        bench_match_template_s100_t4_sse,
        image_size: 100,
        template_size: 4,
        method: MatchTemplateMethod::SumOfSquaredErrors);

    bench_match_template!(
        bench_match_template_s100_t16_sse,
        image_size: 100,
        template_size: 16,
        method: MatchTemplateMethod::SumOfSquaredErrors);

        bench_match_template!(
        bench_match_template_s100_t1_sse_norm,
        image_size: 100,
        template_size: 1,
        method: MatchTemplateMethod::SumOfSquaredErrorsNormalized);

    bench_match_template!(
        bench_match_template_s100_t4_sse_norm,
        image_size: 100,
        template_size: 4,
        method: MatchTemplateMethod::SumOfSquaredErrorsNormalized);

    bench_match_template!(
        bench_match_template_s100_t16_sse_norm,
        image_size: 100,
        template_size: 16,
        method: MatchTemplateMethod::SumOfSquaredErrorsNormalized);
}<commit_msg>Add function find_extremes (#262)<commit_after>//! Functions for performing template matching.
use image::Primitive;
use definitions::Image;
use rect::Rect;
use integral_image::{integral_squared_image, sum_image_pixels};
use image::{GenericImage, GrayImage, Luma};

/// Method used to compute the matching score between a template and an image region.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum MatchTemplateMethod {
    /// Sum of the squares of the difference between image and template pixel
    /// intensities.
    SumOfSquaredErrors,
    /// Divides the sum computed using `SumOfSquaredErrors` by a normalization term.
    SumOfSquaredErrorsNormalized,
}

/// Slides a `template` over an `image` and scores the match at each point using
/// the requested `method`.
///
/// The returned image has dimensions `image.width() - template.width() + 1` by
/// `image.height() - template.height() + 1`.
///
/// # Panics
///
/// If either dimension of `template` is not strictly less than the corresponding dimension
/// of `image`.
pub fn match_template(image: &GrayImage, template: &GrayImage, method: MatchTemplateMethod) -> Image<Luma<f32>> {
    let (image_width, image_height) = image.dimensions();
    let (template_width, template_height) = template.dimensions();

    assert!(image_width > template_width, "image width must strictly exceed template width");
    assert!(image_height > template_height, "image height must strictly exceed template height");

    let should_normalize = method == MatchTemplateMethod::SumOfSquaredErrorsNormalized;
    let image_squared_integral = if should_normalize { Some(integral_squared_image(&image)) } else { None };
    let template_squared_sum = if should_normalize { Some(sum_squares(&template)) } else { None };

    let mut result = Image::new(image_width - template_width + 1, image_height - template_height + 1);

    for y in 0..result.height() {
        for x in 0..result.width() {
            let mut score = 0f32;

            for dy in 0..template_height {
                for dx in 0..template_width {
                    let image_value = unsafe { image.unsafe_get_pixel(x + dx, y + dy)[0] as f32 };
                    let template_value = unsafe { template.unsafe_get_pixel(dx, dy)[0] as f32 };
                    score += (image_value - template_value).powf(2.0);
                }
            }

            if let (&Some(ref i), &Some(t)) = (&image_squared_integral, &template_squared_sum) {
                let region = Rect::at(x as i32, y as i32).of_size(template_width, template_height);
                let norm = normalization_term(i, t, region);
                score /= norm;
            }

            result.put_pixel(x, y, Luma([score]));
        }
    }

    result
}

fn sum_squares(template: &GrayImage) -> f32 {
    template.iter().map(|p| *p as f32 * *p as f32).sum()
}

/// Returns the square root of the product of the sum of squares of
/// pixel intensities in template and the provided region of image.
fn normalization_term(
    image_squared_integral: &Image<Luma<u32>>,
    template_squared_sum: f32,
    region: Rect) -> f32 {
    let image_sum = sum_image_pixels(
        image_squared_integral,
        region.left() as u32,
        region.top() as u32,
        region.right() as u32,
        region.bottom() as u32
    ) as f32;
    (image_sum * template_squared_sum).sqrt()
}

/// The largest and smallest values in an image,
/// together with their locations.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Extremes<T> {
    /// The largest value in an image.
    pub max_value: T,
    /// The smallest value in an image.
    pub min_value: T,
    /// The coordinates of the largest value in an image.
    pub max_value_location: (u32, u32),
    /// The coordinates of the smallest value in an image.
    pub min_value_location: (u32, u32)
}

/// Finds the largest and smallest values in an image and their locations.
/// If there are multiple such values then the lexicographically smallest is returned.
pub fn find_extremes<T>(image: &Image<Luma<T>>) -> Extremes<T>
where
    T : Primitive + 'static
{
    assert!(image.width() > 0 && image.height() > 0, "image must be non-empty");

    let mut min_value = image.get_pixel(0, 0)[0];
    let mut max_value = image.get_pixel(0, 0)[0];

    let mut min_value_location = (0, 0);
    let mut max_value_location = (0, 0);

    for (x, y, p) in image.enumerate_pixels() {
        if p[0] < min_value {
            min_value = p[0];
            min_value_location = (x, y);
        }
        if p[0] > max_value {
            max_value = p[0];
            max_value_location = (x, y);
        }
    }

    Extremes { max_value, min_value, max_value_location, min_value_location }
}

#[cfg(test)]
mod tests {
    use super::*;
    use utils::gray_bench_image;
    use image::GrayImage;
    use test::{Bencher, black_box};

    #[test]
    #[should_panic]
    fn match_template_panics_if_image_width_does_not_exceed_template_width() {
        let _ = match_template(&GrayImage::new(5, 5), &GrayImage::new(5, 4), MatchTemplateMethod::SumOfSquaredErrors);
    }

    #[test]
    #[should_panic]
    fn match_template_panics_if_image_height_does_not_exceed_template_height() {
        let _ = match_template(&GrayImage::new(5, 5), &GrayImage::new(4, 5), MatchTemplateMethod::SumOfSquaredErrors);
    }

    #[test]
    fn match_template_accepts_valid_template_size() {
        let _ = match_template(&GrayImage::new(5, 5), &GrayImage::new(4, 4), MatchTemplateMethod::SumOfSquaredErrors);
    }

    #[test]
    fn match_template_sum_of_squared_errors() {
        let image = gray_image!(
            1, 4, 2;
            2, 1, 3;
            3, 3, 4
        );
        let template = gray_image!(
            1, 2;
            3, 4
        );

        let actual = match_template(&image, &template, MatchTemplateMethod::SumOfSquaredErrors);
        let expected = gray_image!(type: f32,
            14.0, 14.0;
            3.0, 1.0
        );

        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn match_template_sum_of_squared_errors_normalized() {
        let image = gray_image!(
            1, 4, 2;
            2, 1, 3;
            3, 3, 4
        );
        let template = gray_image!(
            1, 2;
            3, 4
        );

        let actual = match_template(&image, &template, MatchTemplateMethod::SumOfSquaredErrorsNormalized);
        let tss = 30f32;
        let expected = gray_image!(type: f32,
            14.0 / (22.0 * tss).sqrt(), 14.0 / (30.0 * tss).sqrt();
            3.0 / (23.0 * tss).sqrt(), 1.0 / (35.0 * tss).sqrt()
        );

        assert_pixels_eq!(actual, expected);
    }

    macro_rules! bench_match_template {
        ($name:ident, image_size: $s:expr, template_size: $t:expr, method: $m:expr) => {
            #[bench]
            fn $name(b: &mut Bencher) {
                let image = gray_bench_image($s, $s);
                let template = gray_bench_image($t, $t);
                b.iter(|| {
                    let result = match_template(&image, &template, MatchTemplateMethod::SumOfSquaredErrors);
                    black_box(result);
                })
            }
        }
    }

    bench_match_template!(
        bench_match_template_s100_t1_sse,
        image_size: 100,
        template_size: 1,
        method: MatchTemplateMethod::SumOfSquaredErrors);

    bench_match_template!(
        bench_match_template_s100_t4_sse,
        image_size: 100,
        template_size: 4,
        method: MatchTemplateMethod::SumOfSquaredErrors);

    bench_match_template!(
        bench_match_template_s100_t16_sse,
        image_size: 100,
        template_size: 16,
        method: MatchTemplateMethod::SumOfSquaredErrors);

        bench_match_template!(
        bench_match_template_s100_t1_sse_norm,
        image_size: 100,
        template_size: 1,
        method: MatchTemplateMethod::SumOfSquaredErrorsNormalized);

    bench_match_template!(
        bench_match_template_s100_t4_sse_norm,
        image_size: 100,
        template_size: 4,
        method: MatchTemplateMethod::SumOfSquaredErrorsNormalized);

    bench_match_template!(
        bench_match_template_s100_t16_sse_norm,
        image_size: 100,
        template_size: 16,
        method: MatchTemplateMethod::SumOfSquaredErrorsNormalized);

    #[test]
    fn test_find_extremes() {
        let image = gray_image!(
            10,  7,  8,  1;
             9, 15,  4,  2
        );

        let expected = Extremes {
            max_value: 15,
            min_value: 1,
            max_value_location: (1, 1),
            min_value_location: (3, 0)
        };

        assert_eq!(find_extremes(&image), expected);
    }
}<|endoftext|>


<commit_before>pub fn borrow(num: &str, digit: char) -> Result<String, &'static str> {
    match digit {
        'V' => {
            let mut parts: Vec<&str> = num.rsplitn(2, "X").collect();
            parts.reverse();
            Ok(parts.join("VV"))
        },
        'I' => {
            Ok(num.replace("X", "VV").replace("V", "IIIII"))
        },
        _ => {
            Ok(num.to_string())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::borrow;

    #[test]
    fn cannot_borrow_i_from_ii() {
        assert_eq!("II", borrow("II", 'I').unwrap());
    }

    #[test]
    fn borrow_i_from_v() {
        assert_eq!("IIIII", borrow("V", 'I').unwrap());
    }

    #[test]
    fn borrow_v_from_x() {
        assert_eq!("VV", borrow("X", 'V').unwrap());
    }

    #[test]
    fn borrow_v_from_cx() {
        assert_eq!("CVV", borrow("CX", 'V').unwrap());
    }

    #[test]
    fn borrow_i_from_x_borrows_transitively() {
        assert_eq!("VIIIII", borrow("X", 'I').unwrap());
    }

    #[test]
    fn borrow_v_from_xx_only_borrows_once() {
        assert_eq!("XVV", borrow("XX", 'V').unwrap());
    }
}
<commit_msg>Refactor borrow, preparing for transitive expand<commit_after>use std::cmp::Ordering;

use cmp;

pub fn borrow(num: &str, needed: char) -> Result<String, &'static str> {
    let chars = num.as_bytes();
    let mut _ret: Result<String, &str> = Err("FIXME1");
    for i in (0..chars.len()).rev() {
        match cmp(chars[i] as char, needed) {
            Ordering::Less => {
                //nop
            },
            Ordering::Equal => {
                _ret = Ok(num.to_string());
                break;
            },
            Ordering::Greater => {
                let (prefix, end) = num.split_at(i);
                let (expand_char, suffix) = end.split_at(1);
                match expand_char {
                    "X" => {
                        _ret = Ok(prefix.to_string() + "VV");
                    },
                    "V" => {
                        _ret = Ok(prefix.to_string() + "IIIII");
                    },
                    _ => {
                        _ret = Err("unknown digit");
                    }
                }
                break;
            }
        }
    }

    _ret
}

#[cfg(test)]
mod tests {
    use super::borrow;

    #[test]
    fn cannot_borrow_i_from_ii() {
        assert_eq!("II", borrow("II", 'I').unwrap());
    }

    #[test]
    fn borrow_i_from_v() {
        assert_eq!("IIIII", borrow("V", 'I').unwrap());
    }

    #[test]
    fn borrow_v_from_x() {
        assert_eq!("VV", borrow("X", 'V').unwrap());
    }

    #[test]
    fn borrow_v_from_cx() {
        assert_eq!("CVV", borrow("CX", 'V').unwrap());
    }

    #[test]
    fn borrow_i_from_x_borrows_transitively() {
        assert_eq!("VIIIII", borrow("X", 'I').unwrap());
    }

    #[test]
    fn borrow_v_from_xx_only_borrows_once() {
        assert_eq!("XVV", borrow("XX", 'V').unwrap());
    }

    // FIXME
    // fn borrow_v_from_cxi_returns_the_tail_part_properly() {
    //     assert_eq!("CVVI", borrow("CXI", 'V').unwrap());
    // }
}
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::sync::{Arc, Condvar, Mutex};
use std::{mem, thread};

use crossbeam_deque as deque;

use super::job::{JobRef, StackJob};
use super::latch::{CountLatch, Latch, LatchProbe, LatchWaitProbe, LockLatch};
use super::unwind::AbortIfPanic;
use super::PanicHandler;

pub struct Scheduler {
    terminator: CountLatch,
    watcher: Watcher,
    threads: Vec<ThreadInfo>,

    inject_stealer: deque::Stealer<JobRef>,
    injector: Mutex<deque::Worker<JobRef>>,

    panic_handler: Option<Box<PanicHandler>>,
}

impl Scheduler {
    pub fn new(
        num: u32,
        stack_size: Option<usize>,
        panic_handler: Option<Box<PanicHandler>>,
    ) -> Arc<Self> {
        let mut stealers = Vec::new();
        let mut workers = Vec::new();

        for _ in 0..num {
            let (w, s) = deque::fifo();
            workers.push(w);
            stealers.push(s);
        }

        let (w, s) = deque::fifo();
        let stealers = stealers
            .into_iter()
            .map(|v| ThreadInfo {
                stealer: v,
                primed: LockLatch::new(),
                terminated: LockLatch::new(),
            })
            .collect();

        let scheduler = Arc::new(Scheduler {
            threads: stealers,
            injector: Mutex::new(w),
            inject_stealer: s,
            panic_handler: panic_handler,
            terminator: CountLatch::new(),
            watcher: Watcher(Mutex::new(()), Condvar::new()),
        });

        for (i, w) in workers.drain(..).enumerate() {
            let sc = scheduler.clone();
            let mut b = thread::Builder::new();

            if let Some(stack_size) = stack_size {
                b = b.stack_size(stack_size);
            }

            b.spawn(move || unsafe { Scheduler::main_loop(sc, i, w) })
                .unwrap();
        }

        for v in &scheduler.threads {
            v.primed.wait();
        }

        scheduler
    }

    /// Push a job into the "external jobs" queue; it will be taken by whatever
    /// worker has nothing to do.
    pub fn inject(&self, job: JobRef) {
        {
            let injector = self.injector.lock().unwrap();
            injector.push(job);
        }

        self.watcher.notify_one();
    }

    // /// Push a slice of jobs into the "external jobs" queue; it will be taken by
    // /// whatever worker has nothing to do.
    // fn inject_slice(&self, jobs: &[JobRef]) {
    //     {
    //         let injector = self.injector.lock().unwrap();
    //         for &job in jobs {
    //             injector.push(job);
    //         }
    //     }

    //     self.watcher.notify_all();
    // }

    /// Push a job into the given `registry`. If we are running on a worker thread for
    /// the registry, this will push onto the deque. Else, it will inject from the
    /// outside (which is slower).
    pub fn inject_or_push(&self, job: JobRef) {
        unsafe {
            let worker_thread = WorkerThread::current();
            if worker_thread.is_null() {
                self.inject(job);
            } else {
                (*worker_thread).push(job);
                self.watcher.notify_one();
            }
        }
    }

    /// If already in a worker-thread of this registry, just execute `op`.
    /// Otherwise, inject `op` in this thread-pool. Either way, block until `op`
    /// completes and return its return value. If `op` panics, that panic will
    /// be propagated as well.  The second argument indicates `true` if injection
    /// was performed, `false` if executed directly.
    pub fn in_worker<OP, R>(&self, op: OP) -> R
    where
        OP: FnOnce(&WorkerThread, bool) -> R + Send,
        R: Send,
    {
        unsafe {
            let worker_thread = WorkerThread::current();
            if worker_thread.is_null() {
                let job = StackJob::new(
                    |_| {
                        let worker_thread = WorkerThread::current();
                        op(&*worker_thread, true)
                    },
                    LockLatch::new(),
                );

                self.inject(job.as_job_ref());

                job.latch.wait();
                job.into_result()
            } else {
                // Perfectly valid to give them a `&T`: this is the
                // current thread, so we know the data structure won't be
                // invalidated until we return.
                op(&*worker_thread, false)
            }
        }
    }

    /// Handles panic.
    pub fn handle_panic(&self, err: Box<::std::any::Any + Send>) {
        match self.panic_handler {
            Some(ref handler) => {
                // If the customizable panic handler itself panics,
                // then we abort.
                let abort_guard = AbortIfPanic;
                handler(err);
                mem::forget(abort_guard);
            }
            None => {
                // Default panic handler aborts.
                let _ = AbortIfPanic; // let this drop.
            }
        }
    }

    pub fn wait_until<T>(&self, latch: &T)
    where
        T: LatchWaitProbe,
    {
        unsafe {
            let worker_thread = WorkerThread::current();
            if worker_thread.is_null() {
                latch.wait();
            } else {
                (*worker_thread).hot_wait_until(latch);
            }
        }
    }

    #[inline]
    pub fn terminate_dec(&self) {
        self.terminator.set();
    }

    #[inline]
    pub fn terminate_inc(&self) {
        self.terminator.increment();
    }

    /// Blocks current thread until all the workers finished their jobs gracefully.
    pub fn wait_until_terminated(&self) {
        self.watcher.notify_all();

        for v in &self.threads {
            v.terminated.wait();
        }
    }

    unsafe fn main_loop(scheduler: Arc<Scheduler>, index: usize, worker: deque::Worker<JobRef>) {
        let worker_thread = WorkerThread {
            scheduler: scheduler,
            index: index,
            worker: worker,
            rand: XorShift64Star::new(),
        };

        WorkerThread::set_current(&worker_thread);

        worker_thread.scheduler.threads[index].primed.set(());

        worker_thread.wait_until(&worker_thread.scheduler.terminator);

        worker_thread.scheduler.threads[index].terminated.set(());
    }
}

struct Watcher(Mutex<()>, Condvar);

impl Watcher {
    #[inline]
    fn wait(&self) {
        let guard = self.0.lock().unwrap();
        let _ = self.1.wait(guard).unwrap();
    }

    #[inline]
    pub fn notify_one(&self) {
        self.1.notify_one()
    }

    #[inline]
    pub fn notify_all(&self) {
        self.1.notify_all()
    }
}

pub struct WorkerThread {
    scheduler: Arc<Scheduler>,
    index: usize,
    worker: deque::Worker<JobRef>,
    rand: XorShift64Star,
}

// This is a bit sketchy, but basically: the WorkerThread is allocated on the
// stack of the worker on entry and stored into this thread local variable. So
// it will remain valid at least until the worker is fully unwound. Using an
// unsafe pointer avoids the need for a RefCell<T> etc.
thread_local! {
    static WORKER_THREAD_STATE: Cell<*const WorkerThread> =
        Cell::new(0 as *const WorkerThread)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread; returns
    /// NULL if this is not a worker thread. This pointer is valid
    /// anywhere on the current thread.
    #[inline]
    pub fn current() -> *const WorkerThread {
        WORKER_THREAD_STATE.with(|t| t.get())
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(thread: *const WorkerThread) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(thread);
        });
    }
}

impl WorkerThread {
    /// Pushs a job to `local` queue.
    #[inline]
    pub unsafe fn push(&self, job: JobRef) {
        self.worker.push(job);
    }

    pub unsafe fn hot_wait_until<L: LatchProbe>(&self, latch: &L) {
        let abort_guard = AbortIfPanic {};

        while !latch.is_set() {
            if let Some(job) = self.steal_local()
                .or_else(|| self.steal())
                .or_else(|| self.scheduler.inject_stealer.steal())
            {
                job.execute();
                self.scheduler.watcher.notify_all();
            } else {
                thread::yield_now();
            }
        }

        mem::forget(abort_guard);
    }

    pub unsafe fn wait_until<L: LatchProbe>(&self, latch: &L) {
        let abort_guard = AbortIfPanic {};

        while !latch.is_set() {
            if let Some(job) = self.steal_local()
                .or_else(|| self.steal())
                .or_else(|| self.scheduler.inject_stealer.steal())
            {
                job.execute();
                self.scheduler.watcher.notify_all();
            } else {
                self.scheduler.watcher.wait();
            }
        }

        mem::forget(abort_guard);
    }

    /// Attempts to obtain a "local" job.
    #[inline]
    unsafe fn steal_local(&self) -> Option<JobRef> {
        self.worker.pop()
    }

    /// Try to steal a single job and return it.
    unsafe fn steal(&self) -> Option<JobRef> {
        let num_threads = self.scheduler.threads.len();
        if num_threads <= 1 {
            return None;
        }

        let start = self.rand.next_usize(num_threads);
        (start..num_threads)
            .chain(0..start)
            .filter(|&i| i != self.index)
            .filter_map(|i| self.scheduler.threads[i].stealer.steal())
            .next()
    }
}

struct ThreadInfo {
    stealer: deque::Stealer<JobRef>,
    primed: LockLatch<()>,
    terminated: LockLatch<()>,
}

/// [xorshift*] is a fast pseudorandom number generator which will even tolerate
/// weak seeding, as long as it's not zero.
///
/// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift*
struct XorShift64Star {
    state: Cell<u64>,
}

impl XorShift64Star {
    fn new() -> Self {
        // Any non-zero seed will do -- this uses the hash of a global counter.
        let mut seed = 0;
        while seed == 0 {
            let mut hasher = DefaultHasher::new();
            static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
            hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed));
            seed = hasher.finish();
        }

        XorShift64Star {
            state: Cell::new(seed),
        }
    }

    fn next(&self) -> u64 {
        let mut x = self.state.get();
        debug_assert_ne!(x, 0);
        x ^= x >> 12;
        x ^= x << 25;
        x ^= x >> 27;
        self.state.set(x);
        x.wrapping_mul(0x2545_f491_4f6c_dd1d)
    }

    /// Return a value from `0..n`.
    fn next_usize(&self, n: usize) -> usize {
        (self.next() % n as u64) as usize
    }
}
<commit_msg>Fixs starvation on wait_until_terminated.<commit_after>use std::cell::Cell;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::sync::{Arc, Condvar, Mutex};
use std::{mem, thread};

use crossbeam_deque as deque;

use super::job::{JobRef, StackJob};
use super::latch::{CountLatch, Latch, LatchProbe, LatchWaitProbe, LockLatch};
use super::unwind::AbortIfPanic;
use super::PanicHandler;

pub struct Scheduler {
    terminator: CountLatch,
    watcher: Watcher,
    threads: Vec<ThreadInfo>,

    inject_stealer: deque::Stealer<JobRef>,
    injector: Mutex<deque::Worker<JobRef>>,

    panic_handler: Option<Box<PanicHandler>>,
}

impl Scheduler {
    pub fn new(
        num: u32,
        stack_size: Option<usize>,
        panic_handler: Option<Box<PanicHandler>>,
    ) -> Arc<Self> {
        let mut stealers = Vec::new();
        let mut workers = Vec::new();

        for _ in 0..num {
            let (w, s) = deque::fifo();
            workers.push(w);
            stealers.push(s);
        }

        let (w, s) = deque::fifo();
        let stealers = stealers
            .into_iter()
            .map(|v| ThreadInfo {
                stealer: v,
                primed: LockLatch::new(),
                terminated: LockLatch::new(),
            })
            .collect();

        let scheduler = Arc::new(Scheduler {
            threads: stealers,
            injector: Mutex::new(w),
            inject_stealer: s,
            panic_handler: panic_handler,
            terminator: CountLatch::new(),
            watcher: Watcher(Mutex::new(()), Condvar::new()),
        });

        for (i, w) in workers.drain(..).enumerate() {
            let sc = scheduler.clone();
            let mut b = thread::Builder::new();

            if let Some(stack_size) = stack_size {
                b = b.stack_size(stack_size);
            }

            b.spawn(move || unsafe { Scheduler::main_loop(sc, i, w) })
                .unwrap();
        }

        for v in &scheduler.threads {
            v.primed.wait();
        }

        scheduler
    }

    /// Push a job into the "external jobs" queue; it will be taken by whatever
    /// worker has nothing to do.
    pub fn inject(&self, job: JobRef) {
        {
            let injector = self.injector.lock().unwrap();
            injector.push(job);
        }

        self.watcher.notify_one();
    }

    // /// Push a slice of jobs into the "external jobs" queue; it will be taken by
    // /// whatever worker has nothing to do.
    // fn inject_slice(&self, jobs: &[JobRef]) {
    //     {
    //         let injector = self.injector.lock().unwrap();
    //         for &job in jobs {
    //             injector.push(job);
    //         }
    //     }

    //     self.watcher.notify_all();
    // }

    /// Push a job into the given `registry`. If we are running on a worker thread for
    /// the registry, this will push onto the deque. Else, it will inject from the
    /// outside (which is slower).
    pub fn inject_or_push(&self, job: JobRef) {
        unsafe {
            let worker_thread = WorkerThread::current();
            if worker_thread.is_null() {
                self.inject(job);
            } else {
                (*worker_thread).push(job);
                self.watcher.notify_one();
            }
        }
    }

    /// If already in a worker-thread of this registry, just execute `op`.
    /// Otherwise, inject `op` in this thread-pool. Either way, block until `op`
    /// completes and return its return value. If `op` panics, that panic will
    /// be propagated as well.  The second argument indicates `true` if injection
    /// was performed, `false` if executed directly.
    pub fn in_worker<OP, R>(&self, op: OP) -> R
    where
        OP: FnOnce(&WorkerThread, bool) -> R + Send,
        R: Send,
    {
        unsafe {
            let worker_thread = WorkerThread::current();
            if worker_thread.is_null() {
                let job = StackJob::new(
                    |_| {
                        let worker_thread = WorkerThread::current();
                        op(&*worker_thread, true)
                    },
                    LockLatch::new(),
                );

                self.inject(job.as_job_ref());

                job.latch.wait();
                job.into_result()
            } else {
                // Perfectly valid to give them a `&T`: this is the
                // current thread, so we know the data structure won't be
                // invalidated until we return.
                op(&*worker_thread, false)
            }
        }
    }

    /// Handles panic.
    pub fn handle_panic(&self, err: Box<::std::any::Any + Send>) {
        match self.panic_handler {
            Some(ref handler) => {
                // If the customizable panic handler itself panics,
                // then we abort.
                let abort_guard = AbortIfPanic;
                handler(err);
                mem::forget(abort_guard);
            }
            None => {
                // Default panic handler aborts.
                let _ = AbortIfPanic; // let this drop.
            }
        }
    }

    pub fn wait_until<T>(&self, latch: &T)
    where
        T: LatchWaitProbe,
    {
        unsafe {
            let worker_thread = WorkerThread::current();
            if worker_thread.is_null() {
                latch.wait();
            } else {
                (*worker_thread).hot_wait_until(latch);
            }
        }
    }

    #[inline]
    pub fn terminate_dec(&self) {
        self.terminator.set();
    }

    #[inline]
    pub fn terminate_inc(&self) {
        self.terminator.increment();
    }

    /// Blocks current thread until all the workers finished their jobs gracefully.
    pub fn wait_until_terminated(&self) {
        let check = || {
            for v in &self.threads {
                if !v.terminated.is_set() {
                    return true;
                }
            }

            false
        };

        while check() {
            self.watcher.notify_all();
            thread::yield_now();
        }
    }

    unsafe fn main_loop(scheduler: Arc<Scheduler>, index: usize, worker: deque::Worker<JobRef>) {
        let worker_thread = WorkerThread {
            scheduler: scheduler,
            index: index,
            worker: worker,
            rand: XorShift64Star::new(),
        };

        WorkerThread::set_current(&worker_thread);

        worker_thread.scheduler.threads[index].primed.set(());

        worker_thread.wait_until(&worker_thread.scheduler.terminator);

        worker_thread.scheduler.threads[index].terminated.set(());
    }
}

struct Watcher(Mutex<()>, Condvar);

impl Watcher {
    #[inline]
    fn wait(&self) {
        let guard = self.0.lock().unwrap();
        let _ = self.1.wait(guard).unwrap();
    }

    #[inline]
    pub fn notify_one(&self) {
        self.1.notify_one()
    }

    #[inline]
    pub fn notify_all(&self) {
        self.1.notify_all()
    }
}

pub struct WorkerThread {
    scheduler: Arc<Scheduler>,
    index: usize,
    worker: deque::Worker<JobRef>,
    rand: XorShift64Star,
}

// This is a bit sketchy, but basically: the WorkerThread is allocated on the
// stack of the worker on entry and stored into this thread local variable. So
// it will remain valid at least until the worker is fully unwound. Using an
// unsafe pointer avoids the need for a RefCell<T> etc.
thread_local! {
    static WORKER_THREAD_STATE: Cell<*const WorkerThread> =
        Cell::new(0 as *const WorkerThread)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread; returns
    /// NULL if this is not a worker thread. This pointer is valid
    /// anywhere on the current thread.
    #[inline]
    pub fn current() -> *const WorkerThread {
        WORKER_THREAD_STATE.with(|t| t.get())
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(thread: *const WorkerThread) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(thread);
        });
    }
}

impl WorkerThread {
    /// Pushs a job to `local` queue.
    #[inline]
    pub unsafe fn push(&self, job: JobRef) {
        self.worker.push(job);
    }

    pub unsafe fn hot_wait_until<L: LatchProbe>(&self, latch: &L) {
        let abort_guard = AbortIfPanic {};

        while !latch.is_set() {
            if let Some(job) = self.steal_local()
                .or_else(|| self.steal())
                .or_else(|| self.scheduler.inject_stealer.steal())
            {
                job.execute();
                self.scheduler.watcher.notify_all();
            } else {
                thread::yield_now();
            }
        }

        mem::forget(abort_guard);
    }

    pub unsafe fn wait_until<L: LatchProbe>(&self, latch: &L) {
        let abort_guard = AbortIfPanic {};

        while !latch.is_set() {
            if let Some(job) = self.steal_local()
                .or_else(|| self.steal())
                .or_else(|| self.scheduler.inject_stealer.steal())
            {
                job.execute();
                self.scheduler.watcher.notify_all();
            } else {
                self.scheduler.watcher.wait();
            }
        }

        mem::forget(abort_guard);
    }

    /// Attempts to obtain a "local" job.
    #[inline]
    unsafe fn steal_local(&self) -> Option<JobRef> {
        self.worker.pop()
    }

    /// Try to steal a single job and return it.
    unsafe fn steal(&self) -> Option<JobRef> {
        let num_threads = self.scheduler.threads.len();
        if num_threads <= 1 {
            return None;
        }

        let start = self.rand.next_usize(num_threads);
        (start..num_threads)
            .chain(0..start)
            .filter(|&i| i != self.index)
            .filter_map(|i| self.scheduler.threads[i].stealer.steal())
            .next()
    }
}

struct ThreadInfo {
    stealer: deque::Stealer<JobRef>,
    primed: LockLatch<()>,
    terminated: LockLatch<()>,
}

/// [xorshift*] is a fast pseudorandom number generator which will even tolerate
/// weak seeding, as long as it's not zero.
///
/// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift*
struct XorShift64Star {
    state: Cell<u64>,
}

impl XorShift64Star {
    fn new() -> Self {
        // Any non-zero seed will do -- this uses the hash of a global counter.
        let mut seed = 0;
        while seed == 0 {
            let mut hasher = DefaultHasher::new();
            static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
            hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed));
            seed = hasher.finish();
        }

        XorShift64Star {
            state: Cell::new(seed),
        }
    }

    fn next(&self) -> u64 {
        let mut x = self.state.get();
        debug_assert_ne!(x, 0);
        x ^= x >> 12;
        x ^= x << 25;
        x ^= x >> 27;
        self.state.set(x);
        x.wrapping_mul(0x2545_f491_4f6c_dd1d)
    }

    /// Return a value from `0..n`.
    fn next_usize(&self, n: usize) -> usize {
        (self.next() % n as u64) as usize
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
use std::str;

use position;

/// A `struct` of a span over a `&str`. It is created from either
/// [two `Position`s](struct.Position.html#method.span) or from a
/// [`Pair`](../iterators/struct.Pair.html#method.span).
pub struct Span<'i> {
    input: &'i [u8],
    start: usize,
    end: usize
}

#[inline]
pub unsafe fn new(input: &[u8], start: usize, end: usize) -> Span {
    Span { input, start, end }
}

impl<'i> Span<'i> {
    /// Returns the `Span`'s start byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.start(), 0);
    /// ```
    #[inline]
    pub fn start(&self) -> usize {
        self.start
    }

    /// Returns the `Span`'s end byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end(), 0);
    /// ```
    #[inline]
    pub fn end(&self) -> usize {
        self.end
    }

    /// Returns the `Span`'s start `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.start_pos(), start);
    /// ```
    #[inline]
    pub fn start_pos(&self) -> position::Position<'i> {
        // Span's start position is always a UTF-8 border.
        unsafe { position::new(self.input, self.start) }
    }

    /// Returns the `Span`'s end `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end_pos(), end);
    /// ```
    #[inline]
    pub fn end_pos(&self) -> position::Position<'i> {
        // Span's end position is always a UTF-8 border.
        unsafe { position::new(self.input, self.end) }
    }

    /// Splits the `Span` into a pair of `Position`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.split(), (start, end));
    /// ```
    #[inline]
    pub fn split(self) -> (position::Position<'i>, position::Position<'i>) {
        // Span's start and end positions are always a UTF-8 borders.
        let pos1 = unsafe { position::new(self.input, self.start) };
        let pos2 = unsafe { position::new(self.input, self.end) };

        (pos1, pos2)
    }

    /// Captures a slice from the `&str` defined by the `Span`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {}
    ///
    /// let input = "abc";
    /// let mut state: Box<pest::ParserState<Rule>> = pest::ParserState::new(input).skip(1).unwrap();
    /// let start_pos = state.position().clone();
    /// state = state.match_string("b").unwrap();
    /// let span = start_pos.span(&state.position().clone());
    /// assert_eq!(span.as_str(), "b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        // Span's start and end positions are always a UTF-8 borders.
        unsafe { str::from_utf8_unchecked(&self.input[self.start..self.end]) }
    }
}

impl<'i> fmt::Debug for Span<'i> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Span")
            .field("str", &self.as_str())
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

impl<'i> Clone for Span<'i> {
    fn clone(&self) -> Span<'i> {
        unsafe { new(self.input, self.start, self.end) }
    }
}

impl<'i> PartialEq for Span<'i> {
    fn eq(&self, other: &Span<'i>) -> bool {
        ptr::eq(self.input, other.input) && self.start == other.start && self.end == other.end
    }
}

impl<'i> Eq for Span<'i> {}

impl<'i> PartialOrd for Span<'i> {
    fn partial_cmp(&self, other: &Span<'i>) -> Option<Ordering> {
        if ptr::eq(self.input, other.input) {
            match self.start.partial_cmp(&other.start) {
                Some(Ordering::Equal) => self.end.partial_cmp(&other.end),
                ordering => ordering
            }
        } else {
            None
        }
    }
}

impl<'i> Ord for Span<'i> {
    fn cmp(&self, other: &Span<'i>) -> Ordering {
        self.partial_cmp(other).expect(
            "cannot compare spans from \
             different inputs"
        )
    }
}

impl<'i> Hash for Span<'i> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (self.input as *const [u8]).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn split() {
        let input = "a";
        let start = position::Position::from_start(input);
        let mut end = start.clone();

        assert!(end.skip(1));

        let span = start.clone().span(&end.clone());

        assert_eq!(span.split(), (start, end));
    }
}
<commit_msg>Removed Ord, PartialOrd.<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
use std::str;

use position;

/// A `struct` of a span over a `&str`. It is created from either
/// [two `Position`s](struct.Position.html#method.span) or from a
/// [`Pair`](../iterators/struct.Pair.html#method.span).
pub struct Span<'i> {
    input: &'i [u8],
    start: usize,
    end: usize
}

#[inline]
pub unsafe fn new(input: &[u8], start: usize, end: usize) -> Span {
    Span { input, start, end }
}

impl<'i> Span<'i> {
    /// Returns the `Span`'s start byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.start(), 0);
    /// ```
    #[inline]
    pub fn start(&self) -> usize {
        self.start
    }

    /// Returns the `Span`'s end byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end(), 0);
    /// ```
    #[inline]
    pub fn end(&self) -> usize {
        self.end
    }

    /// Returns the `Span`'s start `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.start_pos(), start);
    /// ```
    #[inline]
    pub fn start_pos(&self) -> position::Position<'i> {
        // Span's start position is always a UTF-8 border.
        unsafe { position::new(self.input, self.start) }
    }

    /// Returns the `Span`'s end `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end_pos(), end);
    /// ```
    #[inline]
    pub fn end_pos(&self) -> position::Position<'i> {
        // Span's end position is always a UTF-8 border.
        unsafe { position::new(self.input, self.end) }
    }

    /// Splits the `Span` into a pair of `Position`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.split(), (start, end));
    /// ```
    #[inline]
    pub fn split(self) -> (position::Position<'i>, position::Position<'i>) {
        // Span's start and end positions are always a UTF-8 borders.
        let pos1 = unsafe { position::new(self.input, self.start) };
        let pos2 = unsafe { position::new(self.input, self.end) };

        (pos1, pos2)
    }

    /// Captures a slice from the `&str` defined by the `Span`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {}
    ///
    /// let input = "abc";
    /// let mut state: Box<pest::ParserState<Rule>> = pest::ParserState::new(input).skip(1).unwrap();
    /// let start_pos = state.position().clone();
    /// state = state.match_string("b").unwrap();
    /// let span = start_pos.span(&state.position().clone());
    /// assert_eq!(span.as_str(), "b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        // Span's start and end positions are always a UTF-8 borders.
        unsafe { str::from_utf8_unchecked(&self.input[self.start..self.end]) }
    }
}

impl<'i> fmt::Debug for Span<'i> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Span")
            .field("str", &self.as_str())
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

impl<'i> Clone for Span<'i> {
    fn clone(&self) -> Span<'i> {
        unsafe { new(self.input, self.start, self.end) }
    }
}

impl<'i> PartialEq for Span<'i> {
    fn eq(&self, other: &Span<'i>) -> bool {
        ptr::eq(self.input, other.input) && self.start == other.start && self.end == other.end
    }
}

impl<'i> Eq for Span<'i> {}

impl<'i> Hash for Span<'i> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (self.input as *const [u8]).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn split() {
        let input = "a";
        let start = position::Position::from_start(input);
        let mut end = start.clone();

        assert!(end.skip(1));

        let span = start.clone().span(&end.clone());

        assert_eq!(span.split(), (start, end));
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) * st.force(y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            println!("depend_add:({:?},{:?})", x, y);
            st.force(x) + st.force(y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);

                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<commit_msg>stack overflow bug is still puzzling<commit_after>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) * st.force(y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            println!("depend_add:({:?},{:?})", x, y);
            st.force(x) + st.force(y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;4];
            let mut nodes = vec![];
            for i in 0..4 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);
                if nodes.len() == 7 { break; }
                else { item_num += 2 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn hourglass_big<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);

                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<|endoftext|>