1use std::io;
10use std::cmp::PartialEq;
11use std::fmt:: { Display, Formatter, Result };
12use std::collections::btree_map:: { BTreeMap };
13use std::convert::{ From };
14use record:: { BranchData };
15use merger::ops:: { TryMerge, MergeResult, MergeBranch, BranchError };
16use record:: { RecordWrite };
17use report::summary:: { Summary };
18use report::attribute:: { LineNumber, ExecutionCount };
19use report::counter:: { Hit, HitFoundCounter, FoundCounter, HitCounter };
20
21#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone)]
39pub struct BranchUnit(u32, u32);
40
41impl BranchUnit {
42 pub fn new(block: u32, branch: u32) -> BranchUnit {
43 BranchUnit(block, branch)
44 }
45 pub fn block(&self) -> &u32 {
46 &self.0
47 }
48 pub fn branch(&self) -> &u32 {
49 &self.1
50 }
51}
52
53impl Display for BranchUnit {
54 fn fmt(&self, f: &mut Formatter) -> Result {
55 write!(f, "{}-{}", self.0, self.1)
56 }
57}
58
59#[derive(Debug, Clone)]
60pub struct Branch {
61 line_number: LineNumber,
62 block: u32,
63 branch: u32,
64 execution_count: ExecutionCount
65}
66
67impl Branch {
68 pub fn new(
69 line_number: LineNumber,
70 block: u32,
71 branch: u32,
72 execution_count: ExecutionCount
73 ) -> Self {
74 Branch {
75 line_number: line_number,
76 block: block,
77 branch: branch,
78 execution_count: execution_count
79 }
80 }
81 pub fn line_number(&self) -> &LineNumber {
82 &self.line_number
83 }
84 pub fn block(&self) -> &u32 {
85 &self.block
86 }
87 pub fn branch(&self) -> &u32 {
88 &self.branch
89 }
90 pub fn execution_count(&self) -> &ExecutionCount {
91 &self.execution_count
92 }
93}
94
95impl PartialEq<BranchData> for Branch {
96 fn eq(&self, data: &BranchData) -> bool {
97 if self.line_number != data.line {
98 return false;
99 }
100 let branch_matched = self.block == data.block && self.branch == data.branch;
101
102 if !branch_matched {
103 return false;
104 }
105 return true;
106 }
107}
108
109impl PartialEq<Branch> for Branch {
110 fn eq(&self, other: &Branch) -> bool {
111 if self.line_number != *other.line_number() {
112 return false;
113 }
114 let branch_matched = self.block == *other.block() && self.branch == *other.branch();
115
116 if !branch_matched {
117 return false;
118 }
119 return true;
120 }
121}
122
123
124
125
126
127
128
129impl<'a> From<&'a BranchData> for Branch {
130 fn from(data: &'a BranchData) -> Self {
131 Branch::new(
132 data.line,
133 data.block,
134 data.branch,
135 data.taken
136 )
137 }
138}
139
140impl<'a> TryMerge<&'a BranchData> for Branch {
141 type Err = BranchError;
142
143 fn try_merge(&mut self, data: &'a BranchData) -> MergeResult<Self::Err> {
144 if self != data {
145 return Err(
146 BranchError::Mismatch(
147 MergeBranch::from(&self.clone()),
148 MergeBranch::from(data)
149 )
150 );
151 }
152 self.execution_count += data.taken;
153 Ok(())
154 }
155}
156
157impl<'a> TryMerge<&'a Branch> for Branch {
158 type Err = BranchError;
159
160 fn try_merge(&mut self, other: &'a Branch) -> MergeResult<Self::Err> {
161 if self != other {
162 return Err(
163 BranchError::Mismatch(
164 MergeBranch::from(&self.clone()),
165 MergeBranch::from(other)
166 )
167 );
168 }
169 self.execution_count += *other.execution_count();
170 Ok(())
171 }
172}
173
174impl Hit for Branch {
175 fn is_hit(&self) -> bool {
176 self.execution_count.is_hit()
177 }
178}
179
180
181
182
183#[derive(Debug, PartialEq, Clone)]
184pub struct BranchBlocks {
185 blocks: BTreeMap<BranchUnit, Branch>
186}
187
188impl BranchBlocks {
189 pub fn new() -> Self {
190 BranchBlocks {
191 blocks: BTreeMap::new()
192 }
193 }
194}
195
196impl_summary!(BranchBlocks, blocks<BranchUnit, Branch>);
197
198
199impl HitCounter for BranchBlocks {
200 fn hit_count(&self) -> usize {
201 self.iter()
202 .filter(|&(_, branch)| branch.is_hit())
203 .count()
204 }
205}
206
207impl FoundCounter for BranchBlocks {
208 fn found_count(&self) -> usize {
209 self.blocks.len()
210 }
211}
212
213impl HitFoundCounter for BranchBlocks {}
214
215
216
217impl<'a> TryMerge<&'a BranchData> for BranchBlocks {
218 type Err = BranchError;
219
220 fn try_merge(&mut self, data: &'a BranchData) -> MergeResult<Self::Err> {
221 let unit = BranchUnit::new(data.block, data.branch);
222 if !self.blocks.contains_key(&unit) {
223 self.blocks.insert(unit, Branch::from(data));
224 return Ok(());
225 }
226 let block = self.blocks.get_mut(&unit).unwrap();
227 block.try_merge(data)
228 }
229}
230
231impl_try_merge_self_summary!(BranchBlocks:blocks, BranchError);
232
233
234
235#[derive(Debug, Clone)]
236pub struct Branches {
237 branches: BTreeMap<LineNumber, BranchBlocks>
238}
239
240impl Branches {
241 pub fn new() -> Self {
242 Branches {
243 branches: BTreeMap::new()
244 }
245 }
246}
247
248impl HitCounter for Branches {
249 fn hit_count(&self) -> usize {
250 self.iter()
251 .map(|(_, blocks)| blocks.hit_count() )
252 .sum()
253 }
254}
255
256impl FoundCounter for Branches {
257 fn found_count(&self) -> usize {
258 self.iter()
259 .map(|(_, blocks)| blocks.found_count() )
260 .sum()
261 }
262}
263
264impl HitFoundCounter for Branches {}
265
266
267impl_summary!(Branches, branches<LineNumber, BranchBlocks>);
268
269
270impl RecordWrite for Branches {
271 fn write_records<T: io::Write>(&self, output: &mut T) -> io::Result<()> {
272 write!(output, "{}", self)
273 }
274}
275
276impl Display for Branches {
277 fn fmt(&self, f: &mut Formatter) -> Result {
278 if self.is_empty() {
279 return Ok(());
280 }
281 for (line_number, blocks) in self.iter() {
282 for (_, branch) in blocks.iter() {
283 writeln!(f, "BRDA:{},{},{},{}",
284 line_number, branch.block(), branch.branch(), branch.execution_count())?;
285 }
286 }
287 writeln!(f, "BRF:{}", self.found_count())?;
288 writeln!(f, "BRH:{}", self.hit_count())?;
289 Ok(())
290 }
291}
292
293impl_try_merge_self_summary!(Branches:branches, BranchError);
294
295
296impl<'a> TryMerge<&'a BranchData> for Branches {
297 type Err = BranchError;
298
299 fn try_merge(&mut self, data: &'a BranchData) -> MergeResult<Self::Err> {
300 if self.branches.contains_key(&data.line) {
301 let blocks = self.branches.get_mut(&data.line).unwrap();
302 blocks.try_merge(data)
303 } else {
304 let blocks = {
305 let mut blocks = BranchBlocks::new();
306 let _ = blocks.try_merge(data)?;
307 blocks
308 };
309 self.branches.insert(
310 data.line.clone(),
311 blocks
312 );
313 Ok(())
314 }
315 }
316}
317
318
319#[cfg(test)]
320mod tests {
321 use std::collections:: { HashMap };
322 use merger::ops::*;
323 use record:: { BranchData };
324 use report::branch:: { Branch, BranchUnit, Branches, BranchBlocks };
325 use report::summary:: { Summary };
326 use report::counter:: { FoundCounter, HitCounter };
327
328 #[test]
329 fn branch_unit() {
330 let branch1 = BranchUnit(1, 1);
331 let branch2 = BranchUnit(1, 2);
332
333 assert!(branch1 != branch2);
334
335 let same_branch1 = BranchUnit(1, 1);
336 let same_branch2 = BranchUnit(1, 1);
337
338 assert_eq!(same_branch1, same_branch2);
339 }
340
341 #[test]
342 fn branch_unit_as_hash_key() {
343 let mut container = HashMap::new();
344 container.insert(BranchUnit(1, 1), 1);
345
346 assert!( container.contains_key(&BranchUnit(1, 1)) );
347 }
348
349 #[test]
350 fn add_branch_data() {
351 let mut branches = BranchBlocks::new();
352 let b1 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
353 let b2 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
354
355 branches.try_merge(b1).unwrap();
356 branches.try_merge(b2).unwrap();
357
358 let branch = Branch::new(1, 0, 1, 2);
359 assert_eq!(branches.get(&BranchUnit::new(0, 1)), Some(&branch));
360 }
361
362 #[test]
363 fn append_branches() {
364 let mut branches = BranchBlocks::new();
365 let b1 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
366 let b2 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
367
368 branches.try_merge(b1).unwrap();
369 branches.try_merge(b2).unwrap();
370
371 let cloned_branches = branches.clone();
372 branches.try_merge(&cloned_branches).unwrap();
373
374 let branch = Branch::new(1, 0, 1, 2);
375 assert_eq!(branches.get(&BranchUnit::new(0, 1)), Some(&branch));
376 }
377
378 #[test]
379 fn branch_blocks_hit_count_and_found_count() {
380 let mut branches = BranchBlocks::new();
381 let b1 = &BranchData { line: 1, block: 0, branch: 1, taken: 1 };
382 let b2 = &BranchData { line: 1, block: 0, branch: 2, taken: 0 };
383
384 branches.try_merge(b1).unwrap();
385 branches.try_merge(b2).unwrap();
386
387 assert_eq!(branches.hit_count(), 1);
388 assert_eq!(branches.found_count(), 2);
389 }
390
391 #[test]
392 fn branches_hit_count_and_found_count() {
393 let mut branches = Branches::new();
394 branches.try_merge(&BranchData { line: 1, block: 0, branch: 1, taken: 1 }).unwrap();
395 branches.try_merge(&BranchData { line: 1, block: 0, branch: 2, taken: 0 }).unwrap();
396
397 assert_eq!(branches.hit_count(), 1);
398 assert_eq!(branches.found_count(), 2);
399 }
400}