Tests: Added non-overlapping multithreaded iteration testing for trivial an non-trivial values.

TODO: Next, add overlapping multithreaded iteration with trivial and nontrivial values.

Fortune for parapop's current commit: Future small blessing − 末小吉
master
Avril 2 years ago
parent 9272f1addb
commit 729786a568
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -396,6 +396,21 @@ impl<'a, T> Populator<'a, T>
}
}
/// If all values are populated and the `Arc` has no other strong references, then convert it into a boxed slice and return it.
///
/// Otherwise, return the arc.
///
/// # If the values are not all populated
/// But the `Arc` is empty, then a new, single strong reference arc is constructed around the value and returned as its `Err`.
pub fn try_complete_owned(self: Arc<Self>) -> Result<Box<[T]>, Arc<Self>>
{
match Arc::try_unwrap(self) {
Ok(extracted) => extracted.try_complete().map_err(Arc::new),
Err(e) => Err(e),
}
}
/// If all values are populated, returns a slice of all the elements.
///
/// Performs a single atomic load of the number of currently inserted elements to check for completion
@ -460,6 +475,30 @@ impl<'a, T> Populator<'a, T>
}
}
/// Returns the completed population from an `Arc` that has no more than 1 reference.
///
/// # Panics
/// * If the `Arc` has more than one strong reference
/// * If the collection is not fully populated
pub fn complete_owned(self: Arc<Self>) -> Box<[T]>
{
#[inline(never)]
#[cold]
fn panic_uncomplete_or_shared<T>(values: &Arc<T>) -> !
{
let sc = Arc::strong_count(values);
if sc > 1 {
panic!("More than one ({}) reference to the `Arc` holding this instance", sc)
} else {
panic!("Not all values had been populated")
}
}
match self.try_complete_owned() {
Ok(v) => v,
Err(ref e) => panic_uncomplete_or_shared(e),
}
}
/// Create an iterator over references to a completed population if it is completed.
#[inline]
pub fn try_completed_iter(&self) -> Option<iter::FullIterRef<'a, '_, T>>
@ -522,6 +561,7 @@ impl<'a, T> Populator<'a, T>
iter::Iter::new_range(self, range)
}
//TODO: `self: Arc<Self>` version of iter_slice()/iter()
}
impl<'a, T: 'a> FromIterator<Option<T>> for Populator<'a, T>

@ -1,6 +1,22 @@
//! Unit tests
use std::sync::Arc;
use std::thread::{
self,
};
use super::*;
#[macro_export] macro_rules! assert_binds {
($expr:expr, $pat:pat, $msg:literal) => {
match $expr {
$pat => (),
_ => {
panic!("Pattern matched assertion `{}` failed: {}", stringify!($pat), $msg)
}
}
}
}
/// Testing iteration
mod iteration {
use super::*;
@ -30,4 +46,67 @@ mod iteration {
.map(|x| x.parse::<usize>().unwrap())
.sum::<usize>(), "Did not set all elements to 1");
}
#[test]
fn multi_threaded_trivial()
{
let pop = Arc::new(Populator::<usize>::new(10));
let t1 = thread::spawn({
let pop = pop.clone();
move || {
for (i,r) in (10..).zip(pop.iter_slice(0..5)) {
r.insert(i);
}
}
});
let t2 = thread::spawn({
let pop = pop.clone();
move || {
for (i, r) in (0..).zip(pop.iter_slice(5..10)) {
r.insert(i);
}
}
});
thread::yield_now();
assert_binds!((t1.join(), t2.join()), (Ok(_), Ok(_)), "One or more of the threads panicked");
assert_eq!(&pop.complete_owned()[..], &[
10, 11, 12, 13, 14,
0, 1, 2, 3, 4,
], "Bad order of elements");
}
#[test]
fn multi_threaded_nontrivial()
{
let pop = Arc::new(Populator::<String>::new(10));
let t1 = thread::spawn({
let pop = pop.clone();
move || {
for (i,r) in (10..).zip(pop.iter_slice(0..5)) {
r.insert(i.to_string());
}
}
});
let t2 = thread::spawn({
let pop = pop.clone();
move || {
for (i, r) in (0..).zip(pop.iter_slice(5..10)) {
r.insert(i.to_string());
}
}
});
thread::yield_now();
assert_binds!((t1.join(), t2.join()), (Ok(_), Ok(_)), "One or more of the threads panicked");
assert_eq!(&pop.complete_owned()[..], &[
"10", "11", "12", "13", "14",
"0", "1", "2", "3", "4",
], "Bad order of elements");
}
}

Loading…
Cancel
Save