instrumented_stepanov/
lib.rs1use 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
56impl<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
64impl<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
78impl<T> Drop for Instrumented<T> {
80 fn drop(&mut self) {
81 self.base.borrow_mut().counts[InstrumentedBase::DROP] += 1;
82 }
83}
84
85impl<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
96impl<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
107impl<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}