3333import java .util .concurrent .ConcurrentMap ;
3434import java .util .concurrent .atomic .AtomicInteger ;
3535import java .util .concurrent .locks .ReentrantLock ;
36+ import java .util .function .BiFunction ;
37+ import java .util .function .Function ;
3638
3739import org .jspecify .annotations .Nullable ;
3840
3941/**
40- * A {@link ConcurrentHashMap} that uses {@link ReferenceType#SOFT soft} or
42+ * A {@link ConcurrentHashMap} variant that uses {@link ReferenceType#SOFT soft} or
4143 * {@linkplain ReferenceType#WEAK weak} references for both {@code keys} and {@code values}.
4244 *
4345 * <p>This class can be used as an alternative to
@@ -320,7 +322,7 @@ protected Boolean execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> e
320322 return false ;
321323 }
322324 });
323- return ( Boolean .TRUE .equals (result ) );
325+ return Boolean .TRUE .equals (result );
324326 }
325327
326328 @ Override
@@ -335,7 +337,7 @@ protected Boolean execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> e
335337 return false ;
336338 }
337339 });
338- return ( Boolean .TRUE .equals (result ) );
340+ return Boolean .TRUE .equals (result );
339341 }
340342
341343 @ Override
@@ -353,6 +355,114 @@ protected Boolean execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> e
353355 });
354356 }
355357
358+ @ Override
359+ public @ Nullable V computeIfAbsent (@ Nullable K key , Function <@ Nullable ? super K , @ Nullable ? extends V > mappingFunction ) {
360+ return doTask (key , new Task <V >(TaskOption .RESTRUCTURE_BEFORE , TaskOption .RESIZE ) {
361+ @ Override
362+ protected @ Nullable V execute (@ Nullable Reference <K , V > ref , @ Nullable Entry <K , V > entry , @ Nullable Entries <V > entries ) {
363+ if (entry != null ) {
364+ return entry .getValue ();
365+ }
366+ V value = mappingFunction .apply (key );
367+ // Add entry only if not null
368+ if (value != null ) {
369+ Assert .state (entries != null , "No entries segment" );
370+ entries .add (value );
371+ }
372+ return value ;
373+ }
374+ });
375+ }
376+
377+ @ Override
378+ public @ Nullable V computeIfPresent (@ Nullable K key , BiFunction <@ Nullable ? super K , @ Nullable ? super V , @ Nullable ? extends V > remappingFunction ) {
379+ return doTask (key , new Task <V >(TaskOption .RESTRUCTURE_BEFORE , TaskOption .RESIZE ) {
380+ @ Override
381+ protected @ Nullable V execute (@ Nullable Reference <K , V > ref , @ Nullable Entry <K , V > entry , @ Nullable Entries <V > entries ) {
382+ if (entry != null ) {
383+ V oldValue = entry .getValue ();
384+ V value = remappingFunction .apply (key , oldValue );
385+ if (value != null ) {
386+ // Replace entry
387+ entry .setValue (value );
388+ return value ;
389+ }
390+ else {
391+ // Remove entry
392+ if (ref != null ) {
393+ ref .release ();
394+ }
395+ }
396+ }
397+ return null ;
398+ }
399+ });
400+ }
401+
402+ @ Override
403+ public @ Nullable V compute (@ Nullable K key , BiFunction <@ Nullable ? super K , @ Nullable ? super V , @ Nullable ? extends V > remappingFunction ) {
404+ return doTask (key , new Task <V >(TaskOption .RESTRUCTURE_BEFORE , TaskOption .RESIZE ) {
405+ @ Override
406+ protected @ Nullable V execute (@ Nullable Reference <K , V > ref , @ Nullable Entry <K , V > entry , @ Nullable Entries <V > entries ) {
407+ V oldValue = null ;
408+ if (entry != null ) {
409+ oldValue = entry .getValue ();
410+ }
411+ V value = remappingFunction .apply (key , oldValue );
412+ if (value != null ) {
413+ if (entry != null ) {
414+ // Replace entry
415+ entry .setValue (value );
416+ }
417+ else {
418+ // Add entry
419+ Assert .state (entries != null , "No entries segment" );
420+ entries .add (value );
421+ }
422+ return value ;
423+ }
424+ else {
425+ // Remove entry
426+ if (ref != null ) {
427+ ref .release ();
428+ }
429+ }
430+ return null ;
431+ }
432+ });
433+ }
434+
435+ @ Override
436+ public @ Nullable V merge (@ Nullable K key , @ Nullable V value , BiFunction <@ Nullable ? super V , @ Nullable ? super V , @ Nullable ? extends V > remappingFunction ) {
437+ return doTask (key , new Task <V >(TaskOption .RESTRUCTURE_BEFORE , TaskOption .RESIZE ) {
438+ @ Override
439+ protected @ Nullable V execute (@ Nullable Reference <K , V > ref , @ Nullable Entry <K , V > entry , @ Nullable Entries <V > entries ) {
440+ if (entry != null ) {
441+ V oldValue = entry .getValue ();
442+ V newValue = remappingFunction .apply (oldValue , value );
443+ if (newValue != null ) {
444+ // Replace entry
445+ entry .setValue (newValue );
446+ return newValue ;
447+ }
448+ else {
449+ // Remove entry
450+ if (ref != null ) {
451+ ref .release ();
452+ }
453+ return null ;
454+ }
455+ }
456+ else {
457+ // Add entry
458+ Assert .state (entries != null , "No entries segment" );
459+ entries .add (value );
460+ return value ;
461+ }
462+ }
463+ });
464+ }
465+
356466 @ Override
357467 public void clear () {
358468 for (Segment segment : this .segments ) {
0 commit comments