instrumented_stepanov/
lib.rs

1use prettytable::format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR;
2use prettytable::{Cell, Row, Table};
3use std::cell::RefCell;
4use std::ops::Range;
5use std::rc::Rc;
6
7#[derive(Default, Clone, Copy, PartialEq, Eq)]
8pub struct InstrumentedBase {
9    counts: [usize; InstrumentedBase::COLUMNS],
10}
11impl InstrumentedBase {
12    const NEW: usize = 0;
13    const CLONE: usize = 1;
14    const DROP: usize = 2;
15    const EQ: usize = 3;
16    const PARTIAL_CMP: usize = 4;
17    const CMP: usize = 5;
18
19    const COLUMNS: usize = 6;
20
21    pub fn counts_names() -> [&'static str; InstrumentedBase::COLUMNS] {
22        ["new", "clone", "drop", "eq", "partial_cmp", "cmp"]
23    }
24
25    pub fn set(&mut self, c: [usize; InstrumentedBase::COLUMNS]) {
26        self.counts = c;
27    }
28
29    pub fn get(&self) -> [usize; InstrumentedBase::COLUMNS] {
30        self.counts
31    }
32}
33impl std::fmt::Debug for InstrumentedBase {
34    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
35        let name = InstrumentedBase::counts_names();
36        let n: Vec<_> = name.iter().zip(self.counts.iter()).collect();
37        n.fmt(f)
38    }
39}
40
41#[derive(Eq)]
42pub struct Instrumented<T> {
43    value: T,
44    base: Rc<RefCell<InstrumentedBase>>,
45}
46
47impl<T> std::fmt::Debug for Instrumented<T>
48where
49    T: std::fmt::Debug,
50{
51    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
52        self.value.fmt(f)
53    }
54}
55
56/// Conversion
57impl<T> Instrumented<T> {
58    pub fn new(value: T, base: Rc<RefCell<InstrumentedBase>>) -> Self {
59        base.borrow_mut().counts[InstrumentedBase::NEW] += 1;
60        Self { value, base }
61    }
62}
63
64/// Semi regular
65impl<T> Clone for Instrumented<T>
66where
67    T: Clone,
68{
69    fn clone(&self) -> Self {
70        self.base.borrow_mut().counts[InstrumentedBase::CLONE] += 1;
71        Self {
72            value: self.value.clone(),
73            base: self.base.clone(),
74        }
75    }
76}
77
78/// Semi regular
79impl<T> Drop for Instrumented<T> {
80    fn drop(&mut self) {
81        self.base.borrow_mut().counts[InstrumentedBase::DROP] += 1;
82    }
83}
84
85/// Regular
86impl<T> PartialEq for Instrumented<T>
87where
88    T: PartialEq,
89{
90    fn eq(&self, x: &Self) -> bool {
91        self.base.borrow_mut().counts[InstrumentedBase::EQ] += 1;
92        self.value.eq(&x.value)
93    }
94}
95
96/// Totally-ordered
97impl<T> PartialOrd for Instrumented<T>
98where
99    T: PartialOrd,
100{
101    fn partial_cmp(&self, x: &Self) -> Option<std::cmp::Ordering> {
102        self.base.borrow_mut().counts[InstrumentedBase::PARTIAL_CMP] += 1;
103        self.value.partial_cmp(&x.value)
104    }
105}
106
107/// Totally-ordered
108impl<T> Ord for Instrumented<T>
109where
110    T: Ord,
111{
112    fn cmp(&self, x: &Self) -> std::cmp::Ordering {
113        self.base.borrow_mut().counts[InstrumentedBase::CMP] += 1;
114        self.value.cmp(&x.value)
115    }
116}
117
118pub fn table_count_operations<F>(mut i: usize, j: usize, f: F)
119where
120    F: Fn(&mut [Instrumented<usize>]),
121{
122    let mut table = Table::new();
123    table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
124    let hader = InstrumentedBase::counts_names()
125        .iter()
126        .map(|x| Cell::new(x))
127        .collect();
128    table.set_titles(Row::new(hader));
129    while i <= j {
130        let vec = rand_vec(0..i);
131
132        let c = count_operations(vec, &f)
133            .get()
134            .iter()
135            .map(|x| Cell::new(&x.to_string()))
136            .collect();
137        table.add_row(Row::new(c));
138
139        i <<= 1;
140    }
141    table.printstd();
142}
143
144fn rand_vec<T>(r: Range<T>) -> Vec<T>
145where
146    Range<T>: Iterator<Item = T>,
147{
148    use rand::seq::SliceRandom;
149    use rand::thread_rng;
150    let mut rnd = thread_rng();
151    let mut vec: Vec<T> = r.collect();
152    vec.shuffle(&mut rnd);
153
154    vec
155}
156
157pub fn count_operations<T, F>(vec: Vec<T>, f: F) -> InstrumentedBase
158where
159    F: Fn(&mut [Instrumented<T>]),
160{
161    let base = Rc::new(RefCell::new(Default::default()));
162    let mut vec: Vec<Instrumented<T>> = vec
163        .into_iter()
164        .map(|x| Instrumented::new(x, base.clone()))
165        .collect();
166    f(&mut vec);
167    let base2: RefCell<InstrumentedBase> = (*base).clone();
168    let base3: InstrumentedBase = *base2.borrow();
169    base3
170}
171
172#[cfg(test)]
173mod tests {
174    use super::count_operations;
175    use super::InstrumentedBase;
176    use std::default::Default;
177    #[test]
178    fn it_sort1() {
179        let mut vec = Vec::new();
180        (0..4).for_each(|k| vec.push(k));
181        let one = count_operations(vec, |x| x.sort());
182        let mut def: InstrumentedBase = Default::default();
183        def.set([4, 0, 0, 0, 3, 0]);
184        assert_eq!(def, one);
185    }
186    #[test]
187    fn it_sort2() {
188        let mut vec = Vec::new();
189        (0..4).for_each(|k| vec.push(3 - k));
190        let one = count_operations(vec, |x| x.sort());
191        let mut def: InstrumentedBase = Default::default();
192        def.set([4, 0, 0, 0, 6, 0]);
193        assert_eq!(def, one);
194    }
195    #[test]
196    fn print() {
197        let n = count_operations::<u64, _>(vec![], |_x| ());
198        assert_eq!("[(\"new\", 0), (\"clone\", 0), (\"drop\", 0), (\"eq\", 0), (\"partial_cmp\", 0), (\"cmp\", 0)]", format!("{:?}", n));
199    }
200}