Auto merge of #48549 - alexcrichton:update-cargo, r=Mark-Simulacrum
Update Cargo submodule Hopefully a routine update...
This commit is contained in:
commit
178becdd7c
17 changed files with 680 additions and 748 deletions
|
|
@ -1,101 +0,0 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_private, std_panic)]
|
||||
|
||||
extern crate rand;
|
||||
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
|
||||
use std::collections::BinaryHeap;
|
||||
use std::cmp;
|
||||
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
|
||||
static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
// old binaryheap failed this test
|
||||
//
|
||||
// Integrity means that all elements are present after a comparison panics,
|
||||
// even if the order may not be correct.
|
||||
//
|
||||
// Destructors must be called exactly once per element.
|
||||
fn test_integrity() {
|
||||
#[derive(Eq, PartialEq, Ord, Clone, Debug)]
|
||||
struct PanicOrd<T>(T, bool);
|
||||
|
||||
impl<T> Drop for PanicOrd<T> {
|
||||
fn drop(&mut self) {
|
||||
// update global drop count
|
||||
DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialOrd> PartialOrd for PanicOrd<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
if self.1 || other.1 {
|
||||
panic!("Panicking comparison");
|
||||
}
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
let mut rng = thread_rng();
|
||||
const DATASZ: usize = 32;
|
||||
const NTEST: usize = 10;
|
||||
|
||||
// don't use 0 in the data -- we want to catch the zeroed-out case.
|
||||
let data = (1..DATASZ + 1).collect::<Vec<_>>();
|
||||
|
||||
// since it's a fuzzy test, run several tries.
|
||||
for _ in 0..NTEST {
|
||||
for i in 1..DATASZ + 1 {
|
||||
DROP_COUNTER.store(0, Ordering::SeqCst);
|
||||
|
||||
let mut panic_ords: Vec<_> = data.iter()
|
||||
.filter(|&&x| x != i)
|
||||
.map(|&x| PanicOrd(x, false))
|
||||
.collect();
|
||||
let panic_item = PanicOrd(i, true);
|
||||
|
||||
// heapify the sane items
|
||||
rng.shuffle(&mut panic_ords);
|
||||
let mut heap = BinaryHeap::from(panic_ords);
|
||||
let inner_data;
|
||||
|
||||
{
|
||||
// push the panicking item to the heap and catch the panic
|
||||
let thread_result = {
|
||||
let mut heap_ref = AssertUnwindSafe(&mut heap);
|
||||
panic::catch_unwind(move || {
|
||||
heap_ref.push(panic_item);
|
||||
})
|
||||
};
|
||||
assert!(thread_result.is_err());
|
||||
|
||||
// Assert no elements were dropped
|
||||
let drops = DROP_COUNTER.load(Ordering::SeqCst);
|
||||
assert!(drops == 0, "Must not drop items. drops={}", drops);
|
||||
inner_data = heap.clone().into_vec();
|
||||
drop(heap);
|
||||
}
|
||||
let drops = DROP_COUNTER.load(Ordering::SeqCst);
|
||||
assert_eq!(drops, DATASZ);
|
||||
|
||||
let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::<Vec<_>>();
|
||||
data_sorted.sort();
|
||||
assert_eq!(data_sorted, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_integrity();
|
||||
}
|
||||
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags: --test
|
||||
|
||||
#![feature(rustc_private, std_panic)]
|
||||
|
||||
extern crate rand;
|
||||
|
||||
use std::env::*;
|
||||
use std::iter::repeat;
|
||||
use std::ffi::{OsString, OsStr};
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
fn make_rand_name() -> OsString {
|
||||
let mut rng = rand::thread_rng();
|
||||
let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
|
||||
.collect::<String>());
|
||||
let n = OsString::from(n);
|
||||
assert!(var_os(&n).is_none());
|
||||
n
|
||||
}
|
||||
|
||||
fn eq(a: Option<OsString>, b: Option<&str>) {
|
||||
assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_var() {
|
||||
let n = make_rand_name();
|
||||
set_var(&n, "VALUE");
|
||||
eq(var_os(&n), Some("VALUE"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_var() {
|
||||
let n = make_rand_name();
|
||||
set_var(&n, "VALUE");
|
||||
remove_var(&n);
|
||||
eq(var_os(&n), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_var_overwrite() {
|
||||
let n = make_rand_name();
|
||||
set_var(&n, "1");
|
||||
set_var(&n, "2");
|
||||
eq(var_os(&n), Some("2"));
|
||||
set_var(&n, "");
|
||||
eq(var_os(&n), Some(""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
fn test_var_big() {
|
||||
let mut s = "".to_string();
|
||||
let mut i = 0;
|
||||
while i < 100 {
|
||||
s.push_str("aaaaaaaaaa");
|
||||
i += 1;
|
||||
}
|
||||
let n = make_rand_name();
|
||||
set_var(&n, &s);
|
||||
eq(var_os(&n), Some(&s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
fn test_env_set_get_huge() {
|
||||
let n = make_rand_name();
|
||||
let s = repeat("x").take(10000).collect::<String>();
|
||||
set_var(&n, &s);
|
||||
eq(var_os(&n), Some(&s));
|
||||
remove_var(&n);
|
||||
eq(var_os(&n), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_env_set_var() {
|
||||
let n = make_rand_name();
|
||||
|
||||
let mut e = vars_os();
|
||||
set_var(&n, "VALUE");
|
||||
assert!(!e.any(|(k, v)| {
|
||||
&*k == &*n && &*v == "VALUE"
|
||||
}));
|
||||
|
||||
assert!(vars_os().any(|(k, v)| {
|
||||
&*k == &*n && &*v == "VALUE"
|
||||
}));
|
||||
}
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:--test
|
||||
|
||||
#![feature(rustc_private, flt2dec)]
|
||||
|
||||
extern crate core;
|
||||
extern crate rand;
|
||||
|
||||
use std::i16;
|
||||
use std::mem;
|
||||
use std::str;
|
||||
|
||||
use core::num::flt2dec::MAX_SIG_DIGITS;
|
||||
use core::num::flt2dec::strategy::grisu::format_exact_opt;
|
||||
use core::num::flt2dec::strategy::grisu::format_shortest_opt;
|
||||
use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
|
||||
|
||||
use rand::{Rand, XorShiftRng};
|
||||
use rand::distributions::{IndependentSample, Range};
|
||||
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
|
||||
match decode(v).1 {
|
||||
FullDecoded::Finite(decoded) => decoded,
|
||||
full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn iterate<F, G, V>(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize)
|
||||
where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
|
||||
G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
|
||||
V: FnMut(usize) -> Decoded {
|
||||
assert!(k <= 1024);
|
||||
|
||||
let mut npassed = 0; // f(x) = Some(g(x))
|
||||
let mut nignored = 0; // f(x) = None
|
||||
|
||||
for i in 0..n {
|
||||
if (i & 0xfffff) == 0 {
|
||||
println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})",
|
||||
i, n, nignored, npassed, i - nignored - npassed);
|
||||
}
|
||||
|
||||
let decoded = v(i);
|
||||
let mut buf1 = [0; 1024];
|
||||
if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) {
|
||||
let mut buf2 = [0; 1024];
|
||||
let (len2, e2) = g(&decoded, &mut buf2[..k]);
|
||||
if e1 == e2 && &buf1[..len1] == &buf2[..len2] {
|
||||
npassed += 1;
|
||||
} else {
|
||||
println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}",
|
||||
i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1,
|
||||
str::from_utf8(&buf2[..len2]).unwrap(), e2);
|
||||
}
|
||||
} else {
|
||||
nignored += 1;
|
||||
}
|
||||
}
|
||||
println!("{}({}): done, ignored={} passed={} failed={}",
|
||||
func, k, nignored, npassed, n - nignored - npassed);
|
||||
assert!(nignored + npassed == n,
|
||||
"{}({}): {} out of {} values returns an incorrect value!",
|
||||
func, k, n - nignored - npassed, n);
|
||||
(npassed, nignored)
|
||||
}
|
||||
|
||||
pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
|
||||
where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
|
||||
G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
|
||||
let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng());
|
||||
let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000);
|
||||
iterate("f32_random_equivalence_test", k, n, f, g, |_| {
|
||||
let i: u32 = f32_range.ind_sample(&mut rng);
|
||||
let x: f32 = unsafe {mem::transmute(i)};
|
||||
decode_finite(x)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
|
||||
where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
|
||||
G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
|
||||
let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng());
|
||||
let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
|
||||
iterate("f64_random_equivalence_test", k, n, f, g, |_| {
|
||||
let i: u64 = f64_range.ind_sample(&mut rng);
|
||||
let x: f64 = unsafe {mem::transmute(i)};
|
||||
decode_finite(x)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
|
||||
where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
|
||||
G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
|
||||
// we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values,
|
||||
// so why not simply testing all of them?
|
||||
//
|
||||
// this is of course very stressful (and thus should be behind an `#[ignore]` attribute),
|
||||
// but with `-C opt-level=3 -C lto` this only takes about an hour or so.
|
||||
|
||||
// iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges
|
||||
let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test",
|
||||
k, 0x7f7f_ffff, f, g, |i: usize| {
|
||||
let x: f32 = unsafe {mem::transmute(i as u32 + 1)};
|
||||
decode_finite(x)
|
||||
});
|
||||
assert_eq!((npassed, nignored), (2121451881, 17643158));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shortest_random_equivalence_test() {
|
||||
use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
|
||||
f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
|
||||
f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
|
||||
}
|
||||
|
||||
#[test] #[ignore] // it is too expensive
|
||||
fn shortest_f32_exhaustive_equivalence_test() {
|
||||
// it is hard to directly test the optimality of the output, but we can at least test if
|
||||
// two different algorithms agree to each other.
|
||||
//
|
||||
// this reports the progress and the number of f32 values returned `None`.
|
||||
// with `--nocapture` (and plenty of time and appropriate rustc flags), this should print:
|
||||
// `done, ignored=17643158 passed=2121451881 failed=0`.
|
||||
|
||||
use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
|
||||
f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
|
||||
}
|
||||
|
||||
#[test] #[ignore] // it is too expensive
|
||||
fn shortest_f64_hard_random_equivalence_test() {
|
||||
// this again probably has to use appropriate rustc flags.
|
||||
|
||||
use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
|
||||
f64_random_equivalence_test(format_shortest_opt, fallback,
|
||||
MAX_SIG_DIGITS, 100_000_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_f32_random_equivalence_test() {
|
||||
use core::num::flt2dec::strategy::dragon::format_exact as fallback;
|
||||
for k in 1..21 {
|
||||
f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
|
||||
|d, buf| fallback(d, buf, i16::MIN), k, 1_000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_f64_random_equivalence_test() {
|
||||
use core::num::flt2dec::strategy::dragon::format_exact as fallback;
|
||||
for k in 1..21 {
|
||||
f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
|
||||
|d, buf| fallback(d, buf, i16::MIN), k, 1_000);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_private, sort_internals)]
|
||||
|
||||
extern crate core;
|
||||
extern crate rand;
|
||||
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
use core::slice::heapsort;
|
||||
|
||||
use rand::{Rng, XorShiftRng};
|
||||
|
||||
fn main() {
|
||||
let mut v = [0; 600];
|
||||
let mut tmp = [0; 600];
|
||||
let mut rng = XorShiftRng::new_unseeded();
|
||||
|
||||
for len in (2..25).chain(500..510) {
|
||||
let v = &mut v[0..len];
|
||||
let tmp = &mut tmp[0..len];
|
||||
|
||||
for &modulus in &[5, 10, 100, 1000] {
|
||||
for _ in 0..100 {
|
||||
for i in 0..len {
|
||||
v[i] = rng.gen::<i32>() % modulus;
|
||||
}
|
||||
|
||||
// Sort in default order.
|
||||
tmp.copy_from_slice(v);
|
||||
tmp.sort_unstable();
|
||||
assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
// Sort in ascending order.
|
||||
tmp.copy_from_slice(v);
|
||||
tmp.sort_unstable_by(|a, b| a.cmp(b));
|
||||
assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
// Sort in descending order.
|
||||
tmp.copy_from_slice(v);
|
||||
tmp.sort_unstable_by(|a, b| b.cmp(a));
|
||||
assert!(tmp.windows(2).all(|w| w[0] >= w[1]));
|
||||
|
||||
// Test heapsort using `<` operator.
|
||||
tmp.copy_from_slice(v);
|
||||
heapsort(tmp, |a, b| a < b);
|
||||
assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
// Test heapsort using `>` operator.
|
||||
tmp.copy_from_slice(v);
|
||||
heapsort(tmp, |a, b| a > b);
|
||||
assert!(tmp.windows(2).all(|w| w[0] >= w[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort using a completely random comparison function.
|
||||
// This will reorder the elements *somehow*, but won't panic.
|
||||
for i in 0..v.len() {
|
||||
v[i] = i as i32;
|
||||
}
|
||||
v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap());
|
||||
v.sort_unstable();
|
||||
for i in 0..v.len() {
|
||||
assert_eq!(v[i], i as i32);
|
||||
}
|
||||
|
||||
// Should not panic.
|
||||
[0i32; 0].sort_unstable();
|
||||
[(); 10].sort_unstable();
|
||||
[(); 100].sort_unstable();
|
||||
|
||||
let mut v = [0xDEADBEEFu64];
|
||||
v.sort_unstable();
|
||||
assert!(v == [0xDEADBEEF]);
|
||||
}
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-emscripten no threads support
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![feature(sort_unstable)]
|
||||
|
||||
extern crate rand;
|
||||
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering;
|
||||
use std::panic;
|
||||
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize};
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
use std::thread;
|
||||
|
||||
const MAX_LEN: usize = 80;
|
||||
|
||||
static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
|
||||
// FIXME #5244: AtomicUsize is not Copy.
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
|
||||
];
|
||||
|
||||
static VERSIONS: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
#[derive(Clone, Eq)]
|
||||
struct DropCounter {
|
||||
x: u32,
|
||||
id: usize,
|
||||
version: Cell<usize>,
|
||||
}
|
||||
|
||||
impl PartialEq for DropCounter {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.partial_cmp(other) == Some(Ordering::Equal)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for DropCounter {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.version.set(self.version.get() + 1);
|
||||
other.version.set(other.version.get() + 1);
|
||||
VERSIONS.fetch_add(2, Relaxed);
|
||||
self.x.partial_cmp(&other.x)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for DropCounter {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DropCounter {
|
||||
fn drop(&mut self) {
|
||||
DROP_COUNTS[self.id].fetch_add(1, Relaxed);
|
||||
VERSIONS.fetch_sub(self.version.get(), Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! test {
|
||||
($input:ident, $func:ident) => {
|
||||
let len = $input.len();
|
||||
|
||||
// Work out the total number of comparisons required to sort
|
||||
// this array...
|
||||
let mut count = 0usize;
|
||||
$input.to_owned().$func(|a, b| { count += 1; a.cmp(b) });
|
||||
|
||||
// ... and then panic on each and every single one.
|
||||
for panic_countdown in 0..count {
|
||||
// Refresh the counters.
|
||||
VERSIONS.store(0, Relaxed);
|
||||
for i in 0..len {
|
||||
DROP_COUNTS[i].store(0, Relaxed);
|
||||
}
|
||||
|
||||
let v = $input.to_owned();
|
||||
let _ = thread::spawn(move || {
|
||||
let mut v = v;
|
||||
let mut panic_countdown = panic_countdown;
|
||||
v.$func(|a, b| {
|
||||
if panic_countdown == 0 {
|
||||
SILENCE_PANIC.with(|s| s.set(true));
|
||||
panic!();
|
||||
}
|
||||
panic_countdown -= 1;
|
||||
a.cmp(b)
|
||||
})
|
||||
}).join();
|
||||
|
||||
// Check that the number of things dropped is exactly
|
||||
// what we expect (i.e. the contents of `v`).
|
||||
for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
|
||||
let count = c.load(Relaxed);
|
||||
assert!(count == 1,
|
||||
"found drop count == {} for i == {}, len == {}",
|
||||
count, i, len);
|
||||
}
|
||||
|
||||
// Check that the most recent versions of values were dropped.
|
||||
assert_eq!(VERSIONS.load(Relaxed), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
|
||||
|
||||
fn main() {
|
||||
let prev = panic::take_hook();
|
||||
panic::set_hook(Box::new(move |info| {
|
||||
if !SILENCE_PANIC.with(|s| s.get()) {
|
||||
prev(info);
|
||||
}
|
||||
}));
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
for len in (1..20).chain(70..MAX_LEN) {
|
||||
for &modulus in &[5, 20, 50] {
|
||||
for &has_runs in &[false, true] {
|
||||
let mut input = (0..len)
|
||||
.map(|id| {
|
||||
DropCounter {
|
||||
x: rng.next_u32() % modulus,
|
||||
id: id,
|
||||
version: Cell::new(0),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if has_runs {
|
||||
for c in &mut input {
|
||||
c.x = c.id as u32;
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
let a = rng.gen::<usize>() % len;
|
||||
let b = rng.gen::<usize>() % len;
|
||||
if a < b {
|
||||
input[a..b].reverse();
|
||||
} else {
|
||||
input.swap(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test!(input, sort_by);
|
||||
test!(input, sort_unstable_by);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue