@@ -285,6 +285,20 @@ impl<T: 'static> KeyValue<T> {
285285 None => None
286286 }
287287 }
288+
289+ // it's not clear if this is the right design for a public API, or if
290+ // there's even a need for this as a public API, but our benchmarks need
291+ // this to ensure consistent behavior on each run.
292+ #[ cfg( test) ]
293+ fn clear ( & ' static self ) {
294+ let map = match unsafe { get_local_map ( ) } {
295+ Some ( map) => map,
296+ None => return
297+ } ;
298+ let keyval = key_to_key_value ( self ) ;
299+ self . replace ( None ) ; // ensure we have no outstanding borrows
300+ map. remove ( & keyval) ;
301+ }
288302}
289303
290304impl < T : ' static > Deref < T > for Ref < T > {
@@ -392,6 +406,8 @@ impl Drop for TLDValue {
392406
393407#[ cfg( test) ]
394408mod tests {
409+ extern crate test;
410+
395411 use std:: prelude:: * ;
396412 use std:: gc:: { Gc , GC } ;
397413 use super :: * ;
@@ -495,6 +511,26 @@ mod tests {
495511 fail ! ( ) ;
496512 }
497513
514+ #[ test]
515+ fn test_cleanup_drops_values ( ) {
516+ let ( tx, rx) = channel :: < ( ) > ( ) ;
517+ struct Dropper {
518+ tx : Sender < ( ) >
519+ } ;
520+ impl Drop for Dropper {
521+ fn drop ( & mut self ) {
522+ self . tx . send ( ( ) ) ;
523+ }
524+ }
525+ static key: Key < Dropper > = & Key ;
526+ let _ = task:: try ( proc ( ) {
527+ key. replace ( Some ( Dropper { tx : tx } ) ) ;
528+ } ) ;
529+ // At this point the task has been cleaned up and the TLD dropped.
530+ // If the channel doesn't have a value now, then the Sender was leaked.
531+ assert_eq ! ( rx. try_recv( ) , Ok ( ( ) ) ) ;
532+ }
533+
498534 #[ test]
499535 fn test_static_pointer ( ) {
500536 static key: Key < & ' static int > = & Key ;
@@ -543,9 +579,117 @@ mod tests {
543579 #[ should_fail]
544580 fn test_nested_get_set1 ( ) {
545581 static key: Key < int > = & Key ;
546- key. replace ( Some ( 4 ) ) ;
582+ assert_eq ! ( key. replace( Some ( 4 ) ) , None ) ;
547583
548584 let _k = key. get ( ) ;
549585 key. replace ( Some ( 4 ) ) ;
550586 }
587+
588+ // ClearKey is a RAII class that ensures the keys are cleared from the map.
589+ // This is so repeated runs of a benchmark don't bloat the map with extra
590+ // keys and distort the measurements.
591+ // It's not used on the tests because the tests run in separate tasks.
592+ struct ClearKey < T > ( Key < T > ) ;
593+ #[ unsafe_destructor]
594+ impl < T : ' static > Drop for ClearKey < T > {
595+ fn drop ( & mut self ) {
596+ let ClearKey ( ref key) = * self ;
597+ key. clear ( ) ;
598+ }
599+ }
600+
601+ #[ bench]
602+ fn bench_replace_none ( b : & mut test:: Bencher ) {
603+ static key: Key < uint > = & Key ;
604+ let _clear = ClearKey ( key) ;
605+ key. replace ( None ) ;
606+ b. iter ( || {
607+ key. replace ( None )
608+ } ) ;
609+ }
610+
611+ #[ bench]
612+ fn bench_replace_some ( b : & mut test:: Bencher ) {
613+ static key: Key < uint > = & Key ;
614+ let _clear = ClearKey ( key) ;
615+ key. replace ( Some ( 1 u) ) ;
616+ b. iter ( || {
617+ key. replace ( Some ( 2 ) )
618+ } ) ;
619+ }
620+
621+ #[ bench]
622+ fn bench_replace_none_some ( b : & mut test:: Bencher ) {
623+ static key: Key < uint > = & Key ;
624+ let _clear = ClearKey ( key) ;
625+ key. replace ( Some ( 0 u) ) ;
626+ b. iter ( || {
627+ let old = key. replace ( None ) . unwrap ( ) ;
628+ let new = old + 1 ;
629+ key. replace ( Some ( new) )
630+ } ) ;
631+ }
632+
633+ #[ bench]
634+ fn bench_100_keys_replace_last ( b : & mut test:: Bencher ) {
635+ static keys: [ KeyValue < uint > , ..100 ] = [ Key , ..100 ] ;
636+ let _clear = keys. iter ( ) . map ( ClearKey ) . collect :: < Vec < ClearKey < uint > > > ( ) ;
637+ for ( i, key) in keys. iter ( ) . enumerate ( ) {
638+ key. replace ( Some ( i) ) ;
639+ }
640+ b. iter ( || {
641+ let key: Key < uint > = & keys[ 99 ] ;
642+ key. replace ( Some ( 42 ) )
643+ } ) ;
644+ }
645+
646+ #[ bench]
647+ fn bench_1000_keys_replace_last ( b : & mut test:: Bencher ) {
648+ static keys: [ KeyValue < uint > , ..1000 ] = [ Key , ..1000 ] ;
649+ let _clear = keys. iter ( ) . map ( ClearKey ) . collect :: < Vec < ClearKey < uint > > > ( ) ;
650+ for ( i, key) in keys. iter ( ) . enumerate ( ) {
651+ key. replace ( Some ( i) ) ;
652+ }
653+ b. iter ( || {
654+ let key: Key < uint > = & keys[ 999 ] ;
655+ key. replace ( Some ( 42 ) )
656+ } ) ;
657+ for key in keys. iter ( ) { key. clear ( ) ; }
658+ }
659+
660+ #[ bench]
661+ fn bench_get ( b : & mut test:: Bencher ) {
662+ static key: Key < uint > = & Key ;
663+ let _clear = ClearKey ( key) ;
664+ key. replace ( Some ( 42 ) ) ;
665+ b. iter ( || {
666+ key. get ( )
667+ } ) ;
668+ }
669+
670+ #[ bench]
671+ fn bench_100_keys_get_last ( b : & mut test:: Bencher ) {
672+ static keys: [ KeyValue < uint > , ..100 ] = [ Key , ..100 ] ;
673+ let _clear = keys. iter ( ) . map ( ClearKey ) . collect :: < Vec < ClearKey < uint > > > ( ) ;
674+ for ( i, key) in keys. iter ( ) . enumerate ( ) {
675+ key. replace ( Some ( i) ) ;
676+ }
677+ b. iter ( || {
678+ let key: Key < uint > = & keys[ 99 ] ;
679+ key. get ( )
680+ } ) ;
681+ }
682+
683+ #[ bench]
684+ fn bench_1000_keys_get_last ( b : & mut test:: Bencher ) {
685+ static keys: [ KeyValue < uint > , ..1000 ] = [ Key , ..1000 ] ;
686+ let _clear = keys. iter ( ) . map ( ClearKey ) . collect :: < Vec < ClearKey < uint > > > ( ) ;
687+ for ( i, key) in keys. iter ( ) . enumerate ( ) {
688+ key. replace ( Some ( i) ) ;
689+ }
690+ b. iter ( || {
691+ let key: Key < uint > = & keys[ 999 ] ;
692+ key. get ( )
693+ } ) ;
694+ }
551695}
0 commit comments