@@ -414,6 +414,11 @@ ZVirtualMemory ZMappedCache::remove_vmem(ZMappedCacheEntry* const entry, size_t
414414template <typename SelectFunction, typename ConsumeFunction>
415415bool ZMappedCache::try_remove_vmem_size_class (size_t min_size, SelectFunction select, ConsumeFunction consume) {
416416new_max_size:
417+ if (_size < min_size) {
418+ // Not enough left in cache to satisfy the min_size
419+ return false ;
420+ }
421+
417422 // Query the max select size possible given the size of the cache
418423 const size_t max_size = select (_size);
419424
@@ -648,6 +653,37 @@ ZVirtualMemory ZMappedCache::remove_contiguous(size_t size) {
648653 return result;
649654}
650655
656+ ZVirtualMemory ZMappedCache::remove_contiguous_power_of_2 (size_t min_size, size_t max_size) {
657+ precond (is_aligned (min_size, ZGranuleSize));
658+ precond (is_power_of_2 (min_size));
659+ precond (is_aligned (max_size, ZGranuleSize));
660+ precond (is_power_of_2 (max_size));
661+ precond (min_size <= max_size);
662+
663+ ZVirtualMemory result;
664+
665+ const auto select_size_fn = [&](size_t size) {
666+ // Always select a power of 2 within the [min_size, max_size] interval.
667+ return clamp (round_down_power_of_2 (size), min_size, max_size);
668+ };
669+
670+ const auto consume_vmem_fn = [&](ZVirtualMemory vmem) {
671+ assert (result.is_null (), " only consume once" );
672+ assert (min_size <= vmem.size () && vmem.size () <= max_size,
673+ " Must be %zu <= %zu <= %zu" , min_size, vmem.size (), max_size);
674+ assert (is_power_of_2 (vmem.size ()), " Must be power_of_2(%zu)" , vmem.size ());
675+
676+ result = vmem;
677+
678+ // Only require one vmem
679+ return true ;
680+ };
681+
682+ scan_remove_vmem<RemovalStrategy::SizeClasses>(min_size, select_size_fn, consume_vmem_fn);
683+
684+ return result;
685+ }
686+
651687size_t ZMappedCache::remove_discontiguous (size_t size, ZArray<ZVirtualMemory>* out) {
652688 return remove_discontiguous_with_strategy<RemovalStrategy::SizeClasses>(size, out);
653689}
0 commit comments