1
1
use std:: cell:: { Cell , RefCell } ;
2
+ use std:: fmt:: { self , Debug , Formatter } ;
3
+ use std:: hash:: Hash ;
4
+ use std:: marker:: PhantomData ;
5
+ use std:: num:: NonZeroU128 ;
6
+
7
+ use siphasher:: sip128:: { Hasher128 , SipHasher } ;
2
8
3
9
// TODO
4
10
// - Nested tracked call
@@ -39,7 +45,7 @@ fn describe(image: TrackedImage) -> &'static str {
39
45
40
46
thread_local ! {
41
47
static NR : Cell <usize > = Cell :: new( 0 ) ;
42
- static CACHE : RefCell <Vec <( ImageConstraint , & ' static str ) >> =
48
+ static CACHE : RefCell <Vec <( ImageTracker , & ' static str ) >> =
43
49
RefCell :: new( vec![ ] ) ;
44
50
}
45
51
@@ -48,15 +54,18 @@ fn describe(image: TrackedImage) -> &'static str {
48
54
cache
49
55
. borrow ( )
50
56
. iter ( )
51
- . find ( |( ct , _) | ct . valid ( image. inner ) )
57
+ . find ( |( tracker , _) | tracker . valid ( image. inner ) )
52
58
. map ( |& ( _, output) | output)
53
59
} ) ;
54
60
55
61
let output = output. unwrap_or_else ( || {
56
- let ct = ImageConstraint :: default ( ) ;
57
- let image = TrackedImage { inner : image. inner , tracker : Some ( & ct) } ;
62
+ let tracker = ImageTracker :: default ( ) ;
63
+ let image = TrackedImage {
64
+ inner : image. inner ,
65
+ tracker : Some ( & tracker) ,
66
+ } ;
58
67
let output = inner ( image) ;
59
- CACHE . with ( |cache| cache. borrow_mut ( ) . push ( ( ct , output) ) ) ;
68
+ CACHE . with ( |cache| cache. borrow_mut ( ) . push ( ( tracker , output) ) ) ;
60
69
hit = false ;
61
70
output
62
71
} ) ;
@@ -75,40 +84,69 @@ fn describe(image: TrackedImage) -> &'static str {
75
84
#[ derive( Copy , Clone ) ]
76
85
struct TrackedImage < ' a > {
77
86
inner : & ' a Image ,
78
- tracker : Option < & ' a ImageConstraint > ,
87
+ tracker : Option < & ' a ImageTracker > ,
79
88
}
80
89
81
90
impl < ' a > TrackedImage < ' a > {
82
91
fn width ( & self ) -> u32 {
83
92
let output = self . inner . width ( ) ;
84
93
if let Some ( tracker) = & self . tracker {
85
- tracker. width . set ( Some ( output) ) ;
94
+ tracker. width . track ( & output) ;
86
95
}
87
96
output
88
97
}
89
98
90
99
fn height ( & self ) -> u32 {
91
100
let output = self . inner . height ( ) ;
92
101
if let Some ( tracker) = & self . tracker {
93
- tracker. height . set ( Some ( output) ) ;
102
+ tracker. height . track ( & output) ;
94
103
}
95
104
output
96
105
}
97
106
}
98
107
99
108
#[ derive( Debug , Default ) ]
100
- struct ImageConstraint {
101
- width : Cell < Option < u32 > > ,
102
- height : Cell < Option < u32 > > ,
109
+ struct ImageTracker {
110
+ width : HashTracker < u32 > ,
111
+ height : HashTracker < u32 > ,
103
112
}
104
113
105
- impl ImageConstraint {
114
+ impl ImageTracker {
106
115
fn valid ( & self , image : & Image ) -> bool {
107
- self . width . get ( ) . map_or ( true , |v| v == image. width ( ) )
108
- && self . height . get ( ) . map_or ( true , |v| v == image. height ( ) )
116
+ self . width . valid ( & image. width ( ) ) && self . height . valid ( & image. height ( ) )
117
+ }
118
+ }
119
+
120
+ #[ derive( Default ) ]
121
+ struct HashTracker < T : Hash > ( Cell < Option < NonZeroU128 > > , PhantomData < T > ) ;
122
+
123
+ impl < T : Hash > HashTracker < T > {
124
+ fn valid ( & self , value : & T ) -> bool {
125
+ self . 0 . get ( ) . map_or ( true , |v| v == siphash ( value) )
126
+ }
127
+
128
+ fn track ( & self , value : & T ) {
129
+ self . 0 . set ( Some ( siphash ( value) ) ) ;
130
+ }
131
+ }
132
+
133
+ impl < T : Hash > Debug for HashTracker < T > {
134
+ fn fmt ( & self , f : & mut Formatter ) -> fmt:: Result {
135
+ write ! ( f, "HashTracker({:?})" , self . 0 )
109
136
}
110
137
}
111
138
139
+ /// Produce a non zero 128-bit hash of the value.
140
+ fn siphash < T : Hash > ( value : & T ) -> NonZeroU128 {
141
+ let mut state = SipHasher :: new ( ) ;
142
+ value. hash ( & mut state) ;
143
+ state
144
+ . finish128 ( )
145
+ . as_u128 ( )
146
+ . try_into ( )
147
+ . unwrap_or ( NonZeroU128 :: new ( u128:: MAX ) . unwrap ( ) )
148
+ }
149
+
112
150
/// A raster image.
113
151
struct Image {
114
152
width : u32 ,
0 commit comments