Skip to content

Commit c1748cd

Browse files
authored
Merge pull request #23 from segeljakt/rust-dev
Minor refactors, bugfix, features and test additions
2 parents c75f774 + 852131e commit c1748cd

File tree

9 files changed

+131
-77
lines changed

9 files changed

+131
-77
lines changed

rust/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ num-traits = "0.2.12"
2222
arrayvec = "0.5.1"
2323
alga = "0.9.3"
2424
rand = "0.7.3"
25+
fxhash = "0.2.1"
2526

2627
[dev-dependencies]
2728
criterion = "0.3.3"

rust/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ where
3030
fn pop(&mut self);
3131
/// Combines the values in fifo order and returns the result, e.g., `1+v1+v2+...+vn`.
3232
fn query(&self) -> Value;
33+
/// Returns the number of elements inside the window.
34+
fn len(&self) -> usize;
35+
/// Returns true if the window contains no elements.
36+
fn is_empty(&self) -> bool;
3337
}
3438

3539
/// An abstract data type which maintains sliding sub-window aggregates.

rust/src/reactive/flat_fat.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use alga::general::AbstractMonoid;
22
use alga::general::Operator;
3-
use std::collections::HashSet;
3+
use fxhash::FxHashSet as HashSet;
4+
use std::marker::PhantomData;
45

56
pub(crate) trait FAT<Value, BinOp>: Clone
67
where
@@ -49,7 +50,7 @@ where
4950
pub(crate) tree: Vec<Value>,
5051
/// Number of leaves which can be stored in the tree
5152
pub(crate) capacity: usize,
52-
binop: std::marker::PhantomData<BinOp>,
53+
binop: PhantomData<BinOp>,
5354
}
5455

5556
impl<Value, BinOp> FlatFAT<Value, BinOp>
@@ -58,26 +59,32 @@ where
5859
BinOp: Operator,
5960
{
6061
/// Returns all leaf nodes of the tree
62+
#[inline(always)]
6163
pub(crate) fn leaves(&self) -> &[Value] {
6264
&self.tree[self.leaf(0)..]
6365
}
6466
/// Returns the index of the root node
67+
#[inline(always)]
6568
fn root(&self) -> usize {
6669
0
6770
}
6871
/// Returns the index of a leaf node
72+
#[inline(always)]
6973
fn leaf(&self, i: usize) -> usize {
7074
i + self.capacity - 1
7175
}
7276
/// Returns the index of an node's left child
77+
#[inline(always)]
7378
fn left(&self, i: usize) -> usize {
74-
2 * (i + 1) - 1
79+
2 * i + 1
7580
}
7681
/// Returns the index of an node's right child
82+
#[inline(always)]
7783
fn right(&self, i: usize) -> usize {
78-
2 * (i + 1)
84+
2 * i + 2
7985
}
8086
/// Returns the index of an node's parent
87+
#[inline(always)]
8188
fn parent(&self, i: usize) -> usize {
8289
(i - 1) / 2
8390
}
@@ -96,10 +103,10 @@ where
96103
}
97104

98105
fn with_capacity(capacity: usize) -> Self {
99-
assert_ne!(capacity, 0, "Capacity of window must be greater than 0");
106+
assert!(capacity > 1, "Capacity of window must be greater than 1");
100107
Self {
101108
tree: vec![Value::identity(); 2 * capacity - 1],
102-
binop: std::marker::PhantomData,
109+
binop: PhantomData,
103110
capacity,
104111
}
105112
}
@@ -116,7 +123,7 @@ where
116123
self.parent(leaf)
117124
})
118125
.collect();
119-
let mut new_parents: HashSet<usize> = HashSet::new();
126+
let mut new_parents: HashSet<usize> = HashSet::default();
120127
loop {
121128
parents.drain().for_each(|parent| {
122129
let left = self.left(parent);

rust/src/reactive/mod.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ where
3232
}
3333
}
3434
fn inverted(&self) -> bool {
35-
self.front > self.back
35+
self.front >= self.back
3636
}
3737
fn resize(&mut self, capacity: usize) {
3838
let leaves = self.fat.leaves();
@@ -60,7 +60,7 @@ where
6060
{
6161
fn new() -> Self {
6262
Self {
63-
fat: FlatFAT::with_capacity(8),
63+
fat: FlatFAT::with_capacity(2),
6464
size: 0,
6565
front: 0,
6666
back: 0,
@@ -69,18 +69,20 @@ where
6969
fn push(&mut self, v: Value) {
7070
self.fat.update([(self.back, v)].iter().cloned());
7171
self.size += 1;
72-
self.back += 1;
72+
self.back = (self.back + 1) % self.fat.capacity;
7373
if self.size > (3 * self.fat.capacity) / 4 {
7474
self.resize(self.fat.capacity * 2);
7575
}
7676
}
7777
fn pop(&mut self) {
78-
self.fat
79-
.update([(self.front, Value::identity())].iter().cloned());
80-
self.size -= 1;
81-
self.front += 1;
82-
if self.size <= self.fat.capacity / 4 {
83-
self.resize(self.fat.capacity / 2);
78+
if self.size > 0 {
79+
self.fat
80+
.update([(self.front, Value::identity())].iter().cloned());
81+
self.size -= 1;
82+
self.front = (self.front + 1) % self.fat.capacity;
83+
if self.size <= self.fat.capacity / 4 && self.size > 0 {
84+
self.resize(self.fat.capacity / 2);
85+
}
8486
}
8587
}
8688
fn query(&self) -> Value {
@@ -92,4 +94,10 @@ where
9294
self.fat.aggregate()
9395
}
9496
}
97+
fn len(&self) -> usize {
98+
self.size
99+
}
100+
fn is_empty(&self) -> bool {
101+
self.size == 0
102+
}
95103
}

rust/src/recalc/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,10 @@ where
3636
.iter()
3737
.fold(Value::identity(), |acc, elem| acc.operate(&elem))
3838
}
39+
fn len(&self) -> usize {
40+
self.stack.len()
41+
}
42+
fn is_empty(&self) -> bool {
43+
self.stack.is_empty()
44+
}
3945
}

rust/src/soe/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,10 @@ where
3939
fn query(&self) -> Value {
4040
self.agg.clone()
4141
}
42+
fn len(&self) -> usize {
43+
self.stack.len()
44+
}
45+
fn is_empty(&self) -> bool {
46+
self.stack.is_empty()
47+
}
4248
}

rust/src/two_stacks/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ where
5555
fn query(&self) -> Value {
5656
Self::agg(&self.front).operate(&Self::agg(&self.back))
5757
}
58+
fn len(&self) -> usize {
59+
self.front.len() + self.back.len()
60+
}
61+
fn is_empty(&self) -> bool {
62+
self.front.is_empty() && self.back.is_empty()
63+
}
5864
}
5965

6066
impl<Value, BinOp> TwoStacks<Value, BinOp>

rust/tests/common.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use alga::general::TwoSidedInverse;
3939
4040
/// An integer value
4141
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
42-
pub struct Int(pub i32);
42+
pub struct Int(pub i64);
4343

4444
/// Binary operator for calculating the arithmetic sum.
4545
/// Has the following properties:
@@ -94,7 +94,7 @@ impl Operator for Max {
9494

9595
impl Identity<Max> for Int {
9696
fn identity() -> Int {
97-
Int(std::i32::MIN)
97+
Int(std::i64::MIN)
9898
}
9999
}
100100

rust/tests/fifo_window.rs

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
use rand::Rng;
2-
use swag::reactive::*;
3-
use swag::recalc::*;
4-
use swag::soe::*;
5-
use swag::two_stacks::*;
62
use swag::*;
73

84
mod common;
95
use common::*;
106

7+
/// Macro for generating test cases for different algorithms.
8+
macro_rules! test_matrix {
9+
{
10+
$(
11+
$name:ident => [$($module:ident::$algorithm:ident),*]
12+
),*
13+
} => {
14+
$(
15+
mod $name {
16+
$(
17+
#[test]
18+
fn $module() {
19+
super::$name::<swag::$module::$algorithm<_,_>>();
20+
}
21+
)*
22+
}
23+
)*
24+
}
25+
}
26+
1127
/// Basic test for integer sums.
1228
fn test1<Window>()
1329
where
@@ -34,21 +50,21 @@ where
3450
assert_eq!(window.query(), Int(5));
3551
}
3652

37-
fn generate() -> Vec<Int> {
53+
fn synthesize(size: usize) -> Vec<Int> {
3854
let mut rng = rand::thread_rng();
39-
(0..1000)
55+
(0..size)
4056
.map(|_| rng.gen_range(1, 5))
4157
.map(Int)
4258
.collect::<Vec<_>>()
4359
}
4460

45-
/// Tries to aggregate the sum of 1000 randomly generated integers.
61+
/// Tries to aggregate the sum of 1K randomly generated integers.
4662
fn test2<Window>()
4763
where
4864
Window: FifoWindow<Int, Sum>,
4965
{
50-
let values = generate();
51-
let sum: i32 = values.iter().fold(0, |acc, Int(x)| acc + x);
66+
let values = synthesize(1_000);
67+
let sum = values.iter().fold(0, |acc, Int(x)| acc + x);
5268
let mut window = Window::new();
5369
for v in values.clone() {
5470
window.push(v);
@@ -60,13 +76,13 @@ where
6076
assert_eq!(window.query(), Int(0));
6177
}
6278

63-
/// Tries to find the maximum value out 1000 randomly generated integers.
79+
/// Tries to find the maximum value out 1K randomly generated integers.
6480
fn test3<Window>()
6581
where
6682
Window: FifoWindow<Int, Max>,
6783
{
6884
let mut window = Window::new();
69-
let values = generate();
85+
let values = synthesize(1_000);
7086
let max = values.iter().map(|Int(x)| *x).max().unwrap();
7187
for v in values.clone() {
7288
window.push(v);
@@ -75,60 +91,60 @@ where
7591
for _ in values {
7692
window.pop();
7793
}
78-
assert_eq!(window.query(), Int(std::i32::MIN));
79-
}
80-
81-
#[test]
82-
fn test1_recalc() {
83-
test1::<ReCalc<Int, Sum>>();
84-
}
85-
86-
#[test]
87-
fn test2_recalc() {
88-
test2::<ReCalc<Int, Sum>>();
89-
}
90-
91-
#[test]
92-
fn test3_recalc() {
93-
test3::<ReCalc<Int, Max>>();
94-
}
95-
96-
#[test]
97-
fn test1_soe() {
98-
test1::<SoE<Int, Sum>>();
94+
assert_eq!(window.query(), Int(std::i64::MIN));
9995
}
10096

101-
#[test]
102-
fn test2_soe() {
103-
test2::<SoE<Int, Sum>>();
104-
}
105-
106-
#[test]
107-
fn test1_two_stacks() {
108-
test1::<TwoStacks<Int, Sum>>();
109-
}
110-
111-
#[test]
112-
fn test2_two_stacks() {
113-
test2::<TwoStacks<Int, Sum>>();
114-
}
115-
116-
#[test]
117-
fn test3_two_stacks() {
118-
test3::<TwoStacks<Int, Max>>();
97+
/// Fills a window with 1K elements and pushes/pops/queries 1K times.
98+
fn test4<Window>()
99+
where
100+
Window: FifoWindow<Int, Sum>,
101+
{
102+
let mut window = Window::new();
103+
let values = synthesize(1_000);
104+
let sum = values.iter().fold(0, |acc, Int(x)| acc + x);
105+
for v in values.clone() {
106+
window.push(v);
107+
}
108+
for v in values {
109+
window.push(v);
110+
window.pop();
111+
window.query();
112+
assert_eq!(window.query(), Int(sum));
113+
}
119114
}
120115

121-
#[test]
122-
fn test1_reactive() {
123-
test1::<Reactive<Int, Sum>>();
116+
/// Pops more elements from a window than what it contains.
117+
fn test5<Window>()
118+
where
119+
Window: FifoWindow<Int, Sum>,
120+
{
121+
let mut window = Window::new();
122+
window.push(Int(0));
123+
window.push(Int(0));
124+
window.pop();
125+
window.pop();
126+
window.pop();
124127
}
125128

126-
#[test]
127-
fn test2_reactive() {
128-
test2::<Reactive<Int, Sum>>();
129+
/// Pops more elements from a window than what it contains.
130+
fn test6<Window>()
131+
where
132+
Window: FifoWindow<Int, Sum>,
133+
{
134+
let mut window = Window::new();
135+
window.push(Int(1));
136+
window.push(Int(2));
137+
window.push(Int(3));
138+
window.pop();
139+
window.push(Int(4));
140+
window.push(Int(5));
129141
}
130142

131-
#[test]
132-
fn test3_reactive() {
133-
test3::<Reactive<Int, Max>>();
143+
test_matrix! {
144+
test1 => [ recalc::ReCalc, soe::SoE, reactive::Reactive, two_stacks::TwoStacks ],
145+
test2 => [ recalc::ReCalc, soe::SoE, reactive::Reactive, two_stacks::TwoStacks ],
146+
test3 => [ recalc::ReCalc, reactive::Reactive, two_stacks::TwoStacks ],
147+
test4 => [ recalc::ReCalc, soe::SoE, reactive::Reactive, two_stacks::TwoStacks ],
148+
test5 => [ recalc::ReCalc, soe::SoE, reactive::Reactive, two_stacks::TwoStacks ],
149+
test6 => [ recalc::ReCalc, soe::SoE, reactive::Reactive, two_stacks::TwoStacks ]
134150
}

0 commit comments

Comments
 (0)