@@ -22,37 +22,59 @@ local DOUBLE_STORAGE_TYPEOF = ffi.typeof('$[?]', DOUBLE_TYPEOF)
2222local STORAGE_SIZES = {}
2323
2424--- @type evolved.realloc
25- local function float_realloc (old_storage , old_size , new_size )
26- if old_storage then
27- assert (STORAGE_SIZES [old_storage ] == old_size )
28- end
25+ local function float_realloc (src , src_size , dst_size )
26+ if dst_size == 0 then
27+ assert (src and src_size > 0 )
28+ local expected_src_size = STORAGE_SIZES [src ]
29+ assert (expected_src_size == src_size )
30+ STORAGE_SIZES [src ] = nil
31+ return
32+ else
33+ if src then
34+ assert (src_size > 0 )
35+ local expected_src_size = STORAGE_SIZES [src ]
36+ assert (expected_src_size == src_size )
37+ else
38+ assert (src_size == 0 )
39+ end
2940
30- local new_storage = ffi .new (FLOAT_STORAGE_TYPEOF , new_size + 1 )
41+ local dst = ffi .new (FLOAT_STORAGE_TYPEOF , dst_size + 1 )
42+ STORAGE_SIZES [dst ] = dst_size
3143
32- STORAGE_SIZES [new_storage ] = new_size
44+ if src then
45+ ffi .copy (dst + 1 , src + 1 , math.min (src_size , dst_size ) * FLOAT_SIZEOF )
46+ end
3347
34- if old_storage then
35- ffi .copy (new_storage + 1 , old_storage + 1 , math.min (old_size , new_size ) * FLOAT_SIZEOF )
48+ return dst
3649 end
37-
38- return new_storage
3950end
4051
4152--- @type evolved.realloc
42- local function double_realloc (old_storage , old_size , new_size )
43- if old_storage then
44- assert (STORAGE_SIZES [old_storage ] == old_size )
45- end
53+ local function double_realloc (src , src_size , dst_size )
54+ if dst_size == 0 then
55+ assert (src and src_size > 0 )
56+ local expected_src_size = STORAGE_SIZES [src ]
57+ assert (expected_src_size == src_size )
58+ STORAGE_SIZES [src ] = nil
59+ return
60+ else
61+ if src then
62+ assert (src_size > 0 )
63+ local expected_src_size = STORAGE_SIZES [src ]
64+ assert (expected_src_size == src_size )
65+ else
66+ assert (src_size == 0 )
67+ end
4668
47- local new_storage = ffi .new (DOUBLE_STORAGE_TYPEOF , new_size + 1 )
69+ local dst = ffi .new (DOUBLE_STORAGE_TYPEOF , dst_size + 1 )
70+ STORAGE_SIZES [dst ] = dst_size
4871
49- STORAGE_SIZES [new_storage ] = new_size
72+ if src then
73+ ffi .copy (dst + 1 , src + 1 , math.min (src_size , dst_size ) * DOUBLE_SIZEOF )
74+ end
5075
51- if old_storage then
52- ffi .copy (new_storage + 1 , old_storage + 1 , math.min (old_size , new_size ) * DOUBLE_SIZEOF )
76+ return dst
5377 end
54-
55- return new_storage
5678end
5779
5880--- @type evolved.compmove
399421
400422 evo .collect_garbage ()
401423end
424+
425+ do
426+ evo .collect_garbage ()
427+
428+ local alloc_call_count = 0
429+ local free_call_count = 0
430+ local resize_call_count = 0
431+
432+ local function ctor_realloc ()
433+ --- @type evolved.realloc
434+ return function (src , src_size , dst_size )
435+ if dst_size == 0 then
436+ assert (src and src_size > 0 )
437+ free_call_count = free_call_count + 1
438+ return
439+ else
440+ if src then
441+ assert (src_size > 0 )
442+ resize_call_count = resize_call_count + 1
443+ else
444+ assert (src_size == 0 )
445+ alloc_call_count = alloc_call_count + 1
446+ end
447+
448+ local dst = {}
449+
450+ if src then
451+ for i = 1 , math.min (src_size , dst_size ) do
452+ dst [i ] = src [i ]
453+ end
454+ end
455+
456+ return dst
457+ end
458+ end
459+ end
460+
461+ do
462+ local realloc1 = ctor_realloc ()
463+ local realloc2 = ctor_realloc ()
464+
465+ local f1 = evo .builder ():default (44 ):realloc (realloc1 ):build ()
466+
467+ alloc_call_count , free_call_count , resize_call_count = 0 , 0 , 0
468+
469+ do
470+ local e1 = evo .builder ():set (f1 , 21 ):build ()
471+ assert (evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == 21 )
472+ assert (alloc_call_count == 1 and free_call_count == 0 )
473+
474+ local e2 = evo .builder ():set (f1 , 42 ):build ()
475+ assert (evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == 21 )
476+ assert (evo .has (e2 , f1 ) and evo .get (e2 , f1 ) == 42 )
477+ assert (alloc_call_count == 1 and free_call_count == 0 )
478+
479+ evo .collect_garbage ()
480+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
481+
482+ evo .destroy (e1 )
483+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
484+
485+ evo .collect_garbage ()
486+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
487+
488+ evo .destroy (e2 )
489+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
490+
491+ evo .collect_garbage ()
492+ assert (alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0 )
493+ end
494+
495+ alloc_call_count , free_call_count , resize_call_count = 0 , 0 , 0
496+
497+ do
498+ local es , ec = evo .multi_spawn (10 , { [f1 ] = 84 })
499+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
500+
501+ for i = 1 , ec / 2 do evo .destroy (es [i ]) end
502+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
503+
504+ evo .collect_garbage ()
505+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 1 )
506+
507+ evo .set (f1 , evo .REALLOC , realloc2 )
508+ assert (alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 1 )
509+
510+ for i = 1 , ec do evo .destroy (es [i ]) end
511+ evo .collect_garbage ()
512+ assert (alloc_call_count == 2 and free_call_count == 2 and resize_call_count == 1 )
513+ end
514+
515+ alloc_call_count , free_call_count , resize_call_count = 0 , 0 , 0
516+
517+ do
518+ local e1 = evo .builder ():set (f1 , 24 ):build ()
519+ assert (evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == 24 )
520+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
521+
522+ evo .set (f1 , evo .TAG )
523+ assert (evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == nil )
524+ assert (alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0 )
525+
526+ local es , ec = evo .multi_spawn (20 , { [f1 ] = 48 })
527+ for i = 1 , ec do assert (evo .has (es [i ], f1 ) and evo .get (es [i ], f1 ) == nil ) end
528+ assert (alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0 )
529+
530+ evo .remove (f1 , evo .TAG )
531+ assert (evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == 44 )
532+ for i = 1 , ec do assert (evo .has (es [i ], f1 ) and evo .get (es [i ], f1 ) == 44 ) end
533+ assert (alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 0 )
534+
535+ evo .destroy (e1 )
536+ for i = 1 , ec do evo .destroy (es [i ]) end
537+ assert (alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 0 )
538+
539+ evo .collect_garbage ()
540+ assert (alloc_call_count == 2 and free_call_count == 2 and resize_call_count == 0 )
541+ end
542+
543+ alloc_call_count , free_call_count , resize_call_count = 0 , 0 , 0
544+
545+ do
546+ local e1 = evo .builder ():set (f1 , 100 ):build ()
547+ assert (evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == 100 )
548+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
549+
550+ evo .set (f1 , evo .TAG )
551+ assert (evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == nil )
552+ assert (alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0 )
553+
554+ local es , ec = evo .multi_spawn (20 , { [f1 ] = 48 })
555+ for i = 1 , ec do assert (evo .has (es [i ], f1 ) and evo .get (es [i ], f1 ) == nil ) end
556+ assert (alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0 )
557+
558+ evo .destroy (e1 )
559+ for i = 1 , ec do evo .destroy (es [i ]) end
560+ assert (alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0 )
561+
562+ evo .collect_garbage ()
563+ assert (alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0 )
564+ end
565+ end
566+
567+
568+ do
569+ local realloc = ctor_realloc ()
570+
571+ local f1 = evo .builder ():realloc (realloc ):build ()
572+
573+ alloc_call_count , free_call_count , resize_call_count = 0 , 0 , 0
574+
575+ do
576+ local e1 = evo .builder ():set (f1 , 42 ):build ()
577+ assert (evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == 42 )
578+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
579+
580+ evo .destroy (e1 )
581+ assert (not evo .has (e1 , f1 ) and evo .get (e1 , f1 ) == nil )
582+ assert (alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0 )
583+
584+ evo .set (f1 , evo .TAG )
585+ assert (alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0 )
586+ end
587+ end
588+ end
0 commit comments