Skip to content

Commit 12dd758

Browse files
committed
Provide compute method implementations in ConcurrentReferenceHashMap
Closes gh-35794
1 parent 5aec239 commit 12dd758

File tree

2 files changed

+197
-43
lines changed

2 files changed

+197
-43
lines changed

spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@
3333
import java.util.concurrent.ConcurrentMap;
3434
import java.util.concurrent.atomic.AtomicInteger;
3535
import java.util.concurrent.locks.ReentrantLock;
36+
import java.util.function.BiFunction;
37+
import java.util.function.Function;
3638

3739
import org.springframework.lang.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
@@ -365,6 +367,118 @@ protected V execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry)
365367
});
366368
}
367369

370+
@Override
371+
@Nullable
372+
public V computeIfAbsent(@Nullable K key, Function<? super K, ? extends V> mappingFunction) {
373+
return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.RESIZE) {
374+
@Override
375+
protected @Nullable V execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry, @Nullable Entries<V> entries) {
376+
if (entry != null) {
377+
return entry.getValue();
378+
}
379+
V value = mappingFunction.apply(key);
380+
// Add entry only if not null
381+
if (value != null) {
382+
Assert.state(entries != null, "No entries segment");
383+
entries.add(value);
384+
}
385+
return value;
386+
}
387+
});
388+
}
389+
390+
@Override
391+
@Nullable
392+
public V computeIfPresent(@Nullable K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
393+
return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.RESIZE) {
394+
@Override
395+
protected @Nullable V execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry, @Nullable Entries<V> entries) {
396+
if (entry != null) {
397+
V oldValue = entry.getValue();
398+
V value = remappingFunction.apply(key, oldValue);
399+
if (value != null) {
400+
// Replace entry
401+
entry.setValue(value);
402+
return value;
403+
}
404+
else {
405+
// Remove entry
406+
if (ref != null) {
407+
ref.release();
408+
}
409+
}
410+
}
411+
return null;
412+
}
413+
});
414+
}
415+
416+
@Override
417+
@Nullable
418+
public V compute(@Nullable K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
419+
return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.RESIZE) {
420+
@Override
421+
protected @Nullable V execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry, @Nullable Entries<V> entries) {
422+
V oldValue = null;
423+
if (entry != null) {
424+
oldValue = entry.getValue();
425+
}
426+
V value = remappingFunction.apply(key, oldValue);
427+
if (value != null) {
428+
if (entry != null) {
429+
// Replace entry
430+
entry.setValue(value);
431+
}
432+
else {
433+
// Add entry
434+
Assert.state(entries != null, "No entries segment");
435+
entries.add(value);
436+
}
437+
return value;
438+
}
439+
else {
440+
// Remove entry
441+
if (ref != null) {
442+
ref.release();
443+
}
444+
}
445+
return null;
446+
}
447+
});
448+
}
449+
450+
@Override
451+
@Nullable
452+
public V merge(@Nullable K key, @Nullable V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
453+
return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.RESIZE) {
454+
@Override
455+
protected @Nullable V execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry, @Nullable Entries<V> entries) {
456+
if (entry != null) {
457+
V oldValue = entry.getValue();
458+
V newValue = remappingFunction.apply(oldValue, value);
459+
if (newValue != null) {
460+
// Replace entry
461+
entry.setValue(newValue);
462+
return newValue;
463+
}
464+
else {
465+
// Remove entry
466+
if (ref != null) {
467+
ref.release();
468+
}
469+
return null;
470+
}
471+
}
472+
else {
473+
// Add entry
474+
Assert.state(entries != null, "No entries segment");
475+
entries.add(value);
476+
return value;
477+
}
478+
}
479+
});
480+
}
481+
368482
@Override
369483
public void clear() {
370484
for (Segment segment : this.segments) {

0 commit comments

Comments
 (0)