lib.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. use std::collections::HashSet;
  2. use std::fmt::Debug;
  3. use std::time::{Duration, Instant};
  4. use bit_set::BitSet;
  5. pub use model::KvInput;
  6. pub use model::KvModel;
  7. pub use model::KvOp;
  8. pub use model::KvOutput;
  9. pub use model::Model;
  10. use crate::offset_linked_list::{NodeRef, OffsetLinkedList};
  11. mod model;
  12. mod offset_linked_list;
  13. #[derive(Debug)]
  14. pub struct Operation<C: Debug, R: Debug> {
  15. pub call_op: C,
  16. pub call_time: Instant,
  17. pub return_op: R,
  18. pub return_time: Instant,
  19. }
  20. enum EntryKind<'a, C: Debug, R: Debug> {
  21. Call(&'a Operation<C, R>),
  22. Return,
  23. }
  24. struct Entry<'a, C: Debug, R: Debug> {
  25. kind: EntryKind<'a, C, R>,
  26. id: usize,
  27. time: Instant,
  28. other: usize,
  29. }
  30. fn operation_to_entries<'a, C: Debug, R: Debug>(
  31. ops: &[&'a Operation<C, R>],
  32. ) -> Vec<Entry<'a, C, R>> {
  33. let mut result = vec![];
  34. for op in ops {
  35. let id = result.len() >> 1;
  36. result.push(Entry {
  37. kind: EntryKind::Return,
  38. id,
  39. time: op.return_time,
  40. other: 0,
  41. });
  42. result.push(Entry {
  43. kind: EntryKind::Call(op),
  44. id,
  45. time: op.call_time,
  46. other: 0,
  47. });
  48. }
  49. result.sort_by_cached_key(|e| e.time);
  50. let mut this = vec![0; ops.len()];
  51. let mut that = vec![0; ops.len()];
  52. for (index, entry) in result.iter().enumerate() {
  53. match entry.kind {
  54. EntryKind::Call(_) => this[entry.id] = index,
  55. EntryKind::Return => that[entry.id] = index,
  56. }
  57. }
  58. for i in 0..ops.len() {
  59. result[this[i]].other = that[i];
  60. result[that[i]].other = this[i];
  61. }
  62. result
  63. }
  64. fn check_history<T: Model>(
  65. ops: &[&Operation<<T as Model>::Input, <T as Model>::Output>],
  66. ) -> bool {
  67. let entries = operation_to_entries(ops);
  68. let mut list = OffsetLinkedList::create(entries);
  69. let mut all = HashSet::new();
  70. let mut stack = vec![];
  71. let mut flag = BitSet::new();
  72. let mut leg = list.first().expect("Linked list should not be empty");
  73. let mut curr = T::create();
  74. while !list.is_empty() {
  75. let entry = list.get(leg);
  76. let other = NodeRef(entry.other);
  77. match entry.kind {
  78. EntryKind::Call(ops) => {
  79. let mut next = curr.clone();
  80. if next.step(&ops.call_op, &ops.return_op) {
  81. let mut next_flag = flag.clone();
  82. next_flag.insert(entry.id);
  83. if all.insert((next_flag.clone(), next.clone())) {
  84. std::mem::swap(&mut curr, &mut next);
  85. std::mem::swap(&mut flag, &mut next_flag);
  86. stack.push((leg, next, next_flag));
  87. list.lift(leg);
  88. list.lift(other);
  89. if let Some(first) = list.first() {
  90. leg = first;
  91. } else {
  92. break;
  93. }
  94. } else {
  95. leg = list
  96. .succ(leg)
  97. .expect("There should be another element");
  98. }
  99. } else {
  100. leg = list
  101. .succ(leg)
  102. .expect("There should be another element");
  103. }
  104. }
  105. EntryKind::Return => {
  106. if stack.is_empty() {
  107. return false;
  108. }
  109. let (prev_leg, prev, prev_flag) = stack.pop().unwrap();
  110. leg = prev_leg;
  111. curr = prev;
  112. flag = prev_flag;
  113. list.unlift(NodeRef(list.get(leg).other));
  114. list.unlift(leg);
  115. leg = list.succ(leg).expect("There should be another element");
  116. }
  117. }
  118. }
  119. true
  120. }
  121. pub fn check_operations_timeout<T: Model>(
  122. history: &'static [Operation<<T as Model>::Input, <T as Model>::Output>],
  123. _: Option<Duration>,
  124. ) -> bool
  125. where
  126. <T as Model>::Input: Sync,
  127. <T as Model>::Output: Sync,
  128. {
  129. let mut results = vec![];
  130. let mut partitions = vec![];
  131. for sub_history in T::partition(history) {
  132. // Making a copy and pass the original value to the thread below.
  133. partitions.push(sub_history.clone());
  134. results
  135. .push(std::thread::spawn(move || check_history::<T>(&sub_history)));
  136. }
  137. let mut failed = vec![];
  138. for (index, result) in results.into_iter().enumerate() {
  139. let result = result.join().expect("Search thread should never panic");
  140. if !result {
  141. eprintln!("Partition {} failed: {:?}.", index, partitions[index]);
  142. failed.push(index);
  143. }
  144. }
  145. failed.is_empty()
  146. }
  147. #[cfg(test)]
  148. mod tests {
  149. use std::time::{Duration, Instant};
  150. use crate::{check_operations_timeout, Model, Operation};
  151. #[derive(Clone, Debug, Eq, PartialEq, Hash)]
  152. struct CountingModel {
  153. base: usize,
  154. cnt: usize,
  155. }
  156. impl Model for CountingModel {
  157. type Input = usize;
  158. type Output = usize;
  159. fn create() -> Self {
  160. Self { base: 0, cnt: 0 }
  161. }
  162. fn step(&mut self, input: &Self::Input, output: &Self::Output) -> bool {
  163. if self.base == 0 && *input != 0 && *output == 1 {
  164. self.base = *input;
  165. self.cnt = 1;
  166. true
  167. } else if self.base == *input && self.cnt + 1 == *output {
  168. self.cnt += 1;
  169. true
  170. } else {
  171. false
  172. }
  173. }
  174. }
  175. #[test]
  176. fn no_accept() {
  177. let ops = Box::leak(Box::new(vec![]));
  178. let start = Instant::now();
  179. for i in 0..4 {
  180. ops.push(Operation {
  181. call_op: 0usize,
  182. call_time: start,
  183. return_op: i as usize,
  184. return_time: start + Duration::from_secs(i),
  185. });
  186. }
  187. assert!(!check_operations_timeout::<CountingModel>(ops, None));
  188. }
  189. #[test]
  190. fn accept() {
  191. let ops = Box::leak(Box::new(vec![]));
  192. let start = Instant::now();
  193. for i in 0..4 {
  194. ops.push(Operation {
  195. call_op: 1usize,
  196. call_time: start + Duration::from_secs(i * 2),
  197. return_op: (i + 1) as usize,
  198. return_time: start + Duration::from_secs(i + 4),
  199. });
  200. }
  201. assert!(check_operations_timeout::<CountingModel>(ops, None));
  202. }
  203. }