@@ -9,6 +9,45 @@ use crate::CrcParams;
99use crc:: Algorithm ;
1010use crc:: Table ;
1111
12+ // Caching for custom CRC algorithms to prevent repeated memory leaks
13+ #[ cfg( feature = "alloc" ) ]
14+ #[ cfg( feature = "std" ) ]
15+ use std:: collections:: HashMap ;
16+ #[ cfg( feature = "alloc" ) ]
17+ #[ cfg( feature = "std" ) ]
18+ use std:: sync:: { Mutex , OnceLock } ;
19+
20+ #[ cfg( feature = "alloc" ) ]
21+ #[ cfg( all( not( feature = "std" ) , feature = "cache" ) ) ]
22+ use hashbrown:: HashMap ;
23+ #[ cfg( feature = "alloc" ) ]
24+ #[ cfg( all( not( feature = "std" ) , feature = "cache" ) ) ]
25+ use spin:: { Mutex , Once } ;
26+
27+ // Cache key types for custom algorithms
28+ #[ cfg( feature = "alloc" ) ]
29+ type Crc32Key = ( u32 , u32 , bool , bool , u32 , u32 ) ;
30+ #[ cfg( feature = "alloc" ) ]
31+ type Crc64Key = ( u64 , u64 , bool , bool , u64 , u64 ) ;
32+
33+ // Global caches for custom algorithms (std version)
34+ #[ cfg( feature = "alloc" ) ]
35+ #[ cfg( feature = "std" ) ]
36+ static CUSTOM_CRC32_CACHE : OnceLock < Mutex < HashMap < Crc32Key , & ' static Algorithm < u32 > > > > =
37+ OnceLock :: new ( ) ;
38+ #[ cfg( feature = "alloc" ) ]
39+ #[ cfg( feature = "std" ) ]
40+ static CUSTOM_CRC64_CACHE : OnceLock < Mutex < HashMap < Crc64Key , & ' static Algorithm < u64 > > > > =
41+ OnceLock :: new ( ) ;
42+
43+ // Global caches for custom algorithms (no_std + cache version)
44+ #[ cfg( feature = "alloc" ) ]
45+ #[ cfg( all( not( feature = "std" ) , feature = "cache" ) ) ]
46+ static CUSTOM_CRC32_CACHE : Once < Mutex < HashMap < Crc32Key , & ' static Algorithm < u32 > > > > = Once :: new ( ) ;
47+ #[ cfg( feature = "alloc" ) ]
48+ #[ cfg( all( not( feature = "std" ) , feature = "cache" ) ) ]
49+ static CUSTOM_CRC64_CACHE : Once < Mutex < HashMap < Crc64Key , & ' static Algorithm < u64 > > > > = Once :: new ( ) ;
50+
1251#[ allow( unused) ]
1352const RUST_CRC32_AIXM : crc:: Crc < u32 , Table < 16 > > =
1453 crc:: Crc :: < u32 , Table < 16 > > :: new ( & crc:: CRC_32_AIXM ) ;
@@ -104,21 +143,86 @@ pub(crate) fn update(state: u64, data: &[u8], params: CrcParams) -> u64 {
104143 extern crate alloc;
105144 use alloc:: boxed:: Box ;
106145
107- let algorithm: Algorithm < u32 > = Algorithm {
108- width : params. width ,
109- poly : params. poly as u32 ,
110- init : params. init as u32 ,
111- refin : params. refin ,
112- refout : params. refout ,
113- xorout : params. xorout as u32 ,
114- check : params. check as u32 ,
115- residue : 0x00000000 , // unused in this context
116- } ;
117-
118- // ugly, but the crc crate is difficult to work with...
119- let static_algorithm = Box :: leak ( Box :: new ( algorithm) ) ;
120-
121- crc:: Crc :: < u32 , Table < 16 > > :: new ( static_algorithm)
146+ // Use cache if std or cache feature is enabled
147+ #[ cfg( any( feature = "std" , feature = "cache" ) ) ]
148+ {
149+ let key: Crc32Key = (
150+ params. poly as u32 ,
151+ params. init as u32 ,
152+ params. refin ,
153+ params. refout ,
154+ params. xorout as u32 ,
155+ params. check as u32 ,
156+ ) ;
157+
158+ #[ cfg( feature = "std" ) ]
159+ {
160+ let cache =
161+ CUSTOM_CRC32_CACHE . get_or_init ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
162+ let mut cache_guard = cache. lock ( ) . unwrap ( ) ;
163+
164+ let static_algorithm =
165+ cache_guard. entry ( key) . or_insert_with ( || {
166+ let algorithm = Algorithm {
167+ width : params. width ,
168+ poly : params. poly as u32 ,
169+ init : params. init as u32 ,
170+ refin : params. refin ,
171+ refout : params. refout ,
172+ xorout : params. xorout as u32 ,
173+ check : params. check as u32 ,
174+ residue : 0x00000000 ,
175+ } ;
176+ Box :: leak ( Box :: new ( algorithm) )
177+ } ) ;
178+
179+ crc:: Crc :: < u32 , Table < 16 > > :: new ( static_algorithm)
180+ }
181+
182+ #[ cfg( all( not( feature = "std" ) , feature = "cache" ) ) ]
183+ {
184+ let cache =
185+ CUSTOM_CRC32_CACHE . call_once ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
186+ let mut cache_guard = cache. lock ( ) ;
187+
188+ let static_algorithm =
189+ cache_guard. entry ( key) . or_insert_with ( || {
190+ let algorithm = Algorithm {
191+ width : params. width ,
192+ poly : params. poly as u32 ,
193+ init : params. init as u32 ,
194+ refin : params. refin ,
195+ refout : params. refout ,
196+ xorout : params. xorout as u32 ,
197+ check : params. check as u32 ,
198+ residue : 0x00000000 ,
199+ } ;
200+ Box :: leak ( Box :: new ( algorithm) )
201+ } ) ;
202+
203+ crc:: Crc :: < u32 , Table < 16 > > :: new ( static_algorithm)
204+ }
205+ }
206+
207+ // Without cache, just leak (no_std without cache feature)
208+ #[ cfg( not( any( feature = "std" , feature = "cache" ) ) ) ]
209+ {
210+ let algorithm: Algorithm < u32 > = Algorithm {
211+ width : params. width ,
212+ poly : params. poly as u32 ,
213+ init : params. init as u32 ,
214+ refin : params. refin ,
215+ refout : params. refout ,
216+ xorout : params. xorout as u32 ,
217+ check : params. check as u32 ,
218+ residue : 0x00000000 , // unused in this context
219+ } ;
220+
221+ // ugly, but the crc crate is difficult to work with...
222+ let static_algorithm = Box :: leak ( Box :: new ( algorithm) ) ;
223+
224+ crc:: Crc :: < u32 , Table < 16 > > :: new ( static_algorithm)
225+ }
122226 }
123227 #[ cfg( not( feature = "alloc" ) ) ]
124228 panic ! ( "Custom CRC parameters require the 'alloc' feature" )
@@ -142,21 +246,86 @@ pub(crate) fn update(state: u64, data: &[u8], params: CrcParams) -> u64 {
142246 extern crate alloc;
143247 use alloc:: boxed:: Box ;
144248
145- let algorithm: Algorithm < u64 > = Algorithm {
146- width : params. width ,
147- poly : params. poly ,
148- init : params. init ,
149- refin : params. refin ,
150- refout : params. refout ,
151- xorout : params. xorout ,
152- check : params. check ,
153- residue : 0x0000000000000000 , // unused in this context
154- } ;
155-
156- // ugly, but the crc crate is difficult to work with...
157- let static_algorithm = Box :: leak ( Box :: new ( algorithm) ) ;
158-
159- crc:: Crc :: < u64 , Table < 16 > > :: new ( static_algorithm)
249+ // Use cache if std or cache feature is enabled
250+ #[ cfg( any( feature = "std" , feature = "cache" ) ) ]
251+ {
252+ let key: Crc64Key = (
253+ params. poly ,
254+ params. init ,
255+ params. refin ,
256+ params. refout ,
257+ params. xorout ,
258+ params. check ,
259+ ) ;
260+
261+ #[ cfg( feature = "std" ) ]
262+ {
263+ let cache =
264+ CUSTOM_CRC64_CACHE . get_or_init ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
265+ let mut cache_guard = cache. lock ( ) . unwrap ( ) ;
266+
267+ let static_algorithm =
268+ cache_guard. entry ( key) . or_insert_with ( || {
269+ let algorithm = Algorithm {
270+ width : params. width ,
271+ poly : params. poly ,
272+ init : params. init ,
273+ refin : params. refin ,
274+ refout : params. refout ,
275+ xorout : params. xorout ,
276+ check : params. check ,
277+ residue : 0x0000000000000000 ,
278+ } ;
279+ Box :: leak ( Box :: new ( algorithm) )
280+ } ) ;
281+
282+ crc:: Crc :: < u64 , Table < 16 > > :: new ( static_algorithm)
283+ }
284+
285+ #[ cfg( all( not( feature = "std" ) , feature = "cache" ) ) ]
286+ {
287+ let cache =
288+ CUSTOM_CRC64_CACHE . call_once ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
289+ let mut cache_guard = cache. lock ( ) ;
290+
291+ let static_algorithm =
292+ cache_guard. entry ( key) . or_insert_with ( || {
293+ let algorithm = Algorithm {
294+ width : params. width ,
295+ poly : params. poly ,
296+ init : params. init ,
297+ refin : params. refin ,
298+ refout : params. refout ,
299+ xorout : params. xorout ,
300+ check : params. check ,
301+ residue : 0x0000000000000000 ,
302+ } ;
303+ Box :: leak ( Box :: new ( algorithm) )
304+ } ) ;
305+
306+ crc:: Crc :: < u64 , Table < 16 > > :: new ( static_algorithm)
307+ }
308+ }
309+
310+ // Without cache, just leak (no_std without cache feature)
311+ #[ cfg( not( any( feature = "std" , feature = "cache" ) ) ) ]
312+ {
313+ let algorithm: Algorithm < u64 > = Algorithm {
314+ width : params. width ,
315+ poly : params. poly ,
316+ init : params. init ,
317+ refin : params. refin ,
318+ refout : params. refout ,
319+ xorout : params. xorout ,
320+ check : params. check ,
321+ residue : 0x0000000000000000 , // unused in this context
322+ } ;
323+
324+ // ugly, but the crc crate is difficult to work with...
325+ let static_algorithm = Box :: leak ( Box :: new ( algorithm) ) ;
326+
327+ crc:: Crc :: < u64 , Table < 16 > > :: new ( static_algorithm)
328+ }
160329 }
161330 #[ cfg( not( feature = "alloc" ) ) ]
162331 panic ! ( "Custom CRC parameters require the 'alloc' feature" )
0 commit comments