-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrandom_actions.rs
More file actions
155 lines (144 loc) · 5.04 KB
/
random_actions.rs
File metadata and controls
155 lines (144 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use clap::Parser;
use orx_concurrent_vec::*;
use rand::prelude::*;
use rand_chacha::ChaCha8Rng;
use std::ops::Range;
enum ConAction {
/// Pushes the string to the vec.
Push(String),
/// Extends the vec with the elements of the iterator.
Extend(Vec<String>),
/// Maps the string at the given index to its length.
Map(usize),
/// Clones the string at the given index of the vec.
Clone(usize),
/// Replaces the element at the given index with the new string.
Replace(usize, String),
/// Sets value of the element at the given index with the new string.
Set(usize, String),
/// Updates value of the element at the given index by appending the given character.
Update(usize, char),
/// Iterates over all elements, maps them to numbers and sums them.
IterMapReduce,
/// Iterates over the elements in the range and collects their clones.
IterCloned(Range<usize>),
/// Iterate over all elements, and remove the last character from the string
/// if it is longer than one character.
IterMutate,
}
impl ConAction {
fn new(r: &mut ChaCha8Rng, vec_len: usize) -> Self {
let idx = |r: &mut ChaCha8Rng| r.random_range(0..vec_len);
let str = |r: &mut ChaCha8Rng| r.random_range(0..1000).to_string();
if vec_len == 0 {
// to avoid random_range panicking when vec_len = 0
return ConAction::Push(str(r));
}
match r.random_range(0..10) {
0 => ConAction::Push(str(r)),
1 => ConAction::Extend((0..64).map(|_| str(r)).collect()),
2 => ConAction::Map(idx(r)),
3 => ConAction::Clone(idx(r)),
4 => ConAction::Replace(idx(r), str(r)),
5 => ConAction::Set(idx(r), str(r)),
6 => ConAction::Update(idx(r), '7'),
7 => ConAction::IterMapReduce,
8 => {
let i = idx(r);
let j = r.random_range(i..vec_len);
ConAction::IterCloned(i..j)
}
9 => ConAction::IterMutate,
_ => panic!("?"),
}
}
}
/// Continuously applies random concurrent operations.
fn apply_random_concurrent_operations(
vec: &ConcurrentVec<String>,
final_vec_len: usize,
mut r: ChaCha8Rng,
) {
while vec.len() < final_vec_len {
match ConAction::new(&mut r, vec.len()) {
ConAction::Push(value) => {
vec.push(value);
}
ConAction::Extend(iter) => {
vec.extend(iter);
}
ConAction::Map(i) => {
// when we know i is in-bounds
let _num_chars = vec[i].map(|x: &String| x.len());
}
ConAction::Clone(i) => {
let _clone: Option<String> = vec.get_cloned(i);
}
ConAction::Replace(i, new_value) => {
// when we are not sure if i is in or out of bounds
if let Some(elem) = vec.get(i) {
let old_value = elem.replace(new_value);
assert!(old_value.parse::<usize>().is_ok());
}
}
ConAction::Set(i, new_value) => {
// when we know i is in-bounds
vec[i].set(new_value);
}
ConAction::Update(i, c) => {
if let Some(elem) = vec.get(i) {
elem.update(|x| x.push(c));
}
}
ConAction::IterMapReduce => {
let sum: usize = vec
.iter()
.map(|elem| elem.map(|x| x.parse::<usize>().unwrap()))
.sum();
assert!(sum > 0);
}
ConAction::IterCloned(range) => {
let _collected: Vec<_> = vec.slice(range).iter_cloned().collect();
}
ConAction::IterMutate => {
vec.iter().for_each(|elem| {
elem.update(|x: &mut String| {
if x.len() > 1 {
x.pop();
}
});
});
}
}
}
}
/// Program to test and demonstrate safety and convenience of
/// concurrent read and write operations with ConcurrentVec.
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
/// Number of threads to perform random concurrent actions.
#[arg(long, default_value_t = 8)]
num_threads: usize,
/// Final length of the vector to build, read and update concurrently.
#[arg(long, default_value_t = 1000)]
len: usize,
}
fn main() {
let args = Args::parse();
assert!(args.num_threads > 0);
assert!(args.len > 0);
let vec = ConcurrentVec::new();
std::thread::scope(|s| {
let con_vec = &vec;
for i in 0..args.num_threads {
s.spawn(move || {
apply_random_concurrent_operations(
&con_vec,
args.len,
ChaCha8Rng::seed_from_u64((i * 42) as u64),
)
});
}
});
}