@@ -5,6 +5,7 @@ use crate::{
55 api:: SampleType ,
66 internal:: { Sample , Timestamp } ,
77} ;
8+ use anyhow:: Context ;
89use enum_map:: EnumMap ;
910use std:: collections:: HashMap ;
1011use std:: sync:: Arc ;
@@ -14,6 +15,7 @@ use std::sync::Arc;
1415pub struct Observations {
1516 sample_types : Arc < [ SampleType ] > ,
1617 sample_type_index_map : EnumMap < SampleType , Option < usize > > ,
18+ pub paired_samples : Vec < Option < usize > > ,
1719 pub aggregated : HashMap < SampleType , HashMap < Sample , i64 > > ,
1820 pub aggregated2 : HashMap < ( SampleType , SampleType ) , HashMap < Sample , ( i64 , i64 ) > > ,
1921 pub timestamped : HashMap < SampleType , HashMap < Sample , Vec < ( i64 , Timestamp ) > > > ,
@@ -26,75 +28,78 @@ impl Observations {
2628 sample_types : Arc < [ SampleType ] > ,
2729 sample_type_index_map : EnumMap < SampleType , Option < usize > > ,
2830 ) -> Self {
31+ let len = sample_types. len ( ) ;
2932 Self {
3033 sample_types,
3134 sample_type_index_map,
35+ paired_samples : vec ! [ None ; len] ,
3236 ..Default :: default ( )
3337 }
3438 }
3539
40+ pub fn pair_samples ( & mut self , s1 : SampleType , s2 : SampleType ) -> anyhow:: Result < ( ) > {
41+ let i1 = self . sample_type_index_map [ s1] . context ( "invalid sample type" ) ?;
42+ let i2 = self . sample_type_index_map [ s2] . context ( "invalid sample type" ) ?;
43+ anyhow:: ensure!(
44+ self . paired_samples[ i1] . is_none( ) && self . paired_samples[ i2] . is_none( ) ,
45+ "sample type already paired"
46+ ) ;
47+ self . paired_samples [ i1] = Some ( i2) ;
48+ self . paired_samples [ i2] = Some ( i1) ;
49+ Ok ( ( ) )
50+ }
51+
3652 pub fn add (
3753 & mut self ,
3854 sample : Sample ,
3955 timestamp : Option < Timestamp > ,
4056 values : & [ i64 ] ,
4157 ) -> anyhow:: Result < ( ) > {
42- let mut first = None ;
43- let mut second = None ;
44-
45- for ( idx, v) in values. iter ( ) . enumerate ( ) {
46- if * v != 0 {
47- let sample_type = self . sample_types [ idx] ;
48- if first. is_none ( ) {
49- first = Some ( ( sample_type, * v) ) ;
50- } else if second. is_none ( ) {
51- second = Some ( ( sample_type, * v) ) ;
52- } else {
53- anyhow:: bail!( "too many values" ) ;
58+ for i in 0 ..values. len ( ) {
59+ let val1 = values[ i] ;
60+
61+ if let Some ( pair) = self . paired_samples [ i] {
62+ let val2 = values[ pair] ;
63+ if i < pair && ( val1 != 0 || val2 != 0 ) {
64+ let st1 = self . sample_types [ i] ;
65+ let st2 = self . sample_types [ pair] ;
66+ if let Some ( ts) = timestamp {
67+ self . timestamped2
68+ . entry ( ( st1, st2) )
69+ . or_default ( )
70+ . entry ( sample)
71+ . or_default ( )
72+ . push ( ( val1, val2, ts) ) ;
73+ } else {
74+ let entry = self
75+ . aggregated2
76+ . entry ( ( st1, st2) )
77+ . or_default ( )
78+ . entry ( sample)
79+ . or_insert ( ( 0 , 0 ) ) ;
80+ entry. 0 = entry. 0 . saturating_add ( val1) ;
81+ entry. 1 = entry. 1 . saturating_add ( val2) ;
82+ }
5483 }
55- }
56- }
57-
58- match ( first, second) {
59- ( None , None ) => { }
60- ( Some ( ( st, val) ) , None ) => {
84+ } else if val1 != 0 {
85+ let st = self . sample_types [ i] ;
6186 if let Some ( ts) = timestamp {
6287 self . timestamped
6388 . entry ( st)
6489 . or_default ( )
6590 . entry ( sample)
6691 . or_default ( )
67- . push ( ( val , ts) ) ;
92+ . push ( ( val1 , ts) ) ;
6893 } else {
6994 let entry = self
7095 . aggregated
7196 . entry ( st)
7297 . or_default ( )
7398 . entry ( sample)
7499 . or_insert ( 0 ) ;
75- * entry = entry. saturating_add ( val) ;
76- }
77- }
78- ( Some ( ( st1, val1) ) , Some ( ( st2, val2) ) ) => {
79- if let Some ( ts) = timestamp {
80- self . timestamped2
81- . entry ( ( st1, st2) )
82- . or_default ( )
83- . entry ( sample)
84- . or_default ( )
85- . push ( ( val1, val2, ts) ) ;
86- } else {
87- let entry = self
88- . aggregated2
89- . entry ( ( st1, st2) )
90- . or_default ( )
91- . entry ( sample)
92- . or_insert ( ( 0 , 0 ) ) ;
93- entry. 0 = entry. 0 . saturating_add ( val1) ;
94- entry. 1 = entry. 1 . saturating_add ( val2) ;
100+ * entry = entry. saturating_add ( val1) ;
95101 }
96102 }
97- ( None , Some ( _) ) => unreachable ! ( "second set implies first set" ) ,
98103 }
99104
100105 Ok ( ( ) )
@@ -172,7 +177,6 @@ impl Observations {
172177 } )
173178 } ) ;
174179
175-
176180 let ts_iter = self
177181 . timestamped
178182 . into_iter ( )
0 commit comments